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

# 迁移到 v6

> @squarecloud/api v5 与 v6 之间的变化：以纯数据取代类、ID 作为第一个参数、单一错误类、超时和重试。附逐个方法的对照表。

v6 是一次重写：一个扁平的客户端，以纯数据取代类，ID 作为第一个参数，以及单一的错误类。大多数更改都是机械性的。

## 概览

| v5                                                                                       | v6                                                                                                                                                |
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| 带有方法的类（`app.start()`）                                                                    | 纯数据；方法位于客户端上（`api.apps.start(appId)`）                                                                                                             |
| `Collection`                                                                             | `Array`                                                                                                                                           |
| 驼峰命名且使用 `Date` 的类字段（`createdAt`、`modifiedAt`、`uptime`）                                   | API 自身的字段和值（`created_at` 和 `modified` 为 ISO 字符串，`uptime` 为毫秒）                                                                                     |
| `Buffer`                                                                                 | `Uint8Array`（`Buffer` 仍可作为输入）                                                                                                                     |
| 变更操作返回 `Promise<boolean>`（始终为 `true`）                                                    | `Promise<void>`，或 API 返回的数据（`envs.*` → `EnvVars`，`deploys.setWebhook` → URL，`deploys.linkGithubApp` → `LinkedRepository`，`resetCredentials` → 密码） |
| `SquareCloudAPIError extends TypeError`，仅有 `code`                                        | `extends Error`，带有 `status`、`code`、`message`（服务器的）、`method`、`path`、`cause`                                                                        |
| 事件（`userUpdate`、`statusUpdate`、`logsUpdate`、`snapshotsUpdate`）以及 `api.cache`/`app.cache` | 已移除：请自行维护状态                                                                                                                                       |
| `api.api.request()`（原始的 `APIService`）                                                    | 已移除：每个操作都有对应的方法                                                                                                                                   |
| 没有超时，没有重试                                                                                | 每次尝试 30 秒超时，仅对安全失败进行重试（参见[行为变更](#行为变更)）                                                                                                           |
| Node.js >= 20                                                                            | Node.js >= 22、Deno、Bun、边缘运行时                                                                                                                      |
| `@squarecloud/api-types`                                                                 | 类型随 SDK 一起提供（`import type { App } from "@squarecloud/api"`）                                                                                       |

## 构造和选项

| v5                        | v6                                                                                   | 备注                                                                                   |
| ------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
| `new SquareCloudAPI(key)` | `new SquareCloudAPI(key, { baseUrl?, timeoutMs?, maxRetries?, userAgent?, fetch? })` | 空密钥或仅含空白字符的密钥会抛出 `TypeError`。                                                        |
| `SquareCloudAPI.apiInfo`  | `BASE_URL` 和 `{ baseUrl }`                                                           | `BASE_URL` = `https://api.squarecloud.app/v2`。                                       |
| （无）                       | `timeoutMs` (30000)                                                                  | 按每次尝试计算；服务器保持连接的调用和 `ai.chat` 至少等待 120 秒。`<= 0`、`Infinity` 或 `>= 2^31` 会禁用所有超时，包括下限。 |
| （无）                       | `maxRetries` (2)                                                                     | 仅限 GET 上的网络错误和列出的 503 代码；429 永不重试。                                                   |
| （无）                       | `userAgent`                                                                          | 替换整个请求头（默认为 `squarecloud-sdk-js/<version>`）。                                         |
| （无）                       | `fetch`                                                                              | 自定义 `fetch`（代理、追踪、测试）。                                                               |

## 逐个方法对照

| v5                                                                           | v6                                                                                                     | 备注                                                                                                         |
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| `api.user.get()` → `User`                                                    | `api.account.me()`                                                                                     | 返回 `{ user, applications, databases }`。                                                                    |
| `user.plan.expiresIn`                                                        | `new Date(user.plan.duration)`                                                                         | 一个时间戳；`null` 表示永不到期。                                                                                       |
| `api.user.snapshots(scope)`                                                  | `api.account.snapshots({ scope })`                                                                     |                                                                                                            |
| `api.service.status()`                                                       | `api.service.status()`                                                                                 | 新的结构：`status`、`message`、`services`、`dependencies`……                                                        |
| `api.applications.get()`                                                     | `(await api.account.me()).applications`                                                                |                                                                                                            |
| `api.applications.get(id)` / `fetch(id)` / `app.fetch()`                     | `api.apps.get(id)`                                                                                     | 也能找到通过 workspace 共享的应用。                                                                                    |
| `app.isWebsite()`                                                            | `Boolean((await api.apps.get(id)).domain)`                                                             |                                                                                                            |
| `api.applications.create(file)`                                              | `api.apps.create(file, { signal })`                                                                    | 路径、`Blob`/`File` 或 `Uint8Array`；没有超时。                                                                      |
| `api.applications.statusAll()`                                               | `api.apps.statusAll({ workspaceId? })`                                                                 | 普通的 `{ id, running, cpu?, ram? }` 对象（v5 将 `cpu`/`ram` 嵌套在 `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` 和 `network` 位于顶层（v5 将它们嵌套在 `usage` 下）；`uptime` 是以毫秒表示的启动时间戳（停止时为 `null`），而不是 `Date`。 |
| `app.getLogs()`                                                              | `api.apps.logs(id)`                                                                                    |                                                                                                            |
| `app.getMetrics()`                                                           | `api.apps.metrics(id)`                                                                                 | 最新的数据点在前。                                                                                                  |
| `app.realtime()` → 原始 `Response`                                             | `api.apps.realtime(id, { signal })`                                                                    | 由已解析事件组成的异步可迭代对象。                                                                                          |
| `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?)`                                                                       | 不存在的目录会抛出 404 `FILE_NOT_FOUND`（以前是空列表）。                                                                    |
| `app.files.read(path)` → `Buffer \| undefined`                               | `api.apps.files.read(id, path)` → `Uint8Array`                                                         | 以 base64 请求并解码（v5 读取的是字节数组）。当 API 未发送内容时返回空字节，绝不会是 `undefined`。                                            |
| `app.files.create(file, fileName, dir)`                                      | ``api.apps.files.write(id, `${dir}/${fileName}`, content)``                                            | 字符串即为**内容**（以纯文本发送）；v5 将其作为本地路径读取。字节以 base64 发送。空内容会创建一个空文件。                                               |
| `app.files.edit(file, path)`                                                 | `api.apps.files.write(id, path, content)`                                                              | 与 `write` 相同的传输格式：字符串为文本，字节为 base64。                                                                       |
| `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)`                               | 每个方法都返回最终的变量。                                                                                              |
| `app.snapshots.list()`                                                       | `api.apps.snapshots.list(id)`                                                                          | 条目新增了 `name`、`runtime`、`origin`、`version_id` 以及已签名的下载 `url`，全部与 API 发送的一致。                                 |
| `app.snapshots.create()`                                                     | `api.apps.snapshots.create(id)`                                                                        | 返回 202 时为 `{ pending: true }`（v5 会抛出异常），否则为 `{ pending: false, url, key }`。                                |
| `app.snapshots.download()` → `Buffer`                                        | `const s = await api.apps.snapshots.create(id)`，然后 `if (!s.pending) await api.downloadSnapshot(s.url)` | 一个 `ReadableStream`，不缓冲任何内容。待处理（202）的 snapshot 还没有 URL：v5 会抛出异常。                                           |
| `snapshot.url` / `snapshot.download()`                                       | `snapshot.url` / `api.downloadSnapshot(snapshot.url)`                                                  | API 自身的已签名 URL（v5 会根据调用者的 ID 构建出错误的 URL）。                                                                  |
| `app.snapshots.restore({ snapshotId, versionId })`                           | `api.apps.snapshots.restore(id, name, versionId)`                                                      | 传入已列出 snapshot 的 `name` 和 `version_id`。错误请参见 [Snapshots](/zh/sdks/js/snapshots#恢复-snapshot)。               |
| `app.deploys.integrateGithubWebhook(token)`                                  | `api.apps.deploys.setWebhook(id, token)`                                                               | 返回 webhook URL（使用 `"@"` 移除时为 `""`）。                                                                        |
| `app.deploys.linkGithubApp({ repositoryName, repositoryBranch })`            | `api.apps.deploys.linkGithubApp(id, repository, branch)`                                               | 位置参数。返回 `{ id, full_name, branch }`。现在接受 API 密钥（作用域 `apps:deploy`）；v5 需要会话 JWT。                            |
| `app.deploys.unlinkGithubApp()` → `boolean`                                  | `api.apps.deploys.unlinkGithubApp(id)`                                                                 | 解析为 `void`（以前是 `boolean`）。没有任何关联时返回 `400 GIT_NOT_CONFIGURED`。                                              |
| `app.deploys.list()` → `Deployment[][]`                                      | `api.apps.deploys.list(id)` → `DeployEvent[][]`                                                        | 失败的 deploy 以 `state: "error"` 结束，带有 `code`（有详细信息时还带有 `message`）；`source` 始终为 `"git"`。                      |
| `app.deploys.current()`                                                      | `api.apps.deploys.current(id)` → `DeployCurrent`                                                       | 未配置任何内容时为 `{}`。                                                                                            |
| `app.deploys.webhookURL()`                                                   | `(await api.apps.deploys.current(id)).webhook`                                                         |                                                                                                            |
| `app.network`（仅在 `WebsiteApplication` 上）                                     | `api.apps.network`                                                                                     | 任意应用 ID；API 会拒绝非 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`。                                                                                              |
| `network.errors({ start, end, include4xx })`                                 | `api.apps.network.errors(id, start, end, { include_4xx })`                                             | 空窗口时为 `null`。                                                                                              |
| `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()`                              | 未变                                                                                                     | `statusAll()` 返回普通的 `{ id, running, cpu?, ram? }` 对象。                                                      |
| `db.getStatus()` / `getMetrics()`                                            | `api.databases.status(id, { raw? })` / `metrics(id)`                                                   | `ram` 是正在使用的 RAM，例如 `"120.4MB"`（使用 `raw` 时为数字）。指标最新的在前。                                                    |
| `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)`                                                             | 新密码（`"certificate"` 时为 `""`）。                                                                              |
| `db.snapshots.list()` / `create()` / `download()`                            | `api.databases.snapshots.list(id)` / `create(id)` / `api.downloadSnapshot(url)`                        | `download()` 与应用相同：先 `create(id)`，不处于待处理状态时再 `downloadSnapshot(s.url)`。                                    |
| `db.snapshots.restore(snapshotId, versionId)`                                | `api.databases.snapshots.restore(id, name, versionId)`                                                 | 传入已列出 snapshot 的 `name` 和 `version_id`。                                                                    |
| `api.workspaces.list()` / `fetch(id)` / `workspace.fetch()`                  | `api.workspaces.list()` / `get(id)`                                                                    |                                                                                                            |
| `api.workspaces.create({ name })`                                            | `api.workspaces.create(name)`                                                                          | 返回 `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)`                           |                                                                                                            |
| （无）                                                                          | `api.ai.chat(request)`、`api.downloadSnapshot(url)`、`BASE_URL`                                          | 新增。                                                                                                        |

## 类型

类型随 SDK 一起提供，并与 API 的字段名保持一致。相对于 `@squarecloud/api-types` 和 v5 类的主要重命名：

| v5                                                                                                                                                                            | v6                                                                          |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `Application`, `WebsiteApplication`, `BaseApplication`                                                                                                                        | `App`（`api.apps.get()`）、`AppSummary`（`account.me()`）、`AppCreated`           |
| `ApplicationStatus`, `SimpleApplicationStatus`, `SimpleDatabaseStatus`                                                                                                        | `RuntimeStats`（使用 `{ raw: true }` 时为 `RuntimeStats<true>`）、`StatusListItem` |
| `User`                                                                                                                                                                        | `Account`（`{ user, applications, databases }`）、`User`、`Plan`                |
| `Snapshot`, `DatabaseSnapshot`                                                                                                                                                | `Snapshot`, `SnapshotCreated`                                               |
| `Deployment`, `DeploymentState`                                                                                                                                               | `DeployEvent`、`DeployCurrent`（包含 `DeployRepository`）、`LinkedRepository`     |
| 网络查询对象                                                                                                                                                                        | `AnalyticsFilters`（可选的过滤器；`start` 和 `end` 是参数）                              |
| `Workspace`                                                                                                                                                                   | `Workspace`, `WorkspaceCreated`, `WorkspaceGroup`                           |
| `APIErrorCode`（运行时对象）                                                                                                                                                         | `ErrorCode`（仅类型，没有运行时开销；涵盖 API 约定中的每个代码）                                    |
| `APIEndpoint`, `APIEndpoints`, `APIMethod`, `APIRequestArgs`, `APIRequestOptions`, `APIResponse`, `QueryOrBody`, `ClientEvents`, `TypedEventEmitter`, `CollectionConstructor` | 已移除（请求底层机制、事件和 `Collection`）                                                |

## 错误

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

* 合成代码已被移除（`RATE_LIMIT_EXCEEDED`、`PAYLOAD_TOO_LARGE`、`SERVER_UNAVAILABLE`、`UNKNOWN_ERROR_<status>`）：现在会呈现 API 的真实代码（`RATE_LIMITED`、`KEEP_CALM`、`DAILY_SNAPSHOTS_LIMIT_REACHED`、`FILE_TOO_LARGE`……）。
* 没有响应：`status: 0`，带有 `NETWORK_ERROR`（原因位于 `cause` 中）或 `TIMEOUT`。没有代码的响应体为 `UNKNOWN_ERROR`，带有真实的 `status` 和消息 `HTTP <status>`。
* 对于 API 错误，`instanceof TypeError` 不再为 true。
* 过期的密钥与未知密钥一样返回 401 `ACCESS_DENIED`。
* `ai.chat()` 的错误（包括身份验证和速率限制）带有小写的 OpenAI 代码（`access_denied`、`rate_limit_exceeded`……）。
* 被拒绝的 `start`/`stop`/`restart` 返回 409，仅带有代码：`CONTAINER_ALREADY_STARTED`、`CONTAINER_ALREADY_STOPPED`、`CONTAINER_TEMPORARILY_SUSPENDED`、`CONTAINER_NOT_FOUND`、`CONTAINER_INSUFFICIENT_DISK_SPACE`、`CONTAINER_NETWORK_CONFLICT` 或 `ACTION_FAILED`。

## 行为变更

* 调用会超时：默认每次尝试 30 秒（v5 没有超时），对于服务器保持连接的调用至少 120 秒。设置 `timeoutMs: 0` 可取消超时。
* `files.write()` 将字符串视为内容并以纯文本发送；字节以 base64 发送，对二进制安全，空内容会创建一个空文件（与 Python 和 Go SDK 的传输格式相同）。`files.read()` 请求 base64 并对其解码。
* 对不存在的目录调用 `files.list()` 会抛出 404 `FILE_NOT_FOUND`，而不是返回 `[]`。
* `snapshots.create()` 在返回 202 时返回 `{ pending: true }`，而不是抛出异常。
* 字符串结果绝不会是 `undefined`：当 API 未返回时，`setWebhook` 和 `resetCredentials("certificate")` 返回 `""`；`deploys.current()` 返回 `{}`。
* `realtime()` 会在连接断开以及收到 `REALTIME_RECONNECT` 时重新连接（最多连续 3 次，每 5.5 秒最多打开一次）。
* 重试：GET 上的网络错误以及 503 `UPLOAD_BUSY`/`ANALYTICS_BUSY`（外加 GET 上的 `DATABASE_UNAVAILABLE`），带有退避。429 永不重试。`DATABASE_UNAVAILABLE` 可能在变更操作已被应用之后到达：请自行重试你的幂等变更操作。
* 空的、`.` 和 `..` 的 ID 会在本地以 `INVALID_ID` 失败。
* 值为 `undefined`、`""` 或 `false` 的查询参数不会被发送。
