create-zleap-app 0.10.5 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -118,6 +118,9 @@ async function main() {
118
118
  const nameProblem = validateName(name);
119
119
  if (nameProblem) throw new Error(nameProblem);
120
120
  rl?.close();
121
+ // 发布时应用名以 manifest.json 的 name 为准:非交互又没给 --name 时,名字是目录名,发布后控制台里的应用名会被改掉。
122
+ if (!options.name && !rl)
123
+ console.log(red(`! 没有提供 --name,应用名称暂用目录名「${name}」。发布时应用名以 manifest.json 的 name 为准,请改成控制台里的应用名(或重新生成时加 --name "应用名")`));
121
124
 
122
125
  console.log(`\n在 ${cyan(targetDir)} 创建 ${bold(name)}(${appid})`);
123
126
  scaffold({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-zleap-app",
3
- "version": "0.10.5",
3
+ "version": "0.10.6",
4
4
  "description": "一条命令创建 zleapOS 云开发应用(React + TypeScript + Vite),并为 Codex / Claude Code / Pi / OpenCode / Cursor 等 AI 编程工具配好 skills",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -23,9 +23,9 @@
23
23
  },
24
24
  "zleapKit": {
25
25
  "cliPackage": "@zleap-ai/app-cli",
26
- "cliVersion": "0.10.0",
26
+ "cliVersion": "0.10.1",
27
27
  "sdkPackage": "@zleap-ai/app-sdk",
28
- "sdkVersion": "0.10.0",
28
+ "sdkVersion": "0.10.1",
29
29
  "skillsRepo": "RuoFeng2015/zleap-app-kit"
30
30
  },
31
31
  "keywords": [
@@ -117,7 +117,7 @@
117
117
  要点:
118
118
 
119
119
  - `provider.permissions.capabilities` 必须是 `requires` 的子集;`permissions.data[].collection` 必须在 `data.collections` 里——否则上传被拒;
120
- - `input_schema` 会在**提交时**校验(不符返回 `INVOCATION_INPUT_INVALID`),`output_schema` 会约束函数返回值;
120
+ - `input_schema` 会在**提交时**校验:不符时前端 SDK 抛 `SCHEMA_INVALID`(服务端原因 `INVOCATION_INPUT_INVALID`,HTTP 业务码 42200),`output_schema` 会约束函数返回值;
121
121
  - `background.modes` 要含 `"on_demand"` 才能被手动 / 应用调用;定时触发还要含 `"scheduled"`(见 [触发器](triggers.md));
122
122
  - `background.on_install` 固定为 `"disabled"`:**安装不会让任何后台能力自动运行**。
123
123
 
@@ -280,6 +280,14 @@ await zl.cloud.os.database.mutate({
280
280
  可用参数:`collection`、`operation`、`document_key`(`add` 以外必填)、`data`、`value_types`、`field_operations`、
281
281
  `expected_version`(`add` 不接受)、`operation_id`、`request_id`(必填)。`remove` 不接受 `data`。
282
282
 
283
+ 返回值形如 `{ operation_id, stats, document: { _id, _version } }`:`document._id` 是新文档(`add`)或被写文档的键,
284
+ `document._version` 是写入后的版本号,下次 `update` / `remove` 时作为 `expected_version` 传回去。
285
+
286
+ ```js
287
+ const saved = await zl.cloud.os.database.mutate({ collection: 'drafts', operation: 'add', data, request_id: `${context.invocationId}:add` });
288
+ return { id: saved.document._id, version: saved.document._version };
289
+ ```
290
+
283
291
  > **字段命名是 snake_case**(危险)
284
292
  >
285
293
  > 服务端 SDK 用 **snake_case**(`document_key`、`expected_version`、`operation_id`),
@@ -661,7 +669,7 @@ console.log(job.result);
661
669
  | `jobs.wait({ jobId, timeoutSeconds?, pollMilliseconds? })` | 等到终态;`timeoutSeconds` 0–300(默认 25),`pollMilliseconds` 100–5000(默认 500);超时仍未结束抛 `CALL_TIMEOUT`(带 `jobId`) |
662
670
  | `jobs.get({ jobId })` / `jobs.result({ jobId })` | 读一次当前状态 |
663
671
  | `jobs.submit({ kind: 'capability', capability, input, operationId?, waitSeconds? })` | 与 `capabilities.invoke` 等价的另一种写法 |
664
- | `jobs.cancel({ jobId })` | 请求取消,返回 `{ cancelRequested: true }`。**取消不是回滚** |
672
+ | `jobs.cancel({ jobId })` | 请求取消,返回 `{ cancelRequested: true }`。排队中或函数还没开始写数据时,作业以 `cancelled` 结束;正在执行的函数会被立即停止,结果为 `cancelled`。**取消不是回滚**:已提交的写入不会撤销 |
665
673
 
666
674
  同一个 `operationId` 再次提交、输入相同 → 返回原作业;输入不同 → 冲突「同一操作编号的输入不同」。
667
675
  每人同时在排队 / 执行的后台作业最多 16 个(超出 429「本人后台调用队列已满」)。
@@ -43,9 +43,11 @@
43
43
  1. **新项目:用脚手架创建,自动带上 appid**
44
44
 
45
45
  ```bash
46
- npm create zleap-app@latest my-app -- --appid zl3f9a2c7e1b0d4a68
46
+ npm create zleap-app@latest my-app -- --appid zl3f9a2c7e1b0d4a68 --name "客户拜访"
47
47
  ```
48
48
 
49
+ `--name` 填控制台里的应用名:发布时应用名以 `manifest.json` 的 `name` 为准,不填会用目录名(这里是 `my-app`)。
50
+
49
51
  2. **已有项目:把 appid 写进 manifest.json**
50
52
 
51
53
  ```json
@@ -488,6 +488,8 @@ Manifest 校验器接受 `^[a-zA-Z][a-zA-Z0-9_.-]*$`(≤128),但**数据
488
488
  规则是一个布尔表达式,决定某条文档能否被读/写,例如 `doc.status == 'open'`。
489
489
 
490
490
  - 操作数:`doc.<字段>`、`auth.uid`、`auth.openid`、`now`、数字、单引号字符串、`true`/`false`/`null`;
491
+ - `auth.openid` 是调用者在**本应用数据域**里的身份,等于他写入的文档上的 `_openid`(例如 `doc._openid == auth.openid`
492
+ 表示「只能读写自己的记录」)。它和页面里 `zl.auth.getIdentity()` 拿到的 `openid` **不是同一个值**,不要拿后者去比较或写进规则;
491
493
  - 运算:`==`、`!=`、`<`、`<=`、`>`、`>=`、`&&`、`||`、`!`、括号;
492
494
  - 最多 64 个节点、8 层嵌套;
493
495
  - 不能两边都是字面量;与 `true`/`false`/`null` 比较时另一边必须是 `doc.<字段>`;
@@ -386,7 +386,9 @@ off(); // 取消订阅
386
386
  - 回调**只带变更坐标,不带文档内容**——收到后用 `get` / `watch` 重读;
387
387
  - 只会收到**本集合**的变更(一个订阅覆盖应用所有集合,SDK 按 `collection_key` 过滤);
388
388
  - 推送是**协商可选**的:宿主没有推送能力、或还没 `init` 时返回一个空的取消函数,回调永远不会触发。
389
- 所以**保留一个低频的 `watch` / `get` 兜底是安全的**,不要假设一定有实时通知。
389
+ 所以**保留一个低频的 `watch` / `get` 兜底是安全的**,不要假设一定有实时通知;
390
+ - 时延:写入确认后平台立即转发,通常 1 秒内到达;平台繁忙时退回定时转发,可能延迟到几十秒。
391
+ 自己写入后要马上看到结果的,直接用写入返回值或重读,不要等 `onChange`。
390
392
 
391
393
  ### 不支持的方法
392
394
 
@@ -151,6 +151,7 @@
151
151
  | `VERSION_CONFLICT` | 乐观锁冲突,或键已存在等 409 类错误 | 重新读取最新版本再改 |
152
152
  | `DOCUMENT_NOT_FOUND` | 文档不存在(或 404 类错误) | 检查文档键;读取时可用 `throwOnNotFound: false` |
153
153
  | `COLLECTION_NOT_FOUND` | 集合不存在 | 在 Manifest `data.collections` 声明;生产环境要单独开通集合 |
154
+ | `SCOPE_FORBIDDEN` | 读写了 manifest **没声明**的集合(或没授权) | 先在 `data.collections` 声明再部署;已声明还报这个,看「权限」里是否勾了数据读写 |
154
155
  | `INDEX_REQUIRED` | 查询需要扫描的行数超过单次上限 | 给筛选字段建索引;已有索引仍超限时缩小筛选范围 |
155
156
  | `RESOURCE_NOT_READY` | 云数据库正在开通,或数据服务还没加载本应用 | 通常一分钟内自动就绪,稍后刷新重试 |
156
157
 
@@ -43,9 +43,11 @@
43
43
  1. **新项目:用脚手架创建,自动带上 appid**
44
44
 
45
45
  ```bash
46
- npm create zleap-app@latest my-app -- --appid zl3f9a2c7e1b0d4a68
46
+ npm create zleap-app@latest my-app -- --appid zl3f9a2c7e1b0d4a68 --name "客户拜访"
47
47
  ```
48
48
 
49
+ `--name` 填控制台里的应用名:发布时应用名以 `manifest.json` 的 `name` 为准,不填会用目录名(这里是 `my-app`)。
50
+
49
51
  2. **已有项目:把 appid 写进 manifest.json**
50
52
 
51
53
  ```json
@@ -151,6 +151,7 @@
151
151
  | `VERSION_CONFLICT` | 乐观锁冲突,或键已存在等 409 类错误 | 重新读取最新版本再改 |
152
152
  | `DOCUMENT_NOT_FOUND` | 文档不存在(或 404 类错误) | 检查文档键;读取时可用 `throwOnNotFound: false` |
153
153
  | `COLLECTION_NOT_FOUND` | 集合不存在 | 在 Manifest `data.collections` 声明;生产环境要单独开通集合 |
154
+ | `SCOPE_FORBIDDEN` | 读写了 manifest **没声明**的集合(或没授权) | 先在 `data.collections` 声明再部署;已声明还报这个,看「权限」里是否勾了数据读写 |
154
155
  | `INDEX_REQUIRED` | 查询需要扫描的行数超过单次上限 | 给筛选字段建索引;已有索引仍超限时缩小筛选范围 |
155
156
  | `RESOURCE_NOT_READY` | 云数据库正在开通,或数据服务还没加载本应用 | 通常一分钟内自动就绪,稍后刷新重试 |
156
157
 
@@ -212,6 +212,14 @@ async function deploy() {
212
212
  const packageId = id(pack.id);
213
213
  if (!appId || !versionId) throw new StepError(`上传回执缺少 app_id / version_id:${published.stdout}`);
214
214
  ok(`已上传 v${report.version}:app_id=${appId} version_id=${versionId} package_id=${packageId}`);
215
+ // 平台 appid 应用:带云函数 / 后台能力的版本上传后平台自动签名;签不上时回执带原因(旧平台没有这个字段)。
216
+ const autoSign = published.json?.result?.auto_sign;
217
+ if (autoSign?.status === 'failed') {
218
+ warn(
219
+ `平台自动签名失败(${autoSign.reason ?? '未知原因'}):云函数 / 后台能力暂时不可用。打开应用或切换版本时平台会自动重试;` +
220
+ `也可以运行 npx zleap-app prepare ${appId} --version-id ${versionId} 查看详细错误。`,
221
+ );
222
+ }
215
223
  writeJSON(stateFile, { appId, versionId, packageId, version: report.version, digest: report.digest, at: new Date().toISOString() });
216
224
 
217
225
  if (has('no-install')) return finish(appId, false);