# API使用文档

本文档基于当前 `[[path]].js` 源码整理，面向调用方说明 Worker API 的使用方式、权限边界、请求格式与常见动作。

## 1. 设计定位

- 运行环境：Cloudflare Pages Functions + D1 + Analytics Engine。
- 强调高内聚、低耦合、控制 CPU 与 D1 调用次数。
- 所有复杂关系查询应在调用方自行编排，不在 Worker 内做关联。
- 角色只有两种：
  - `admin`
  - `apptoken`
- DDL 能力对两类角色都开放，但 `apptoken` 只能操作属于自己的资源。

## 2. 路由与请求方式

### 2.1 路由规则

Worker 通过 URL 最后一段识别动作名：

- `GET /health`
- `POST /select`
- `POST /insert`
- `POST /issueScopedToken`
- `POST /createTable`

也就是说，动作名就是路径最后一段。

### 2.2 HTTP Method 规则

推荐统一使用 `POST /{action}`，因为它最稳定，也最符合源码设计。

源码同时支持以下映射：

- `GET`：只允许 `/health`
- `POST`：按路径最后一段作为动作名
- `PATCH` / `PUT`：无论路径什么，都会被强制映射为 `update`
- `DELETE`：无论路径什么，都会被强制映射为 `delete`
- `OPTIONS`：返回 CORS 预检

因此：

- 推荐：`POST /update`
- 不推荐但源码可工作：`PATCH /anything`

## 3. 认证与角色

### 3.1 admin

`admin` 通过请求头携带 `Authorization: Bearer {ADMIN_KEY}` 进入系统。

特点：

- 可访问全部表
- 可覆盖数据库绑定
- 可签发开发者 token
- 可查看全部 schema
- 可执行全局 DDL
- 可使用 `purgeAll`
- 可在变更类请求中使用 `allowTableScan: true` 绕过"必须带精确 id 条件"的限制

### 3.2 apptoken

apptoken 令牌本质上也是 JWT，通常由 `issueApp` 生成。

特点：

- 只能访问属于自己 `appId` 的数据
- 非 admin 下，表名会自动改写为：`{appId}_{table}`
- 默认只读未软删除数据
- 可以自由控制属于自己的表、索引和数据
- 可使用 `seal/open` 生成短期调用
- 不能覆盖 `X-DB-Binding`
- 如果应用被封禁（status=0），所有请求将返回 `ERR_TOKEN_REVOKED_OR_BANNED`

### 3.3 open 模式

1. apptoken 先调用 `seal`
2. 得到 `hash`
3. 外部再调用 `POST /open` 并提交该 `hash`
4. Worker 在服务端解封后执行封装好的动作

限制：

- `open` 不能执行 DDL
- 不能执行 `batch`、`transaction`
- 不能再次执行 `open` / `seal`
- 不能执行 `issueApp`

## 4. 请求头

通用请求头：

- `Content-Type: application/json`
- `Authorization: Bearer {token}`

可选请求头：

- `Idempotency-Key: {uuid}`\
  用于幂等写请求，格式要求为 36 位 UUID 风格字符串。
- `X-Cache-TTL: {seconds}`\
  控制读请求缓存时间。
- `If-None-Match: {etag}`\
  配合缓存使用。
- `Cache-Control: no-cache` 或 `no-store`\
  跳过读缓存。
- `X-DB-Binding: {bindingName}`\
  仅 admin 可用，用于切换目标 D1 绑定。
- `X-Client-Features: featureA,featureB`
- `X-Request-ID`

## 5. 统一响应格式

### 5.1 成功响应

```json
{
  "success": true,
  "code": 0,
  "msg": "OK",
  "data": {},
  "meta": {
    "reqId": "xxx",
    "durationMs": 12.34,
    "apiVersion": "2026-05-06",
    "features": []
  }
}
```

常见 `meta` 字段：

- `reqId`：请求追踪 id
- `durationMs`：耗时
- `apiVersion`
- `features`
- `dbRows`
- `budgetUsed`
- `budgetLimit`
- `sqlFingerprint`
- `cacheStatus`
- `nextCursor`
- `hasMore`
- `pageSize`
- `orderBy`
- `orderDesc`

### 5.2 失败响应

```json
{
  "success": false,
  "code": "ERR_CODE",
  "msg": "Operation Failed",
  "data": null,
  "meta": {
    "reqId": "xxx"
  }
}
```

