> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Migración a v6

> Qué cambió entre @squarecloud/api v5 y v6: datos planos en lugar de clases, ids como primer argumento, una única clase de error, timeouts y reintentos. Una tabla método por método.

La v6 es una reescritura: un cliente plano, datos planos en lugar de clases, ids como primer argumento y una única clase de error. La mayoría de los cambios son mecánicos.

## De un vistazo

| v5                                                                                                | v6                                                                                                                                                                                    |
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Clases con métodos (`app.start()`)                                                                | Datos planos; métodos en el cliente (`api.apps.start(appId)`)                                                                                                                         |
| `Collection`                                                                                      | `Array`                                                                                                                                                                               |
| Campos de clase en camelCase con `Date`s (`createdAt`, `modifiedAt`, `uptime`)                    | Los campos y valores de la propia API (`created_at` y `modified` como strings ISO, `uptime` en ms)                                                                                    |
| `Buffer`                                                                                          | `Uint8Array` (un `Buffer` se sigue aceptando como entrada)                                                                                                                            |
| Las mutaciones devuelven `Promise<boolean>` (siempre `true`)                                      | `Promise<void>`, o los datos que devuelve la API (`envs.*` → `EnvVars`, `deploys.setWebhook` → URL, `deploys.linkGithubApp` → `LinkedRepository`, `resetCredentials` → la contraseña) |
| `SquareCloudAPIError extends TypeError` solo con `code`                                           | `extends Error` con `status`, `code`, `message` (el del servidor), `method`, `path`, `cause`                                                                                          |
| Eventos (`userUpdate`, `statusUpdate`, `logsUpdate`, `snapshotsUpdate`) y `api.cache`/`app.cache` | Eliminados: mantén tu propio estado                                                                                                                                                   |
| `api.api.request()` (el `APIService` sin procesar)                                                | Eliminado: cada operación tiene un método                                                                                                                                             |
| Sin timeout, sin reintentos                                                                       | Timeout de 30 s por intento, reintentos solo para fallos seguros (consulta [Cambios de comportamiento](#cambios-de-comportamiento))                                                   |
| Node.js >= 20                                                                                     | Node.js >= 22, Deno, Bun, edge                                                                                                                                                        |
| `@squarecloud/api-types`                                                                          | Los tipos se incluyen en el SDK (`import type { App } from "@squarecloud/api"`)                                                                                                       |

## Construcción y opciones

| v5                        | v6                                                                                   | Notas                                                                                                                                                                 |
| ------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `new SquareCloudAPI(key)` | `new SquareCloudAPI(key, { baseUrl?, timeoutMs?, maxRetries?, userAgent?, fetch? })` | Una clave vacía o compuesta solo por espacios lanza un `TypeError`.                                                                                                   |
| `SquareCloudAPI.apiInfo`  | `BASE_URL` y `{ baseUrl }`                                                           | `BASE_URL` = `https://api.squarecloud.app/v2`.                                                                                                                        |
| (ninguno)                 | `timeoutMs` (30000)                                                                  | Por intento; las llamadas mantenidas abiertas y `ai.chat` esperan al menos 120 s. `<= 0`, `Infinity` o `>= 2^31` desactiva todos los timeouts, incluidos los mínimos. |
| (ninguno)                 | `maxRetries` (2)                                                                     | Solo errores de red en GET y los códigos 503 indicados; nunca 429.                                                                                                    |
| (ninguno)                 | `userAgent`                                                                          | Reemplaza todo el encabezado (por defecto `squarecloud-sdk-js/<version>`).                                                                                            |
| (ninguno)                 | `fetch`                                                                              | `fetch` personalizado (proxies, trazas, tests).                                                                                                                       |

## Método por método

| v5                                                                           | v6                                                                                                             | Notas                                                                                                                                                                                             |
| ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api.user.get()` → `User`                                                    | `api.account.me()`                                                                                             | Devuelve `{ user, applications, databases }`.                                                                                                                                                     |
| `user.plan.expiresIn`                                                        | `new Date(user.plan.duration)`                                                                                 | Una marca de tiempo; `null` nunca caduca.                                                                                                                                                         |
| `api.user.snapshots(scope)`                                                  | `api.account.snapshots({ scope })`                                                                             |                                                                                                                                                                                                   |
| `api.service.status()`                                                       | `api.service.status()`                                                                                         | Nueva forma: `status`, `message`, `services`, `dependencies`...                                                                                                                                   |
| `api.applications.get()`                                                     | `(await api.account.me()).applications`                                                                        |                                                                                                                                                                                                   |
| `api.applications.get(id)` / `fetch(id)` / `app.fetch()`                     | `api.apps.get(id)`                                                                                             | También encuentra aplicaciones compartidas en workspaces.                                                                                                                                         |
| `app.isWebsite()`                                                            | `Boolean((await api.apps.get(id)).domain)`                                                                     |                                                                                                                                                                                                   |
| `api.applications.create(file)`                                              | `api.apps.create(file, { signal })`                                                                            | Una ruta, `Blob`/`File` o `Uint8Array`; sin timeout.                                                                                                                                              |
| `api.applications.statusAll()`                                               | `api.apps.statusAll({ workspaceId? })`                                                                         | Objetos planos `{ id, running, cpu?, ram? }` (la v5 anidaba `cpu`/`ram` dentro de `usage`).                                                                                                       |
| `statusAll()[i].fetch()` (`SimpleApplicationStatus`, `SimpleDatabaseStatus`) | `api.apps.status(id)` / `api.databases.status(id)`                                                             |                                                                                                                                                                                                   |
| `api.applications.domains()` / `loadBalancers()`                             | `api.apps.domains()` / `api.apps.loadBalancers()`                                                              |                                                                                                                                                                                                   |
| `app.getStatus()`                                                            | `api.apps.status(id, { raw? })`                                                                                | `cpu`, `ram`, `storage` y `network` están en el nivel superior (la v5 los anidaba dentro de `usage`); `uptime` es la marca de tiempo de inicio en ms (`null` cuando está detenida), no un `Date`. |
| `app.getLogs()`                                                              | `api.apps.logs(id)`                                                                                            |                                                                                                                                                                                                   |
| `app.getMetrics()`                                                           | `api.apps.metrics(id)`                                                                                         | El punto más reciente primero.                                                                                                                                                                    |
| `app.realtime()` → `Response` sin procesar                                   | `api.apps.realtime(id, { signal })`                                                                            | Un async iterable de eventos ya analizados.                                                                                                                                                       |
| `app.start()` / `stop()` / `restart()` / `delete()`                          | `api.apps.start(id)` / `stop(id)` / `restart(id)` / `delete(id)`                                               |                                                                                                                                                                                                   |
| `app.commit(file, fileName)`                                                 | `api.apps.commit(id, file, { path?, filename?, signal? })`                                                     |                                                                                                                                                                                                   |
| `app.files.list(path)`                                                       | `api.apps.files.list(id, path?)`                                                                               | Un directorio inexistente lanza 404 `FILE_NOT_FOUND` (antes era una lista vacía).                                                                                                                 |
| `app.files.read(path)` → `Buffer \| undefined`                               | `api.apps.files.read(id, path)` → `Uint8Array`                                                                 | Se solicita en base64 y se decodifica (la v5 leía un array de bytes). Bytes vacíos, nunca `undefined`, cuando la API no envía contenido.                                                          |
| `app.files.create(file, fileName, dir)`                                      | ``api.apps.files.write(id, `${dir}/${fileName}`, content)``                                                    | Un string es el **contenido** (se envía como texto plano); la v5 lo interpretaba como una ruta local. Los bytes se envían en base64. Un contenido vacío crea un archivo vacío.                    |
| `app.files.edit(file, path)`                                                 | `api.apps.files.write(id, path, content)`                                                                      | El mismo formato de envío que `write`: texto para strings, base64 para bytes.                                                                                                                     |
| `app.files.move(path, newPath)` / `delete(path)`                             | `api.apps.files.move(id, path, to)` / `delete(id, path)`                                                       |                                                                                                                                                                                                   |
| `app.envs.list()`                                                            | `api.apps.envs.get(id)`                                                                                        |                                                                                                                                                                                                   |
| `app.envs.set(envs)` / `replace(envs)` / `delete(keys)`                      | `api.apps.envs.set(id, envs)` / `replace(id, envs)` / `delete(id, keys)`                                       | Cada uno devuelve las variables resultantes.                                                                                                                                                      |
| `app.snapshots.list()`                                                       | `api.apps.snapshots.list(id)`                                                                                  | Los elementos ganan `name`, `runtime`, `origin`, `version_id` y una `url` de descarga firmada, todo tal como lo envía la API.                                                                     |
| `app.snapshots.create()`                                                     | `api.apps.snapshots.create(id)`                                                                                | `{ pending: true }` en un 202 (la v5 lanzaba un error); si no, `{ pending: false, url, key }`.                                                                                                    |
| `app.snapshots.download()` → `Buffer`                                        | `const s = await api.apps.snapshots.create(id)`, y después `if (!s.pending) await api.downloadSnapshot(s.url)` | Un `ReadableStream`, sin nada en memoria. Un snapshot pendiente (202) aún no tiene URL: la v5 lanzaba un error.                                                                                   |
| `snapshot.url` / `snapshot.download()`                                       | `snapshot.url` / `api.downloadSnapshot(snapshot.url)`                                                          | La URL firmada de la propia API (la v5 construía una incorrecta a partir del id del llamante).                                                                                                    |
| `app.snapshots.restore({ snapshotId, versionId })`                           | `api.apps.snapshots.restore(id, name, versionId)`                                                              | Pasa el `name` y el `version_id` de un snapshot del listado. Consulta [Snapshots](/es/sdks/js/snapshots#restaurar-un-snapshot) para ver los errores.                                              |
| `app.deploys.integrateGithubWebhook(token)`                                  | `api.apps.deploys.setWebhook(id, token)`                                                                       | Devuelve la URL del webhook (`""` cuando se elimina con `"@"`).                                                                                                                                   |
| `app.deploys.linkGithubApp({ repositoryName, repositoryBranch })`            | `api.apps.deploys.linkGithubApp(id, repository, branch)`                                                       | Posicional. Devuelve `{ id, full_name, branch }`. Ahora se aceptan claves de API (scope `apps:deploy`); la v5 necesitaba un JWT de sesión.                                                        |
| `app.deploys.unlinkGithubApp()` → `boolean`                                  | `api.apps.deploys.unlinkGithubApp(id)`                                                                         | Se resuelve en `void` (antes `boolean`). `400 GIT_NOT_CONFIGURED` cuando no hay nada vinculado.                                                                                                   |
| `app.deploys.list()` → `Deployment[][]`                                      | `api.apps.deploys.list(id)` → `DeployEvent[][]`                                                                | Un deploy fallido termina en `state: "error"` con `code` (y `message` cuando hay detalles); `source` es siempre `"git"`.                                                                          |
| `app.deploys.current()`                                                      | `api.apps.deploys.current(id)` → `DeployCurrent`                                                               | `{}` cuando no hay nada configurado.                                                                                                                                                              |
| `app.deploys.webhookURL()`                                                   | `(await api.apps.deploys.current(id)).webhook`                                                                 |                                                                                                                                                                                                   |
| `app.network` (solo en `WebsiteApplication`)                                 | `api.apps.network`                                                                                             | Cualquier id de aplicación; la API rechaza las aplicaciones que no son web.                                                                                                                       |
| `network.setCustomDomain(domain)`                                            | `api.apps.network.setDomain(id, domain)`                                                                       |                                                                                                                                                                                                   |
| `network.analytics({ start, end, contentType, ... })`                        | `api.apps.network.analytics(id, start, end, { content_type, ... })`                                            | `null` para una ventana vacía.                                                                                                                                                                    |
| `network.errors({ start, end, include4xx })`                                 | `api.apps.network.errors(id, start, end, { include_4xx })`                                                     | `null` para una ventana vacía.                                                                                                                                                                    |
| `network.logs({ start, end })` / `performance({ start, end })`               | `api.apps.network.logs(id, start, end)` / `performance(id, start, end)`                                        |                                                                                                                                                                                                   |
| `network.dns()` / `purgeCache()`                                             | `api.apps.network.dns(id)` / `purgeCache(id)`                                                                  |                                                                                                                                                                                                   |
| `api.databases.fetch(id)` / `db.fetch()`                                     | `api.databases.get(id)`                                                                                        |                                                                                                                                                                                                   |
| `api.databases.create(options)` / `statusAll()`                              | sin cambios                                                                                                    | `statusAll()` devuelve objetos planos `{ id, running, cpu?, ram? }`.                                                                                                                              |
| `db.getStatus()` / `getMetrics()`                                            | `api.databases.status(id, { raw? })` / `metrics(id)`                                                           | `ram` es la RAM en uso, p. ej. `"120.4MB"` (un número con `raw`). Las métricas llegan del punto más reciente al más antiguo.                                                                      |
| `db.start()` / `stop()` / `update(changes)` / `delete()`                     | `api.databases.start(id)` / `stop(id)` / `update(id, changes)` / `delete(id)`                                  |                                                                                                                                                                                                   |
| `db.credentials.certificate()`                                               | `api.databases.certificate(id)`                                                                                |                                                                                                                                                                                                   |
| `db.credentials.reset(type)`                                                 | `api.databases.resetCredentials(id, type)`                                                                     | La nueva contraseña (`""` para `"certificate"`).                                                                                                                                                  |
| `db.snapshots.list()` / `create()` / `download()`                            | `api.databases.snapshots.list(id)` / `create(id)` / `api.downloadSnapshot(url)`                                | `download()` igual que en las aplicaciones: `create(id)` y después `downloadSnapshot(s.url)` cuando no está pendiente.                                                                            |
| `db.snapshots.restore(snapshotId, versionId)`                                | `api.databases.snapshots.restore(id, name, versionId)`                                                         | Pasa el `name` y el `version_id` de un snapshot del listado.                                                                                                                                      |
| `api.workspaces.list()` / `fetch(id)` / `workspace.fetch()`                  | `api.workspaces.list()` / `get(id)`                                                                            |                                                                                                                                                                                                   |
| `api.workspaces.create({ name })`                                            | `api.workspaces.create(name)`                                                                                  | Devuelve `WorkspaceCreated` (`{ id, name }`).                                                                                                                                                     |
| `api.workspaces.delete(id)` / `workspace.delete()`                           | `api.workspaces.delete(id)`                                                                                    |                                                                                                                                                                                                   |
| `api.workspaces.leave(id)` / `workspace.leave()`                             | `api.workspaces.leave(id)`                                                                                     |                                                                                                                                                                                                   |
| `api.workspaces.generateInviteCode()`                                        | `api.workspaces.members.inviteCode()`                                                                          |                                                                                                                                                                                                   |
| `workspace.members.add(code, group)`                                         | `api.workspaces.members.add(workspaceId, code, group)`                                                         |                                                                                                                                                                                                   |
| `workspace.members.update(memberId, group)` / `remove(memberId)`             | `api.workspaces.members.update(workspaceId, memberId, group)` / `remove(workspaceId, memberId)`                |                                                                                                                                                                                                   |
| `workspace.applications.add(appId)` / `remove(appId)`                        | `api.workspaces.apps.add(workspaceId, appId)` / `remove(workspaceId, appId)`                                   |                                                                                                                                                                                                   |
| (ninguno)                                                                    | `api.ai.chat(request)`, `api.downloadSnapshot(url)`, `BASE_URL`                                                | Nuevo.                                                                                                                                                                                            |

## Tipos

Los tipos se incluyen en el SDK y reflejan los nombres de campo de la API. Los principales cambios de nombre respecto a `@squarecloud/api-types` y a las clases de la v5:

| v5                                                                                                                                                                            | v6                                                                                                  |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `Application`, `WebsiteApplication`, `BaseApplication`                                                                                                                        | `App` (`api.apps.get()`), `AppSummary` (`account.me()`), `AppCreated`                               |
| `ApplicationStatus`, `SimpleApplicationStatus`, `SimpleDatabaseStatus`                                                                                                        | `RuntimeStats` (`RuntimeStats<true>` con `{ raw: true }`), `StatusListItem`                         |
| `User`                                                                                                                                                                        | `Account` (`{ user, applications, databases }`), `User`, `Plan`                                     |
| `Snapshot`, `DatabaseSnapshot`                                                                                                                                                | `Snapshot`, `SnapshotCreated`                                                                       |
| `Deployment`, `DeploymentState`                                                                                                                                               | `DeployEvent`, `DeployCurrent` (con `DeployRepository`), `LinkedRepository`                         |
| Objetos de consulta de red                                                                                                                                                    | `AnalyticsFilters` (los filtros opcionales; `start` y `end` son argumentos)                         |
| `Workspace`                                                                                                                                                                   | `Workspace`, `WorkspaceCreated`, `WorkspaceGroup`                                                   |
| `APIErrorCode` (objeto en tiempo de ejecución)                                                                                                                                | `ErrorCode` (solo tipo, sin coste en tiempo de ejecución; todos los códigos del contrato de la API) |
| `APIEndpoint`, `APIEndpoints`, `APIMethod`, `APIRequestArgs`, `APIRequestOptions`, `APIResponse`, `QueryOrBody`, `ClientEvents`, `TypedEventEmitter`, `CollectionConstructor` | Eliminados (infraestructura de peticiones, eventos y `Collection`)                                  |

## Errores

```ts theme={"system"}
// v5
catch (e) { if (e.code === "RATE_LIMIT_EXCEEDED") ... }

// v6
catch (e) {
  if (e instanceof SquareCloudAPIError && e.status === 429) {
    console.log(e.code, e.message); // KEEP_CALM "Please wait 5 seconds..." or RATE_LIMITED
  }
}
```

* Los códigos sintéticos desaparecen (`RATE_LIMIT_EXCEEDED`, `PAYLOAD_TOO_LARGE`, `SERVER_UNAVAILABLE`, `UNKNOWN_ERROR_<status>`): aparece el código real de la API (`RATE_LIMITED`, `KEEP_CALM`, `DAILY_SNAPSHOTS_LIMIT_REACHED`, `FILE_TOO_LARGE`...).
* Sin respuesta: `status: 0` con `NETWORK_ERROR` (la causa en `cause`) o `TIMEOUT`. Un cuerpo sin código es `UNKNOWN_ERROR` con el `status` real y el mensaje `HTTP <status>`.
* `instanceof TypeError` ya no es verdadero para los errores de la API.
* Una clave caducada da 401 `ACCESS_DENIED`, igual que una desconocida.
* Los errores de `ai.chat()`, incluidos los de autenticación y límites de tasa, llevan el código de OpenAI en minúsculas (`access_denied`, `rate_limit_exceeded`, ...).
* Un `start`/`stop`/`restart` rechazado es un 409 con solo un código: `CONTAINER_ALREADY_STARTED`, `CONTAINER_ALREADY_STOPPED`, `CONTAINER_TEMPORARILY_SUSPENDED`, `CONTAINER_NOT_FOUND`, `CONTAINER_INSUFFICIENT_DISK_SPACE`, `CONTAINER_NETWORK_CONFLICT` o `ACTION_FAILED`.

## Cambios de comportamiento

* Las llamadas tienen timeout: 30 s por intento por defecto (la v5 no tenía timeout), al menos 120 s para las llamadas que el servidor mantiene abiertas. Establece `timeoutMs: 0` para no tener ninguno.
* `files.write()` trata un string como el contenido y lo envía como texto plano; los bytes van en base64, de forma segura para binarios, y un contenido vacío crea un archivo vacío (el mismo formato de envío que los SDKs de Python y Go). `files.read()` pide base64 y lo decodifica.
* `files.list()` de un directorio inexistente lanza 404 `FILE_NOT_FOUND` en lugar de devolver `[]`.
* `snapshots.create()` devuelve `{ pending: true }` en un 202 en lugar de lanzar un error.
* Los resultados de tipo string nunca son `undefined`: `setWebhook` y `resetCredentials("certificate")` devuelven `""` cuando la API no envía nada; `deploys.current()` devuelve `{}`.
* `realtime()` se reconecta cuando se cae la conexión y con `REALTIME_RECONNECT` (hasta 3 veces seguidas, como máximo una apertura cada 5,5 s).
* Reintentos: errores de red en GET y 503 `UPLOAD_BUSY`/`ANALYTICS_BUSY` (más `DATABASE_UNAVAILABLE` en GET), con backoff. Un 429 nunca se reintenta. `DATABASE_UNAVAILABLE` puede llegar después de que se haya aplicado una mutación: reintenta tú mismo tus mutaciones idempotentes.
* Los ids vacíos, `.` y `..` fallan localmente con `INVALID_ID`.
* Los valores de query que son `undefined`, `""` o `false` no se envían.
