Files
Genarrative/docs/technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md
kdletters 9a79494c68
Some checks failed
CI / verify (push) Has been cancelled
feat: add spacetimedb json migration tooling
2026-04-27 14:56:37 +08:00

9.8 KiB
Raw Blame History

SpacetimeDB JSON 字符串迁移 procedure 设计

背景

spacetime sql 只能稳定读取 public 表或数据库 owner 可见表。当前 ai_result_reference 等运行真相表保持 private直接 SQL 导出会遇到 no such table 或 private table 提示,不能作为跨服务器迁移的稳定方案。

SpacetimeDB reducer 必须保持确定性不能访问文件系统和网络。procedure 可以返回数据,也可以在事务中读取 private 表,因此迁移改为:

  1. spacetime-module 内的导出 procedure 读取迁移白名单表,并直接返回迁移 JSON 字符串。
  2. Node 运维脚本默认通过 spacetime call 调用导出 procedure把返回的 JSON 字符串写入本地文件。
  3. Node 运维脚本读取本地 JSON 文件内容,并通过 HTTP request body 作为字符串参数传给导入 procedure。
  4. 导入 procedure 校验 JSON 与表白名单后,在事务中写入目标数据库。

procedure 不再访问 HTTP 文件桥,也不接收部署机本地文件路径。这样可以避开 SpacetimeDB 对 private/special-purpose 地址的 HTTP 访问限制,并避免把 private 表内容通过临时 HTTP 服务转发。

spacetime login show --token 输出的是 CLI 登录 token不是 HTTP /v1/database/.../call 所需的数据库连接 token。运维脚本默认走 CLI 登录态,迁移时不要把 CLI token 传给 --token;只有显式传 --use-http 时才需要数据库连接 token。

接口

迁移操作员授权

迁移 procedure 会读取并写入 private 表,不能对任意登录身份开放。模块内新增私有表 database_migration_operator 作为迁移操作员白名单:

  • operator_identity: 被授权调用迁移 procedure 的 SpacetimeDB identity。
  • created_at: 授权写入时间。
  • created_by: 发起授权的 identity。
  • note: 运维备注,只用于区分来源、环境或临时用途。

database_migration_operator 只控制迁移 procedure 调用权限,不会被导出或导入,避免把源库的运维权限复制到目标库。

首次授权时,操作员表为空,必须通过编译进模块的 GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET 引导密钥授权第一位操作员。发布脚本会在构建或发布 SpacetimeDB 模块时自动生成一份强随机引导密钥、注入 wasm 编译环境,并在控制台显示;运维人员必须记录对应数据库本次发布输出的密钥。表内已经存在操作员后,后续授权与撤销只能由已有操作员发起;此时不再接受引导密钥越权扩权。

新增 procedure

  • authorize_database_migration_operator: 授权或更新迁移操作员备注。
  • revoke_database_migration_operator: 撤销迁移操作员。

运维流程:

npm run spacetime:publish:maincloud -- --database <database>
# 控制台会输出:
# [spacetime:maincloud] 迁移引导密钥: <本次发布随机密钥>

发布完成后,在同一台机器上用当前 spacetime login 身份授权操作员:

node scripts/spacetime-authorize-migration-operator.mjs \
  --server maincloud \
  --database xushi-p4wfr \
  --bootstrap-secret <本次发布随机密钥> \
  --operator-identity <identity-hex> \
  --note "2026-04-27 migration"

迁移完成后可以撤销临时操作员:

node scripts/spacetime-revoke-migration-operator.mjs \
  --server maincloud \
  --database xushi-p4wfr \
  --operator-identity <identity-hex>

生产环境建议迁移完成后用 --no-migration-bootstrap-secret 重新发布一个未设置 GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET 的模块版本,避免引导密钥长期留在 wasm 中。

发布脚本密钥行为

当前所有会构建或发布 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 时也会再次显示该文件里的密钥。

如果迁移完成后不希望 wasm 继续携带引导密钥,重新发布时传 --no-migration-bootstrap-secret。远端发布包若使用 --skip-spacetime-build,必须同时传 --no-migration-bootstrap-secret,否则脚本会拒绝生成一个无法注入旧 wasm 的新密钥。

导出

export_database_migration_to_file(ctx, input)

输入字段:

  • include_tables: 可选表名白名单。为空时导出当前实现支持的全部迁移表。

返回字段:

  • ok: 是否成功。
  • schema_version: 迁移 JSON 结构版本。
  • migration_json: 成功时包含完整迁移 JSON 字符串,失败时为空。
  • table_stats: 表级导出统计。
  • error_message: 失败原因。

导入

import_database_migration_from_file(ctx, input)