常见错误码：

- `ERR_UNAUTHORIZED`
- `ERR_FORBIDDEN`
- `ERR_FORBIDDEN_DB_BINDING_OVERRIDE`
- `ERR_FORBIDDEN_ACTION_SCOPE`
- `ERR_FORBIDDEN_TABLE_SCOPE`
- `ERR_FORBIDDEN_DEBUG_MODE`
- `ERR_DEBUG_MODE_READONLY`
- `ERR_DEBUG_QUERY_TOO_EXPENSIVE`
- `ERR_FORBIDDEN_SOFT_DELETE_SCOPE`
- `ERR_ID_LIST_LIMIT_EXCEEDED`
- `ERR_INVALID_CACHE_TTL`
- `ERR_INVALID_IDEMPOTENCY_KEY`
- `ERR_QUERY_BUDGET_EXCEEDED`
- `ERR_LIMIT_EXCEEDED`
- `ERR_TOO_MANY_REQUESTS`
- `ERR_INVALID_PAYLOAD`
- `ERR_TABLE_NOT_FOUND`
- `ERR_COLUMN_MISSING`
- `ERR_DUPLICATE_ENTRY`
- `ERR_NOT_FOUND_OR_ACCESS_DENIED`
- `ERR_IDEMPOTENT_CONFLICT`
- `ERR_PURGE_API_DISABLED`
- `ERR_PURGE_CONFIRM_REQUIRED`
- `ERR_UNSUPPORTED_MEDIA_TYPE`
- `ERR_TOKEN_REVOKED_OR_BANNED`

失败响应中 `meta` 可能包含的额外字段：

- `field`：触发约束的具体字段名（如唯一索引冲突）
- `retryable`：布尔值，标识是否可重试（如 `ERR_TOO_MANY_REQUESTS`）
- `retryAfterMs`：建议重试间隔毫秒数
- `clientAction`：建议客户端采取的操作，如 `"reduce_limit"`、`"retry_later"`、`"use_idempotency_key"`
- `detail`：开发模式（`DEV=true`）下的原始错误信息
- `idempotencyKey`：冲突时返回的原始幂等键
- `hint`：建议操作，如 `"retry_with_same_body"`
- `suggestedLimit` / `suggestedColumnsCount`：预算超限时给出的降级建议

## 6. 通用请求体规则

### 6.1 基础字段

不同动作字段不同，但最常见字段如下：

- `table`：逻辑表名
- `where`：过滤条件
- `values`：写入或更新内容
- `columns`：返回列
- `returning`：写操作返回列
- `limit`
- `orderBy`
- `orderDesc`
- `cursor`
- `ids`

### 6.2 表名规则

- admin：使用真实表名
- apptoken：如果未带自己前缀，系统自动补为 `{appId}_{table}`
- 保留前缀不可用：`sqlite_`、`_sys_`、`_cf_`、`d1_`

示例：

- apptoken 的 `table: "orders"` 最终会访问 `app_xxx_orders`
- admin 的 `table: "app_xxx_orders"` 会直接访问该表

### 6.3 查询条件 `where`

支持对象形式条件，不支持数组直接作为顶层 `where`。

支持操作符：

- 等值：`field: value`
- `$eq`
- `$ne`
- `$gt`
- `$gte`
- `$lt`
- `$lte`
- `$in`
- `$nin`
- `$between`
- `$like`
- `$match`
- `$isNull`
- `$or`
- `$and`

示例：

```json
{
  "where": {
    "$and": [
      { "status": "paid" },
      { "price": { "$gte": 100 } },
      { "deleted_at": { "$isNull": true } }
    ]
  }
}
```

### 6.4 JSON 路径字段

系统支持使用点号 `.` 分隔的路径访问 JSON 字段中的嵌套值，适用于 `columns`、`where`、`orderBy` 等位置：

- 查询列：`"columns": ["id", "profile.name", "profile.email"]`
- 过滤条件：`"where": { "profile.age": { "$gte": 18 } }`
- 排序：`"orderBy": "profile.score"`

底层实现：`profile.name` 会被编译为 SQLite 的 JSON 提取语法 `"profile"->>'$.name'`。

### 6.5 软删除可见性

读请求默认自动追加：

