From d796e7d491599fabafa519fd05fe297d083f9d67 Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Fri, 1 May 2026 22:57:00 +0800 Subject: [PATCH 1/3] Reset Jenkins workspaces before build deploy and migration --- .../JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md | 5 +++-- ...NS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md | 3 ++- jenkins/Jenkinsfile.build-and-deploy | 2 ++ jenkins/Jenkinsfile.database-export | 2 ++ jenkins/Jenkinsfile.database-import | 2 ++ jenkins/Jenkinsfile.deploy | 2 ++ 6 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/technical/JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md b/docs/technical/JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md index 46687974..c220d263 100644 --- a/docs/technical/JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md +++ b/docs/technical/JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md @@ -16,7 +16,7 @@ 1. 构建产物目录统一使用 `build/<版本号>/`。 2. 默认使用 Jenkins `BUILD_NUMBER` 作为版本号,避免依赖时间戳;如有需要也允许显式传 `BUILD_VERSION`。 -3. `构建` 与 `构建并部署` 在 `checkout scm` 后、实际构建前必须执行 `git reset --hard HEAD` 与 `git clean -fd`,避免固定源码目录内的 Git 变更和未跟踪文件影响发布包;不使用 `-x`,避免删除 `node_modules/` 等忽略目录后与 `RUN_NPM_CI=false` 冲突。 +3. 所有使用仓库源码的 Jenkins 流水线在实际执行脚本前必须先执行 `git reset --hard HEAD`,避免固定源码目录内的 Git 变更影响本次构建、部署或迁移操作;其中 `构建` 与 `构建并部署` 在实际构建前还必须执行 `git clean -fd` 清理未跟踪文件,不使用 `-x`,避免删除 `node_modules/` 等忽略目录后与 `RUN_NPM_CI=false` 冲突。 4. `构建并部署` 可选填写 `COMMIT_HASH`。留空时使用 Jenkins SCM 当前检出的提交;填写时只能是 7 到 40 位十六进制 commit hash,流水线会先按 SCM checkout 得到仓库,再尽量拉取 `origin` 全部分支引用、解析该 hash 并 detached checkout 到对应 commit 后构建。 5. `部署` 流水线允许人工启动;没有上游触发 cause 时按人工部署处理,不再直接失败。 6. `部署` 流水线仅在存在上游触发 cause 时校验上游作业名与传入的 `EXPECTED_UPSTREAM_JOB` 一致;如配置了环境变量 `GENARRATIVE_ALLOWED_UPSTREAM_JOB`,还必须与该值一致。 @@ -84,7 +84,8 @@ jenkins/Jenkinsfile.deploy 1. 读取触发原因;人工启动时跳过上游门禁,上游触发时同时兼容 `BuildUpstreamCause` 与经典 `UpstreamCause` 并继续校验上游作业名。 2. 校验 `BUILD_VERSION`、`SOURCE_WORKSPACE_ROOT`、`DEPLOY_DIRECTORY` 非空。 -3. 执行: +3. 在 `SOURCE_WORKSPACE_ROOT` 内执行 `git reset --hard HEAD`,确保部署脚本和构建产物选择不受本地改动影响。 +4. 执行: ```bash scripts/jenkins-deploy-release.sh \ diff --git a/docs/technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md b/docs/technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md index a51de72e..b0fc049d 100644 --- a/docs/technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md +++ b/docs/technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md @@ -86,7 +86,8 @@ Genarrative-Database-Import 2. `INCREMENTAL` 与 `REPLACE_EXISTING` 互斥,Jenkinsfile 会在执行前阻止同时启用。 3. Jenkinsfile 不打印 token;生产环境应通过 Jenkins 凭据或目标机器环境变量传入敏感值。 4. 如果不传 `TOKEN`,导入脚本会创建临时 Web API identity,并调用迁移授权/撤销 procedure 收敛权限窗口。 -5. 如果日志出现 `SpacetimeDB HTTP 413: Failed to buffer the request body: length limit exceeded`,优先把 `CHUNK_SIZE` 调低到 `262144` 或更小后重跑。该参数只降低单次 HTTP body,不改变导入表范围。 +5. 导入导出流水线在调用仓库内迁移脚本前都会执行 `git reset --hard HEAD`,确保固定源码目录中的本地改动不会影响本次迁移操作。 +6. 如果日志出现 `SpacetimeDB HTTP 413: Failed to buffer the request body: length limit exceeded`,优先把 `CHUNK_SIZE` 调低到 `262144` 或更小后重跑。该参数只降低单次 HTTP body,不改变导入表范围。 ## 5. 本地部署测试参数 diff --git a/jenkins/Jenkinsfile.build-and-deploy b/jenkins/Jenkinsfile.build-and-deploy index 149f496c..ee82db1e 100644 --- a/jenkins/Jenkinsfile.build-and-deploy +++ b/jenkins/Jenkinsfile.build-and-deploy @@ -113,6 +113,8 @@ pipeline { sh ''' bash -lc ' set -euo pipefail + # 每条流水线开头先强制回到 SCM 检出的干净提交,避免固定源码目录残留改动影响本次执行。 + git reset --hard HEAD requested_commit="${COMMIT_HASH:-}" if [[ -n "${requested_commit}" ]]; then # Jenkins 先按 SCM 配置完成 checkout;如指定 commit,再拉取远端引用并切到该提交构建。 diff --git a/jenkins/Jenkinsfile.database-export b/jenkins/Jenkinsfile.database-export index f8d8876a..808416d6 100644 --- a/jenkins/Jenkinsfile.database-export +++ b/jenkins/Jenkinsfile.database-export @@ -56,6 +56,8 @@ pipeline { sh """ bash -lc ' set -euo pipefail + # 导出流水线复用固定源码目录时,先清掉本地改动,确保执行的是 Jenkins SCM 检出的脚本。 + git reset --hard HEAD export_dir="${params.OUTPUT_DIRECTORY}" if [[ -z "\${export_dir}" ]]; then export_dir="database-exports" diff --git a/jenkins/Jenkinsfile.database-import b/jenkins/Jenkinsfile.database-import index afd0ad97..140fa23d 100644 --- a/jenkins/Jenkinsfile.database-import +++ b/jenkins/Jenkinsfile.database-import @@ -70,6 +70,8 @@ pipeline { sh """ bash -lc ' set -euo pipefail + # 导入流水线复用固定源码目录时,先清掉本地改动,确保迁移脚本来自 Jenkins SCM 检出的版本。 + git reset --hard HEAD args=(scripts/spacetime-import-migration-json.mjs --in "${params.INPUT_FILE}") if [[ -n "${params.DATABASE}" ]]; then args+=(--database "${params.DATABASE}") diff --git a/jenkins/Jenkinsfile.deploy b/jenkins/Jenkinsfile.deploy index a342f78e..c06238f6 100644 --- a/jenkins/Jenkinsfile.deploy +++ b/jenkins/Jenkinsfile.deploy @@ -115,6 +115,8 @@ pipeline { sh """ bash -lc ' set -euo pipefail + # 部署流水线也先清回上游工作区的当前提交,避免复用目录中的本地改动影响部署脚本或产物选择。 + git reset --hard HEAD test -d "build/${params.BUILD_VERSION}" deploy_script="${env.DEPLOY_SCRIPT_PATH}" chmod +x "\${deploy_script}" From fb6fb6e9f543abf53e1d7e9dad5f9399aa281072 Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Fri, 1 May 2026 23:03:50 +0800 Subject: [PATCH 2/3] fix: restore migration bootstrap secret on deploy failure --- ..._RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md | 4 +-- scripts/jenkins-deploy-release.sh | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/docs/technical/JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md b/docs/technical/JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md index c220d263..d42303f6 100644 --- a/docs/technical/JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md +++ b/docs/technical/JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md @@ -101,7 +101,7 @@ scripts/jenkins-deploy-release.sh \ 脚本语义: 1. 若部署目录已有旧版本且存在 `stop.sh`,先执行旧版本 `stop.sh`。 -2. 覆盖前如果旧部署目录存在 `migration-bootstrap-secret.txt`,先复制到 `deploy-state/migration-bootstrap-secret.previous.txt`,供新版本 `start.sh` 在 schema 冲突自动迁移时授权导出旧库。该文件属于 Jenkins 部署状态,不放入 `run/`,避免 `sudo` 启停脚本生成的 root 私有运行目录阻断后续部署写入。 +2. 覆盖前如果旧部署目录存在 `migration-bootstrap-secret.txt`,先复制到 `deploy-state/migration-bootstrap-secret.previous.txt`,供新版本 `start.sh` 在 schema 冲突自动迁移时授权导出旧库。该文件属于 Jenkins 部署状态,不放入 `run/`,避免 `sudo` 启停脚本生成的 root 私有运行目录阻断后续部署写入;如果后续部署失败,部署脚本必须把该快照复制回部署目录根下的 `migration-bootstrap-secret.txt`,避免当前仍在运行的数据库丢失对应迁移引导密钥。 3. 只删除发布产物白名单中的旧文件,例如 `web/`、`api-server`、`spacetime_module.wasm`、`migration-bootstrap-secret.txt`、`scripts/`、`.env*`、`start.sh`、`stop.sh`、`web-server.mjs`、`README.md`。 4. 将指定版本目录中的同名发布产物复制到部署目录;文件产物使用普通复制,`web/`、`scripts/` 等目录产物必须递归复制。 5. 把 `WEB_PORT`、`MIGRATE_ON_CONFLICT`、`MIGRATION_DIRECTORY` 写入部署目录 `.env.local`,确保通过 sudo 执行 `start.sh` 时仍能读取 Jenkins 参数;启动前读取 `.env` 与 `.env.local` 中最终的 `GENARRATIVE_SPACETIME_DATABASE`,打印并校验其符合 SpacetimeDB 数据库名规则。Jenkins 参数 `MIGRATION_EXPORT_TOKEN` / `MIGRATION_IMPORT_TOKEN` 会分别写入 `GENARRATIVE_SPACETIME_MIGRATION_EXPORT_TOKEN` / `GENARRATIVE_SPACETIME_MIGRATION_IMPORT_TOKEN`;如果参数为空,部署目录已有同名变量时会尽量保留。 @@ -110,7 +110,7 @@ scripts/jenkins-deploy-release.sh \ 如果 `RUN_DEPLOY_HOOKS_WITH_SUDO=true`,旧版本 `stop.sh` 和新版本 `start.sh` 会改为 `sudo -n` 调用;这要求 Jenkins 运行用户提前配置免密 sudo,否则部署会直接失败,不会进入交互式密码提示。 -这样可以满足“发布文件直接覆盖”的要求,同时保留部署目录里像 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录,不会因为部署被整体删除。`run/` 只承载 pid 等启停运行状态;`deploy-state/` 承载 Jenkins 覆盖部署前保存的旧迁移引导密钥,必须由 Jenkins 用户保持可写。发布白名单内的 `.env`、`.env.local` 会先以构建产物中的文件为准;部署脚本会在启动 hook 前移除这些环境文件中的 UTF-8 BOM 与 CRLF,并把 Jenkins 部署参数 `WEB_PORT` 写入 `.env.local` 的 `GENARRATIVE_WEB_PORT`,把 `MIGRATE_ON_CONFLICT` 写入 `GENARRATIVE_SPACETIME_MIGRATE_ON_CONFLICT`,把 `MIGRATION_DIRECTORY` 写入 `GENARRATIVE_SPACETIME_MIGRATION_DIR`,并在启动前输出最终 `GENARRATIVE_SPACETIME_DATABASE`,避免 `start.sh` 在 Bash 下把首行变量名误解析成命令,也避免端口、数据库名和迁移配置只停留在上游构建阶段。`start.sh` 会先执行 Ubuntu 专用 `sync_ubuntu_spacetime_install`,优先从 `/usr/.local/share/spacetime/bin//spacetimedb-cli` 或 `$HOME/.local/share/spacetime/bin//spacetimedb-cli` 同步到部署目录 `.spacetimedb/bin/current/spacetimedb-cli`,后续启动、探活和 root-dir 占用判定都使用部署目录内 `.spacetimedb/`,且不再额外设置 `--data-dir`,避免 Jenkins 机器全局 `spacetime login` 变化影响本地库更新;如遇 `403 Forbidden`,按 `SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md` 排查数据库所有者与 CLI 身份。 +这样可以满足“发布文件直接覆盖”的要求,同时保留部署目录里像 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录,不会因为部署被整体删除。`run/` 只承载 pid 等启停运行状态;`deploy-state/` 承载 Jenkins 覆盖部署前保存的旧迁移引导密钥,必须由 Jenkins 用户保持可写,并在部署失败时作为恢复源写回根目录 `migration-bootstrap-secret.txt`。发布白名单内的 `.env`、`.env.local` 会先以构建产物中的文件为准;部署脚本会在启动 hook 前移除这些环境文件中的 UTF-8 BOM 与 CRLF,并把 Jenkins 部署参数 `WEB_PORT` 写入 `.env.local` 的 `GENARRATIVE_WEB_PORT`,把 `MIGRATE_ON_CONFLICT` 写入 `GENARRATIVE_SPACETIME_MIGRATE_ON_CONFLICT`,把 `MIGRATION_DIRECTORY` 写入 `GENARRATIVE_SPACETIME_MIGRATION_DIR`,并在启动前输出最终 `GENARRATIVE_SPACETIME_DATABASE`,避免 `start.sh` 在 Bash 下把首行变量名误解析成命令,也避免端口、数据库名和迁移配置只停留在上游构建阶段。`start.sh` 会先执行 Ubuntu 专用 `sync_ubuntu_spacetime_install`,优先从 `/usr/.local/share/spacetime/bin//spacetimedb-cli` 或 `$HOME/.local/share/spacetime/bin//spacetimedb-cli` 同步到部署目录 `.spacetimedb/bin/current/spacetimedb-cli`,后续启动、探活和 root-dir 占用判定都使用部署目录内 `.spacetimedb/`,且不再额外设置 `--data-dir`,避免 Jenkins 机器全局 `spacetime login` 变化影响本地库更新;如遇 `403 Forbidden`,按 `SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md` 排查数据库所有者与 CLI 身份。 ### 4.3 构建并部署 diff --git a/scripts/jenkins-deploy-release.sh b/scripts/jenkins-deploy-release.sh index 1187e051..427e29f7 100644 --- a/scripts/jenkins-deploy-release.sh +++ b/scripts/jenkins-deploy-release.sh @@ -182,6 +182,8 @@ 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=( ".env" ".env.local" @@ -307,9 +309,40 @@ save_previous_migration_bootstrap_secret() { exit 1 } chmod 600 "${target_file}" 2>/dev/null || true + RESTORE_PREVIOUS_MIGRATION_BOOTSTRAP_SECRET_ON_FAILURE="1" echo "[jenkins-deploy] 已保存旧模块迁移引导密钥,用于 schema 冲突时导出旧库。" } +restore_previous_migration_bootstrap_secret_on_failure() { + local exit_code=$? + local source_file="" + local target_file="" + + if [[ "${exit_code}" -eq 0 || "${DEPLOY_COMPLETED}" == "1" ]]; then + return 0 + fi + + if [[ "${RESTORE_PREVIOUS_MIGRATION_BOOTSTRAP_SECRET_ON_FAILURE}" != "1" ]]; then + exit "${exit_code}" + fi + + source_file="$(previous_migration_bootstrap_secret_file)" + target_file="${DEPLOY_DIR}/migration-bootstrap-secret.txt" + if [[ ! -f "${source_file}" ]]; then + echo "[jenkins-deploy] 部署失败,但未找到旧迁移引导密钥快照,无法恢复: ${source_file}" >&2 + exit "${exit_code}" + fi + + if cp "${source_file}" "${target_file}"; then + chmod 600 "${target_file}" 2>/dev/null || true + echo "[jenkins-deploy] 部署失败,已恢复旧迁移引导密钥: ${target_file}" >&2 + else + echo "[jenkins-deploy] 部署失败,且恢复旧迁移引导密钥失败: ${target_file}" >&2 + fi + + exit "${exit_code}" +} + clear_previous_migration_bootstrap_secret() { local target_file @@ -358,6 +391,7 @@ fi SOURCE_DIR="$(cd "${SOURCE_DIR}" && pwd)" mkdir -p "${DEPLOY_DIR}" DEPLOY_DIR="$(cd "${DEPLOY_DIR}" && pwd)" +trap restore_previous_migration_bootstrap_secret_on_failure EXIT if [[ ! -f "${SOURCE_DIR}/start.sh" ]]; then echo "[jenkins-deploy] 发布目录缺少 start.sh: ${SOURCE_DIR}" >&2 @@ -457,3 +491,4 @@ else fi echo "[jenkins-deploy] 完成" +DEPLOY_COMPLETED="1" From a2c71fcb3acae8df89499c9a2b0f69f2f8dc0286 Mon Sep 17 00:00:00 2001 From: kdletters Date: Sat, 2 May 2026 17:04:11 +0800 Subject: [PATCH 3/3] chore: remove maincloud configuration --- .codex/skills/spacetimedb-cli/SKILL.md | 8 +- .env.local | 6 +- AGENTS.md | 2 +- ...RIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md | 2 +- ..._NODE_FREEZE_AND_DEPRECATION_2026-04-24.md | 2 +- .../PROJECT_WORK_EXPERIENCE_PLAYBOOK.md | 4 +- ...ME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md | 2 +- ...B_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md | 6 +- ...OT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md | 20 +- ...ND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md | 4 +- ...DATABASE_MIGRATION_PIPELINES_2026-04-29.md | 6 +- ...DEL_ROUTING_RPG_AND_CREATION_2026-04-30.md | 2 +- ...EPLOY_CUTOVER_EXECUTION_PLAN_2026-04-22.md | 2 +- ...NTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md | 4 +- ..._DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md | 2 +- ...3D_Q1_INTEGRATION_ACCEPTANCE_2026-05-01.md | 2 +- ...CETIME_CLIENT_AND_API_FACADE_2026-04-30.md | 4 +- ...E_REDEEM_CODE_IMPLEMENTATION_2026-04-28.md | 2 +- .../PUZZLE_FORM_CREATION_FLOW_2026-04-29.md | 4 +- ...PUZZLE_IMAGE_ASSET_PROXY_FIX_2026-04-27.md | 2 +- docs/technical/README.md | 7 +- ...GENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md | 2 +- ...OM_WORLD_LIBRARY_TIMEOUT_FIX_2026-04-29.md | 8 +- ...FORGE_VIEW_BACKEND_MIGRATION_2026-04-28.md | 2 +- ...OVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md | 2 +- ..._OPENING_STORY_BOOTSTRAP_FIX_2026-04-26.md | 10 +- ...ETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md | 10 +- ...ND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md | 6 +- ...ETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md | 42 +++ ...N_STRING_MIGRATION_PROCEDURE_2026-04-27.md | 39 +-- ...EPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md | 6 +- ...PACETIMEDB_MAINCLOUD_PUBLISH_2026-04-24.md | 63 ---- ..._SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md | 4 +- jenkins/Jenkinsfile.database-export | 2 +- jenkins/Jenkinsfile.database-import | 2 +- package.json | 3 +- ...erver-maincloud.mjs => api-server-dev.mjs} | 28 +- scripts/deploy-rust-remote.sh | 2 +- scripts/jenkins-deploy-release.sh | 10 +- scripts/spacetime-migration-common.mjs | 44 ++- scripts/spacetime-publish-maincloud.sh | 283 ------------------ server-rs/crates/api-server/src/assets.rs | 2 +- server-rs/crates/api-server/src/config.rs | 19 +- server-rs/crates/api-server/src/puzzle.rs | 4 +- 44 files changed, 172 insertions(+), 514 deletions(-) create mode 100644 docs/technical/SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md delete mode 100644 docs/technical/SPACETIMEDB_MAINCLOUD_PUBLISH_2026-04-24.md rename scripts/{api-server-maincloud.mjs => api-server-dev.mjs} (71%) delete mode 100644 scripts/spacetime-publish-maincloud.sh diff --git a/.codex/skills/spacetimedb-cli/SKILL.md b/.codex/skills/spacetimedb-cli/SKILL.md index 3bd0d454..ad00a2d8 100644 --- a/.codex/skills/spacetimedb-cli/SKILL.md +++ b/.codex/skills/spacetimedb-cli/SKILL.md @@ -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 diff --git a/.env.local b/.env.local index 95f32753..6ff657dd 100644 --- a/.env.local +++ b/.env.local @@ -54,11 +54,7 @@ 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 -ADMIN_API_TARGET=http://127.0.0.1:8082 \ No newline at end of file +ADMIN_API_TARGET=http://127.0.0.1:8082 diff --git a/AGENTS.md b/AGENTS.md index 706b4611..2eed8397 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 ## 文档图谱 diff --git a/docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md b/docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md index 7ca7e503..e4225fb9 100644 --- a/docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md +++ b/docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md @@ -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. 最小验收标准 diff --git a/docs/audits/engineering/SERVER_NODE_FREEZE_AND_DEPRECATION_2026-04-24.md b/docs/audits/engineering/SERVER_NODE_FREEZE_AND_DEPRECATION_2026-04-24.md index ff65dd05..cf861d8c 100644 --- a/docs/audits/engineering/SERVER_NODE_FREEZE_AND_DEPRECATION_2026-04-24.md +++ b/docs/audits/engineering/SERVER_NODE_FREEZE_AND_DEPRECATION_2026-04-24.md @@ -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) diff --git a/docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md b/docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md index 1d490fc8..e99b495a 100644 --- a/docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md +++ b/docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md @@ -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. 一句话总结 diff --git a/docs/reference/RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md b/docs/reference/RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md index 60aad456..091c8353 100644 --- a/docs/reference/RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md +++ b/docs/reference/RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md @@ -753,7 +753,7 @@ RPG 运行时链: 这些脚本不直接参与玩法,但直接支撑开发、发布、绑定和检查: -### `scripts/api-server-maincloud.mjs` +### `scripts/api-server-dev.mjs` 职责: diff --git a/docs/technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md b/docs/technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md index a0a0ac71..e5eda6e8 100644 --- a/docs/technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md +++ b/docs/technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md @@ -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:`,并重启后台前端 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. 后续扩展边界 diff --git a/docs/technical/AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md b/docs/technical/AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md index 8367add3..ffd2b6e2 100644 --- a/docs/technical/AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md +++ b/docs/technical/AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md @@ -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. 认证快照同步失败会影响进程重启后的远端恢复完整性,需要在目标库恢复后重新完成一次成功同步。 diff --git a/docs/technical/BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md b/docs/technical/BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md index 726a3e04..0eb3d515 100644 --- a/docs/technical/BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md +++ b/docs/technical/BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md @@ -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. 用户打开草稿页时碰到短暂断链,不再被立即判定成稳定的坏网关故障。 ## 落地范围 diff --git a/docs/technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md b/docs/technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md index b0fc049d..4cdaf4fa 100644 --- a/docs/technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md +++ b/docs/technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md @@ -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`;为空时使用 `/.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. 文件清单 diff --git a/docs/technical/LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md b/docs/technical/LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md index 3b7bb215..664e8931 100644 --- a/docs/technical/LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md +++ b/docs/technical/LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md @@ -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` 重新启动后端,并执行相应自动测试。 diff --git a/docs/technical/M7_TEST_DEPLOY_CUTOVER_EXECUTION_PLAN_2026-04-22.md b/docs/technical/M7_TEST_DEPLOY_CUTOVER_EXECUTION_PLAN_2026-04-22.md index 3b4a3c59..e57c1d58 100644 --- a/docs/technical/M7_TEST_DEPLOY_CUTOVER_EXECUTION_PLAN_2026-04-22.md +++ b/docs/technical/M7_TEST_DEPLOY_CUTOVER_EXECUTION_PLAN_2026-04-22.md @@ -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. 文档目标 diff --git a/docs/technical/MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md b/docs/technical/MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md index 69c7091b..0e99499b 100644 --- a/docs/technical/MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md +++ b/docs/technical/MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md @@ -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 ``` diff --git a/docs/technical/MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md b/docs/technical/MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md index 1411fc43..32203a52 100644 --- a/docs/technical/MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md +++ b/docs/technical/MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md @@ -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。 diff --git a/docs/technical/MATCH3D_Q1_INTEGRATION_ACCEPTANCE_2026-05-01.md b/docs/technical/MATCH3D_Q1_INTEGRATION_ACCEPTANCE_2026-05-01.md index 40a8b19f..99e408ea 100644 --- a/docs/technical/MATCH3D_Q1_INTEGRATION_ACCEPTANCE_2026-05-01.md +++ b/docs/technical/MATCH3D_Q1_INTEGRATION_ACCEPTANCE_2026-05-01.md @@ -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 联调链路单独排查。 diff --git a/docs/technical/MATCH3D_SPACETIME_CLIENT_AND_API_FACADE_2026-04-30.md b/docs/technical/MATCH3D_SPACETIME_CLIENT_AND_API_FACADE_2026-04-30.md index e6a95861..ecf2f746 100644 --- a/docs/technical/MATCH3D_SPACETIME_CLIENT_AND_API_FACADE_2026-04-30.md +++ b/docs/technical/MATCH3D_SPACETIME_CLIENT_AND_API_FACADE_2026-04-30.md @@ -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. 后续接入点 diff --git a/docs/technical/PROFILE_REDEEM_CODE_IMPLEMENTATION_2026-04-28.md b/docs/technical/PROFILE_REDEEM_CODE_IMPLEMENTATION_2026-04-28.md index 4155e906..464d1683 100644 --- a/docs/technical/PROFILE_REDEEM_CODE_IMPLEMENTATION_2026-04-28.md +++ b/docs/technical/PROFILE_REDEEM_CODE_IMPLEMENTATION_2026-04-28.md @@ -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`。 diff --git a/docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md b/docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md index 70609e82..dd646464 100644 --- a/docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md +++ b/docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md @@ -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` 真相源。 diff --git a/docs/technical/PUZZLE_IMAGE_ASSET_PROXY_FIX_2026-04-27.md b/docs/technical/PUZZLE_IMAGE_ASSET_PROXY_FIX_2026-04-27.md index 670b7c02..97eb1f04 100644 --- a/docs/technical/PUZZLE_IMAGE_ASSET_PROXY_FIX_2026-04-27.md +++ b/docs/technical/PUZZLE_IMAGE_ASSET_PROXY_FIX_2026-04-27.md @@ -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` 重启后,点击拼图结果页“生成或更换图片”,候选图应能写回并正常展示。 diff --git a/docs/technical/README.md b/docs/technical/README.md index 07c3d8fb..ff13f080 100644 --- a/docs/technical/README.md +++ b/docs/technical/README.md @@ -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 聊天提示词原样迁移,覆盖回复、建议、好感变化与限轮收束。 diff --git a/docs/technical/RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md b/docs/technical/RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md index 689bbff7..455c05cc 100644 --- a/docs/technical/RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md +++ b/docs/technical/RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md @@ -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` 重启后端。 diff --git a/docs/technical/RPG_HOME_CUSTOM_WORLD_LIBRARY_TIMEOUT_FIX_2026-04-29.md b/docs/technical/RPG_HOME_CUSTOM_WORLD_LIBRARY_TIMEOUT_FIX_2026-04-29.md index 4408473b..6728bf9e 100644 --- a/docs/technical/RPG_HOME_CUSTOM_WORLD_LIBRARY_TIMEOUT_FIX_2026-04-29.md +++ b/docs/technical/RPG_HOME_CUSTOM_WORLD_LIBRARY_TIMEOUT_FIX_2026-04-29.md @@ -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` 重启后端。 diff --git a/docs/technical/RPG_INVENTORY_EQUIPMENT_FORGE_VIEW_BACKEND_MIGRATION_2026-04-28.md b/docs/technical/RPG_INVENTORY_EQUIPMENT_FORGE_VIEW_BACKEND_MIGRATION_2026-04-28.md index 07594d9a..f6f26edc 100644 --- a/docs/technical/RPG_INVENTORY_EQUIPMENT_FORGE_VIEW_BACKEND_MIGRATION_2026-04-28.md +++ b/docs/technical/RPG_INVENTORY_EQUIPMENT_FORGE_VIEW_BACKEND_MIGRATION_2026-04-28.md @@ -83,7 +83,7 @@ 6. 修改后执行: - Rust 相关测试。 - TypeScript 相关测试。 - - `npm run api-server:maincloud`。 + - `npm run api-server`。 ## 5. 本次实现结果 diff --git a/docs/technical/RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md b/docs/technical/RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md index 9c825702..2e374a21 100644 --- a/docs/technical/RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md +++ b/docs/technical/RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md @@ -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` ## 后续编辑约定 diff --git a/docs/technical/RPG_RUNTIME_OPENING_STORY_BOOTSTRAP_FIX_2026-04-26.md b/docs/technical/RPG_RUNTIME_OPENING_STORY_BOOTSTRAP_FIX_2026-04-26.md index e869795c..a3d53309 100644 --- a/docs/technical/RPG_RUNTIME_OPENING_STORY_BOOTSTRAP_FIX_2026-04-26.md +++ b/docs/technical/RPG_RUNTIME_OPENING_STORY_BOOTSTRAP_FIX_2026-04-26.md @@ -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`。 diff --git a/docs/technical/RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md b/docs/technical/RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md index a9bbd81c..35312bbe 100644 --- a/docs/technical/RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md +++ b/docs/technical/RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md @@ -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` diff --git a/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md b/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md index 2dc49f6b..ae2aa550 100644 --- a/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md +++ b/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md @@ -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/ ./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 身份。 安全边界: diff --git a/docs/technical/SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md b/docs/technical/SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md new file mode 100644 index 00000000..0c092f05 --- /dev/null +++ b/docs/technical/SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md @@ -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 ` 执行。 + +## 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。 diff --git a/docs/technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md b/docs/technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md index 294c0069..cc8ab42f 100644 --- a/docs/technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md +++ b/docs/technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md @@ -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 -# 控制台会输出: -# [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 \ @@ -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 ``` @@ -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//.json`。 +3. 如果发布失败且输出可判定为 schema 冲突,脚本自动导出旧库迁移 JSON 到 `database-migrations//.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 `:指定迁移 JSON 输出目录。 -- `--clear-database`:显式清库发布;该模式代表人工确认清库,不触发自动迁移。 +- `GENARRATIVE_SPACETIME_MIGRATE_ON_CONFLICT=false`:禁用冲突自动迁移,只保留原始发布失败。 +- `GENARRATIVE_SPACETIME_MIGRATION_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 表时,必须同步把表加入迁移白名单与本文档。 diff --git a/docs/technical/SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md b/docs/technical/SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md index b7817b50..8d3e5583 100644 --- a/docs/technical/SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md +++ b/docs/technical/SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md @@ -16,7 +16,7 @@ error starting database: failed to init replica 1 for : 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. 脚本诊断 diff --git a/docs/technical/SPACETIMEDB_MAINCLOUD_PUBLISH_2026-04-24.md b/docs/technical/SPACETIMEDB_MAINCLOUD_PUBLISH_2026-04-24.md deleted file mode 100644 index 3948086d..00000000 --- a/docs/technical/SPACETIMEDB_MAINCLOUD_PUBLISH_2026-04-24.md +++ /dev/null @@ -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 --server maincloud --bin-path --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 服务。 diff --git a/docs/technical/SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md b/docs/technical/SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md index e8fdd394..50e8e788 100644 --- a/docs/technical/SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md +++ b/docs/technical/SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md @@ -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` 有更新权限。 diff --git a/jenkins/Jenkinsfile.database-export b/jenkins/Jenkinsfile.database-export index 808416d6..f89a988d 100644 --- a/jenkins/Jenkinsfile.database-export +++ b/jenkins/Jenkinsfile.database-export @@ -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') diff --git a/jenkins/Jenkinsfile.database-import b/jenkins/Jenkinsfile.database-import index 140fa23d..790799bf 100644 --- a/jenkins/Jenkinsfile.database-import +++ b/jenkins/Jenkinsfile.database-import @@ -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') diff --git a/package.json b/package.json index 6cbe731e..c330c117 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/scripts/api-server-maincloud.mjs b/scripts/api-server-dev.mjs similarity index 71% rename from scripts/api-server-maincloud.mjs rename to scripts/api-server-dev.mjs index 92709e10..ddf386aa 100644 --- a/scripts/api-server-maincloud.mjs +++ b/scripts/api-server-dev.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); } diff --git a/scripts/deploy-rust-remote.sh b/scripts/deploy-rust-remote.sh index 5776afce..7ad6c7b1 100644 --- a/scripts/deploy-rust-remote.sh +++ b/scripts/deploy-rust-remote.sh @@ -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 diff --git a/scripts/jenkins-deploy-release.sh b/scripts/jenkins-deploy-release.sh index 427e29f7..aa26a7ef 100644 --- a/scripts/jenkins-deploy-release.sh +++ b/scripts/jenkins-deploy-release.sh @@ -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")" diff --git a/scripts/spacetime-migration-common.mjs b/scripts/spacetime-migration-common.mjs index 091f3ebe..bb065993 100644 --- a/scripts/spacetime-migration-common.mjs +++ b/scripts/spacetime-migration-common.mjs @@ -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) { diff --git a/scripts/spacetime-publish-maincloud.sh b/scripts/spacetime-publish-maincloud.sh deleted file mode 100644 index 99a299f4..00000000 --- a/scripts/spacetime-publish-maincloud.sh +++ /dev/null @@ -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 - 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 传入。" >&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 < 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()