输入字段:

  • migration_json: 导出 procedure 生成的完整迁移 JSON 字符串。
  • include_tables: 可选表名白名单。为空时导入文件内所有支持表。
  • replace_existing: 是否先清空目标表。跨服务器全量迁移必须为 true
  • dry_run: 只解析和统计,不写表。

返回字段:

  • ok: 是否成功。
  • schema_version: 迁移 JSON 结构版本。
  • migration_json: 导入场景恒为空,避免重复回传大 JSON。
  • table_stats: 表级导入或跳过统计。
  • error_message: 失败原因。

保留 export_database_migration_to_file / import_database_migration_from_file 名称,是为了减少已经记住的 procedure 名变更;语义上不再代表 module 直接读写文件。

Node 脚本

本机导出时,先确保本机 SpacetimeDB 服务和源数据库可访问,然后授权本机调用身份:

node scripts/spacetime-authorize-migration-operator.mjs \
  --server dev \
  --database xushi-p4wfr \
  --bootstrap-secret <本机源库发布时输出的随机密钥> \
  --operator-identity <本机 spacetime login show 中的 identity> \
  --note "local export"

导出脚本负责调用本机源库 procedure 并保存返回 JSON

node scripts/spacetime-export-migration-json.mjs \
  --server dev \
  --database xushi-p4wfr \
  --out tmp/spacetime-migrations/source-2026-04-27.json

tmp/spacetime-migrations/source-2026-04-27.json 复制到服务器后,在服务器上登录目标 SpacetimeDB并授权服务器侧调用身份

node scripts/spacetime-authorize-migration-operator.mjs \
  --server maincloud \
  --database xushi-p4wfr \
  --bootstrap-secret <服务器目标库发布时输出的随机密钥> \
  --operator-identity <服务器 spacetime login show 中的 identity> \
  --note "server import"

导入脚本负责读取服务器本地文件并把 JSON 字符串传入目标库 procedure

node scripts/spacetime-import-migration-json.mjs \
  --server maincloud \
  --database xushi-p4wfr \
  --in tmp/spacetime-migrations/source-2026-04-27.json \
  --replace-existing

正式导入前建议先加 --dry-run,确认 JSON 可解析、版本匹配、表名都在迁移白名单内。

如需分批迁移,可用逗号分隔表名:

node scripts/spacetime-export-migration-json.mjs \
  --database xushi-p4wfr \
  --out tmp/spacetime-migrations/ai.json \
  --include ai_task,ai_task_stage,ai_text_chunk,ai_result_reference

--server 支持 devlocalmaincloud,也可以直接传 SpacetimeDB 服务器 URL。脚本默认走 spacetime call,使用当前机器的 CLI 登录态。数据库名可通过 --databaseGENARRATIVE_SPACETIME_MAINCLOUD_DATABASEGENARRATIVE_SPACETIME_DATABASE 提供。

授权脚本额外支持:

  • --bootstrap-secretGENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET
  • --operator-identityGENARRATIVE_SPACETIME_MIGRATION_OPERATOR_IDENTITY
  • --note

表范围

首版覆盖当前 private table 报错相关与主运行真相表:

  • 认证:auth_store_snapshotuser_accountauth_identityrefresh_session
  • AIai_taskai_task_stageai_text_chunkai_result_reference
  • 运行存档与账户投影:runtime_snapshotruntime_settinguser_browse_historyprofile_dashboard_stateprofile_wallet_ledgerprofile_invite_codeprofile_referral_relationprofile_played_worldprofile_membershipprofile_recharge_orderprofile_save_archive
  • RPG 运行真相:player_progressionchapter_progressionnpc_statestory_sessionstory_eventinventory_slotbattle_statetreasure_recordquest_recordquest_log
  • 自定义世界:custom_world_profilecustom_world_sessioncustom_world_agent_sessioncustom_world_agent_messagecustom_world_agent_operationcustom_world_draft_cardcustom_world_gallery_entry
  • 资产索引:asset_objectasset_entity_binding
  • 拼图:puzzle_agent_sessionpuzzle_agent_messagepuzzle_work_profilepuzzle_runtime_run
  • 大鱼:big_fish_creation_sessionbig_fish_agent_messagebig_fish_asset_slotbig_fish_runtime_run

后续新增 SpacetimeDB 表时,必须同步把表加入迁移白名单与本文档。

风险与限制

迁移 JSON 作为 procedure 返回值和 HTTP request body 传递,会受 SpacetimeDB 调用响应体、请求体以及中间代理大小限制。数据量较大时,先按 include_tables 分批迁移;若单表本身过大,再补充分片 procedure而不是恢复 HTTP 文件桥。

spacetime call 在 PowerShell 中手写 JSON 容易被剥掉双引号。推荐使用仓库里的 Node 脚本,由脚本直接走 HTTP API避免 shell 二次处理和命令行长度限制。