```json
{ "deleted_at": { "$isNull": true } }
```

特殊情况：

- `withDeleted: true`：admin / apptoken 可读取包含已删除记录
- `onlyDeleted: true`：只读取已删除记录

### 6.6 字段脱敏与限制

非 admin 会自动屏蔽这些字段：

- `password`
- `password_hash`
- `secret`
- `token`
- `internal_note`

如果 token 自带 `mask`，这些字段也会被一起屏蔽：

### 6.7 更新宏

更新类 `values` 支持宏：

- `"$NOW"` 或 `"$NOW(+1d)"`、`"$NOW(-2h)"`、`"$NOW(+30m)"`、`"$NOW(-60s)"`
- `"$INC(1)"`
- `"$DEC(1)"`
- `"$MUL(2)"`
- `"$DIV(2)"`
- `"$SET_MIN(10)"`
- `"$SET_MAX(100)"`
- `"$CONCAT(_suffix)"`
- `"$TOGGLE"`
- `"$LOWER"`
- `"$UPPER"`
- `"$TRIM"`

以及对象形式：

```json
{
  "score": { "$INC": 5 },
  "profile": {
    "$SET_PATH": {
      "path": "stats.level",
      "value": 3
    }
  }
}
```

JSON 数组/对象操作：

```json
{
  "tags": { "$PUSH": "new-tag" }
}
```

向数组字段追加元素（使用 `json_insert`）。

```json
{
  "settings": { "$MERGE": { "theme": "dark" } }
}
```

合并 JSON 对象（使用 `json_patch`）。

```json
{
  "settings": { "$REMOVE": "$.theme" }
}
```

从 JSON 字段移除路径（使用 `json_remove`）。

## 7. 角色能力矩阵

| 动作类别             | admin      | apptoken          |
| ---------------- | ---------- | ----------------- |
| 读数据              | 全部表        | 仅自己表              |
| 写数据              | 全部表        | 仅自己表              |
| DDL              | 全部表/索引     | 仅自己名下表/索引         |
| 切换 DB 绑定         | 支持         | 不支持               |
| issueApp         | 支持         | 不支持               |
| seal             | 不支持        | 支持                |
| open             | 支持 hash 执行 | 支持 hash 执行        |
| purgeAll         | 支持         | 不支持               |
| 导出 schema        | 支持         | 不支持               |

## 8. 动作总览

### 8.1 读动作

- `select`
- `count`
- `aggregate`
- `mget`
- `exists`
- `head`
- `distinct`
- `bulkExists`
- `selectByIdsPreserveOrder`

### 8.2 写动作

- `insert`
- `upsert`
- `update`
- `patch`
- `delete`
- `softDelete`
- `restore`
- `toggle`
- `deleteByIds`
- `restoreByIds`
- `toggleByIds`

### 8.3 DDL / 管理动作

- `showTables`
- `describeTable`
- `createTable`
- `dropTable`
- `alterTable`
- `createIndex`
- `dropIndex`
- `truncateTable`
- `exportSchema`
- `introspect`
- `validateOnly`
- `issueApp`
- `inspectToken`
- `seal`
- `open`
- `batch`
- `transaction`
- `purgeAll`

## 9. 主要动作说明

### 9.1 select

用于分页读取。

请求示例：

```json
{
  "table": "orders",
  "columns": ["id", "status", "amount", "created_at"],
  "where": {
    "status": "paid",
    "amount": { "$gte": 100 }
  },
  "limit": 20,
  "orderBy": "created_at",
  "orderDesc": true
}
```

说明：

- 不支持 `offset`，必须使用游标 `cursor`
- 支持 JSON 路径字段，如 `profile.name`

翻页时传回上次响应中的 `meta.nextCursor`：

```json
{
  "table": "orders",
  "limit": 20,
  "cursor": "eyJ..."
}
```

### 9.2 count

```json
{
  "table": "orders",
  "where": {
    "status": "paid"
  }
}
```

返回：

```json
{
  "count": 123
}
```

### 9.3 aggregate

```json
{
  "table": "orders",
  "where": { "status": "paid" },
  "groupBy": ["currency"],
  "fields": {
    "totalAmount": { "$sum": "amount" },
    "avgAmount": { "$avg": "amount" },
    "rowCount": { "$count": "*" }
  }
}
```

支持聚合：

