This commit is contained in:
@@ -44,8 +44,8 @@ spacetime generate --lang typescript|csharp|rust|unrealcpp --out-dir ./bindings
|
||||
### Publishing & Deployment
|
||||
|
||||
```bash
|
||||
# Publish to Maincloud (default)
|
||||
spacetime publish my-database --yes
|
||||
# Publish to an explicit server
|
||||
spacetime publish my-database --server http://127.0.0.1:3101 --yes
|
||||
|
||||
# Publish to local server
|
||||
spacetime publish my-database --server local --yes
|
||||
@@ -133,8 +133,8 @@ spacetime logout
|
||||
|
||||
| Name | URL | Description |
|
||||
|------|-----|-------------|
|
||||
| `maincloud` | `https://maincloud.spacetimedb.com` | Production cloud (default) |
|
||||
| `local` | `http://127.0.0.1:3000` | Local development server |
|
||||
| `dev` | `http://127.0.0.1:3101` | Genarrative local development server |
|
||||
|
||||
## Common Workflows
|
||||
|
||||
@@ -224,6 +224,6 @@ rustup target add wasm32-unknown-unknown
|
||||
## Notes
|
||||
|
||||
- Many commands are marked UNSTABLE and may change
|
||||
- Default server is `maincloud` unless configured otherwise
|
||||
- Genarrative scripts should pass `--server` or `--server-url` explicitly instead of relying on the CLI default
|
||||
- Use `--yes` flag in scripts to avoid interactive prompts
|
||||
- Dev mode watches files and auto-rebuilds on changes
|
||||
|
||||
@@ -54,10 +54,6 @@ GENARRATIVE_SPACETIME_SERVER_URL="http://127.0.0.1:3101"
|
||||
GENARRATIVE_SPACETIME_DATABASE="xushi-p4wfr"
|
||||
GENARRATIVE_SPACETIME_TOKEN=""
|
||||
|
||||
GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL="https://maincloud.spacetimedb.com"
|
||||
GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE="xushi-p4wfr"
|
||||
GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN=""
|
||||
|
||||
# admin
|
||||
GENARRATIVE_ADMIN_USERNAME=admin
|
||||
GENARRATIVE_ADMIN_PASSWORD=123456
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
- 涉及 `crates/spacetime-module` 的表、reducer、view、Rust API 使用时,按 `spacetimedb-rust` 与 `spacetimedb-concepts` 执行。
|
||||
- 涉及前端或 Node 侧的 SpacetimeDB TypeScript SDK、订阅、绑定使用时,按 `spacetimedb-typescript` 与 `spacetimedb-concepts` 执行。
|
||||
- 若仓库内旧实现或旧文档与这些 skill 冲突,先修正文档和方案,再继续编码。
|
||||
- 修改后端代码后,必须使用 `npm run api-server:maincloud` 自动重新运行后端,并执行相应自动测试;不要再使用旧的后端重启命令。
|
||||
- 修改后端代码后,必须使用 `npm run api-server` 自动重新运行后端,并执行相应自动测试;不要再使用旧的后端重启命令。
|
||||
- 数据库表结构更改后,需要对齐migration.rs
|
||||
|
||||
## 文档图谱
|
||||
|
||||
@@ -628,7 +628,7 @@ SpacetimeDB 方向:
|
||||
4. LLM、OSS、图片生成等外部 I/O 放在 `api-server` / `platform-*` crate 中,再把确定结果写回 SpacetimeDB。
|
||||
5. 前端调用 reducer 使用生成绑定和对象参数,不编辑生成代码。
|
||||
6. 涉及表结构修改时同步更新 `migration.rs`。
|
||||
7. 修改后端代码后统一执行 `npm run api-server:maincloud`,并跑对应自动测试。
|
||||
7. 修改后端代码后统一执行 `npm run api-server`,并跑对应自动测试。
|
||||
|
||||
## 9. 最小验收标准
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
1. `package.json` 中不存在 `server-node:*`、`dev:node`、`m7:api-compare`、`check:server-node-freeze` 等旧入口。
|
||||
2. `scripts/` 下不存在 `dev-node.mjs`、`smoke-server-node.ts`、`m7-api-compare.ts`、`smoke-same-origin-stack.ts` 等旧 Node 后端脚本。
|
||||
3. `package.json` 与 `package-lock.json` 中不存在 `express`、`@types/express`、`pg`、`postgres` 依赖。
|
||||
4. 当前开发入口继续固定为 `npm run dev`、`npm run dev:web`、`npm run api-server:maincloud` 与 Rust / SpacetimeDB 相关脚本,不恢复旧 Node 后端切换开关。
|
||||
4. 当前开发入口继续固定为 `npm run dev`、`npm run dev:web`、`npm run api-server` 与 Rust / SpacetimeDB 相关脚本,不恢复旧 Node 后端切换开关。
|
||||
|
||||
## 9. Caddy 本地服务入口移除(2026-04-26)
|
||||
|
||||
|
||||
@@ -255,14 +255,14 @@ node scripts/vite-cli.mjs --port=3000 --host=0.0.0.0
|
||||
后端代码更新后统一执行:
|
||||
|
||||
```bash
|
||||
npm run api-server:maincloud
|
||||
npm run api-server
|
||||
```
|
||||
|
||||
执行要求:
|
||||
|
||||
- 该命令是后端更新后的默认重启入口,不再使用此前的后端重启命令。
|
||||
- 重启后必须继续执行与本次后端改动对应的自动测试;涉及 Rust workspace 时优先跑 `server-rs` 下的检查或测试脚本。
|
||||
- 若本次改动涉及 SpacetimeDB 发布、绑定生成或 Maincloud 联调,按 `spacetimedb-cli` 经验执行,并在验证记录中写清楚实际命令与结果。
|
||||
- 若本次改动涉及 SpacetimeDB 发布、绑定生成或本地联调,按 `spacetimedb-cli` 经验执行,并在验证记录中写清楚实际命令与结果。
|
||||
|
||||
## 14. 一句话总结
|
||||
|
||||
|
||||
@@ -753,7 +753,7 @@ RPG 运行时链:
|
||||
|
||||
这些脚本不直接参与玩法,但直接支撑开发、发布、绑定和检查:
|
||||
|
||||
### `scripts/api-server-maincloud.mjs`
|
||||
### `scripts/api-server-dev.mjs`
|
||||
|
||||
职责:
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
|
||||
`tableStats` 中单表失败必须展示 `errorMessage`,不能让整页变成空白。SpacetimeDB private 表或当前身份不可见的表在 `/sql` 下可能返回 `no such table` / `marked private`,后台服务必须将这类错误归一为“不可统计(private 或当前身份不可见)”,避免把预期的访问边界展示成原始 HTTP 400 故障。
|
||||
|
||||
线上如果大量表都显示“不可统计(private 或当前身份不可见)”,优先检查 `api-server` 启动环境中的 `GENARRATIVE_SPACETIME_TOKEN` / `GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN` 是否存在且属于目标库 owner。Jenkins 覆盖发布包时必须保留部署目录已有运行 token;只带迁移 token 不能让后台概览读取 private 表。
|
||||
线上如果大量表都显示“不可统计(private 或当前身份不可见)”,优先检查 `api-server` 启动环境中的 `GENARRATIVE_SPACETIME_TOKEN` 是否存在且属于目标库 owner。Jenkins 覆盖发布包时必须保留部署目录已有运行 token;只带迁移 token 不能让后台概览读取 private 表。
|
||||
|
||||
### 4.6 API 调试 contract
|
||||
|
||||
@@ -380,7 +380,7 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
|
||||
### 7.1 本地联调
|
||||
|
||||
1. 启动后端:`npm run api-server:maincloud`。
|
||||
1. 启动后端:`npm run api-server`。
|
||||
2. 启动后台前端:在 `apps/admin-web` 执行 `npm run dev`。
|
||||
3. 后台 dev server 通过 Vite proxy 转发 `/admin/api` 到 `ADMIN_API_TARGET`;未配置时默认 `http://127.0.0.1:3100`。
|
||||
4. 若使用非 3100 端口,在仓库根目录 `.env.local` 设置 `ADMIN_API_TARGET=http://127.0.0.1:<api-server-port>`,并重启后台前端 dev server。
|
||||
@@ -437,7 +437,7 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
- 后续接入根 workspace 后,补充后台工程 build/typecheck 脚本。
|
||||
3. 后端:
|
||||
- 继续保留 `cargo test -p api-server --manifest-path server-rs/Cargo.toml admin`。
|
||||
- 修改后端管理 API 后必须运行 `npm run api-server:maincloud` 并手动验证 `/admin` 为 404、`/admin/api/login` 可用。
|
||||
- 修改后端管理 API 后必须运行 `npm run api-server` 并手动验证 `/admin` 为 404、`/admin/api/login` 可用。
|
||||
|
||||
## 9. 后续扩展边界
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
## 2. 根因
|
||||
|
||||
### 2.1 Maincloud 目标库挂起
|
||||
### 2.1 远端目标库挂起
|
||||
|
||||
CLI 直接查询 `xushi-p4wfr` 返回:
|
||||
|
||||
@@ -20,7 +20,7 @@ Error: database is suspended
|
||||
HTTP status server error (503 Service Unavailable)
|
||||
```
|
||||
|
||||
这说明 `maincloud.spacetimedb.com` 入口在线,但具体数据库 `xushi-p4wfr` 当前不可订阅、不可查 schema、不可执行 SQL。所有依赖该库的 procedure 都会失败。
|
||||
这说明远端 SpacetimeDB 入口在线,但具体数据库 `xushi-p4wfr` 当前不可订阅、不可查 schema、不可执行 SQL。所有依赖该库的 procedure 都会失败。
|
||||
|
||||
### 2.2 认证快照同步被当成硬失败
|
||||
|
||||
@@ -64,7 +64,7 @@ HTTP status server error (503 Service Unavailable)
|
||||
|
||||
## 4. 本地可跑链路
|
||||
|
||||
Maincloud `xushi-p4wfr` 挂起期间,抓大鹅本地体验应使用本地 SpacetimeDB:
|
||||
远端 `xushi-p4wfr` 挂起期间,抓大鹅本地体验应使用本地 SpacetimeDB:
|
||||
|
||||
```powershell
|
||||
spacetime --root-dir=server-rs/.spacetimedb/local start --edition standalone --listen-addr 127.0.0.1:3101
|
||||
@@ -75,10 +75,10 @@ spacetime --root-dir=server-rs/.spacetimedb/local publish xushi-p4wfr --server h
|
||||
再让 Rust API 指向本地库:
|
||||
|
||||
```powershell
|
||||
$env:GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL="http://127.0.0.1:3101"
|
||||
$env:GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE="xushi-p4wfr"
|
||||
$env:GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN=""
|
||||
npm run api-server:maincloud
|
||||
$env:GENARRATIVE_SPACETIME_SERVER_URL="http://127.0.0.1:3101"
|
||||
$env:GENARRATIVE_SPACETIME_DATABASE="xushi-p4wfr"
|
||||
$env:GENARRATIVE_SPACETIME_TOKEN=""
|
||||
npm run api-server
|
||||
```
|
||||
|
||||
最后重启前端:
|
||||
@@ -96,10 +96,10 @@ npm run dev:web
|
||||
1. `GET http://127.0.0.1:3000/api/auth/login-options` 返回 `["phone","password"]`。
|
||||
2. `GET http://127.0.0.1:3000/api/runtime/match3d/gallery` 返回 `{"items":[]}`,不再返回 SpacetimeDB 503。
|
||||
3. 未登录请求 `POST http://127.0.0.1:3000/api/creation/match3d/sessions` 返回 `401`,说明同源请求已进入 Rust 鉴权层,不再被 Vite `404`。
|
||||
4. 隔离端口指向挂起的 Maincloud 并使用 mock 短信时,手机号验证码登录返回 `200` 和 token;日志只记录“认证快照写入 SpacetimeDB 失败,当前认证流程继续”。
|
||||
4. 隔离端口指向挂起的远端库并使用 mock 短信时,手机号验证码登录返回 `200` 和 token;日志只记录“认证快照写入 SpacetimeDB 失败,当前认证流程继续”。
|
||||
|
||||
## 6. 后续
|
||||
|
||||
1. Maincloud `xushi-p4wfr` 仍需恢复数据库挂起状态,否则正式云端玩法 procedure 仍不可用。
|
||||
1. 远端 `xushi-p4wfr` 仍需恢复数据库挂起状态,否则对应玩法 procedure 仍不可用。
|
||||
2. 本地开发如只为体验抓大鹅,可继续使用本地 SpacetimeDB 链路。
|
||||
3. 认证快照同步失败会影响进程重启后的云端恢复完整性,需要在 Maincloud 恢复后重新完成一次成功同步。
|
||||
3. 认证快照同步失败会影响进程重启后的远端恢复完整性,需要在目标库恢复后重新完成一次成功同步。
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
但当前链路仍暴露出两个直接体验问题:
|
||||
|
||||
1. 前端草稿进度页仍把大鱼吃小鱼展示成单个 `compile` 步骤,用户会感觉“整个生成过程只有一步,而且一直卡在第一步”。
|
||||
2. 前端在打开大鱼草稿或结果页时,会通过 `GET /api/runtime/big-fish/agent/sessions/:sessionId` 拉取完整会话;当 Maincloud 上游偶发抖动时,Rust `spacetime-client` 统一 10 秒超时会直接映射成 `502`,用户会看到反复报错。
|
||||
2. 前端在打开大鱼草稿或结果页时,会通过 `GET /api/runtime/big-fish/agent/sessions/:sessionId` 拉取完整会话;当 SpacetimeDB 上游偶发抖动时,Rust `spacetime-client` 统一 10 秒超时会直接映射成 `502`,用户会看到反复报错。
|
||||
|
||||
## 修复口径
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
这样可以覆盖两类常见情况:
|
||||
|
||||
1. Maincloud 连接偶发抖动,第一次 procedure 超时但第二次马上恢复。
|
||||
1. SpacetimeDB 连接偶发抖动,第一次 procedure 超时但第二次马上恢复。
|
||||
2. 用户打开草稿页时碰到短暂断链,不再被立即判定成稳定的坏网关故障。
|
||||
|
||||
## 落地范围
|
||||
|
||||
@@ -39,7 +39,7 @@ Genarrative-Database-Export
|
||||
关键参数:
|
||||
|
||||
1. `DATABASE`:目标 SpacetimeDB 数据库名;留空时读取仓库环境变量。
|
||||
2. `SERVER`:SpacetimeDB server 别名,默认 `maincloud`。
|
||||
2. `SERVER`:SpacetimeDB server 别名,默认 `dev`。
|
||||
3. `SERVER_URL`:显式服务地址;填写后优先于 `SERVER`。
|
||||
4. `DEPLOY_DIRECTORY`:固定部署目录,默认 `/var/lib/jenkins/deploy/Genarrative`。
|
||||
5. `ROOT_DIR`:可选,透传给 `spacetime --root-dir`;为空时使用 `<DEPLOY_DIRECTORY>/.spacetimedb`。
|
||||
@@ -91,7 +91,7 @@ Genarrative-Database-Import
|
||||
|
||||
## 5. 本地部署测试参数
|
||||
|
||||
`Genarrative-Build-And-Deploy` 增加以下本地发布包参数,便于在 Jenkins 中测试本地 SpacetimeDB,不依赖 Maincloud:
|
||||
`Genarrative-Build-And-Deploy` 增加以下本地发布包参数,便于在 Jenkins 中测试本地 SpacetimeDB:
|
||||
|
||||
1. `DATABASE`:发布包默认数据库名,默认 `genarrative-pipeline-local-test`。SpacetimeDB CLI 当前要求数据库名匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`,只能使用小写字母、数字,并用单个短横线分隔;不要使用大写字母、点号、下划线、首尾短横线或连续短横线。
|
||||
2. `API_PORT`:发布包内 api-server 端口,默认 `8082`。
|
||||
@@ -107,7 +107,7 @@ SERVER_URL=http://127.0.0.1:3101
|
||||
DEPLOY_DIRECTORY=/var/lib/jenkins/deploy/Genarrative
|
||||
```
|
||||
|
||||
这样脚本会自动使用 `/var/lib/jenkins/deploy/Genarrative/.spacetimedb` 作为 `spacetime --root-dir`,避免回退到 Jenkins 用户全局 CLI 登录态,也避免误连 Maincloud。
|
||||
这样脚本会自动使用 `/var/lib/jenkins/deploy/Genarrative/.spacetimedb` 作为 `spacetime --root-dir`,避免回退到 Jenkins 用户全局 CLI 登录态,也避免误连非本地目标。
|
||||
|
||||
## 6. 文件清单
|
||||
|
||||
|
||||
@@ -76,4 +76,4 @@ Responses 非流式解析优先读取 `output_text`,再兼容 `output[].conten
|
||||
3. `platform-llm` 单测覆盖 Responses 非流式、Responses SSE、Responses web_search tools 请求体。
|
||||
4. `cargo test -p platform-llm --manifest-path server-rs/Cargo.toml` 通过。
|
||||
5. `cargo test -p api-server creation_agent_llm_turn --manifest-path server-rs/Cargo.toml` 通过。
|
||||
6. 修改后按项目约束使用 `npm run api-server:maincloud` 重新启动后端,并执行相应自动测试。
|
||||
6. 修改后按项目约束使用 `npm run api-server` 重新启动后端,并执行相应自动测试。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
日期:`2026-04-22`
|
||||
|
||||
归档说明:截至 `2026-04-26`,Rust 迁移已完成,旧 `server-node/` 已删除,M7 阶段性预检包装入口已移除。后续长期检查统一使用 `server-rs/scripts/check.ps1`、`server-rs/scripts/smoke.ps1`、`server-rs/scripts/oss-smoke.ps1` 与 `npm run api-server:maincloud`。
|
||||
归档说明:截至 `2026-04-26`,Rust 迁移已完成,旧 `server-node/` 已删除,M7 阶段性预检包装入口已移除。后续长期检查统一使用 `server-rs/scripts/check.ps1`、`server-rs/scripts/smoke.ps1`、`server-rs/scripts/oss-smoke.ps1` 与 `npm run api-server`。
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
|
||||
@@ -784,7 +784,7 @@ B3 当前落地状态:
|
||||
1. 创作到发布到试玩主链通过。
|
||||
2. 运行态点击、入槽、三消、失败、胜利通过。
|
||||
3. 移动端视口检查通过。
|
||||
4. `npm run api-server:maincloud` 通过。
|
||||
4. `npm run api-server` 通过。
|
||||
5. 对应测试与 `npm run check:encoding` 通过。
|
||||
|
||||
---
|
||||
@@ -820,7 +820,7 @@ npm run check:encoding -- docs/technical/MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IM
|
||||
```powershell
|
||||
cargo test -p module-match3d
|
||||
cargo test -p shared-contracts
|
||||
npm run api-server:maincloud
|
||||
npm run api-server
|
||||
npm run check:encoding
|
||||
```
|
||||
|
||||
|
||||
@@ -110,4 +110,4 @@ server-rs/crates/module-match3d
|
||||
1. `cargo test -p module-match3d` 通过。
|
||||
2. `cargo test -p shared-contracts match3d` 通过。
|
||||
3. `npm run check:encoding` 覆盖新增中文文档和新增源码。
|
||||
4. 本阶段不要求运行 `npm run api-server:maincloud`,因为未修改后端运行服务入口、SpacetimeDB 表或 `api-server` facade。
|
||||
4. 本阶段不要求运行 `npm run api-server`,因为未修改后端运行服务入口、SpacetimeDB 表或 `api-server` facade。
|
||||
|
||||
@@ -143,4 +143,4 @@ npm run check:encoding
|
||||
3. 不把 Match3D 公开广场并入更复杂的推荐、排行和运营榜单策略。
|
||||
4. 不删除 `/match3d` 本地 playground;它作为开发调试入口继续保留。
|
||||
5. 全量 `npm run typecheck` 曾存在非 Match3D 既有阻塞,本轮以 Q1 定向测试和后端定向检查作为集成验收口径。
|
||||
6. Maincloud 运行态仍依赖当前 SpacetimeDB 环境稳定性;如 `npm run api-server:maincloud` 现场遇到订阅 HTTP 500,应按 Maincloud/SpacetimeDB 联调链路单独排查。
|
||||
6. 运行态仍依赖当前 SpacetimeDB 环境稳定性;如 `npm run api-server` 现场遇到订阅 HTTP 500,应按本地 SpacetimeDB 联调链路单独排查。
|
||||
|
||||
@@ -119,10 +119,10 @@ cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
|
||||
cargo check -p api-server --manifest-path server-rs\Cargo.toml
|
||||
cargo test -p shared-contracts match3d --manifest-path server-rs\Cargo.toml
|
||||
npm run check:encoding
|
||||
npm run api-server:maincloud
|
||||
npm run api-server
|
||||
```
|
||||
|
||||
`api-server:maincloud` 是修改后端后的必跑项;如果本地缺少 Maincloud 环境或 SpacetimeDB 发布态不一致,需要在最终结果里明确说明。
|
||||
`api-server` 是修改后端后的必跑项;如果本地 SpacetimeDB 发布态不一致,需要在最终结果里明确说明。
|
||||
|
||||
## 7. 后续接入点
|
||||
|
||||
|
||||
@@ -128,4 +128,4 @@
|
||||
- Rust/module-runtime:覆盖公共码、唯一码、私有码、失败场景、流水来源和余额累加。
|
||||
- Axum:覆盖用户鉴权、管理员鉴权、runtime error 到 400 的映射和兼容路径。
|
||||
- 前端:覆盖入口替换、独立 modal、成功刷新余额和失败展示后端 message。
|
||||
- 验证命令:`cargo test`、目标前端测试、`npm run api-server:maincloud`、`npm run check:encoding`。
|
||||
- 验证命令:`cargo test`、目标前端测试、`npm run api-server`、`npm run check:encoding`。
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
4. 玩家在生成草稿前退出,再次从创作中心点击这条拼图草稿时,必须恢复到填表页,并回填之前自动保存的作品名称、作品描述和画面描述;只有执行 `compile_puzzle_draft` 且生成结果页草稿后,草稿入口才进入结果页。
|
||||
5. 表单自动保存走 `save_puzzle_form_draft` action,不消耗光点,不生成图片,不改变 `stage = collecting_anchors`;生成草稿按钮仍单独触发 `compile_puzzle_draft` 并进入进度页。
|
||||
6. 点击拼图入口始终创建新草稿,不复用上一次未完成 session;恢复旧草稿只通过“我的创作”中的草稿卡进入。
|
||||
7. 若 Maincloud 仍运行旧 wasm,缺少 `save_puzzle_form_draft` procedure,前端提交生成或生成失败页重试时不得继续复用空 `seedText` 的表单 session,必须用当前表单 payload 新建带真实 seed 的 session 再执行 `compile_puzzle_draft`。
|
||||
7. 若运行中的旧 wasm 缺少 `save_puzzle_form_draft` procedure,前端提交生成或生成失败页重试时不得继续复用空 `seedText` 的表单 session,必须用当前表单 payload 新建带真实 seed 的 session 再执行 `compile_puzzle_draft`。
|
||||
8. api-server 也要兼容旧 wasm:`save_puzzle_form_draft` 缺失时,自动保存 action 降级返回当前 session;`compile_puzzle_draft` 前置保存缺失且当前 session 为空 seed 时,创建一条带表单 seed 的替代 session 后继续编译,避免再次暴露 `No such procedure`。
|
||||
9. 正式修复仍是发布最新 SpacetimeDB wasm。当前 Maincloud `xushi-p4wfr` 的迁移操作员表为空,但旧库引导密钥来自旧 wasm,本次临时生成的新引导密钥无法授权导出迁移,需使用已有迁移操作员 token 或数据库 owner 重新授权后发布;禁止为绕过冲突直接清库,除非明确接受数据丢失。
|
||||
9. 正式修复仍是发布最新 SpacetimeDB wasm。如果目标库的迁移操作员表为空,但旧库引导密钥来自旧 wasm,本次临时生成的新引导密钥无法授权导出迁移,需使用已有迁移操作员 token 或数据库 owner 重新授权后发布;禁止为绕过冲突直接清库,除非明确接受数据丢失。
|
||||
|
||||
1. 作品名称为必填字段,保存到 `workTitle`,兼容写入旧 `seedText`,同时作为作品级 `workTitle` 的真相源。
|
||||
2. 作品描述为必填字段,保存到 `workDescription`,作为作品详情页、作品列表和发布资料中的 `summary` 真相源。
|
||||
|
||||
@@ -28,4 +28,4 @@
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `cargo check -p api-server --manifest-path server-rs/Cargo.toml`
|
||||
3. `npm run api-server:maincloud` 重启后,点击拼图结果页“生成或更换图片”,候选图应能写回并正常展示。
|
||||
3. `npm run api-server` 重启后,点击拼图结果页“生成或更换图片”,候选图应能写回并正常展示。
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
|
||||
- [PRODUCT_NAMING_BAIMENG_RENAME_2026-05-01.md](./PRODUCT_NAMING_BAIMENG_RENAME_2026-05-01.md):冻结当前对外中文命名,产品展示名统一为“百梦”,消费单位为“光点”,公开账号标识为“百梦号”,创作侧称谓为“百梦主”。
|
||||
- [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md):冻结 SpacetimeDB 表结构变更约束、自动迁移可接受范围、冲突后的系统行为,以及保留旧数据的增量迁移流程;凡涉及 `spacetime publish`、表字段调整或 `migration.rs` 对齐时优先参考。
|
||||
- [SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md](./SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md):记录旧云端 SpacetimeDB 配置、发布脚本和默认文档口径的移除结果,冻结后续仅使用本地或显式 `SERVER_URL` 的运维规则。
|
||||
- [SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md](./SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md):记录本地 standalone 启动时报 `mismatched database identity` 的 root-dir/replica 数据残留根因、备份重建步骤和脚本诊断口径。
|
||||
- [AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md](./AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md):记录 Maincloud `xushi-p4wfr` 挂起导致认证快照同步和抓大鹅创作失败的根因、认证同步非阻断修复、`/api/creation` Vite 代理补齐和本地 SpacetimeDB 可跑链路。
|
||||
- [AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md](./AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md):记录远端库挂起导致认证快照同步和抓大鹅创作失败的根因、认证同步非阻断修复、`/api/creation` Vite 代理补齐和本地 SpacetimeDB 可跑链路。
|
||||
- [LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md](./LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md):冻结 RPG 运行时剧情推理使用 `doubao-seed-character-251128` 的 `/chat/completions`,以及所有模板创作大模型推理使用 `deepseek-v3-2-251201` 的 `/responses`。
|
||||
- [PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md](./PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md):冻结邀请码从“我的 Tab 填写”迁到注册环节的前后端边界、`profile_invite_code.metadata_json` 表结构扩展、管理员邀请码虚拟主体和奖励规则。
|
||||
- [MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md](./MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md):冻结抓大鹅 Match3D 首版 demo 的独立玩法域、表与 procedure、HTTP facade、前端即时反馈/后端权威确认协议,以及可并行开发包。
|
||||
@@ -25,7 +26,7 @@
|
||||
- [RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md](./RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md):冻结 RPG 创作结果页保存、Agent session/result preview 真相优先级和结果页入口裁决迁移到后端 result-view 的落地边界。
|
||||
- [RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md](./RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md):记录 RPG 创作 profile 生成移除非浏览器 legacy AI 回退,统一通过 `server-rs` 的 `/api/runtime/custom-world/profile` 生成世界底稿。
|
||||
- [CREATION_PUBLIC_GALLERY_AND_AGENT_RESTORE_GUARD_FIX_2026-04-28.md](./CREATION_PUBLIC_GALLERY_AND_AGENT_RESTORE_GUARD_FIX_2026-04-28.md):记录 RPG Agent 旧 URL 恢复指针必须有本机用户归属才读取受保护 session,以及 Big Fish 公开广场读取失败按空广场降级的修复口径。
|
||||
- [BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md](./BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md):记录大鱼吃小鱼草稿进度页从单步 compile 改为多阶段感知展示,以及大鱼会话读取在 Maincloud 抖动时增加短重试与超时语义收口的修复口径。
|
||||
- [BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md](./BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md):记录大鱼吃小鱼草稿进度页从单步 compile 改为多阶段感知展示,以及大鱼会话读取在 SpacetimeDB 抖动时增加短重试与超时语义收口的修复口径。
|
||||
- [BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md](./BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md):记录大鱼吃小鱼草稿生成、生图、动作三类提示词从业务脚本中抽离到独立 `prompt/big_fish.rs` 模块的边界与职责划分。
|
||||
- [BIG_FISH_MAIN_IMAGE_TRANSPARENT_BACKGROUND_ALIGNMENT_2026-04-28.md](./BIG_FISH_MAIN_IMAGE_TRANSPARENT_BACKGROUND_ALIGNMENT_2026-04-28.md):记录大鱼吃小鱼等级主图与动作关键帧正式图在 Rust 后端复用 RPG 角色主图透明背景 alpha 后处理的对齐口径,并明确场地背景不走该处理。
|
||||
- [PUZZLE_IMAGE_AND_FRONTEND_RULES_ALIGNMENT_2026-04-29.md](./PUZZLE_IMAGE_AND_FRONTEND_RULES_ALIGNMENT_2026-04-29.md):记录拼图生成图片回到 1:1,运行时拖动、交换、合并与拆分由前端即时裁决,以及移动端棋盘贴近屏幕边缘的落地边界。
|
||||
@@ -45,7 +46,7 @@
|
||||
- [SPACETIMEDB_TABLE_CATALOG.md](./SPACETIMEDB_TABLE_CATALOG.md):持续维护当前 SpacetimeDB 表目录,按领域说明每张表的作用、字段结构、索引和常用 `spacetime sql` 查询模板。
|
||||
- [RPG_OPENING_SCENE_ACT_IMAGE_PRESENTATION_SYNC_2026-04-26.md](./RPG_OPENING_SCENE_ACT_IMAGE_PRESENTATION_SYNC_2026-04-26.md):记录开局场景与普通场景复用同一场景展示解析服务,修复列表幕缩略图和详情幕背景预览图片不一致的问题。
|
||||
- [FRONTEND_FIRST_LOAD_PERFORMANCE_FIX_2026-04-26.md](./FRONTEND_FIRST_LOAD_PERFORMANCE_FIX_2026-04-26.md):记录网站启动后首次加载约三分钟的前端根因,收口 `RouteImageReadyGate` 首屏图片门控和 Vite dev server 无关文件监听范围。
|
||||
- [RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md](./RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md):记录 RPG 作品删除时报 `No such procedure` 的根因,补齐 `delete_custom_world_agent_session` 在有效 SpacetimeDB 模块入口中的导出,并要求发布后核验 Maincloud schema。
|
||||
- [RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md](./RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md):记录 RPG 作品删除时报 `No such procedure` 的根因,补齐 `delete_custom_world_agent_session` 在有效 SpacetimeDB 模块入口中的导出,并要求发布后核验 schema。
|
||||
- [CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md](./CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md):冻结当前后端唯一落地口径,明确新功能以 `server-rs + Axum + SpacetimeDB` 为准,旧 `server-node` / Express / PostgreSQL 与 Go 方向只允许作为迁移参考。
|
||||
- [RPG_DRAFT_GENERATION_CONTINUE_AND_ETA_FIX_2026-04-25.md](./RPG_DRAFT_GENERATION_CONTINUE_AND_ETA_FIX_2026-04-25.md):记录世界草稿生成失败/中断后进度不再误到 `100%`、主按钮改为“继续生成草稿”并复用已保存底稿续跑,以及按阶段耗时模型估算预计等待时间的修复口径。
|
||||
- [RUNTIME_NPC_CHAT_LLM_MIGRATION_2026-04-25.md](./RUNTIME_NPC_CHAT_LLM_MIGRATION_2026-04-25.md):冻结运行时 NPC 聊天从 Rust 确定性兜底迁到 `platform-llm` 的边界,要求旧 Node 聊天提示词原样迁移,覆盖回复、建议、好感变化与限轮收束。
|
||||
|
||||
@@ -48,4 +48,4 @@ Agent 路由保持原有 submit/finalize 分工:
|
||||
3. `cargo test -p api-server runtime_chat`
|
||||
4. `cargo test -p api-server creation_agent_llm_turn`
|
||||
5. `node scripts/check-encoding.mjs docs/technical/RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md server-rs/crates/api-server/src/runtime_chat.rs server-rs/crates/api-server/src/custom_world.rs server-rs/crates/api-server/src/big_fish.rs docs/technical/README.md`
|
||||
6. 修改后端代码后,使用 `npm run api-server:maincloud` 重启后端。
|
||||
6. 修改后端代码后,使用 `npm run api-server` 重启后端。
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
2. `GET /api/runtime/custom-world-gallery`
|
||||
3. 个人看板、浏览历史、存档等私有数据
|
||||
|
||||
其中 `custom-world-library` 通过 `api-server -> spacetime-client -> list_custom_world_profiles procedure` 读取当前用户作品。旧实现把每个作品的完整 `profile_payload_json` 一并返回给首页列表,而首页卡片只需要标题、摘要、封面、状态和计数字段。用户作品较多或 Maincloud 连接抖动时,这个 procedure 容易超过 `spacetime-client` 固定 `10s` 等待窗口,最终由 Axum 映射成 `502 Bad Gateway`,前端控制台显示 `SpacetimeDB procedure 调用超时`。
|
||||
其中 `custom-world-library` 通过 `api-server -> spacetime-client -> list_custom_world_profiles procedure` 读取当前用户作品。旧实现把每个作品的完整 `profile_payload_json` 一并返回给首页列表,而首页卡片只需要标题、摘要、封面、状态和计数字段。用户作品较多或 SpacetimeDB 连接抖动时,这个 procedure 容易超过 `spacetime-client` 固定 `10s` 等待窗口,最终由 Axum 映射成 `502 Bad Gateway`,前端控制台显示 `SpacetimeDB procedure 调用超时`。
|
||||
|
||||
## 2. 修复口径
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
1. `list_custom_world_profiles` 仍保持旧 procedure 名称和返回 envelope,避免本轮重新生成 bindings。
|
||||
2. 列表返回的 `profile_payload_json` 改为轻量摘要 JSON,只包含首页卡片和标签兜底需要的少量字段。
|
||||
3. 单条详情、发布、下架、编辑继续使用完整 profile snapshot,确保进入详情或结果页时仍有完整世界数据。
|
||||
4. `spacetime-client` 的 procedure 等待窗口从硬编码 `10s` 改为可配置,Maincloud 默认使用更宽的窗口吸收连接冷启动与短时抖动。
|
||||
5. Axum 的 `GET /api/runtime/custom-world-library` 首屏接口改走已有 `custom-world/works` 轻量读模型,并在用户点击详情/编辑时再调用 owner-only detail 接口取完整 profile,避免 Maincloud wasm 尚未发布轻量 profile procedure 时首页继续命中重 procedure。
|
||||
4. `spacetime-client` 的 procedure 等待窗口从硬编码 `10s` 改为可配置,用更宽的窗口吸收连接冷启动与短时抖动。
|
||||
5. Axum 的 `GET /api/runtime/custom-world-library` 首屏接口改走已有 `custom-world/works` 轻量读模型,并在用户点击详情/编辑时再调用 owner-only detail 接口取完整 profile,避免旧 wasm 尚未发布轻量 profile procedure 时首页继续命中重 procedure。
|
||||
|
||||
## 3. 轻量 profile JSON 字段
|
||||
|
||||
@@ -47,4 +47,4 @@
|
||||
3. `cargo check -p spacetime-client` 通过。
|
||||
4. `cargo check -p api-server` 通过。
|
||||
5. `npm run check:encoding` 通过。
|
||||
6. 修改后按项目约束使用 `npm run api-server:maincloud` 重启后端。
|
||||
6. 修改后按项目约束使用 `npm run api-server` 重启后端。
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
6. 修改后执行:
|
||||
- Rust 相关测试。
|
||||
- TypeScript 相关测试。
|
||||
- `npm run api-server:maincloud`。
|
||||
- `npm run api-server`。
|
||||
|
||||
## 5. 本次实现结果
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ server-rs/crates/api-server/src/prompt/rpg/
|
||||
1. `npm run check:encoding`
|
||||
2. `npm run test -- src/services/ai.test.ts src/hooks/rpg-runtime-story/storyResponseOptions.test.ts`
|
||||
3. `cargo check -p api-server`
|
||||
4. `npm run api-server:maincloud`
|
||||
4. `npm run api-server`
|
||||
|
||||
## 后续编辑约定
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ npm run typecheck -- --pretty false
|
||||
npm run check:encoding
|
||||
```
|
||||
|
||||
局部测试、局部 ESLint、全量类型检查与编码检查均通过。后端代码未在本次任务中修改,因此未执行 `npm run api-server:maincloud`。
|
||||
局部测试、局部 ESLint、全量类型检查与编码检查均通过。后端代码未在本次任务中修改,因此未执行 `npm run api-server`。
|
||||
|
||||
## 2026-04-27 第二轮复查修正
|
||||
|
||||
@@ -123,7 +123,7 @@ npm test -- --run src/data/sceneEncounterPreviews.test.ts src/hooks/rpg-runtime-
|
||||
npx eslint src/data/sceneEncounterPreviews.ts src/data/sceneEncounterPreviews.test.ts src/services/customWorldSceneActRuntime.ts src/hooks/rpg-runtime-story/storyChoiceRuntime.ts src/hooks/rpg-runtime-story/storyChoiceRuntime.test.ts src/hooks/rpg-runtime-story/uiTypes.ts src/components/rpg-runtime-panels/RpgAdventurePanelOverlays.tsx
|
||||
```
|
||||
|
||||
以上局部测试与局部 ESLint 已通过。后端代码未在本轮修改中触碰,因此不需要执行 `npm run api-server:maincloud`。
|
||||
以上局部测试与局部 ESLint 已通过。后端代码未在本轮修改中触碰,因此不需要执行 `npm run api-server`。
|
||||
|
||||
## 2026-04-27 第三轮复查修正
|
||||
|
||||
@@ -149,7 +149,7 @@ npx eslint src/hooks/rpg-session/useRpgSessionBootstrap.ts src/hooks/useGameFlow
|
||||
npm run typecheck -- --pretty false
|
||||
```
|
||||
|
||||
以上局部测试、局部 ESLint 与全量类型检查已通过。后端代码未在本轮修改中触碰,因此仍不需要执行 `npm run api-server:maincloud`。
|
||||
以上局部测试、局部 ESLint 与全量类型检查已通过。后端代码未在本轮修改中触碰,因此仍不需要执行 `npm run api-server`。
|
||||
|
||||
## 2026-04-27 第四轮复查修正
|
||||
|
||||
@@ -183,7 +183,7 @@ npm run typecheck -- --pretty false
|
||||
npm run check:encoding
|
||||
```
|
||||
|
||||
以上相关测试、局部 ESLint、全量类型检查与编码检查均通过。后端代码未在本轮修改中触碰,因此未执行 `npm run api-server:maincloud`。
|
||||
以上相关测试、局部 ESLint、全量类型检查与编码检查均通过。后端代码未在本轮修改中触碰,因此未执行 `npm run api-server`。
|
||||
|
||||
## 2026-04-27 第五轮误导链路闭口
|
||||
|
||||
@@ -232,4 +232,4 @@ npx eslint src/hooks/rpg-session/useRpgSessionBootstrap.ts src/hooks/useGameFlow
|
||||
npm run typecheck -- --pretty false
|
||||
```
|
||||
|
||||
以上测试、ESLint 与类型检查已通过。后端代码未在本轮修改中触碰,因此仍不需要执行 `npm run api-server:maincloud`。
|
||||
以上测试、ESLint 与类型检查已通过。后端代码未在本轮修改中触碰,因此仍不需要执行 `npm run api-server`。
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
创作页或作品详情删除 RPG 作品时报 `No such procedure`。
|
||||
|
||||
本次核对 Maincloud `xushi-p4wfr` schema 后确认:
|
||||
本次核对 `xushi-p4wfr` schema 后确认:
|
||||
|
||||
1. 已发布 / 作品库 profile 删除依赖 `delete_custom_world_profile_and_return`。
|
||||
2. 草稿作品删除依赖 `delete_custom_world_agent_session`。
|
||||
3. 本地 Rust client 绑定里存在 `delete_custom_world_agent_session`,但 Maincloud schema 中没有该 procedure。
|
||||
3. 本地 Rust client 绑定里存在 `delete_custom_world_agent_session`,但目标 schema 中没有该 procedure。
|
||||
|
||||
## 根因
|
||||
|
||||
`server-rs/crates/spacetime-module/src/custom_world/mod.rs` 中有一份草稿删除实现,但当前有效发布入口仍是 `server-rs/crates/spacetime-module/src/lib.rs` 中的 custom world 实现。`lib.rs` 未导出 `delete_custom_world_agent_session`,导致发布到 Maincloud 的模块 schema 缺少该 procedure。
|
||||
`server-rs/crates/spacetime-module/src/custom_world/mod.rs` 中有一份草稿删除实现,但当前有效发布入口仍是 `server-rs/crates/spacetime-module/src/lib.rs` 中的 custom world 实现。`lib.rs` 未导出 `delete_custom_world_agent_session`,导致发布后的模块 schema 缺少该 procedure。
|
||||
|
||||
## 落地口径
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
1. `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`
|
||||
2. `npm run check:encoding`
|
||||
3. `npm run spacetime:publish:maincloud`
|
||||
4. 发布后用 `spacetime describe xushi-p4wfr --server maincloud --json` 确认 schema 包含:
|
||||
3. 发布最新 SpacetimeDB wasm。
|
||||
4. 发布后用 `spacetime describe xushi-p4wfr --server <目标服务> --json` 确认 schema 包含:
|
||||
- `delete_custom_world_profile_and_return`
|
||||
- `delete_custom_world_agent_session`
|
||||
|
||||
@@ -112,9 +112,9 @@ npm run dev:rust:logs -- --follow
|
||||
2. 仅供测试断言使用的辅助函数使用 `#[cfg(test)]` 限定,避免进入 `cargo run -p api-server` 的普通二进制编译。
|
||||
3. 已无调用入口且无迁移价值的映射函数直接删除;如果后续新增同类 SpacetimeDB 记录映射,再按实际调用路径补回,避免提前保留死代码。
|
||||
|
||||
Maincloud API 重启补充:
|
||||
api-server 单独重启补充:
|
||||
|
||||
1. `npm run api-server:maincloud` 会先读取 `.env`、`.env.local`,把 `GENARRATIVE_SPACETIME_MAINCLOUD_*` 映射为 `api-server` 使用的 `GENARRATIVE_SPACETIME_*`,再运行 `cargo run -p api-server --manifest-path server-rs/Cargo.toml`。
|
||||
1. `npm run api-server` 会先读取 `.env`、`.env.local`,使用 `GENARRATIVE_SPACETIME_*` 启动 `cargo run -p api-server --manifest-path server-rs/Cargo.toml`。
|
||||
2. Windows 下脚本会尽力停止本仓库 `server-rs/target/debug/api-server.exe` 对应的旧进程,避免 cargo 重新编译时 exe 被占用。
|
||||
3. 旧进程已经退出或清理过程中出现瞬时等待失败时,不应阻断新的 `api-server` 启动;脚本只记录清理失败并继续启动。
|
||||
|
||||
@@ -191,7 +191,7 @@ cd build/<timestamp>
|
||||
./stop.sh
|
||||
```
|
||||
|
||||
如果后续通过 Jenkins 的部署脚本把发布包覆盖到固定部署目录,部署阶段默认只替换 `web/`、`api-server`、`spacetime_module.wasm`、`migration-bootstrap-secret.txt`、`scripts/`、`.env*`、`start.sh`、`stop.sh`、`web-server.mjs`、`README.md` 等发布产物;后台管理前端位于 `web/admin/`,随 `web/` 一并覆盖。文件产物使用普通复制,`web/`、`scripts/` 等目录产物递归复制,不会删除部署目录中的 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录。Jenkins 覆盖 `.env.local` 时会保留目标部署目录已有的 `GENARRATIVE_SPACETIME_TOKEN` / `GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN`,避免后台表统计在部署后失去读取 private 表所需的 owner 身份。
|
||||
如果后续通过 Jenkins 的部署脚本把发布包覆盖到固定部署目录,部署阶段默认只替换 `web/`、`api-server`、`spacetime_module.wasm`、`migration-bootstrap-secret.txt`、`scripts/`、`.env*`、`start.sh`、`stop.sh`、`web-server.mjs`、`README.md` 等发布产物;后台管理前端位于 `web/admin/`,随 `web/` 一并覆盖。文件产物使用普通复制,`web/`、`scripts/` 等目录产物递归复制,不会删除部署目录中的 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录。Jenkins 覆盖 `.env.local` 时会保留目标部署目录已有的 `GENARRATIVE_SPACETIME_TOKEN`,避免后台表统计在部署后失去读取 private 表所需的 owner 身份。
|
||||
|
||||
安全边界:
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# SpacetimeDB 云端配置移除记录
|
||||
|
||||
日期:`2026-05-02`
|
||||
|
||||
## 1. 目标
|
||||
|
||||
当前项目不再使用旧云端 SpacetimeDB 目标,仓库内不再保留云端专用配置、脚本入口和文档默认口径。后续开发、迁移、Jenkins 流水线与后台验证均以本地或显式传入的 SpacetimeDB 服务为准。
|
||||
|
||||
## 2. 入口调整
|
||||
|
||||
1. 根工程后端单独启动入口统一为:
|
||||
|
||||
```bash
|
||||
npm run api-server
|
||||
```
|
||||
|
||||
2. 该入口读取 `.env`、`.env.local` 与当前进程环境中的 `GENARRATIVE_SPACETIME_*`,默认服务地址回落到 `http://127.0.0.1:3101`。
|
||||
3. 已移除旧云端发布入口和脚本。SpacetimeDB 模块发布继续通过本地联调脚本、发布包 `start.sh` 或显式 `spacetime publish --server <server-url>` 执行。
|
||||
|
||||
## 3. 环境变量口径
|
||||
|
||||
`api-server`、迁移脚本和 Jenkins 部署脚本只使用以下运行变量:
|
||||
|
||||
```text
|
||||
GENARRATIVE_SPACETIME_SERVER_URL
|
||||
GENARRATIVE_SPACETIME_DATABASE
|
||||
GENARRATIVE_SPACETIME_TOKEN
|
||||
```
|
||||
|
||||
旧云端专用变量不再作为兼容回退读取。需要连接其它 SpacetimeDB 服务时,必须显式设置 `GENARRATIVE_SPACETIME_SERVER_URL` 或在脚本参数中传入 `--server-url`。
|
||||
|
||||
## 4. 迁移脚本口径
|
||||
|
||||
1. `scripts/spacetime-migration-common.mjs` 默认 server 为本地 `dev`,解析到 `http://127.0.0.1:3101`。
|
||||
2. 授权、撤销、导出等 CLI 调用会显式传 `-s`,避免落回机器上的 SpacetimeDB CLI 默认服务。
|
||||
3. Jenkins 数据库导入导出流水线默认 `SERVER=dev`,需要操作其它目标时必须显式填写 `SERVER_URL`。
|
||||
|
||||
## 5. 后续约束
|
||||
|
||||
1. 新增 SpacetimeDB 运维脚本时,不允许把云端服务写成默认值。
|
||||
2. 文档中的验证命令统一使用 `npm run api-server`。
|
||||
3. 如果某次任务需要连接非本地 SpacetimeDB,必须在文档和验证记录中写清楚实际 `SERVER_URL`、数据库名和 root-dir。
|
||||
@@ -13,7 +13,7 @@ SpacetimeDB reducer 必须保持确定性,不能访问文件系统和网络。
|
||||
|
||||
procedure 不再访问 HTTP 文件桥,也不接收部署机本地文件路径。这样可以避开 SpacetimeDB 对 private/special-purpose 地址的 HTTP 访问限制,并避免把 private 表内容通过临时 HTTP 服务转发。
|
||||
|
||||
SpacetimeDB Wasm 运行环境不支持 `std::time::SystemTime::now()`,procedure 或 reducer 内需要当前时间时必须使用 `ctx.timestamp`。如果共享 crate 同时服务前端/本地纯逻辑与 SpacetimeDB 模块,应提供 `*_at(now_ms)` 或显式时间参数版本,SpacetimeDB 模块只调用注入时间的函数,避免发布后在 maincloud 触发 `time not implemented on this platform` panic。
|
||||
SpacetimeDB Wasm 运行环境不支持 `std::time::SystemTime::now()`,procedure 或 reducer 内需要当前时间时必须使用 `ctx.timestamp`。如果共享 crate 同时服务前端/本地纯逻辑与 SpacetimeDB 模块,应提供 `*_at(now_ms)` 或显式时间参数版本,SpacetimeDB 模块只调用注入时间的函数,避免发布后触发 `time not implemented on this platform` panic。
|
||||
|
||||
`spacetime login show --token` 输出的是 CLI 登录 token,不是 HTTP `/v1/database/.../call` 所需的数据库连接 token。导入脚本如果没有显式传 `--token`,会自动调用 `POST /v1/identity` 获取 Web API token;迁移时不要把 CLI token 传给 `--token`。
|
||||
|
||||
@@ -41,17 +41,13 @@ SpacetimeDB Wasm 运行环境不支持 `std::time::SystemTime::now()`,procedur
|
||||
|
||||
运维流程:
|
||||
|
||||
```bash
|
||||
npm run spacetime:publish:maincloud -- --database <database>
|
||||
# 控制台会输出:
|
||||
# [spacetime:maincloud] 迁移引导密钥: <本次发布随机密钥>
|
||||
```
|
||||
本地开发发布时,`npm run dev:rust` 会在发布模块前输出本次随机生成的迁移引导密钥。发布包部署时,`npm run deploy:rust:remote` 会把同一份密钥写入发布包根目录的 `migration-bootstrap-secret.txt`,目标服务器执行 `./start.sh` 发布 wasm 时也会再次显示该密钥。
|
||||
|
||||
发布完成后,在同一台机器上用当前 `spacetime login` 身份授权操作员:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <本次发布随机密钥> \
|
||||
--operator-identity <identity-hex> \
|
||||
@@ -62,7 +58,7 @@ node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-revoke-migration-operator.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--operator-identity <identity-hex>
|
||||
```
|
||||
@@ -71,9 +67,8 @@ node scripts/spacetime-revoke-migration-operator.mjs \
|
||||
|
||||
### 发布脚本密钥行为
|
||||
|
||||
当前所有会构建或发布 `spacetime-module` 的脚本默认都会生成并显示迁移引导密钥:
|
||||
当前会构建或发布 `spacetime-module` 的脚本默认都会生成并显示迁移引导密钥:
|
||||
|
||||
- `npm run spacetime:publish:maincloud`:在本机 `cargo build` 前生成密钥,控制台输出 `[spacetime:maincloud] 迁移引导密钥: ...`。
|
||||
- `npm run dev:rust`:在本地 `spacetime publish --module-path` 前生成密钥,控制台输出 `[dev:rust] 迁移引导密钥: ...`。
|
||||
- `npm run deploy:rust:remote`:在构建发布包 wasm 前生成密钥,控制台输出 `[deploy:rust] 迁移引导密钥: ...`,并把同一份密钥写入发布包根目录的 `migration-bootstrap-secret.txt`。服务器执行 `./start.sh` 发布 wasm 时也会再次显示该文件里的密钥。
|
||||
|
||||
@@ -145,11 +140,11 @@ Node 导入脚本默认在文件超过 `524288` bytes 时使用分片导入;
|
||||
|
||||
### 发布冲突自动迁移
|
||||
|
||||
`npm run spacetime:publish:maincloud` 默认采用冲突感知发布:
|
||||
Ubuntu 发布包的 `start.sh` 默认采用冲突感知发布:
|
||||
|
||||
1. 先不清库发布新 wasm。
|
||||
2. 如果发布成功,流程结束。
|
||||
3. 如果发布失败且输出可判定为 schema 冲突,脚本自动导出旧库迁移 JSON 到 `tmp/spacetime-migrations/maincloud/<database>/<timestamp>.json`。
|
||||
3. 如果发布失败且输出可判定为 schema 冲突,脚本自动导出旧库迁移 JSON 到 `database-migrations/<database>/<timestamp>.json` 或 `GENARRATIVE_SPACETIME_MIGRATION_DIR` 指定目录。
|
||||
4. 导出成功后执行清库发布新 wasm。
|
||||
5. 新 wasm 发布成功后,把第 3 步导出的 JSON 自动导入回灌。
|
||||
|
||||
@@ -159,15 +154,11 @@ SpacetimeDB 2.1 对 schema 冲突的报错文案可能不再包含 `schema confl
|
||||
|
||||
任一阶段失败都会中止流程,并保留已经导出的迁移 JSON。非 schema 冲突的发布失败不会进入迁移流程。
|
||||
|
||||
```bash
|
||||
npm run spacetime:publish:maincloud -- --database xushi-p4wfr
|
||||
```
|
||||
|
||||
可选参数:
|
||||
|
||||
- `--no-migrate-on-conflict`:禁用冲突自动迁移,只保留原始发布失败。
|
||||
- `--migration-dir <dir>`:指定迁移 JSON 输出目录。
|
||||
- `--clear-database`:显式清库发布;该模式代表人工确认清库,不触发自动迁移。
|
||||
- `GENARRATIVE_SPACETIME_MIGRATE_ON_CONFLICT=false`:禁用冲突自动迁移,只保留原始发布失败。
|
||||
- `GENARRATIVE_SPACETIME_MIGRATION_DIR=<dir>`:指定迁移 JSON 输出目录。
|
||||
- `./start.sh --clear-database`:显式清库发布;该模式代表人工确认清库,不触发自动迁移。
|
||||
|
||||
冲突自动迁移需要发布脚本本次生成的 `GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET`。因此不要和 `--no-migration-bootstrap-secret` 同时使用。
|
||||
|
||||
@@ -237,7 +228,7 @@ node scripts/spacetime-export-migration-json.mjs \
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <服务器目标库发布时输出的随机密钥> \
|
||||
--operator-identity <服务器 spacetime login show 中的 identity> \
|
||||
@@ -248,7 +239,7 @@ node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-import-migration-json.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <服务器目标库发布时输出的随机密钥> \
|
||||
--in tmp/spacetime-migrations/source-2026-04-27.json
|
||||
@@ -258,7 +249,7 @@ node scripts/spacetime-import-migration-json.mjs \
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-import-migration-json.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <服务器目标库发布时输出的随机密钥> \
|
||||
--in tmp/spacetime-migrations/source-2026-04-27.json \
|
||||
@@ -298,7 +289,7 @@ node scripts/spacetime-export-migration-json.mjs \
|
||||
--include ai_task,ai_task_stage,ai_text_chunk,ai_result_reference
|
||||
```
|
||||
|
||||
`--server` 支持 `dev`、`local`、`maincloud`,也可以直接传 SpacetimeDB 服务器 URL。导出、授权、撤销默认走 `spacetime call`,使用当前机器的 CLI 登录态;导入默认走 Web API request body,避免大 JSON 触发命令行长度限制。数据库名可通过 `--database`、`GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE` 或 `GENARRATIVE_SPACETIME_DATABASE` 提供。
|
||||
`--server` 支持 `dev`、`local`,也可以直接传 SpacetimeDB 服务器 URL。导出、授权、撤销默认走 `spacetime call`,使用当前机器的 CLI 登录态;导入默认走 Web API request body,避免大 JSON 触发命令行长度限制。数据库名可通过 `--database` 或 `GENARRATIVE_SPACETIME_DATABASE` 提供。
|
||||
|
||||
授权脚本额外支持:
|
||||
|
||||
@@ -319,7 +310,7 @@ node scripts/spacetime-export-migration-json.mjs \
|
||||
- 拼图:`puzzle_agent_session`、`puzzle_agent_message`、`puzzle_work_profile`、`puzzle_runtime_run`
|
||||
- 大鱼:`big_fish_creation_session`、`big_fish_agent_message`、`big_fish_asset_slot`
|
||||
|
||||
`big_fish_runtime_run` 当前运行态已由前端本地运行服务承接,不再加入迁移白名单;但 maincloud 旧库仍可能存在该表。为避免热升级被 “Removing the table big_fish_runtime_run requires a manual migration” 阻断,模块发布期可以保留兼容空壳表,后续确认旧数据可丢弃后再走正式删除表迁移。
|
||||
`big_fish_runtime_run` 当前运行态已由前端本地运行服务承接,不再加入迁移白名单;但旧库仍可能存在该表。为避免热升级被 “Removing the table big_fish_runtime_run requires a manual migration” 阻断,模块发布期可以保留兼容空壳表,后续确认旧数据可丢弃后再走正式删除表迁移。
|
||||
|
||||
后续新增 SpacetimeDB 表时,必须同步把表加入迁移白名单与本文档。
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ error starting database: failed to init replica 1 for <new-database-identity>: m
|
||||
2. `replica 1` 的持久化数据仍带有旧库 `c20037fcfaac4e5c4b1f492f026a4f6119a98f56319b77f21ef021ededf8b7ae`。
|
||||
3. SpacetimeDB 因同一个副本目录中 identity 不一致而拒绝继续启动。
|
||||
|
||||
这不是 Rust 编译错误,也不是 `api-server:maincloud` 的 token 错误。只要错误来自 `server-rs/.spacetimedb/local/.../spacetime-standalone.log`,优先按本地 root-dir 数据目录污染处理。
|
||||
这不是 Rust 编译错误,也不是 `api-server` 的 token 错误。只要错误来自 `server-rs/.spacetimedb/local/.../spacetime-standalone.log`,优先按本地 root-dir 数据目录污染处理。
|
||||
|
||||
## 2. 根因
|
||||
|
||||
@@ -37,7 +37,7 @@ server-rs/.spacetimedb/local
|
||||
1. 不在脚本里默认删除 `.spacetimedb` 数据,避免误删本地开发数据。
|
||||
2. 如果只是本地开发库且数据可丢弃,优先备份后重建 `data` 目录。
|
||||
3. 如果数据必须保留,不要清理目录;应改回创建旧库时使用的 database/root-dir,或先导出迁移数据。
|
||||
4. Maincloud 发布与本地 standalone root-dir 是两条链路;不要通过切回 `server-node` 或 PostgreSQL 绕过。
|
||||
4. 本地 standalone root-dir 与其它部署目标是两条链路;不要通过切回 `server-node` 或 PostgreSQL 绕过。
|
||||
|
||||
## 4. 本地可丢弃数据时的修复
|
||||
|
||||
@@ -77,7 +77,7 @@ npm run dev:rust
|
||||
|
||||
1. 用旧库对应的 database/root-dir 重新启动。
|
||||
2. 使用迁移导出脚本导出旧数据,再清理本地 root-dir 并导入到新库。
|
||||
3. 如目标其实是 Maincloud,改用 `npm run api-server:maincloud` 连接云端,避免误启动本地 standalone。
|
||||
3. 如目标其实是其它已运行的 SpacetimeDB 服务,改用 `GENARRATIVE_SPACETIME_SERVER_URL` 指向该服务,避免误启动本地 standalone。
|
||||
|
||||
## 6. 脚本诊断
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
# SpacetimeDB Maincloud 发布与 api-server 适配方案
|
||||
|
||||
## 目标
|
||||
|
||||
新增一条明确的 npm 命令链,用于把 `server-rs/crates/spacetime-module` 发布到 SpacetimeDB Maincloud,并让 `api-server` 可以使用同一套 Maincloud 数据库配置启动。
|
||||
|
||||
## 环境变量约定
|
||||
|
||||
Maincloud 发布不复用本地 `spacetime.local.json`,避免误把本地开发库名发布到云端。需要显式提供:
|
||||
|
||||
| 变量 | 用途 |
|
||||
| -------------------------------------------- | ------------------------------------------------------------ |
|
||||
| `GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE` | Maincloud 数据库名,发布脚本优先读取 |
|
||||
| `GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL` | Maincloud 服务地址,默认 `https://maincloud.spacetimedb.com` |
|
||||
| `GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN` | `api-server` 连接 Maincloud 时使用的 token |
|
||||
|
||||
兼容 `api-server` 现有变量:
|
||||
|
||||
| 变量 | 用途 |
|
||||
| ---------------------------------- | --------------------------- |
|
||||
| `GENARRATIVE_SPACETIME_SERVER_URL` | `api-server` 实际连接地址 |
|
||||
| `GENARRATIVE_SPACETIME_DATABASE` | `api-server` 实际连接数据库 |
|
||||
| `GENARRATIVE_SPACETIME_TOKEN` | `api-server` 实际连接 token |
|
||||
|
||||
## npm 命令
|
||||
|
||||
```bash
|
||||
npm run spacetime:publish:maincloud
|
||||
```
|
||||
|
||||
执行内容:
|
||||
|
||||
1. 使用 `cargo build -p spacetime-module --target wasm32-unknown-unknown --release` 构建 wasm。
|
||||
2. 使用 `spacetime publish <database> --server maincloud --bin-path <wasm> --yes` 发布到 Maincloud。
|
||||
3. 发布前输出目标数据库名和 server,便于在 Jenkins 或手工日志中确认实际发布目标。
|
||||
4. 输出 `api-server` 需要的 Maincloud 环境变量,便于部署进程复用。
|
||||
|
||||
如需 schema 冲突时清库发布:
|
||||
|
||||
```bash
|
||||
npm run spacetime:publish:maincloud -- --clear-database
|
||||
```
|
||||
|
||||
## api-server 启动
|
||||
|
||||
```bash
|
||||
npm run api-server:maincloud
|
||||
```
|
||||
|
||||
执行内容:
|
||||
|
||||
1. 从 `.env` 与 `.env.local` 读取默认环境。
|
||||
2. 将 `GENARRATIVE_SPACETIME_MAINCLOUD_*` 映射为 `api-server` 已支持的 `GENARRATIVE_SPACETIME_*`。
|
||||
3. 在 Windows 启动前检查 `server-rs/target/debug/api-server.exe` 对应的旧进程;如果旧进程仍在运行,先停止它,避免 Rust 编译阶段覆盖 exe 时出现 `failed to remove file ... 拒绝访问。 (os error 5)`。
|
||||
4. 启动 `cargo run -p api-server --manifest-path server-rs/Cargo.toml`。
|
||||
|
||||
## 设计约束
|
||||
|
||||
- Maincloud 数据库名必须显式配置,不能默认读取本地 `spacetime.local.json`。
|
||||
- Maincloud 数据库名必须匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`,只能使用小写字母、数字,并用单个短横线分隔;否则 `spacetime publish` 会报 `invalid characters in database name`。
|
||||
- 发布脚本只处理 SpacetimeDB 模块发布,不启动本地 SpacetimeDB。
|
||||
- `api-server` 继续通过 `SpacetimeClientConfig` 的 `server_url / database / token` 连接数据库,不在前端增加逻辑。
|
||||
- Windows 进程清理只能匹配本仓库 `server-rs/target/debug/api-server.exe` 的完整路径,不能按进程名泛化清理,避免影响其他 Rust 服务。
|
||||
@@ -20,7 +20,7 @@ SpacetimeDB 的数据库更新权限绑定到创建或被授权的身份。只
|
||||
|
||||
1. 部署机上执行 `start.sh` 的用户切换过 `spacetime login` 身份。
|
||||
2. 固定部署目录保留了旧 `.spacetimedb/`,但当前 CLI 身份不是旧数据库创建者。
|
||||
3. `GENARRATIVE_SPACETIME_SERVER_URL` 指向 Maincloud,而当前 CLI 身份不是该 Maincloud 数据库的所有者或授权成员。
|
||||
3. `GENARRATIVE_SPACETIME_SERVER_URL` 指向其它 SpacetimeDB 服务,而当前 CLI 身份不是该数据库的所有者或授权成员。
|
||||
4. `.env.local` 中的 `GENARRATIVE_SPACETIME_DATABASE` 指向了另一个环境的数据库名或数据库 identity。
|
||||
|
||||
## 3. 落地修复
|
||||
@@ -62,7 +62,7 @@ mv .spacetimedb ".spacetimedb.backup.$(date +%Y%m%d-%H%M%S)"
|
||||
2. 找到创建该数据库的 SpacetimeDB 身份。
|
||||
3. 用该身份对应的 CLI root 执行发布,或在 SpacetimeDB 侧补授权后再发布。
|
||||
|
||||
如果目标是 Maincloud:
|
||||
如果目标是其它 SpacetimeDB 服务:
|
||||
|
||||
1. 执行 `spacetime login show` 确认当前身份。
|
||||
2. 确认该身份对 `GENARRATIVE_SPACETIME_DATABASE` 有更新权限。
|
||||
|
||||
@@ -15,7 +15,7 @@ pipeline {
|
||||
string(name: 'AGENT_LABEL', defaultValue: 'built-in', description: '执行节点标签')
|
||||
string(name: 'GENARRATIVE_WORKSPACE_ROOT', defaultValue: '', description: '源码根目录,留空则使用当前 Jenkins 工作区')
|
||||
string(name: 'DATABASE', defaultValue: '', description: 'SpacetimeDB 数据库名,留空则读取环境变量')
|
||||
string(name: 'SERVER', defaultValue: 'maincloud', description: 'SpacetimeDB server 别名,例如 maincloud/local/dev')
|
||||
string(name: 'SERVER', defaultValue: 'dev', description: 'SpacetimeDB server 别名,例如 dev/local')
|
||||
string(name: 'SERVER_URL', defaultValue: '', description: 'SpacetimeDB server URL,填写后优先于 SERVER')
|
||||
string(name: 'DEPLOY_DIRECTORY', defaultValue: '/var/lib/jenkins/deploy/Genarrative', description: '固定部署目录,ROOT_DIR 为空时使用其 .spacetimedb')
|
||||
string(name: 'ROOT_DIR', defaultValue: '', description: 'spacetime CLI root-dir,可选,优先于 DEPLOY_DIRECTORY')
|
||||
|
||||
@@ -15,7 +15,7 @@ pipeline {
|
||||
string(name: 'AGENT_LABEL', defaultValue: 'built-in', description: '执行节点标签')
|
||||
string(name: 'GENARRATIVE_WORKSPACE_ROOT', defaultValue: '', description: '源码根目录,留空则使用当前 Jenkins 工作区')
|
||||
string(name: 'DATABASE', defaultValue: '', description: 'SpacetimeDB 数据库名,留空则读取环境变量')
|
||||
string(name: 'SERVER', defaultValue: 'maincloud', description: 'SpacetimeDB server 别名,例如 maincloud/local/dev')
|
||||
string(name: 'SERVER', defaultValue: 'dev', description: 'SpacetimeDB server 别名,例如 dev/local')
|
||||
string(name: 'SERVER_URL', defaultValue: '', description: 'SpacetimeDB server URL,填写后优先于 SERVER')
|
||||
string(name: 'DEPLOY_DIRECTORY', defaultValue: '/var/lib/jenkins/deploy/Genarrative', description: '固定部署目录,ROOT_DIR 为空时使用其 .spacetimedb')
|
||||
string(name: 'ROOT_DIR', defaultValue: '', description: 'spacetime CLI root-dir,可选,优先于 DEPLOY_DIRECTORY')
|
||||
|
||||
@@ -12,9 +12,8 @@
|
||||
"admin-web:build": "node scripts/admin-web-build.mjs build",
|
||||
"admin-web:typecheck": "node scripts/admin-web-build.mjs typecheck",
|
||||
"admin-web:preview": "npm --prefix apps/admin-web run preview --",
|
||||
"spacetime:publish:maincloud": "node scripts/run-bash-script.mjs scripts/spacetime-publish-maincloud.sh",
|
||||
"spacetime:generate": "node scripts/generate-spacetime-bindings.mjs",
|
||||
"api-server:maincloud": "node scripts/api-server-maincloud.mjs",
|
||||
"api-server": "node scripts/api-server-dev.mjs",
|
||||
"deploy:rust:remote": "node scripts/run-bash-script.mjs scripts/deploy-rust-remote.sh",
|
||||
"build:rust:ubuntu": "node scripts/run-bash-script.mjs scripts/deploy-rust-remote.sh",
|
||||
"build": "node scripts/build-gate.mjs",
|
||||
|
||||
@@ -41,21 +41,13 @@ loadEnvFile(resolve(repoRoot, '.env.local'), mergedEnv);
|
||||
mergedEnv.GENARRATIVE_API_HOST = mergedEnv.GENARRATIVE_API_HOST || '127.0.0.1';
|
||||
mergedEnv.GENARRATIVE_API_PORT = mergedEnv.GENARRATIVE_API_PORT || '3100';
|
||||
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL =
|
||||
mergedEnv.GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL ||
|
||||
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL ||
|
||||
'https://maincloud.spacetimedb.com';
|
||||
mergedEnv.GENARRATIVE_SPACETIME_DATABASE =
|
||||
mergedEnv.GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE ||
|
||||
mergedEnv.GENARRATIVE_SPACETIME_DATABASE ||
|
||||
'';
|
||||
mergedEnv.GENARRATIVE_SPACETIME_TOKEN =
|
||||
mergedEnv.GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN ||
|
||||
mergedEnv.GENARRATIVE_SPACETIME_TOKEN ||
|
||||
'';
|
||||
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL || 'http://127.0.0.1:3101';
|
||||
mergedEnv.GENARRATIVE_SPACETIME_DATABASE = mergedEnv.GENARRATIVE_SPACETIME_DATABASE || '';
|
||||
mergedEnv.GENARRATIVE_SPACETIME_TOKEN = mergedEnv.GENARRATIVE_SPACETIME_TOKEN || '';
|
||||
|
||||
if (!mergedEnv.GENARRATIVE_SPACETIME_DATABASE) {
|
||||
console.error(
|
||||
'[api-server:maincloud] 缺少 GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE 或 GENARRATIVE_SPACETIME_DATABASE。',
|
||||
'[api-server] 缺少 GENARRATIVE_SPACETIME_DATABASE。',
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -78,7 +70,7 @@ function stopExistingWindowsApiServer() {
|
||||
' Wait-Process -Id $process.Id -Timeout 5 -ErrorAction SilentlyContinue',
|
||||
' Write-Output $process.Id',
|
||||
' } catch {',
|
||||
' Write-Error "[api-server:maincloud] 忽略旧进程清理瞬时失败 pid=$($process.Id): $($_.Exception.Message)"',
|
||||
' Write-Error "[api-server] 忽略旧进程清理瞬时失败 pid=$($process.Id): $($_.Exception.Message)"',
|
||||
' }',
|
||||
'}',
|
||||
'exit 0',
|
||||
@@ -97,7 +89,7 @@ function stopExistingWindowsApiServer() {
|
||||
).trim();
|
||||
|
||||
if (output) {
|
||||
console.log(`[api-server:maincloud] 已停止旧 api-server 进程: ${output}`);
|
||||
console.log(`[api-server] 已停止旧 api-server 进程: ${output}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,13 +97,13 @@ try {
|
||||
stopExistingWindowsApiServer();
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[api-server:maincloud] 清理旧 api-server 进程失败: ${error.message}`,
|
||||
`[api-server] 清理旧 api-server 进程失败: ${error.message}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[api-server:maincloud] SpacetimeDB ${mergedEnv.GENARRATIVE_SPACETIME_DATABASE} @ ${mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL}`,
|
||||
`[api-server] SpacetimeDB ${mergedEnv.GENARRATIVE_SPACETIME_DATABASE} @ ${mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL}`,
|
||||
);
|
||||
|
||||
const child = spawn(
|
||||
@@ -125,13 +117,13 @@ const child = spawn(
|
||||
);
|
||||
|
||||
child.on('error', (error) => {
|
||||
console.error(`[api-server:maincloud] 启动 cargo 失败: ${error.message}`);
|
||||
console.error(`[api-server] 启动 cargo 失败: ${error.message}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
child.on('exit', (code, signal) => {
|
||||
if (signal) {
|
||||
console.error(`[api-server:maincloud] api-server 被信号终止: ${signal}`);
|
||||
console.error(`[api-server] api-server 被信号终止: ${signal}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -1134,7 +1134,7 @@ if ! run_publish "${PUBLISH_LOG}" "${PUBLISH_ARGS[@]}"; then
|
||||
echo "[start] 当前 start.sh 使用的 CLI root: ${SPACETIME_ROOT_DIR}" >&2
|
||||
spacetime --root-dir="${SPACETIME_ROOT_DIR}" login show >&2 || true
|
||||
echo "[start] 如果目标是本地库且可以清空数据:先执行 ./stop.sh,备份或删除 ${SPACETIME_ROOT_DIR},再重新执行 ./start.sh --clear-database。" >&2
|
||||
echo "[start] 如果目标是 Maincloud 或必须保留数据:请切换到创建该数据库的 SpacetimeDB 身份,或把 GENARRATIVE_SPACETIME_DATABASE 改为当前身份有权限的库。" >&2
|
||||
echo "[start] 如果必须保留数据:请切换到创建该数据库的 SpacetimeDB 身份,或把 GENARRATIVE_SPACETIME_DATABASE 改为当前身份有权限的库。" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
|
||||
@@ -181,7 +181,6 @@ MIGRATION_IMPORT_TOKEN=""
|
||||
PRESERVED_MIGRATION_EXPORT_TOKEN=""
|
||||
PRESERVED_MIGRATION_IMPORT_TOKEN=""
|
||||
PRESERVED_SPACETIME_TOKEN=""
|
||||
PRESERVED_SPACETIME_MAINCLOUD_TOKEN=""
|
||||
DEPLOY_COMPLETED="0"
|
||||
RESTORE_PREVIOUS_MIGRATION_BOOTSTRAP_SECRET_ON_FAILURE="0"
|
||||
DEPLOY_ITEMS=(
|
||||
@@ -402,7 +401,6 @@ normalize_release_env_files "${SOURCE_DIR}"
|
||||
PRESERVED_MIGRATION_EXPORT_TOKEN="$(read_env_value "GENARRATIVE_SPACETIME_MIGRATION_EXPORT_TOKEN" "${DEPLOY_DIR}/.env" "${DEPLOY_DIR}/.env.local")"
|
||||
PRESERVED_MIGRATION_IMPORT_TOKEN="$(read_env_value "GENARRATIVE_SPACETIME_MIGRATION_IMPORT_TOKEN" "${DEPLOY_DIR}/.env" "${DEPLOY_DIR}/.env.local")"
|
||||
PRESERVED_SPACETIME_TOKEN="$(read_env_value "GENARRATIVE_SPACETIME_TOKEN" "${DEPLOY_DIR}/.env" "${DEPLOY_DIR}/.env.local")"
|
||||
PRESERVED_SPACETIME_MAINCLOUD_TOKEN="$(read_env_value "GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN" "${DEPLOY_DIR}/.env" "${DEPLOY_DIR}/.env.local")"
|
||||
|
||||
if [[ -x "${DEPLOY_DIR}/stop.sh" ]]; then
|
||||
echo "[jenkins-deploy] 先停止旧版本: ${DEPLOY_DIR}"
|
||||
@@ -464,14 +462,8 @@ elif [[ -n "${PRESERVED_MIGRATION_IMPORT_TOKEN}" ]] \
|
||||
write_env_override "${DEPLOY_DIR}/.env.local" "GENARRATIVE_SPACETIME_MIGRATION_IMPORT_TOKEN" "${PRESERVED_MIGRATION_IMPORT_TOKEN}"
|
||||
fi
|
||||
if [[ -n "${PRESERVED_SPACETIME_TOKEN}" ]] \
|
||||
&& [[ -z "$(read_env_value "GENARRATIVE_SPACETIME_TOKEN" "${DEPLOY_DIR}/.env" "${DEPLOY_DIR}/.env.local")" ]] \
|
||||
&& [[ -z "$(read_env_value "GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN" "${DEPLOY_DIR}/.env" "${DEPLOY_DIR}/.env.local")" ]]; then
|
||||
write_env_override "${DEPLOY_DIR}/.env.local" "GENARRATIVE_SPACETIME_TOKEN" "${PRESERVED_SPACETIME_TOKEN}"
|
||||
fi
|
||||
if [[ -n "${PRESERVED_SPACETIME_MAINCLOUD_TOKEN}" ]] \
|
||||
&& [[ -z "$(read_env_value "GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN" "${DEPLOY_DIR}/.env" "${DEPLOY_DIR}/.env.local")" ]] \
|
||||
&& [[ -z "$(read_env_value "GENARRATIVE_SPACETIME_TOKEN" "${DEPLOY_DIR}/.env" "${DEPLOY_DIR}/.env.local")" ]]; then
|
||||
write_env_override "${DEPLOY_DIR}/.env.local" "GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN" "${PRESERVED_SPACETIME_MAINCLOUD_TOKEN}"
|
||||
write_env_override "${DEPLOY_DIR}/.env.local" "GENARRATIVE_SPACETIME_TOKEN" "${PRESERVED_SPACETIME_TOKEN}"
|
||||
fi
|
||||
|
||||
DEPLOY_DATABASE="$(read_env_value "GENARRATIVE_SPACETIME_DATABASE" "${DEPLOY_DIR}/.env" "${DEPLOY_DIR}/.env.local")"
|
||||
|
||||
@@ -8,27 +8,15 @@ export function parseArgs(argv) {
|
||||
process.env.GENARRATIVE_SPACETIME_MIGRATION_CHUNK_SIZE,
|
||||
'GENARRATIVE_SPACETIME_MIGRATION_CHUNK_SIZE',
|
||||
),
|
||||
database:
|
||||
process.env.GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE ||
|
||||
process.env.GENARRATIVE_SPACETIME_DATABASE ||
|
||||
'',
|
||||
database: process.env.GENARRATIVE_SPACETIME_DATABASE || '',
|
||||
bootstrapSecret: process.env.GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET || '',
|
||||
includeTables: [],
|
||||
operatorIdentity: process.env.GENARRATIVE_SPACETIME_MIGRATION_OPERATOR_IDENTITY || '',
|
||||
passthrough: [],
|
||||
note: '',
|
||||
server:
|
||||
process.env.GENARRATIVE_SPACETIME_MAINCLOUD_SERVER ||
|
||||
process.env.GENARRATIVE_SPACETIME_SERVER ||
|
||||
'',
|
||||
serverUrl:
|
||||
process.env.GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL ||
|
||||
process.env.GENARRATIVE_SPACETIME_SERVER_URL ||
|
||||
'',
|
||||
token:
|
||||
process.env.GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN ||
|
||||
process.env.GENARRATIVE_SPACETIME_TOKEN ||
|
||||
'',
|
||||
server: process.env.GENARRATIVE_SPACETIME_SERVER || '',
|
||||
serverUrl: process.env.GENARRATIVE_SPACETIME_SERVER_URL || '',
|
||||
token: process.env.GENARRATIVE_SPACETIME_TOKEN || '',
|
||||
};
|
||||
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
@@ -117,11 +105,7 @@ export function buildSpacetimeCallArgs(options, procedureName, input) {
|
||||
args.push(`--root-dir=${options.rootDir}`);
|
||||
}
|
||||
args.push('call');
|
||||
if (options.server) {
|
||||
args.push('-s', options.server);
|
||||
} else if (options.serverUrl) {
|
||||
args.push('-s', options.serverUrl);
|
||||
}
|
||||
args.push('-s', resolveCliServer(options));
|
||||
args.push(...options.passthrough);
|
||||
if (!options.passthrough.includes('--no-config')) {
|
||||
args.push('--no-config');
|
||||
@@ -388,7 +372,7 @@ export function resolveServerUrl(options) {
|
||||
return options.serverUrl;
|
||||
}
|
||||
|
||||
const server = (options.server || 'maincloud').trim();
|
||||
const server = (options.server || 'dev').trim();
|
||||
if (server.startsWith('http://') || server.startsWith('https://')) {
|
||||
return server;
|
||||
}
|
||||
@@ -398,13 +382,25 @@ export function resolveServerUrl(options) {
|
||||
if (server === 'local') {
|
||||
return 'http://127.0.0.1:3000';
|
||||
}
|
||||
if (!server || server === 'maincloud') {
|
||||
return 'https://maincloud.spacetimedb.com';
|
||||
if (!server) {
|
||||
return 'http://127.0.0.1:3101';
|
||||
}
|
||||
|
||||
throw new Error(`未知 SpacetimeDB server: ${server}。请改用 --server-url 显式传入地址。`);
|
||||
}
|
||||
|
||||
function resolveCliServer(options) {
|
||||
if (options.serverUrl) {
|
||||
return options.serverUrl;
|
||||
}
|
||||
|
||||
const server = (options.server || '').trim();
|
||||
if (!server || server === 'dev') {
|
||||
return 'http://127.0.0.1:3101';
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
function trimPreview(text) {
|
||||
const trimmed = text.trim();
|
||||
if (trimmed.length <= 4000) {
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
SERVER_RS_DIR="${REPO_ROOT}/server-rs"
|
||||
MODULE_PATH="${SERVER_RS_DIR}/target/wasm32-unknown-unknown/release/spacetime_module.wasm"
|
||||
SPACETIME_SERVER_ALIAS="maincloud"
|
||||
CLEAR_DATABASE=0
|
||||
MIGRATE_ON_CONFLICT=1
|
||||
MIGRATION_DIR=""
|
||||
MIGRATION_BOOTSTRAP_SECRET=""
|
||||
MIGRATION_BOOTSTRAP_SECRET_MODE="auto"
|
||||
|
||||
load_env_file() {
|
||||
local env_file="$1"
|
||||
local line key value
|
||||
|
||||
if [[ ! -f "${env_file}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
while IFS= read -r line || [[ -n "${line}" ]]; do
|
||||
line="${line%$'\r'}"
|
||||
line="${line#$'\xef\xbb\xbf'}"
|
||||
[[ -z "${line}" || "${line}" == \#* ]] && continue
|
||||
[[ "${line}" =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]] || continue
|
||||
key="${BASH_REMATCH[1]}"
|
||||
value="${BASH_REMATCH[2]}"
|
||||
value="${value%\"}"
|
||||
value="${value#\"}"
|
||||
value="${value%\'}"
|
||||
value="${value#\'}"
|
||||
if [[ -z "${!key+x}" ]]; then
|
||||
export "${key}=${value}"
|
||||
fi
|
||||
done <"${env_file}"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
用法:
|
||||
npm run spacetime:publish:maincloud
|
||||
npm run spacetime:publish:maincloud -- --database <database>
|
||||
npm run spacetime:publish:maincloud -- --clear-database
|
||||
npm run spacetime:publish:maincloud -- --no-migrate-on-conflict
|
||||
npm run spacetime:publish:maincloud -- --no-migration-bootstrap-secret
|
||||
|
||||
说明:
|
||||
发布 server-rs/crates/spacetime-module 到 SpacetimeDB Maincloud。
|
||||
数据库名优先读取 --database,其次读取 GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE。
|
||||
默认遇到 schema 冲突时会先导出迁移 JSON,再清库发布并导入回灌。
|
||||
默认在构建 wasm 前随机生成迁移引导密钥,注入 GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET 并显示在控制台。
|
||||
EOF
|
||||
}
|
||||
|
||||
generate_migration_bootstrap_secret() {
|
||||
node -e 'const crypto = require("crypto"); process.stdout.write(crypto.randomBytes(32).toString("hex"));'
|
||||
}
|
||||
|
||||
prepare_migration_bootstrap_secret() {
|
||||
case "${MIGRATION_BOOTSTRAP_SECRET_MODE}" in
|
||||
auto)
|
||||
MIGRATION_BOOTSTRAP_SECRET="$(generate_migration_bootstrap_secret)"
|
||||
;;
|
||||
manual)
|
||||
if [[ "${#MIGRATION_BOOTSTRAP_SECRET}" -lt 16 ]]; then
|
||||
echo "[spacetime:maincloud] 迁移引导密钥至少需要 16 个字符。" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
disabled)
|
||||
unset GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET
|
||||
echo "[spacetime:maincloud] 未启用迁移引导密钥。"
|
||||
return
|
||||
;;
|
||||
*)
|
||||
echo "[spacetime:maincloud] 未知迁移引导密钥模式: ${MIGRATION_BOOTSTRAP_SECRET_MODE}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
export GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET="${MIGRATION_BOOTSTRAP_SECRET}"
|
||||
echo "[spacetime:maincloud] 迁移引导密钥: ${MIGRATION_BOOTSTRAP_SECRET}"
|
||||
}
|
||||
|
||||
timestamp_slug() {
|
||||
node -e 'process.stdout.write(new Date().toISOString().replace(/[:.]/g, "-"));'
|
||||
}
|
||||
|
||||
validate_spacetime_database_name() {
|
||||
local database="$1"
|
||||
|
||||
if [[ ! "${database}" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
||||
echo "[spacetime:maincloud] --database 必须匹配 SpacetimeDB 数据库名规则 ^[a-z0-9]+(-[a-z0-9]+)*$,只能使用小写字母、数字,并用单个短横线分隔: ${database}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_publish_conflict_output() {
|
||||
local output="$1"
|
||||
[[ "${output}" == *"conflict"* ]] \
|
||||
|| [[ "${output}" == *"schema"* && "${output}" == *"clear"* ]] \
|
||||
|| [[ "${output}" == *"manual migration"* ]] \
|
||||
|| [[ "${output}" == *"default value annotation"* ]] \
|
||||
|| [[ "${output}" == *"delete-data"* ]]
|
||||
}
|
||||
|
||||
run_publish() {
|
||||
local output_file="$1"
|
||||
shift
|
||||
set +e
|
||||
spacetime "$@" >"${output_file}" 2>&1
|
||||
local status=$?
|
||||
set -e
|
||||
cat "${output_file}"
|
||||
return "${status}"
|
||||
}
|
||||
|
||||
run_conflict_migration_publish() {
|
||||
local migration_root migration_file publish_log
|
||||
|
||||
if [[ "${MIGRATION_BOOTSTRAP_SECRET_MODE}" == "disabled" ]]; then
|
||||
echo "[spacetime:maincloud] schema 冲突需要迁移引导密钥;请去掉 --no-migration-bootstrap-secret 后重试。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
migration_root="${MIGRATION_DIR:-${REPO_ROOT}/tmp/spacetime-migrations/maincloud/${SPACETIME_DATABASE}}"
|
||||
mkdir -p "${migration_root}"
|
||||
migration_file="${migration_root}/$(timestamp_slug).json"
|
||||
publish_log="$(mktemp)"
|
||||
|
||||
echo "[spacetime:maincloud] 检测到 schema 冲突,开始导出旧库迁移 JSON: ${migration_file}"
|
||||
node "${REPO_ROOT}/scripts/spacetime-export-migration-json.mjs" \
|
||||
--server "${SPACETIME_SERVER_ALIAS}" \
|
||||
--server-url "${SPACETIME_SERVER_URL}" \
|
||||
--database "${SPACETIME_DATABASE}" \
|
||||
--bootstrap-secret "${MIGRATION_BOOTSTRAP_SECRET}" \
|
||||
--out "${migration_file}" \
|
||||
--note "publish conflict export $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
echo "[spacetime:maincloud] 清库发布新 SpacetimeDB wasm"
|
||||
if ! run_publish "${publish_log}" publish "${SPACETIME_DATABASE}" --server "${SPACETIME_SERVER_ALIAS}" --bin-path "${MODULE_PATH}" --clear-database --yes; then
|
||||
echo "[spacetime:maincloud] 清库发布失败,迁移 JSON 已保留: ${migration_file}" >&2
|
||||
rm -f "${publish_log}"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "${publish_log}"
|
||||
|
||||
echo "[spacetime:maincloud] 导入迁移 JSON 回灌数据"
|
||||
if ! node "${REPO_ROOT}/scripts/spacetime-import-migration-json.mjs" \
|
||||
--server "${SPACETIME_SERVER_ALIAS}" \
|
||||
--server-url "${SPACETIME_SERVER_URL}" \
|
||||
--database "${SPACETIME_DATABASE}" \
|
||||
--bootstrap-secret "${MIGRATION_BOOTSTRAP_SECRET}" \
|
||||
--in "${migration_file}" \
|
||||
--note "publish conflict import $(date -u +%Y-%m-%dT%H:%M:%SZ)"; then
|
||||
echo "[spacetime:maincloud] 导入失败,迁移 JSON 已保留: ${migration_file}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[spacetime:maincloud] schema 冲突迁移完成,迁移 JSON: ${migration_file}"
|
||||
}
|
||||
|
||||
load_env_file "${REPO_ROOT}/.env"
|
||||
load_env_file "${REPO_ROOT}/.env.local"
|
||||
|
||||
SPACETIME_DATABASE="${GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE:-}"
|
||||
SPACETIME_SERVER_URL="${GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL:-https://maincloud.spacetimedb.com}"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--database)
|
||||
SPACETIME_DATABASE="${2:?缺少 --database 的值}"
|
||||
shift 2
|
||||
;;
|
||||
--server-url)
|
||||
SPACETIME_SERVER_URL="${2:?缺少 --server-url 的值}"
|
||||
shift 2
|
||||
;;
|
||||
--clear-database)
|
||||
CLEAR_DATABASE=1
|
||||
shift
|
||||
;;
|
||||
--no-migrate-on-conflict)
|
||||
MIGRATE_ON_CONFLICT=0
|
||||
shift
|
||||
;;
|
||||
--migration-dir)
|
||||
MIGRATION_DIR="${2:?缺少 --migration-dir 的值}"
|
||||
shift 2
|
||||
;;
|
||||
--migration-bootstrap-secret)
|
||||
MIGRATION_BOOTSTRAP_SECRET="${2:?缺少 --migration-bootstrap-secret 的值}"
|
||||
MIGRATION_BOOTSTRAP_SECRET_MODE="manual"
|
||||
shift 2
|
||||
;;
|
||||
--no-migration-bootstrap-secret)
|
||||
MIGRATION_BOOTSTRAP_SECRET=""
|
||||
MIGRATION_BOOTSTRAP_SECRET_MODE="disabled"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "[spacetime:maincloud] 未知参数: $1" >&2
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${SPACETIME_DATABASE}" ]]; then
|
||||
echo "[spacetime:maincloud] 缺少 GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE。" >&2
|
||||
echo "[spacetime:maincloud] 请在 .env.local 中配置,或通过 --database <database> 传入。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
validate_spacetime_database_name "${SPACETIME_DATABASE}"
|
||||
|
||||
echo "[spacetime:maincloud] SpacetimeDB 发布数据库: ${SPACETIME_DATABASE}"
|
||||
echo "[spacetime:maincloud] SpacetimeDB server: ${SPACETIME_SERVER_ALIAS} (${SPACETIME_SERVER_URL})"
|
||||
|
||||
if ! command -v cargo >/dev/null 2>&1; then
|
||||
echo "[spacetime:maincloud] 缺少 cargo 命令。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v node >/dev/null 2>&1; then
|
||||
echo "[spacetime:maincloud] 缺少 node 命令,无法生成迁移引导密钥。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v spacetime >/dev/null 2>&1; then
|
||||
echo "[spacetime:maincloud] 缺少 spacetime CLI,请先安装并登录 Maincloud。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
prepare_migration_bootstrap_secret
|
||||
|
||||
echo "[spacetime:maincloud] 构建 spacetime-module wasm"
|
||||
cargo build \
|
||||
--manifest-path "${SERVER_RS_DIR}/Cargo.toml" \
|
||||
-p spacetime-module \
|
||||
--target wasm32-unknown-unknown \
|
||||
--release
|
||||
|
||||
PUBLISH_ARGS=(
|
||||
publish
|
||||
"${SPACETIME_DATABASE}"
|
||||
--server "${SPACETIME_SERVER_ALIAS}"
|
||||
--bin-path "${MODULE_PATH}"
|
||||
--yes
|
||||
)
|
||||
|
||||
if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then
|
||||
# Maincloud 清库只在 schema 冲突时触发,避免无冲突升级误删线上数据。
|
||||
PUBLISH_ARGS+=(-c=on-conflict)
|
||||
fi
|
||||
|
||||
echo "[spacetime:maincloud] 发布 SpacetimeDB wasm: ${SPACETIME_DATABASE} -> ${SPACETIME_SERVER_ALIAS}"
|
||||
PUBLISH_LOG="$(mktemp)"
|
||||
if ! run_publish "${PUBLISH_LOG}" "${PUBLISH_ARGS[@]}"; then
|
||||
PUBLISH_OUTPUT="$(cat "${PUBLISH_LOG}")"
|
||||
rm -f "${PUBLISH_LOG}"
|
||||
if [[ "${CLEAR_DATABASE}" -eq 0 && "${MIGRATE_ON_CONFLICT}" -eq 1 ]] && is_publish_conflict_output "${PUBLISH_OUTPUT}"; then
|
||||
run_conflict_migration_publish
|
||||
else
|
||||
echo "[spacetime:maincloud] 发布失败。" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
rm -f "${PUBLISH_LOG}"
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
[spacetime:maincloud] 发布完成。api-server 可使用以下环境:
|
||||
GENARRATIVE_SPACETIME_SERVER_URL=${SPACETIME_SERVER_URL}
|
||||
GENARRATIVE_SPACETIME_DATABASE=${SPACETIME_DATABASE}
|
||||
GENARRATIVE_SPACETIME_TOKEN=
|
||||
EOF
|
||||
@@ -144,7 +144,7 @@ pub async fn get_asset_history(
|
||||
AssetHistoryListResponse {
|
||||
assets: entries
|
||||
.into_iter()
|
||||
// 中文注释:Maincloud 旧 wasm 的历史素材 procedure 仍按类型返回,HTTP 门面必须兜底做账号隔离。
|
||||
// 中文注释:旧 wasm 的历史素材 procedure 仍按类型返回,HTTP 门面必须兜底做账号隔离。
|
||||
.filter(|entry| {
|
||||
is_asset_history_owned_by(
|
||||
entry.owner_user_id.as_deref(),
|
||||
|
||||
@@ -415,24 +415,19 @@ impl AppConfig {
|
||||
config.oss_success_action_status = oss_success_action_status;
|
||||
}
|
||||
|
||||
if let Some(spacetime_server_url) = read_first_non_empty_env(&[
|
||||
"GENARRATIVE_SPACETIME_SERVER_URL",
|
||||
"GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL",
|
||||
]) {
|
||||
if let Some(spacetime_server_url) =
|
||||
read_first_non_empty_env(&["GENARRATIVE_SPACETIME_SERVER_URL"])
|
||||
{
|
||||
config.spacetime_server_url = spacetime_server_url;
|
||||
}
|
||||
|
||||
if let Some(spacetime_database) = read_first_non_empty_env(&[
|
||||
"GENARRATIVE_SPACETIME_DATABASE",
|
||||
"GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE",
|
||||
]) {
|
||||
if let Some(spacetime_database) =
|
||||
read_first_non_empty_env(&["GENARRATIVE_SPACETIME_DATABASE"])
|
||||
{
|
||||
config.spacetime_database = spacetime_database;
|
||||
}
|
||||
|
||||
config.spacetime_token = read_first_non_empty_env(&[
|
||||
"GENARRATIVE_SPACETIME_TOKEN",
|
||||
"GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN",
|
||||
]);
|
||||
config.spacetime_token = read_first_non_empty_env(&["GENARRATIVE_SPACETIME_TOKEN"]);
|
||||
if let Some(spacetime_pool_size) =
|
||||
read_first_positive_u32_env(&["GENARRATIVE_SPACETIME_POOL_SIZE"])
|
||||
{
|
||||
|
||||
@@ -546,7 +546,7 @@ pub async fn execute_puzzle_agent_action(
|
||||
let session = match save_result {
|
||||
Ok(session) => Ok(session),
|
||||
Err(error) if is_missing_puzzle_form_draft_procedure_error(&error) => {
|
||||
// 中文注释:Maincloud 旧 wasm 缺少该自动保存 procedure 时,返回当前 session,避免填表页被非关键错误打断。
|
||||
// 中文注释:旧 wasm 缺少该自动保存 procedure 时,返回当前 session,避免填表页被非关键错误打断。
|
||||
tracing::warn!(
|
||||
provider = PUZZLE_AGENT_API_BASE_PROVIDER,
|
||||
session_id = %session_id,
|
||||
@@ -2210,7 +2210,7 @@ async fn create_seeded_puzzle_session_when_form_save_missing(
|
||||
return Ok(session_id.to_string());
|
||||
}
|
||||
|
||||
// 中文注释:旧 Maincloud 缺自动保存 procedure 时,空 session 无法被编译;这里重建带表单 seed 的 session 保证生成主链可继续。
|
||||
// 中文注释:旧 wasm 缺自动保存 procedure 时,空 session 无法被编译;这里重建带表单 seed 的 session 保证生成主链可继续。
|
||||
let replacement_session_id = build_prefixed_uuid_id("puzzle-session-");
|
||||
let replacement = state
|
||||
.spacetime_client()
|
||||
|
||||
Reference in New Issue
Block a user