> ## 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.

# Migration zu v6

> Was sich zwischen @squarecloud/api v5 und v6 geändert hat: einfache Daten statt Klassen, IDs als erstes Argument, eine Fehlerklasse, Timeouts und Wiederholungen. Eine Tabelle Methode für Methode.

v6 ist eine Neuentwicklung: ein flacher Client, einfache Daten statt Klassen, IDs als erstes Argument und eine einzige Fehlerklasse. Die meisten Änderungen sind mechanisch.

## Auf einen Blick

| v5                                                                                                     | v6                                                                                                                                                                                         |
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Klassen mit Methoden (`app.start()`)                                                                   | Einfache Daten; Methoden am Client (`api.apps.start(appId)`)                                                                                                                               |
| `Collection`                                                                                           | `Array`                                                                                                                                                                                    |
| Klassenfelder in camelCase mit `Date`s (`createdAt`, `modifiedAt`, `uptime`)                           | Die eigenen Felder und Werte der API (`created_at` und `modified` als ISO-Strings, `uptime` in ms)                                                                                         |
| `Buffer`                                                                                               | `Uint8Array` (ein `Buffer` wird als Eingabe weiterhin akzeptiert)                                                                                                                          |
| Mutationen geben `Promise<boolean>` zurück (immer `true`)                                              | `Promise<void>` oder die Daten, die die API zurückgibt (`envs.*` → `EnvVars`, `deploys.setWebhook` → URL, `deploys.linkGithubApp` → `LinkedRepository`, `resetCredentials` → das Passwort) |
| `SquareCloudAPIError extends TypeError` nur mit `code`                                                 | `extends Error` mit `status`, `code`, `message` (die des Servers), `method`, `path`, `cause`                                                                                               |
| Ereignisse (`userUpdate`, `statusUpdate`, `logsUpdate`, `snapshotsUpdate`) und `api.cache`/`app.cache` | Entfernt: Verwalte deinen eigenen Zustand                                                                                                                                                  |
| `api.api.request()` (der rohe `APIService`)                                                            | Entfernt: Jede Operation hat eine Methode                                                                                                                                                  |
| Kein Timeout, keine Wiederholungen                                                                     | 30 s Timeout pro Versuch, Wiederholungen nur bei sicheren Fehlern (siehe [Verhaltensänderungen](#verhaltensänderungen))                                                                    |
| Node.js >= 20                                                                                          | Node.js >= 22, Deno, Bun, Edge                                                                                                                                                             |
| `@squarecloud/api-types`                                                                               | Die Typen sind im SDK enthalten (`import type { App } from "@squarecloud/api"`)                                                                                                            |

## Konstruktion und Optionen

| v5                        | v6                                                                                   | Hinweise                                                                                                                                                                  |
| ------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `new SquareCloudAPI(key)` | `new SquareCloudAPI(key, { baseUrl?, timeoutMs?, maxRetries?, userAgent?, fetch? })` | Ein leerer oder nur aus Leerzeichen bestehender Schlüssel wirft einen `TypeError`.                                                                                        |
| `SquareCloudAPI.apiInfo`  | `BASE_URL` und `{ baseUrl }`                                                         | `BASE_URL` = `https://api.squarecloud.app/v2`.                                                                                                                            |
| (keine)                   | `timeoutMs` (30000)                                                                  | Pro Versuch; offen gehaltene Aufrufe und `ai.chat` warten mindestens 120 s. `<= 0`, `Infinity` oder `>= 2^31` deaktiviert jedes Timeout, einschließlich der Mindestwerte. |
| (keine)                   | `maxRetries` (2)                                                                     | Nur Netzwerkfehler bei GET und die aufgeführten 503-Codes; nie 429.                                                                                                       |
| (keine)                   | `userAgent`                                                                          | Ersetzt den gesamten Header (Standard `squarecloud-sdk-js/<version>`).                                                                                                    |
| (keine)                   | `fetch`                                                                              | Eigenes `fetch` (Proxys, Tracing, Tests).                                                                                                                                 |

## Methode für Methode

| v5                                                                           | v6                                                                                                        | Hinweise                                                                                                                                                                           |
| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api.user.get()` → `User`                                                    | `api.account.me()`                                                                                        | Gibt `{ user, applications, databases }` zurück.                                                                                                                                   |
| `user.plan.expiresIn`                                                        | `new Date(user.plan.duration)`                                                                            | Ein Zeitstempel; `null` läuft nie ab.                                                                                                                                              |
| `api.user.snapshots(scope)`                                                  | `api.account.snapshots({ scope })`                                                                        |                                                                                                                                                                                    |
| `api.service.status()`                                                       | `api.service.status()`                                                                                    | Neue Form: `status`, `message`, `services`, `dependencies`...                                                                                                                      |
| `api.applications.get()`                                                     | `(await api.account.me()).applications`                                                                   |                                                                                                                                                                                    |
| `api.applications.get(id)` / `fetch(id)` / `app.fetch()`                     | `api.apps.get(id)`                                                                                        | Findet auch über Workspaces geteilte Apps.                                                                                                                                         |
| `app.isWebsite()`                                                            | `Boolean((await api.apps.get(id)).domain)`                                                                |                                                                                                                                                                                    |
| `api.applications.create(file)`                                              | `api.apps.create(file, { signal })`                                                                       | Ein Pfad, `Blob`/`File` oder `Uint8Array`; kein Timeout.                                                                                                                           |
| `api.applications.statusAll()`                                               | `api.apps.statusAll({ workspaceId? })`                                                                    | Einfache Objekte `{ id, running, cpu?, ram? }` (v5 verschachtelte `cpu`/`ram` unter `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` und `network` liegen auf oberster Ebene (v5 verschachtelte sie unter `usage`); `uptime` ist der Startzeitpunkt in ms (`null`, wenn gestoppt), kein `Date`. |
| `app.getLogs()`                                                              | `api.apps.logs(id)`                                                                                       |                                                                                                                                                                                    |
| `app.getMetrics()`                                                           | `api.apps.metrics(id)`                                                                                    | Der neueste Punkt zuerst.                                                                                                                                                          |
| `app.realtime()` → rohe `Response`                                           | `api.apps.realtime(id, { signal })`                                                                       | Ein Async Iterable geparster Ereignisse.                                                                                                                                           |
| `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?)`                                                                          | Ein fehlendes Verzeichnis wirft 404 `FILE_NOT_FOUND` (früher eine leere Liste).                                                                                                    |
| `app.files.read(path)` → `Buffer \| undefined`                               | `api.apps.files.read(id, path)` → `Uint8Array`                                                            | Als Base64 angefordert und dekodiert (v5 las ein Byte-Array). Leere Bytes, nie `undefined`, wenn die API keinen Inhalt sendet.                                                     |
| `app.files.create(file, fileName, dir)`                                      | ``api.apps.files.write(id, `${dir}/${fileName}`, content)``                                               | Ein String ist der **Inhalt** (als reiner Text gesendet); v5 las ihn als lokalen Pfad. Bytes werden als Base64 gesendet. Leerer Inhalt erstellt eine leere Datei.                  |
| `app.files.edit(file, path)`                                                 | `api.apps.files.write(id, path, content)`                                                                 | Dasselbe Übertragungsformat wie `write`: Text für Strings, Base64 für 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)`                                  | Jede gibt die resultierenden Variablen zurück.                                                                                                                                     |
| `app.snapshots.list()`                                                       | `api.apps.snapshots.list(id)`                                                                             | Einträge erhalten `name`, `runtime`, `origin`, `version_id` und eine signierte Download-`url`, alles so, wie die API es sendet.                                                    |
| `app.snapshots.create()`                                                     | `api.apps.snapshots.create(id)`                                                                           | `{ pending: true }` bei 202 (v5 warf einen Fehler), sonst `{ pending: false, url, key }`.                                                                                          |
| `app.snapshots.download()` → `Buffer`                                        | `const s = await api.apps.snapshots.create(id)`, dann `if (!s.pending) await api.downloadSnapshot(s.url)` | Ein `ReadableStream`, nichts gepuffert. Ein ausstehender Snapshot (202) hat noch keine URL: v5 warf einen Fehler.                                                                  |
| `snapshot.url` / `snapshot.download()`                                       | `snapshot.url` / `api.downloadSnapshot(snapshot.url)`                                                     | Die eigene signierte URL der API (v5 baute aus der ID des Aufrufers eine falsche).                                                                                                 |
| `app.snapshots.restore({ snapshotId, versionId })`                           | `api.apps.snapshots.restore(id, name, versionId)`                                                         | Übergib `name` und `version_id` eines aufgelisteten Snapshots. Die Fehler findest du unter [Snapshots](/de/sdks/js/snapshots#snapshot-wiederherstellen).                           |
| `app.deploys.integrateGithubWebhook(token)`                                  | `api.apps.deploys.setWebhook(id, token)`                                                                  | Gibt die Webhook-URL zurück (`""`, wenn mit `"@"` entfernt).                                                                                                                       |
| `app.deploys.linkGithubApp({ repositoryName, repositoryBranch })`            | `api.apps.deploys.linkGithubApp(id, repository, branch)`                                                  | Positionsargumente. Gibt `{ id, full_name, branch }` zurück. API-Schlüssel werden jetzt akzeptiert (Scope `apps:deploy`); v5 benötigte ein Session-JWT.                            |
| `app.deploys.unlinkGithubApp()` → `boolean`                                  | `api.apps.deploys.unlinkGithubApp(id)`                                                                    | Wird zu `void` aufgelöst (war `boolean`). `400 GIT_NOT_CONFIGURED`, wenn nichts verknüpft ist.                                                                                     |
| `app.deploys.list()` → `Deployment[][]`                                      | `api.apps.deploys.list(id)` → `DeployEvent[][]`                                                           | Ein fehlgeschlagener Deploy endet in `state: "error"` mit `code` (und `message`, wenn es Details gibt); `source` ist immer `"git"`.                                                |
| `app.deploys.current()`                                                      | `api.apps.deploys.current(id)` → `DeployCurrent`                                                          | `{}`, wenn nichts konfiguriert ist.                                                                                                                                                |
| `app.deploys.webhookURL()`                                                   | `(await api.apps.deploys.current(id)).webhook`                                                            |                                                                                                                                                                                    |
| `app.network` (nur bei `WebsiteApplication`)                                 | `api.apps.network`                                                                                        | Jede App-ID; die API lehnt Nicht-Web-Apps ab.                                                                                                                                      |
| `network.setCustomDomain(domain)`                                            | `api.apps.network.setDomain(id, domain)`                                                                  |                                                                                                                                                                                    |
| `network.analytics({ start, end, contentType, ... })`                        | `api.apps.network.analytics(id, start, end, { content_type, ... })`                                       | `null` für ein leeres Fenster.                                                                                                                                                     |
| `network.errors({ start, end, include4xx })`                                 | `api.apps.network.errors(id, start, end, { include_4xx })`                                                | `null` für ein leeres Fenster.                                                                                                                                                     |
| `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()`                              | unverändert                                                                                               | `statusAll()` gibt einfache Objekte `{ id, running, cpu?, ram? }` zurück.                                                                                                          |
| `db.getStatus()` / `getMetrics()`                                            | `api.databases.status(id, { raw? })` / `metrics(id)`                                                      | `ram` ist der genutzte RAM, z. B. `"120.4MB"` (eine Zahl mit `raw`). Metriken kommen mit dem neuesten zuerst.                                                                      |
| `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)`                                                                | Das neue Passwort (`""` für `"certificate"`).                                                                                                                                      |
| `db.snapshots.list()` / `create()` / `download()`                            | `api.databases.snapshots.list(id)` / `create(id)` / `api.downloadSnapshot(url)`                           | `download()` wie bei Apps: `create(id)`, dann `downloadSnapshot(s.url)`, wenn nicht ausstehend.                                                                                    |
| `db.snapshots.restore(snapshotId, versionId)`                                | `api.databases.snapshots.restore(id, name, versionId)`                                                    | Übergib `name` und `version_id` eines aufgelisteten Snapshots.                                                                                                                     |
| `api.workspaces.list()` / `fetch(id)` / `workspace.fetch()`                  | `api.workspaces.list()` / `get(id)`                                                                       |                                                                                                                                                                                    |
| `api.workspaces.create({ name })`                                            | `api.workspaces.create(name)`                                                                             | Gibt `WorkspaceCreated` (`{ id, name }`) zurück.                                                                                                                                   |
| `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)`                              |                                                                                                                                                                                    |
| (keine)                                                                      | `api.ai.chat(request)`, `api.downloadSnapshot(url)`, `BASE_URL`                                           | Neu.                                                                                                                                                                               |

## Typen

Die Typen sind im SDK enthalten und spiegeln die Feldnamen der API wider. Die wichtigsten Umbenennungen gegenüber `@squarecloud/api-types` und den Klassen von v5:

| v5                                                                                                                                                                            | v6                                                                                  |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `Application`, `WebsiteApplication`, `BaseApplication`                                                                                                                        | `App` (`api.apps.get()`), `AppSummary` (`account.me()`), `AppCreated`               |
| `ApplicationStatus`, `SimpleApplicationStatus`, `SimpleDatabaseStatus`                                                                                                        | `RuntimeStats` (`RuntimeStats<true>` mit `{ raw: true }`), `StatusListItem`         |
| `User`                                                                                                                                                                        | `Account` (`{ user, applications, databases }`), `User`, `Plan`                     |
| `Snapshot`, `DatabaseSnapshot`                                                                                                                                                | `Snapshot`, `SnapshotCreated`                                                       |
| `Deployment`, `DeploymentState`                                                                                                                                               | `DeployEvent`, `DeployCurrent` (mit `DeployRepository`), `LinkedRepository`         |
| Abfrageobjekte des Netzwerks                                                                                                                                                  | `AnalyticsFilters` (die optionalen Filter; `start` und `end` sind Argumente)        |
| `Workspace`                                                                                                                                                                   | `Workspace`, `WorkspaceCreated`, `WorkspaceGroup`                                   |
| `APIErrorCode` (Laufzeitobjekt)                                                                                                                                               | `ErrorCode` (nur ein Typ, keine Laufzeitkosten; jeder Code aus dem Vertrag der API) |
| `APIEndpoint`, `APIEndpoints`, `APIMethod`, `APIRequestArgs`, `APIRequestOptions`, `APIResponse`, `QueryOrBody`, `ClientEvents`, `TypedEventEmitter`, `CollectionConstructor` | Entfernt (Request-Infrastruktur, Ereignisse und `Collection`)                       |

## Fehler

```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
  }
}
```

* Synthetische Codes gibt es nicht mehr (`RATE_LIMIT_EXCEEDED`, `PAYLOAD_TOO_LARGE`, `SERVER_UNAVAILABLE`, `UNKNOWN_ERROR_<status>`): Der echte Code der API kommt durch (`RATE_LIMITED`, `KEEP_CALM`, `DAILY_SNAPSHOTS_LIMIT_REACHED`, `FILE_TOO_LARGE`...).
* Keine Antwort: `status: 0` mit `NETWORK_ERROR` (die Ursache in `cause`) oder `TIMEOUT`. Ein Body ohne Code ist `UNKNOWN_ERROR` mit dem echten `status` und der Nachricht `HTTP <status>`.
* `instanceof TypeError` ist für API-Fehler nicht mehr wahr.
* Ein abgelaufener Schlüssel ergibt 401 `ACCESS_DENIED`, wie ein unbekannter.
* Fehler von `ai.chat()`, einschließlich Authentifizierung und Rate Limits, tragen den kleingeschriebenen OpenAI-Code (`access_denied`, `rate_limit_exceeded`, ...).
* Ein abgelehntes `start`/`stop`/`restart` ergibt 409 nur mit einem Code: `CONTAINER_ALREADY_STARTED`, `CONTAINER_ALREADY_STOPPED`, `CONTAINER_TEMPORARILY_SUSPENDED`, `CONTAINER_NOT_FOUND`, `CONTAINER_INSUFFICIENT_DISK_SPACE`, `CONTAINER_NETWORK_CONFLICT` oder `ACTION_FAILED`.

## Verhaltensänderungen

* Aufrufe haben ein Timeout: standardmäßig 30 s pro Versuch (v5 hatte keins), mindestens 120 s für Aufrufe, die der Server offen hält. Setze `timeoutMs: 0` für keins.
* `files.write()` behandelt einen String als Inhalt und sendet ihn als reinen Text; Bytes gehen als Base64, binärsicher, und leerer Inhalt erstellt eine leere Datei (dasselbe Übertragungsformat wie bei den SDKs für Python und Go). `files.read()` fordert Base64 an und dekodiert es.
* `files.list()` eines fehlenden Verzeichnisses wirft 404 `FILE_NOT_FOUND`, statt `[]` zurückzugeben.
* `snapshots.create()` gibt bei 202 `{ pending: true }` zurück, statt einen Fehler zu werfen.
* String-Ergebnisse sind nie `undefined`: `setWebhook` und `resetCredentials("certificate")` geben `""` zurück, wenn die API keines sendet; `deploys.current()` gibt `{}` zurück.
* `realtime()` verbindet sich bei abgebrochenen Verbindungen und bei `REALTIME_RECONNECT` neu (bis zu 3 Mal hintereinander, höchstens ein Öffnen pro 5,5 s).
* Wiederholungen: Netzwerkfehler bei GET und 503 `UPLOAD_BUSY`/`ANALYTICS_BUSY` (plus `DATABASE_UNAVAILABLE` bei GET), mit Backoff. 429 wird nie wiederholt. `DATABASE_UNAVAILABLE` kann eintreffen, nachdem eine Mutation angewendet wurde: Wiederhole deine idempotenten Mutationen selbst.
* Leere IDs sowie `.` und `..` schlagen lokal mit `INVALID_ID` fehl.
* Query-Werte, die `undefined`, `""` oder `false` sind, werden nicht gesendet.