- `$count`
- `$sum`
- `$avg`
- `$max`
- `$min`

### 9.4 mget

按 id 批量查询，不保证返回顺序。

```json
{
  "table": "orders",
  "ids": ["id1", "id2", "id3"],
  "columns": ["id", "status"]
}
```

### 9.5 bulkExists

```json
{
  "table": "orders",
  "ids": ["id1", "id2", "id3"]
}
```

返回：

```json
{
  "foundIds": ["id1", "id3"],
  "missingIds": ["id2"]
}
```

### 9.6 selectByIdsPreserveOrder

按传入 `ids` 顺序返回。

```json
{
  "table": "orders",
  "ids": ["id3", "id1", "id2"],
  "columns": ["id", "status"]
}
```

### 9.7 exists

```json
{
  "table": "orders",
  "where": {
    "id": "order_001"
  }
}
```

返回：

```json
{
  "exists": true
}
```

### 9.8 head

查询满足条件的最新一条，固定按 `id DESC LIMIT 1`。

```json
{
  "table": "orders",
  "where": {
    "status": "paid"
  },
  "columns": ["id", "status"]
}
```

### 9.9 distinct

```json
{
  "table": "orders",
  "field": "status",
  "limit": 20
}
```

### 9.10 调试模式 (dryRun / explain / profile)

所有读动作（`select`、`count`、`aggregate`、`mget`、`exists`、`head`、`distinct`、`bulkExists`、`selectByIdsPreserveOrder`）均支持三种调试参数：

**dryRun**：只返回 SQL 和预算信息，不执行查询。

```json
{
  "table": "orders",
  "where": { "status": "paid" },
  "limit": 20,
  "dryRun": true
}
```

返回内容包含：

- `action`：动作名
- `sql`：即将执行的 SQL 语句
- `params`：绑定参数列表
- `sqlFingerprint`：SQL 摘要
- `budgetUsed`：预估查询预算
- `budgetLimit`：当前预算上限
- `cache.eligible`：是否满足缓存条件
- `cache.ttl`：缓存 TTL
- `cache.authScoped`：是否带鉴权

**explain**：返回 `EXPLAIN QUERY PLAN` 结果，用于分析 SQL 执行计划。

```json
{
  "table": "orders",
  "where": { "status": "paid" },
  "explain": true
}
```

**profile**：返回更详细的查询分析信息，包含 plan（执行计划）、cache（缓存信息）等。

```json
{
  "table": "orders",
  "where": { "status": "paid" },
  "limit": 20,
  "profile": true
}
```

权限限制：

- 必须为 `admin` 或 `apptoken`（`role='apptoken'`）
- `sealed` token 不可使用调试模式
- `explain` / `profile` 仅适用于读动作
- `explain` / `profile` 预算不能超过 `80`，否则报错 `ERR_DEBUG_QUERY_TOO_EXPENSIVE`

### 9.11 insert

支持单条和批量。

单条：

```json
{
  "table": "orders",
  "values": {
    "user_id": "u1",
    "status": "pending",
    "amount": 99.5
  },
  "returning": true
}
```

批量：

```json
{
  "table": "orders",
  "values": [
    { "user_id": "u1", "status": "pending" },
    { "user_id": "u2", "status": "paid" }
  ]
}
```

说明：

- 未传 `id` 会自动生成
- 自动保留系统字段：`id`、`created_at`、`updated_at`、`deleted_at`

### 9.12 upsert

请求格式与 `insert` 基本一致，但遇到冲突时做更新。

```json
{
  "table": "orders",
  "values": {
    "id": "order_001",
    "status": "paid",
    "amount": 100
  },
  "returning": ["id", "status", "amount"],
  "conflictTarget": "user_id"
}
```

可选字段：

- `conflictTarget`：指定冲突检测的目标字段，默认 `"id"`
- `skipTime`：admin 可传 `true` 跳过 `updated_at` 自动更新

### 9.13 update / patch

源码中两者都走同一逻辑。

```json
{
  "table": "orders",
  "where": {
    "id": "order_001"
  },
  "values": {
    "status": "paid",
    "paid_at": "$NOW"
  },
  "returning": true
}
```

强限制：

- 必须有 `where`
- 变更类请求默认必须命中精确 `id`
- 否则报错 `ERR_MUTATION_REQUIRES_EXACT_ID_OR_ADMIN_BYPASS`

