# 安装与更新

普通用户可以从桌面「应用市场」安装官方的「随记」「待办」，或通过「构建应用」创建自己的应用。开发者也可以使用下面的 HTTP 接口管理应用源码。接口要求登录态，生产环境还要求已经验证的邮箱，仅用于开发工具或宿主集成；用户应用内部仍然只使用 `platform.*`，不要直接请求这些接口。

## 应用市场与发布

`GET /api/marketplace` 返回官方应用与用户发布的应用。每项包含 `id`、`name`、`description`、`version`、`is_official`、`author_name`、`author_avatar_url`、`icon_url` 和 `installed_app_id`（未安装时为 `null`）。版本用于内部记录，市场界面不展示。作者昵称与头像读取当前用户资料；只有 `is_official: true` 的条目显示蓝色认证徽章。

`POST /api/marketplace/:appId/publish` 发布当前用户拥有的应用，无需请求体。返回 `{ id, name, version, published: true }`，市场 ID 格式为 `user:应用ID`。重复发布更新同一条市场记录。也可以在「构建应用」会话中明确要求 Agent 发布；Agent 不会在创建后自动上架。

发布内容包含名称、描述、设计理念、源码、图标与绑定的表结构，不复制使用记录、登录会话或模型配置。应用源码通过不可变快照保存，作者的昵称与头像不作为快照冻结。

`POST /api/marketplace/:id/install` 安装应用，无需请求体。官方 ID 为 `notes`、`tasks`；用户应用使用列表返回的 `user:...` ID。首次安装返回 HTTP 201 和应用元数据；重复安装返回同一个应用（官方条目 HTTP 200，用户条目 HTTP 201），不会重置记录、修改过的源码或图标。安装创建独立的空数据集，并要求用户在首次运行时确认数据访问权限。

`GET /api/marketplace/:id/avatar` 与 `GET /api/marketplace/:id/icon` 返回用户发布条目的作者头像与应用图标，要求登录；没有对应图片时返回 HTTP 404。客户端使用名称首字作为后备显示。当前不支持已安装应用自动跟随市场版本升级。

## 账号与邮箱验证

本地开发环境跳过邮箱验证。生产环境注册时发送 6 位邮箱验证码，10 分钟有效。每次验证码最多尝试 5 次，重发间隔至少 60 秒，每小时最多 5 次。发送失败或过期时，可在验证页面重新发送。未验证账户可以查看验证状态、重发和退出登录，不能访问应用和个人数据。

验证邮件由 Cloudflare Email Sending 发送。验证码绑定当前登录账号，验证成功后更换 session，并撤销这个账号的其他旧 session。生产 Cookie 使用 HttpOnly、Secure 和 SameSite=Lax。

## 创建应用

`POST /api/apps` 创建应用，成功返回 HTTP 201 和应用元数据。

```http
POST /api/apps
Content-Type: application/json

{
  "name": "你好",
  "table_ids": [],
  "files": {
    "app.json": "{\"name\":\"你好\",\"entry\":\"index.js\"}",
    "index.js": "export default function render(root, platform) { root.replaceChildren(platform.ui.title('你好')); }"
  }
}
```

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `name` | string | 必填，不能是空白字符串。 |
| `description` | string | 可选，应用用途和目标用户，最多 2000 字。 |
| `design_brief` | string | 可选，设计理念与形象偏好，最多 2000 字。 |
| `files` | object | 路径到文件内容字符串的映射，建议使用此形式。 |
| `source` | string | 单文件兼容入口，等价于 `index.js` 的内容。 |
| `table_ids` | string[] | 需要使用的数据集 ID。 |

请优先传入完整的 `files`，不要同时使用 `source` 和 `files` 表达两份入口代码。省略 `app.json` 时平台会自动生成基础配置。

HTTP 创建接口保存资料但不会自动调用图片模型；创造模式会在创建后自动生成图标。名称修改、上传图标和重新生成请参考[应用名称与图标](/doc/app-icons)。

`table_ids` 非空时，`data.list()` 和 `data.get()` 只发现绑定的数据集；空数组会列出当前用户的全部数据集。应用首次运行需要用户确认该范围，记录读写也由统一应用网关强制校验。空绑定代表整个个人空间，授权界面会说明包含今后创建的数据集。创建应用时仍应明确绑定所需的数据集。用户之间的数据隔离由服务端处理。

## 读取应用包

`GET /api/apps/:id` 返回应用元数据，以及 `entry`、`files`、`source`、`revision`。其中 `source` 是入口文件内容，`files` 包含完整文件包。

`GET /api/apps` 返回当前用户的应用列表，不包含完整源码。

## 更新应用包

`PUT /api/apps/:id` 要求至少提供 `source` 或 `files`，可以同时提供新的 `table_ids`。

```http
PUT /api/apps/APP_ID
Content-Type: application/json

{
  "files": {
    "app.json": "{\"entry\":\"index.js\"}",
    "index.js": "export default function render(root, platform) { root.replaceChildren(platform.ui.title('已经更新')); }"
  },
  "table_ids": ["DATASET_ID"]
}
```

更新文件包会替换原有文件集合，不是只修改请求中出现的文件。请先读取原包，修改目标文件，再提交完整 `files`。省略 `table_ids` 会保留原有绑定；传入空数组会恢复发现全部数据集。

已经打开的应用不会自动热更新。关闭应用标签后重新打开，才能加载新源码。当前没有面向用户的版本回滚 API，请在自己的项目中保留源码版本。旧源码快照会保留，更新失败不切换当前引用。

## 应用授权

首次打开会显示数据范围与读写能力；在桌面「管理应用」中可以撤销。扩大数据绑定或修改能力声明后，需要再次确认。撤销会阻止旧实例继续调用；重新授权不会恢复旧授权实例，必须重新打开。已送达服务端的写入不能假设被撤回。

宿主通过 `/api/runtime/apps/:id/bootstrap` 读取授权描述；用户确认后以 `policyHash` 调用 `PUT .../grant`。授权后的 bootstrap 返回 `grantId`、固定 revision 的包和能力集合；宿主 invoke 必须同时携带 `grantId` 和 `revision`。这些是宿主接口，用户应用只使用 `platform.*`，不得自行保存凭据或直接请求 HTTP。