admin 如确需全表/范围更新，必须显式传：

```json
{
  "allowTableScan": true
}
```

### 9.14 delete

```json
{
  "table": "orders",
  "where": {
    "id": "order_001"
  },
  "returning": ["id", "status"]
}
```

### 9.15 softDelete

本质是把 `deleted_at` 设为当前时间。

```json
{
  "table": "orders",
  "where": {
    "id": "order_001"
  }
}
```

### 9.16 restore

```json
{
  "table": "orders",
  "where": {
    "id": "order_001"
  }
}
```

作用：把 `deleted_at` 恢复为 `null`。

### 9.17 toggle

```json
{
  "table": "orders",
  "where": {
    "id": "order_001"
  },
  "field": "enabled",
  "returning": true
}
```

### 9.18 deleteByIds / restoreByIds / toggleByIds

按 id 列表批量执行删除 / 恢复 / 切换操作。

### deleteByIds

```json
{
  "table": "orders",
  "ids": ["id1", "id2", "id3"],
  "returning": true
}
```

### restoreByIds

```json
{
  "table": "orders",
  "where": {
    "id": "order_001"
  }
}
```

作用：把 `deleted_at` 恢复为 `null`。

### 9.17 toggle

```json
{
  "table": "orders",
  "where": {
    "id": "order_001"
  },
  "field": "enabled",
  "returning": true
}
```

### 9.18 deleteByIds / restoreByIds / toggleByIds

按 id 列表批量执行删除 / 恢复 / 切换操作。

### deleteByIds

```json
{
  "table": "orders",
  "ids": ["id1", "id2", "id3"],
  "returning": true
}
```

### restoreByIds

```json
{
  "table": "orders",
  "ids": ["id1", "id2", "id3"],
  "returning": true,
  "skipTime": true
}
```

`skipTime: true` 可跳过 `updated_at` 自动更新。

### toggleByIds

```json
{
  "table": "orders",
  "ids": ["id1", "id2"],
  "field": "enabled",
  "returning": true,
  "skipTime": true
}
```

`toggleByIds` 必须额外提供 `field` 指定要切换的布尔字段。

## 10. DDL 动作

### 10.1 showTables

列出当前可见表：

- admin：全部业务表
- apptoken：仅自己前缀表

```json
{}
```

支持 `bypassCache: true` 跳过缓存（仅 admin 有效）。

### 10.2 describeTable

查看表结构：

```json
{
  "table": "orders"
}
```

支持 `bypassCache: true` 跳过缓存（仅 admin 有效）。

### 10.3 createTable

```json
{
  "table": "orders",
  "columns": {
    "user_id": "TEXT NOT NULL",
    "status": "TEXT",
    "amount": "REAL DEFAULT 0"
  },
  "indexes": ["user_id", "status"]
}
```

系统自动带上：

- `id TEXT PRIMARY KEY`
- `created_at DATETIME DEFAULT CURRENT_TIMESTAMP`
- `updated_at DATETIME DEFAULT CURRENT_TIMESTAMP`
- `deleted_at DATETIME`

支持的类型约束：

- `TEXT`、`INTEGER`、`REAL`、`NUMERIC`、`BLOB`、`BOOLEAN`
- `NOT NULL`、`UNIQUE`
- `DEFAULT CURRENT_TIMESTAMP`、`DEFAULT NULL`、`DEFAULT 数值`、`DEFAULT '字符串'`

### 10.4 alterTable

支持四种方式，四选一：

重命名表：

```json
{
  "table": "orders",
  "renameTo": "orders_v2"
}
```

新增列：

```json
{
  "table": "orders",
  "addColumn": {
    "name": "remark",
    "type": "TEXT"
  }
}
```

重命名列：

```json
{
  "table": "orders",
  "renameColumn": {
    "oldName": "remark",
    "newName": "memo"
  }
}
```

删除列：

```json
{
  "table": "orders",
  "dropColumn": "memo"
}
```

### 10.5 createIndex

```json
{
  "table": "orders",
  "columns": ["user_id", "status"],
  "indexName": "idx_user_status",
  "unique": false
}
```

说明：

- admin 可自定义完整索引名
- apptoken 下索引名前缀会强制归属到自己的 `appId`

### 10.6 dropIndex

```json
{
  "indexName": "idx_user_status"
}
```

### 10.7 truncateTable

```json
{
  "table": "orders"
}
```

作用：删除表内全部数据，但不删除表结构。

## 11. 管理与调试动作

### 11.1 issueApp

仅 admin 可用，用于签发一个新的 app token。

```json
{
  "appName": "demo-app"
}
```

返回中包含：

- `appId`：生成的应用 id，格式为 `app_xxxxxxxxxx`
- `token`

该 token 的 payload 至少包含：

- `appId`
- `role: "apptoken"`
- `appName`
- `iat`

系统会自动在 `_sys_apps` 表中记录该应用的 `app_id`、`app_name` 和 `status`（默认 1，表示启用）。如果 `status` 被设为 `0`，该应用的所有请求将被拒绝。

### 11.2 inspectToken

admin 可查看任意 token；apptoken 只能查看同 `appId` 的 token。

```json
{
  "hash": "jwt_or_hash"
}
```

如果不传 `hash`，会尝试读取当前 `Authorization`。

### 11.3 seal

仅 apptoken 可用，把一个动作和其 payload 封装成短期 hash。

```json
{
  "action": "select",
  "ttl": 300,
  "payload": {
    "table": "orders",
    "where": {
      "status": "paid"
    },
    "limit": 10
  }
}
```

不能封装的动作：

- `seal`、`open`、`issueApp`、`batch`、`transaction`、`exportSchema`、`showTables`、`describeTable`
- 所有 DDL 动作（`createTable`、`dropTable`、`alterTable`、`createIndex`、`dropIndex`、`truncateTable`）

### 11.4 open

```json
{
  "hash": "sealed_hash"
}
```

用于执行 `seal` 产生的封装请求。

### 11.5 introspect

返回：

- API 版本
- 服务端支持特性
- 当前身份信息
- 限制项
- 默认缓存策略

请求：

```json
{}
```

### 11.6 validateOnly

只校验某个动作是否符合格式与预算，不真正执行。

```json
{
  "action": "select",
  "payload": {
    "table": "orders",
    "limit": 50,
    "where": {
      "status": "paid"
    }
  }
}
```

### 11.7 exportSchema

仅 admin 可用，导出当前数据库的 TypeScript interface 定义。

```json
{}
```

### 11.8 purgeAll

仅 admin 可用，且必须开启环境变量 `ENABLE_PURGE_API=true`。

```json
{
  "confirm": true,
  "mode": "drop",
  "bindings": ["db_1", "db_2"]
}
```

**注意：`confirm`** **必须为布尔值** **`true`（旧文档中字符串版本不再有效）。**

`mode`：

- `drop`：删除表
- `truncate`：清空表数据

## 12. batch 与 transaction

请求结构：

```json
{
  "ops": [
    {
      "action": "insert",
      "payload": {
        "table": "orders",
        "values": { "id": "o1", "status": "pending" }
      }
    },
    {
      "action": "update",
      "payload": {
        "table": "orders",
        "where": { "id": "o1" },
        "values": { "status": "paid" }
      }
    }
  ]
}
```

限制：

- 最多 `30` 个用户级操作
- 只允许变更类（mutation）和 DDL 类动作
- 总预算不能超过 `min(400, token预算 * 4)`

返回结果会带：

- 每个操作的执行结果
- `summary.successCount`
- `summary.failedCount`
- `summary.changedRows`
- `summary.opsByAction`
- `summary.topSqlFingerprints`

## 13. 缓存、ETag、幂等

### 13.1 读缓存

支持缓存的动作：

- `select`
- `count`
- `aggregate`
- `mget`
- `exists`
- `head`
- `distinct`
- `bulkExists`
- `selectByIdsPreserveOrder`
- `open`（当其封装的是读动作时）

默认 TTL：

- `count` / `aggregate`：20 秒
- `select`：
  - `limit <= 50`：60 秒
  - `limit > 50`：20 秒
- 空结果最多缓存 10 秒

TTL 上限：

- 带鉴权请求：60 秒
- 公共请求：300 秒

### 13.2 幂等

写请求建议带：

```http
Idempotency-Key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```

行为：

- 相同 `appId + key + 请求体摘要` 命中后直接回放缓存结果
- 重复并发写入可能返回 `ERR_IDEMPOTENT_CONFLICT`
- 响应头会附加 `X-Idempotent-Cache-Hit: 1` 或 `X-Idempotent-Replay: 1`

## 14. 查询预算与限流

### 14.1 单请求预算

默认最大查询预算：

- 普通请求：`120`
- batch/transaction 总预算：`400`

token 还可通过 `budgetLimit` 进一步缩小自己的上限。

### 14.2 IP 级限流

系统按 IP 记录每分钟预算消耗，总上限：

- `8000 / 分钟`

超出返回：

- `ERR_TOO_MANY_REQUESTS`

### 14.3 非 admin 读限制

- `select.limit` 最大会被压到 `200`
- `mget / bulkExists / selectByIdsPreserveOrder` 的 `ids` 最多 `50`

### 14.4 遥测 (Analytics Engine)

当出现以下任一条件时，请求数据会异步写入绑定的 `SQLAE` Analytics Engine 数据集：

- 状态码 `>= 400`
- 请求耗时 `> 50ms`
- 随机采样 10%

写入数据点包含：

- **索引**：`appId`
- **Blobs**：`action`、`ip`、`reqId`、`method`、`table`、`role`、`status code`、`error`、`ua`、`country`、`dbName`、`cacheStatus`、`trace steps`、`sqlFingerprint`
- **数值**：`status`、`duration`、`payloadSize`、`responseSize`、`dbRows`、`dbOps`、`cacheTtl`、`queryBudget`

## 15. 使用建议

### 15.1 推荐接入方式

对业务调用方，建议统一遵循：

1. 全部使用 `POST /{action}`
2. 全部显式传 `table`
3. 写请求全部带 `Idempotency-Key`
4. 翻页只使用 `cursor`，不要设计 `offset`
5. 复杂查询拆成多次简单查询，不依赖关联能力

### 15.2 推荐角色分工

- 平台管理端：使用 `admin`
- 业务应用服务：使用 `issueApp` 生成的 apptoken
- 面向外部临时开放的查询：apptoken 先 `seal`，外部再 `open`

## 16. 最小调用示例

### 16.1 apptoken 查询自己的 orders

```http
POST /select
Authorization: Bearer <apptoken-token>
Content-Type: application/json
```

```json
{
  "table": "orders",
  "where": {
    "status": "paid"
  },
  "limit": 20
}
```

### 16.2 admin 为某 app 创建表

```http
POST /createTable
Authorization: Bearer <admin-key>
Content-Type: application/json
```

```json
{
  "table": "app_abc123_orders",
  "columns": {
    "user_id": "TEXT NOT NULL",
    "status": "TEXT",
    "amount": "REAL"
  }
}
```

### 16.3 issueApp 创建新应用并签发 token

```http
POST /issueApp
Authorization: Bearer <admin-key>
Content-Type: application/json
```

```json
{
  "appName": "my-demo-app"
}
```

返回包含 `appId` 和 `token`。

### 16.4 apptoken 封装开放查询

```http
POST /seal
Authorization: Bearer <apptoken-token>
Content-Type: application/json
```

```json
{
  "action": "select",
  "ttl": 300,
  "payload": {
    "table": "orders",
    "where": {
      "status": "paid"
    },
    "limit": 10
  }
}
```

然后外部调用：

```http
POST /open
Content-Type: application/json
```

```json
{
  "hash": "<seal返回的hash>"
}
```

## 17. 当前版本特性清单

当前 `apiVersion`：`2026-05-06`

支持的 `features`：

- `cacheTtlTuning`
- `dryRun`
- `explain`
- `profile`
- `mget`
- `exists`
- `head`
- `distinct`
- `bulkExists`
- `selectByIdsPreserveOrder`
- `validateOnly`
- `introspect`
- `sqlFingerprint`
- `queryBudget`
- `weightedRateLimit`
- `ddlOwnerHardening`
- `patch`
- `inspectToken`
- `deleteByIds`
- `restoreByIds`
- `toggleByIds`
- `purgeAll`

## 18. 结论

这个 Worker API 的核心模型可以概括为：

- `admin` 负责全局管理、签发 token、跨库和全局 DDL
- `apptoken` 负责操作自己名下的表、数据、索引与开放访问能力
- 数据接口强调简单、可组合、可缓存、可控预算
- 所有复杂关系查询应在调用方自行编排，不在 Worker 内做关联

