Merge branch 'master' into fix-login-autofill+86
Project CI / Frontend tests (pull_request) Successful in 47s
Project CI / Repository checks (pull_request) Successful in 57s
Project CI / Native shell tests (pull_request) Successful in 2m11s
Project CI / Backend tests (pull_request) Successful in 3m50s

This commit is contained in:
2026-07-23 14:10:50 +08:00
155 changed files with 9602 additions and 110 deletions
+31 -4
View File
@@ -1,6 +1,6 @@
---
name: spacetimedb-cli
description: SpacetimeDB 2.6 CLI reference for Genarrative. Use for spacetime build, publish, generate, call, sql, logs, server management, local dev, explicit server targeting, version checks, and remote runtime verification.
description: SpacetimeDB 2.7 CLI reference for Genarrative. Use for spacetime build, publish, generate, call, sql, logs, server management, local dev, explicit server targeting, version checks, and remote runtime verification.
---
# SpacetimeDB CLI
@@ -68,6 +68,31 @@ spacetime call --server http://127.0.0.1:3101 my-db reducer_needing_identity 0xa
spacetime subscribe my-db "SELECT * FROM users" --num-updates 10 --server http://127.0.0.1:3101
```
## Standalone MCP Endpoint (2.7)
SpacetimeDB 2.7 standalone exposes an authenticated JSON-RPC MCP endpoint at
`POST /v1/database/{name_or_identity}/mcp`. It advertises `ping`, `get_schema`,
`sql`, and `call`. The SQL and reducer tools execute with the bearer token's
identity, so keep routine smoke checks read-only.
```bash
curl -fsS \
-H "Authorization: Bearer ${SPACETIME_TOKEN}" \
-H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"genarrative-smoke","version":"1.0.0"}}}' \
http://127.0.0.1:3101/v1/database/my-db/mcp
curl -fsS \
-H "Authorization: Bearer ${SPACETIME_TOKEN}" \
-H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"ping","arguments":{"message":"genarrative"}}}' \
http://127.0.0.1:3101/v1/database/my-db/mcp
```
For repository upgrade validation, also call `tools/list` and the read-only
`get_schema` tool against an isolated local database. Do not use `sql` or `call`
for writes unless that mutation is explicitly in scope.
## Server & Auth
```bash
@@ -102,7 +127,7 @@ curl -fsS http://127.0.0.1:3101/v1/ping
| Flag | Description |
|------|-------------|
| `--server`, `-s` | Target server nickname, host, or URL |
| `--yes`, `-y` | Non-interactive prompt skipping; in 2.6 use scoped values |
| `--yes`, `-y` | Non-interactive prompt skipping; in 2.6+ use scoped values |
| `--delete-data`, `-c` | Publish data policy: `always`, `on-conflict`, or `never` |
| `--module-path`, `-p` | Module project path |
| `--bin-path`, `-b` | Publish/generate from compiled wasm |
@@ -146,6 +171,8 @@ pid="$(systemctl show spacetimedb.service -p MainPID --value)"
## Notes
- Procedure calls remain stable in 2.6; module HTTP handlers/webhooks and RLS capabilities still require their documented gates.
- 2.5 fixed `publish --delete-data` config fallback; 2.6 keeps that behavior and improves CLI binary distribution.
- Procedure calls remain stable in 2.7; module HTTP handlers/webhooks and RLS capabilities still require their documented gates.
- 2.5 fixed `publish --delete-data` config fallback; 2.6 kept that behavior and improved CLI binary distribution; 2.7 adds `spacetime sql --format json` and database `lock` / `unlock`.
- The official 2.7.0 Linux release archives and container image currently use the `v2.7.0-hotfix3` asset tag while binaries report `2.7.0`; keep the asset tag distinct from the runtime version check.
- Do not assume `spacetime version install 2.7.0` selected hotfix3: stale updater metadata can install bare-tag commit `a08663c7...`. For the current release, verify CLI commit `d220349a...` and use the official hotfix3 archive or repository provision flow when it differs.
- Genarrative scripts should pass `--server` or `--server-url` explicitly instead of relying on CLI defaults.
+20 -8
View File
@@ -1,6 +1,6 @@
---
name: spacetimedb-concepts
description: Understand SpacetimeDB 2.6 architecture, reducer/procedure/table/view semantics, schema evolution, subscriptions, identity, and Genarrative-specific backend boundaries. Use when designing or reviewing SpacetimeDB-backed features.
description: Understand SpacetimeDB 2.7 architecture, reducer/procedure/table/view semantics, schema evolution, subscriptions, identity, and Genarrative-specific backend boundaries. Use when designing or reviewing SpacetimeDB-backed features.
---
# SpacetimeDB Core Concepts
@@ -20,7 +20,7 @@ SpacetimeDB is a relational database that also executes application logic in upl
1. **Reducers are transactional**: they do not return data to callers. Read through subscriptions, read models, views, or BFF endpoints.
2. **Reducers are deterministic**: no filesystem, network, wall-clock, or external RNG. Use `ctx.timestamp`, `ctx.rng()` / `ctx.random()`, and tables.
3. **Procedures are stable in 2.6**: they can use explicit transactions and outgoing HTTP via `ctx.http`.
3. **Procedures are stable in 2.7**: they can use explicit transactions and outgoing HTTP via `ctx.http`.
4. **Identity comes from context**: use `ctx.sender()` or language equivalent for authorization. Never trust identity passed as an argument.
5. **Auto-increment IDs are not ordering guarantees**: gaps are normal. Use timestamps or explicit sequence columns for ordering.
6. **Schema changes need migration discipline**: existing Genarrative table fields must be appended with defaults; update migration code, table catalog, generated bindings, and run `npm run check:spacetime-schema`.
@@ -44,25 +44,25 @@ Reducers are deterministic transactional functions. They are the primary client-
## Procedures
Procedures are stable in 2.6. They can be scheduled, can open explicit transactions with `with_tx` / `try_with_tx`, and can use outgoing HTTP (`ctx.http`).
Procedures are stable in 2.7. They can be scheduled, can open explicit transactions with `with_tx` / `try_with_tx`, and can use outgoing HTTP (`ctx.http`).
Genarrative default: keep external provider protocols in `platform-*` and orchestration in `api-server` unless a task explicitly moves a workflow into a module procedure.
Module HTTP handlers/webhooks and RLS `client_visibility_filter` remain subject to their documented gates in 2.6.
Module HTTP handlers/webhooks and RLS `client_visibility_filter` remain subject to their documented gates in 2.7.
## Views
Views expose computed read-only data. SpacetimeDB 2.6 supports primary keys on procedural views in Rust, TypeScript, and C#. Clients can receive `OnUpdate` events when subscribed to such views with primary keys. Ensure the view never returns duplicate primary keys, because that can fail view refresh and roll back the triggering transaction.
Views expose computed read-only data. SpacetimeDB 2.7 supports primary keys on procedural views in Rust, TypeScript, C#, and C++. Clients can receive update events when subscribed to such views with primary keys. Ensure the view never returns duplicate primary keys, because that can fail view refresh and roll back the triggering transaction.
## Event Tables
Event tables broadcast reducer/procedure-specific facts to subscribers and must be subscribed explicitly. They are excluded from `subscribe_to_all_tables()`.
2.6 supports broader layout-altering automigrations for event tables, including column removal, reordering, and type changes that regular tables reject. This relaxed migration behavior is for event-only tables, not persistent tables.
Since 2.6, event tables support broader layout-altering automigrations, including column removal, reordering, and type changes that regular tables reject. This relaxed migration behavior is for event-only tables, not persistent tables.
Event-table primary keys and constraints are transaction-scoped. They can reject duplicate event rows within one transaction, but event rows are not retained in client cache, so clients observe event tables through insert callbacks only. Do not design Genarrative event tables around `OnUpdate` / `on_update` / `onUpdate`; use a persistent table or a primary-keyed procedural view when update callbacks are required.
Official 2.4.1 through 2.6 release notes document primary-key-backed update callbacks for procedural views, not event tables.
Official 2.4.1 through 2.7 release notes document primary-key-backed update callbacks for procedural views, not event tables.
## Subscriptions
@@ -78,7 +78,18 @@ Best practices:
- Avoid overlapping queries that duplicate row delivery.
- Use indexes for subscribed filters.
## 2.2.0 to 2.6.1 Delta
## Standalone MCP
SpacetimeDB 2.7 standalone exposes `POST /v1/database/{name_or_identity}/mcp`
using MCP JSON-RPC protocol `2025-06-18`. Its tools are `ping`, `get_schema`,
`sql`, and `call`; SQL and reducer calls run with the authenticated caller's
identity. In Genarrative this is an operator/developer integration surface, not
a replacement for `api-server` BFF routes, `spacetime-client` facades, or public
read models. Upgrade smoke should use an isolated local database and restrict
itself to `initialize`, `tools/list`, `ping`, and `get_schema` unless writes are
explicitly intended.
## 2.2.0 to 2.7.0 Delta
Genarrative introduced SpacetimeDB around 2.2.0. Important changes since then:
@@ -89,6 +100,7 @@ Genarrative introduced SpacetimeDB around 2.2.0. Important changes since then:
- **2.5.0**: procedures are stable, C# procedural views gain primary keys, event tables allow broader layout-altering automigrations, BTreeSet storage makes row insertion deterministic and avoids accidentally quadratic bulk insert behavior, `wasm_memory_bytes` billing metric semantics changed, template version constraints unified, `publish --delete-data` config fallback fixed, CLI `call` accepts hex Identity arguments.
- **2.6.0**: procedural-view primary keys are available across Rust, TypeScript, and C#, commitlog gains `max_segment_size` / `write_buffer_size` / `preallocate_segments`, the default write buffer increases for throughput, event-table automigrations improve, and CLI binary distribution expands.
- **2.6.1**: procedure contexts again receive the caller `Identity` and `ConnectionId`; generated TypeScript `Option<T>` fields use optional keys; `spacetime init --template` lists available templates when no template argument is supplied.
- **2.7.0**: existing tables can add unique or primary-key constraints when current data satisfies them; standalone exposes an authenticated database MCP endpoint; Rust adds context-capability and table-accessor traits; `spacetime sql --format json` and database locking are available; view cleanup, backing-table migration, connection metrics, and memory metrics improve. Official current release assets use the `v2.7.0-hotfix3` tag while binaries report `2.7.0`.
## Debugging Checklist
+4 -4
View File
@@ -1,6 +1,6 @@
---
name: spacetimedb-rust
description: Develop SpacetimeDB 2.6 server modules in Rust for Genarrative. Use when writing or reviewing tables, reducers, procedures, views, migrations, row mappers, schema changes, and module logic.
description: Develop SpacetimeDB 2.7 server modules in Rust for Genarrative. Use when writing or reviewing tables, reducers, procedures, views, migrations, row mappers, schema changes, and module logic.
---
# SpacetimeDB Rust Module Development
@@ -181,11 +181,11 @@ fn deal_damage(ctx: &ReducerContext, target: Identity, amount: u32) {
Event tables must be subscribed explicitly and are excluded from `subscribe_to_all_tables()`.
In 2.6, event tables support broader layout-altering automigrations than regular tables, including column removal, reordering, and type changes. This relaxed migration policy does not apply to persistent tables.
Since 2.6, event tables support broader layout-altering automigrations than regular tables, including column removal, reordering, and type changes. This relaxed migration policy does not apply to persistent tables.
Event-table primary keys and constraints are enforced only within the current transaction. They do not make event rows persistent, and client SDKs expose event tables as insert-only event streams. Do not rely on `OnUpdate` / `on_update` / `onUpdate` for event tables; use a persistent table or a primary-keyed procedural view when update callbacks are required.
Official 2.4.1 through 2.6 release notes tie primary-key-backed update callbacks to procedural views, not event tables.
Official 2.4.1 through 2.7 release notes tie primary-key-backed update callbacks to procedural views, not event tables.
## Views
@@ -228,7 +228,7 @@ For scheduled reducers, check `ctx.sender_auth().is_internal()` when the reducer
## Procedures
Procedures remain stable in 2.6 and no longer require the `unstable` feature.
Procedures remain stable in 2.7 and no longer require the `unstable` feature.
```rust
use spacetimedb::{procedure, ProcedureContext};
+2 -2
View File
@@ -56,7 +56,7 @@ Linux Docker Engine 若要从宿主机 CLI 连到容器内服务,直接用 `ht
## 构建工具链
`api-server` 容器镜像只构建 Linux release API 二进制,不构建 `spacetime-module`。当前 `api-server -> spacetime-client -> spacetimedb-sdk 2.6.1` 依赖链要求 Rust 1.93,因此 `deploy/container/api-server.Dockerfile` 的 Rust builder 固定为 `rust:1.93-bookworm`。镜像构建阶段会同时复制 `public/`,用于满足 API 二进制里 `include_bytes!` 引用的内置素材;不要把 `public/generated-*` 放入镜像上下文。如果本机 Docker Hub 拉取失败,可以先在本机准备同名本地 builder 镜像,但不要把临时 bootstrap 容器或私有 registry 凭据写入仓库。
`api-server` 容器镜像只构建 Linux release API 二进制,不构建 `spacetime-module`。当前 `api-server -> spacetime-client -> spacetimedb-sdk 2.7.0` 依赖链继续兼容 Rust 1.93,因此 `deploy/container/api-server.Dockerfile` 的 Rust builder 固定为 `rust:1.93-bookworm`。镜像构建阶段会同时复制 `public/`,用于满足 API 二进制里 `include_bytes!` 引用的内置素材;不要把 `public/generated-*` 放入镜像上下文。如果本机 Docker Hub 拉取失败,可以先在本机准备同名本地 builder 镜像,但不要把临时 bootstrap 容器或私有 registry 凭据写入仓库。
### Gitea CI 预构建 Job 镜像
@@ -156,7 +156,7 @@ npm run container:worker-smoke -- status
npm run container:worker-smoke -- smoke --force
```
`container:worker-smoke` 默认会把本机 `spacetime` 2.6.1 CLI 打成轻量 SpacetimeDB 镜像,避免首次 smoke 必须拉取官方大镜像;普通 `npm run container:*` 压测默认使用 `clockworklabs/spacetime:v2.6.1`。如果 Docker build 阶段在容器内拉取 crates.io 依赖不稳定,可让容器内 Cargo 复用本机 Cargo 缓存构建当前二进制,再打入临时 smoke 镜像。该模式默认使用 `rust:1.93-bookworm` 作为 builder、Debian bookworm smoke runtime 承载构建产物;需要换 builder 镜像时设置 `GENARRATIVE_WORKER_SMOKE_CARGO_IMAGE`,需要换运行时基础镜像时设置 `GENARRATIVE_WORKER_SMOKE_LOCAL_BASE_IMAGE`
`container:worker-smoke` 默认会把本机 `spacetime` 2.7.0 CLI 打成轻量 SpacetimeDB 镜像,避免首次 smoke 必须拉取官方大镜像;普通 `npm run container:*` 压测默认使用 `clockworklabs/spacetime:v2.7.0-hotfix3`(容器内二进制报告 2.7.0。如果 Docker build 阶段在容器内拉取 crates.io 依赖不稳定,可让容器内 Cargo 复用本机 Cargo 缓存构建当前二进制,再打入临时 smoke 镜像。该模式默认使用 `rust:1.93-bookworm` 作为 builder、Debian bookworm smoke runtime 承载构建产物;需要换 builder 镜像时设置 `GENARRATIVE_WORKER_SMOKE_CARGO_IMAGE`,需要换运行时基础镜像时设置 `GENARRATIVE_WORKER_SMOKE_LOCAL_BASE_IMAGE`
```bash
npm run container:worker-smoke -- smoke --local-binary
+1 -1
View File
@@ -2,7 +2,7 @@ name: genarrative-container-loadtest
services:
spacetimedb:
image: ${GENARRATIVE_CONTAINER_SPACETIME_IMAGE:-clockworklabs/spacetime:v2.6.1}
image: ${GENARRATIVE_CONTAINER_SPACETIME_IMAGE:-clockworklabs/spacetime:v2.7.0-hotfix3}
user: root
command:
[
@@ -253,6 +253,14 @@
- 验证方式:核对 `spacetime --version`,运行 `npm run spacetime:generate``npm run check:spacetime-schema``cargo check` / 定向测试、server provision 工具测试、encoding / diff 门禁。
- 关联文档:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 2026-07-23 SpacetimeDB 工具链统一升级到 2.7.0
- 背景:SpacetimeDB 2.7.0 增加满足数据约束时的 unique / primary-key 非破坏迁移、Rust SDK capability traits、standalone MCP endpoint、SQL JSON 输出和更多连接/视图/内存指标,并修复旧 procedural-view backing table 的自动迁移。官方当前发行资产位于 `v2.7.0-hotfix3` 标签,二进制和 Rust crates 版本仍为 2.7.0。
- 决策:`server-rs/Cargo.toml``spacetimedb``spacetimedb-sdk``spacetimedb-lib` 精确锁定 2.7.0;本地 CLI / standalone 与 Rust bindings 使用官方 2.7.0 hotfix3 构建,worker smoke 本地镜像按运行版本标记 2.7.0,官方容器和生产 provision 下载根固定到 `v2.7.0-hotfix3`。provision 从 hotfix 资产标签解析运行版本时必须得到 2.7.0,并同时核对 CLI commit 为 `d220349a...`;裸 tag `a08663c7...` 不得因版本号相同而被复用,下载 / 安装结果也必须通过同一 commit 门禁。
- 影响范围:Rust workspace lockfile、SpacetimeDB bindings、本地 dev 版本门禁、容器 smoke / loadtest、server provision Jenkins 与项目 SpacetimeDB skills / 文档;现役 module 没有 procedural view,本次不修改 schema 或 migration。
- 验证方式:核对 CLI 版本和 commit,重新生成 Rust bindings,运行 `npm run check:spacetime-schema`、相关 Cargo check、server provision 工具测试、容器配置、Rust 1.93 兼容检查、standalone `/v1/ping`、encoding 和 diff 门禁。
- 关联文档:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 2026-07-10 外部生成任务只持久化轻量媒体引用并独立维护摘要投影
- 背景:编辑器 worker 化后直接把同步接口 payload 序列化进 `external_generation_job.request_payload_json`;前端又把已有 OSS `objectKey` 下载成 Data URL 再提交,导致单个任务 JSON 膨胀到数 MB,正式任务列表读取 20 条任务时同时搬运约 65 MB payload,并放大为 SpacetimeDB 与 api-server 的瞬时内存峰值。此前“禁止 Data URL 持久化”只覆盖工程、素材、图层和元数据,遗漏了正式生成任务表。
@@ -1,6 +1,6 @@
# Genarrative 项目共享概览
更新时间:`2026-07-18`
更新时间:`2026-07-23`
## 一句话定位
@@ -31,7 +31,7 @@ Genarrative / 陶泥儿是一个 AI 原生互动内容与小游戏平台,把 A
server-rs + Axum + SpacetimeDB
```
当前 SpacetimeDB crate、SDK、CLI / standalone生成 bindings 和容器压测镜像统一按 `2.6.1` 对齐;遇到版本不匹配时先升级到 `server-rs/Cargo.toml` 锁定版本,升级后重启对应 SpacetimeDB 进程再重试。
当前 SpacetimeDB crate、SDK、CLI / standalone生成 bindings 统一按 `2.7.0` 对齐;官方 CLI / standalone 发行包与容器镜像使用 `v2.7.0-hotfix3` 资产标签,二进制仍报告 `2.7.0`遇到版本不匹配时先升级到 `server-rs/Cargo.toml` 锁定版本,升级后重启对应 SpacetimeDB 进程再重试。
职责边界:
@@ -2,7 +2,7 @@
> 2026-07-18 状态更新:旧创作入口、全部模板业务 API/worker/运行态及 SpacetimeDB 业务逻辑已退役。本文逐玩法路由、流程和 DTO 章节仅作为历史设计记录;相关持久化表仍按原结构作为最小 schema 数据壳编译,当前编译与运行边界以 `server-rs/Cargo.toml`、`server-rs/crates/api-server/src/app.rs` 和 `docs/technical/【架构下线】旧创作模板业务退役方案-2026-07-17.md` 为准。
更新时间:`2026-07-21`
更新时间:`2026-07-23`
## 后端主线
@@ -18,7 +18,7 @@ server-rs + Axum + SpacetimeDB
`server-rs/Cargo.toml` 是 workspace 事实源。默认构建成员为 `crates/api-server`;第三方依赖版本和 workspace 内 crate path 统一放在 `[workspace.dependencies]`
SpacetimeDB 版本口径:当前 Rust crate `spacetimedb``spacetimedb-sdk``spacetimedb-lib` 统一锁定 `2.6.1`;本地 `spacetime` CLI / standalone、生成的 `spacetime-client` bindings 和容器压测镜像也必须与 `server-rs/Cargo.toml` 锁定版本对齐,避免 BSATN / procedure result 反序列化错配。遇到版本不匹配时,不继续沿着业务超时排查,先把 CLI / standalone 直接升级到锁定版本并重启后再重试。2.6.1 还修复了 procedure context 中调用者 `Identity` / `ConnectionId` 丢失问题,因此依赖调用者身份的 procedure 不得继续运行在 2.6.0 standalone 上。
SpacetimeDB 版本口径:当前 Rust crate `spacetimedb``spacetimedb-sdk``spacetimedb-lib` 统一锁定 `2.7.0`;本地 `spacetime` CLI / standalone、生成的 `spacetime-client` bindings 和容器压测镜像也必须与 `server-rs/Cargo.toml` 锁定版本对齐,避免 BSATN / procedure result 反序列化错配。2.7.0 官方 CLI / standalone 发行包与容器镜像使用 `v2.7.0-hotfix3` 资产标签,二进制版本仍为 `2.7.0`;不得回退使用缺少后续 backing-view 迁移修复的裸 tag 构建。遇到版本不匹配时,不继续沿着业务超时排查,先把 CLI / standalone 直接升级到锁定版本并重启后再重试。2.6.1 还修复了 procedure context 中调用者 `Identity` / `ConnectionId` 丢失问题,因此依赖调用者身份的 procedure 不得继续运行在 2.6.0 standalone 上。
当前主要 crate
@@ -1,6 +1,6 @@
# 本地开发验证与生产运维
更新时间:`2026-07-21`
更新时间:`2026-07-23`
## 标准开发流程
@@ -151,7 +151,7 @@ spacetime sql <database> "SELECT * FROM runtime_setting LIMIT 1" --server http:/
本地 `npm run dev:spacetime` 发布模块时必须显式忽略仓库根目录的 `spacetime.json`,由脚本固定追加 `--no-config` 并使用命令参数里传入的数据库名和 `--server http://127.0.0.1:3101`。否则 CLI 可能把发布目标改写到配置文件里的其他数据库,导致 `dev:spacetime` 启动后又因发布失败自动退出,浏览器随后会在 `ws://127.0.0.1:3101/v1/database/.../subscribe` 看到连接拒绝。
本地 `spacetime` CLI / standalone 版本必须和 `server-rs/Cargo.toml` 里锁定的 `spacetimedb` 版本一致;当前统一版本为 `2.6.1`。若版本错配,procedure 返回值可能在宿主侧触发 `Failed to BSATN deserialize procedure return value`api-server 最终表现为现役 settings、editor project 或 profile procedure 超时。排障时先运行 `spacetime --version`,再对照 `server-rs/Cargo.toml``spacetimedb = "..."`遇到版本不匹配时直接执行 `spacetime version install <version> && spacetime version use <version>`或在目标就是最新版本时执行 `spacetime version upgrade`升级后重启 `npm run dev:spacetime` 再重试。当前 `scripts/dev.mjs`在启动和复用本地 SpacetimeDB 前写入并校验 `dev-spacetime-tool-version`。2.6.1 修复了 procedure context 中调用者 `Identity` / `ConnectionId` 始终为空的回归,依赖 `ctx.sender` 鉴权时必须同时确认宿主已升级。
本地 `spacetime` CLI / standalone 版本必须和 `server-rs/Cargo.toml` 里锁定的 `spacetimedb` 版本一致;当前统一版本为 `2.7.0`。官方发行包位于 `v2.7.0-hotfix3` 资产标签,二进制仍报告 `2.7.0`;运行态和 provision 必须使用该 hotfix 构建,不得只按裸 `v2.7.0` tag 下载。当前 updater 元数据可能让 `spacetime version install 2.7.0` 装到裸 tag commit `a08663c7...`,所以 2.7.0 安装后必须核对 `spacetime --version` 的 commit 为 hotfix3 `d220349a...`;不一致时改用官方 hotfix3 archive 或仓库 provision 流程。若版本错配,procedure 返回值可能在宿主侧触发 `Failed to BSATN deserialize procedure return value`api-server 最终表现为现役 settings、editor project 或 profile procedure 超时。排障时先运行 `spacetime --version`,再对照 `server-rs/Cargo.toml``spacetimedb = "..."`其它版本可执行 `spacetime version install <version> && spacetime version use <version>`,升级后重启 `npm run dev:spacetime` 再重试。当前 `scripts/dev.mjs`把 tool version 和 commit 一起写入 `dev-spacetime-tool-version`,启动新 standalone 与复用已有本地进程时都要求 `2.7.0 + d220349a...` 同时匹配;旧单行版本记录会拒绝复用并要求重启。2.6.1 修复了 procedure context 中调用者 `Identity` / `ConnectionId` 始终为空的回归,依赖 `ctx.sender` 鉴权时必须同时确认宿主已升级。
本地 `.env``.env.local``.env.secrets.local` 修改后必须重启 `api-server` 才会生效;若已经通过 `npm run dev` 启动完整联调,可在该终端输入 `rs api-server`。排查图片编辑器 VectorEngine 生成链路时,确认 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY``VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS` 只在本地或服务器密钥文件中配置,不能写入 Git。`VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS` 是单次 attempt 的配置上限,默认 `1000000`;配置加载层允许显式值低于该默认值,不再在读取环境变量时强制抬高。业务模型和 VectorEngine provider 首选请求都使用 `gpt-image-2`,符合条件时才回退到兜底模型 `gpt-image-2-c`;图片协议、URL / base64 响应解析、远端图片下载和 provider 侧结构化日志在 `server-rs/crates/platform-image``api-server` 只做编辑器请求编排、OSS / asset 持久化、计费和失败审计落库。`platform-image` 会在 JSON 生成和 multipart 编辑请求发送前按同一 GPT-image-2 family 规则归一显式像素尺寸;若请求发送失败,先按同一 `request_id` 查看 provider 日志与 `external_api_call_failure.metadata_json.errorSource`,当前 multipart `/v1/images/edits` 单独强制 HTTP/1.1。
@@ -247,7 +247,7 @@ SpacetimeDB bindings
npm run spacetime:generate
```
后台账号 procedure 的 identity、唯一索引和版本事务使用隔离 smoke 验证;脚本会在随机本机端口启动临时 SpacetimeDB 2.6、发布当前 module,结束后自动关闭并清理临时数据:
后台账号 procedure 的 identity、唯一索引和版本事务使用隔离 smoke 验证;脚本会在随机本机端口启动仓库锁定版本的临时 SpacetimeDB、发布当前 module,结束后自动关闭并清理临时数据:
```bash
npm run check:admin-account-procedures
@@ -609,7 +609,7 @@ worker 被硬杀或断电后,lease 过期任务只有尚未耗尽 `max_attempt
- `api-server` 正常运行时 `/healthz` 只返回进程存活状态,`/readyz` 会同时检查进程是否仍接收新流量和 SpacetimeDB 连接租约是否健康;收到 `SIGINT` / `SIGTERM` 后会先把 readiness 标记为不可用,再让 Axum 停止接新连接并等待已有 HTTP 请求排空。systemd 仍以 `KillSignal=SIGINT` 停服务,`TimeoutStopSec=90` 作为长请求排空上限。
- SpacetimeDB 健康检查默认使用 `GENARRATIVE_SPACETIME_HEALTH_CHECK_TIMEOUT_SECONDS=2` 的短等待窗口,和业务 procedure 的 `GENARRATIVE_SPACETIME_PROCEDURE_TIMEOUT_SECONDS` 分开。`/readyz` 失败时 `details.spacetime.stage` 会标出当前卡住阶段:`pool_acquire``connect_build``connect_handshake``read_model_subscribe``procedure_result``reducer_result``read_cache``elapsedMs` / `timeoutMs` 用于确认是否命中健康检查窗口。业务请求日志也会写入 `operation_kind``operation_name``spacetime_stage``elapsed_ms`,后续 45 秒超时不再只靠 Nginx `request_time=45s` 推断。
- `genarrative-api.service` 设置 `LimitNOFILE=65535``TasksMax=2048`;上线后用 `systemctl show genarrative-api.service -p LimitNOFILE -p TasksMax -p TimeoutStopUSec``cat /proc/$(pidof api-server)/limits` 核对。
- Server provision 不再通过 Windows helper 下载,也不再通过 Linux build 节点中转 SpacetimeDB / otelcol 工具包;Linux build 节点只负责从内网 Git 源准备 provision 脚本和配置并上传给目标 agent。`Prepare Provision Tools` 在目标 dev / release agent 工作区内先检查 `/usr/local/bin/otelcol-contrib``${SPACETIME_ROOT}/bin/current`版本已满足时直接复用目标机现有文件生成 `provision-tools/`,只有缺失或版本不匹配时才使用 `PROVISION_DOWNLOADS_DIR` 里的本地包或从配置的下载源准备 SpacetimeDB `2.6.1` / `otelcol-contrib 0.151.0`;如果目标服务器下载需要代理,在 `PROVISION_DOWNLOAD_PROXY` 配置目标机可访问的 HTTP 代理。
- Server provision 不再通过 Windows helper 下载,也不再通过 Linux build 节点中转 SpacetimeDB / otelcol 工具包;Linux build 节点只负责从内网 Git 源准备 provision 脚本和配置并上传给目标 agent。`Prepare Provision Tools` 在目标 dev / release agent 工作区内先检查 `/usr/local/bin/otelcol-contrib``${SPACETIME_ROOT}/bin/current`SpacetimeDB 必须同时匹配运行版本 `2.7.0` 和 hotfix3 commit `d220349a...` 才能复用,裸 tag `a08663c7...` 即使版本号相同也必须拒绝;只有缺失或版本 / commit 不匹配时才使用 `PROVISION_DOWNLOADS_DIR` 里的本地包或从配置的下载源准备官方 `v2.7.0-hotfix3` 资产。`SPACETIME_EXPECTED_COMMIT` 与下载根必须成对调整,安装结果也执行同一 commit 门禁。otelcol-contrib 当前锁定 `0.151.0`;如果目标服务器下载需要代理,在 `PROVISION_DOWNLOAD_PROXY` 配置目标机可访问的 HTTP 代理。
-`Genarrative-Server-Provision` 外,`Genarrative-Stdb-Module-Build``Genarrative-Web-Build``Genarrative-Api-Build``Genarrative-*Deploy``Genarrative-Database-Import/Export``Genarrative-Full-Build-And-Deploy``Genarrative-Notify-Email` 的生产流水线现都以 Linux agent 为主,仍按各自 Jenkinsfile 的 checkout 口径执行。Server provision 不使用公网备用 Git 源,目标部署 agent 也不再需要访问源码 Git remote。
- `otelcol-contrib.service` 作为可选系统服务加入 provision,默认监听 `127.0.0.1:4317/4318` 并使用 `deploy/otelcol/genarrative-debug.yaml`。api-server 是否发送 OTLP 仍由 `GENARRATIVE_OTEL_ENABLED` 控制,服务 unit 见 `deploy/systemd/otelcol-contrib.service`。该服务必须存在系统用户 / 组 `otelcol`,并且 `/etc/otelcol/genarrative-debug.yaml` 已安装到目标机;若看到 `status=217/USER``Failed to determine user credentials`,优先检查 `getent passwd otelcol`,再补齐 `/etc/otelcol` 配置目录并重启服务。
- Nginx `/api/``/admin/api/` 通过 `genarrative_api` upstream 代理到 `127.0.0.1:8082`upstream keepalive 为 64;通用 API 使用 `genarrative_api_rps`,后台 API 使用 `genarrative_admin_rps`。通用 `/api` location 保留 `client_max_body_size 64m` 作为编辑器图片、视频和文档请求的反代兜底,真实大小仍由路由与业务校验负责。若线上出现 `413 Request Entity Too Large` 且 access log 中 `request_time=0.000``upstream_status=-`,说明请求在 Nginx 层被拦截,先核对 release 模板与实际媒体大小。`limit_conn_status 429``limit_req_status 429` 必须在 HTTP 与 HTTPS server 中同时生效。
@@ -25,7 +25,8 @@ pipeline {
string(name: 'PROVISION_DOWNLOADS_DIR', defaultValue: 'provision-tool-downloads', description: '目标服务器工作区内暂存 SpacetimeDB/otelcol 安装包的相对目录')
string(name: 'PROVISION_TOOLS_DIR', defaultValue: 'provision-tools', description: '目标机工作区内由已下载安装包生成的工具包目录')
string(name: 'PROVISION_DOWNLOAD_PROXY', defaultValue: '', description: '可选,目标服务器下载 SpacetimeDB 和 otelcol-contrib 时使用的代理地址,例如 http://127.0.0.1:7890;留空不设置代理')
string(name: 'SPACETIME_DOWNLOAD_ROOT', defaultValue: 'https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.6.1', description: '目标服务器使用的 SpacetimeDB Linux release tarball 根地址;默认固定到项目锁定版本')
string(name: 'SPACETIME_DOWNLOAD_ROOT', defaultValue: 'https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.7.0-hotfix3', description: '目标服务器使用的 SpacetimeDB Linux release tarball 根地址;默认固定到项目锁定版本的官方 hotfix 资产标签')
string(name: 'SPACETIME_EXPECTED_COMMIT', defaultValue: 'd220349adb7af7eefa810eb08a185609356b83f6', description: 'SpacetimeDB CLI 预期构建 commit;用于拒绝同版本号但缺少 hotfix 的旧二进制')
string(name: 'SPACETIME_TARGET_HOST', defaultValue: 'x86_64-unknown-linux-gnu', description: 'SpacetimeDB 预编译包 host tripledevelopment/release Linux amd64 使用默认值')
string(name: 'SPACETIME_ROOT', defaultValue: '/stdb', description: 'SpacetimeDB root-dir')
string(name: 'RELEASE_ROOT', defaultValue: '/opt/genarrative/releases', description: 'release 根目录')
@@ -95,6 +96,9 @@ pipeline {
if (!(params.SPACETIME_DOWNLOAD_ROOT?.trim() ==~ /^https?:\/\/\S+$/)) {
error('SPACETIME_DOWNLOAD_ROOT 不能为空。')
}
if (!(params.SPACETIME_EXPECTED_COMMIT?.trim() ==~ /^[0-9a-f]{40}$/)) {
error('SPACETIME_EXPECTED_COMMIT 必须是 40 位小写十六进制 commit。')
}
if (!(params.SPACETIME_TARGET_HOST?.trim() ==~ /^[0-9A-Za-z._-]+$/)) {
error("SPACETIME_TARGET_HOST 只能包含字母、数字、点号、下划线和短横线: ${params.SPACETIME_TARGET_HOST}")
}
@@ -209,7 +213,8 @@ BASH
OTELCOL_VERSION="${OTELCOL_VERSION:-0.151.0}" \
PREPARE_OTELCOL="${ENABLE_OTELCOL:-true}" \
PROVISION_DOWNLOAD_PROXY="${PROVISION_DOWNLOAD_PROXY:-}" \
SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.6.1}" \
SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.7.0-hotfix3}" \
SPACETIME_EXPECTED_COMMIT="${SPACETIME_EXPECTED_COMMIT:-d220349adb7af7eefa810eb08a185609356b83f6}" \
SPACETIME_TARGET_HOST="${SPACETIME_TARGET_HOST:-x86_64-unknown-linux-gnu}" \
SPACETIME_ROOT="${SPACETIME_ROOT:-/stdb}" \
scripts/prepare-server-provision-tools.sh
+1 -1
View File
@@ -20,7 +20,7 @@ const repoRoot = path.resolve(
'..',
);
const database = 'admin-account-smoke';
const expectedSpacetimeVersion = '2.6.1';
const expectedSpacetimeVersion = '2.7.0';
const commandTimeoutMs = 5 * 60 * 1000;
function assert(condition, message) {
+84 -3
View File
@@ -37,11 +37,15 @@ chmod +x "${TARGET_BIN_DIR}/otelcol-contrib"
cat >"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-cli" <<'EOF'
#!/usr/bin/env bash
echo "spacetimedb-cli 2.6.1"
cat <<'VERSION'
spacetime Path: /tmp/spacetimedb-cli
Commit: d220349adb7af7eefa810eb08a185609356b83f6
spacetimedb tool version 2.7.0; spacetimedb-lib version 2.7.0;
VERSION
EOF
cat >"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-standalone" <<'EOF'
#!/usr/bin/env bash
echo "spacetimedb-standalone 2.6.1"
echo "spacetimedb-standalone 2.7.0"
EOF
chmod +x \
"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-cli" \
@@ -58,7 +62,6 @@ if ! (
OTELCOL_TARGET_BIN="${TARGET_BIN_DIR}/otelcol-contrib" \
OTELCOL_VERSION="0.151.0" \
SPACETIME_ROOT="${SPACETIME_ROOT_DIR}" \
SPACETIME_EXPECTED_VERSION="2.6.1" \
"${REPO_ROOT}/scripts/prepare-server-provision-tools.sh" \
>"${OUTPUT_LOG}" 2>&1
); then
@@ -83,4 +86,82 @@ if grep -q "下载 " "${OUTPUT_LOG}"; then
exit 1
fi
BARE_TAG_ROOT_DIR="${TMP_ROOT}/bare-tag-stdb"
BARE_TAG_WORK_DIR="${TMP_ROOT}/bare-tag-workspace"
BARE_TAG_LOG="${TMP_ROOT}/bare-tag.log"
mkdir -p "${BARE_TAG_ROOT_DIR}/bin/current" "${BARE_TAG_WORK_DIR}"
cat >"${BARE_TAG_ROOT_DIR}/bin/current/spacetimedb-cli" <<'EOF'
#!/usr/bin/env bash
cat <<'VERSION'
spacetime Path: /tmp/spacetimedb-cli
Commit: a08663c7b94688a2542577532d472f751e641f5b
spacetimedb tool version 2.7.0; spacetimedb-lib version 2.7.0;
VERSION
EOF
cat >"${BARE_TAG_ROOT_DIR}/bin/current/spacetimedb-standalone" <<'EOF'
#!/usr/bin/env bash
echo "spacetimedb-standalone 2.7.0"
EOF
chmod +x \
"${BARE_TAG_ROOT_DIR}/bin/current/spacetimedb-cli" \
"${BARE_TAG_ROOT_DIR}/bin/current/spacetimedb-standalone"
if (
cd "${BARE_TAG_WORK_DIR}"
PATH="${FAKE_BIN_DIR}:${PATH}" \
WORKSPACE="${BARE_TAG_WORK_DIR}" \
PROVISION_TOOLS_DIR="provision-tools" \
PROVISION_DOWNLOADS_DIR="downloads" \
PROVISION_TOOLS_TMP_PARENT="${BARE_TAG_WORK_DIR}/.tmp/server-provision-tools" \
PROVISION_REQUIRE_LOCAL_DOWNLOADS="true" \
PREPARE_OTELCOL="false" \
SPACETIME_ROOT="${BARE_TAG_ROOT_DIR}" \
"${REPO_ROOT}/scripts/prepare-server-provision-tools.sh" \
>"${BARE_TAG_LOG}" 2>&1
); then
echo "[check-server-provision-tools] 裸 v2.7.0 tag 不应通过 hotfix3 复用门禁。" >&2
cat "${BARE_TAG_LOG}" >&2
exit 1
fi
grep -q "SpacetimeDB commit 不匹配" "${BARE_TAG_LOG}"
if grep -q "复用目标机已有 SpacetimeDB 安装" "${BARE_TAG_LOG}"; then
echo "[check-server-provision-tools] 裸 v2.7.0 tag 被错误复用。" >&2
cat "${BARE_TAG_LOG}" >&2
exit 1
fi
BARE_ARCHIVE_DIR="${TMP_ROOT}/bare-archive"
BARE_ARCHIVE_PATH="${TMP_ROOT}/bare-spacetime.tar.gz"
BARE_ARCHIVE_WORK_DIR="${TMP_ROOT}/bare-archive-workspace"
BARE_ARCHIVE_LOG="${TMP_ROOT}/bare-archive.log"
mkdir -p "${BARE_ARCHIVE_DIR}" "${BARE_ARCHIVE_WORK_DIR}"
cp \
"${BARE_TAG_ROOT_DIR}/bin/current/spacetimedb-cli" \
"${BARE_TAG_ROOT_DIR}/bin/current/spacetimedb-standalone" \
"${BARE_ARCHIVE_DIR}/"
tar -czf "${BARE_ARCHIVE_PATH}" -C "${BARE_ARCHIVE_DIR}" \
spacetimedb-cli spacetimedb-standalone
if (
cd "${BARE_ARCHIVE_WORK_DIR}"
PATH="${FAKE_BIN_DIR}:${PATH}" \
WORKSPACE="${BARE_ARCHIVE_WORK_DIR}" \
PROVISION_TOOLS_DIR="provision-tools" \
PROVISION_DOWNLOADS_DIR="downloads" \
PROVISION_TOOLS_TMP_PARENT="${BARE_ARCHIVE_WORK_DIR}/.tmp/server-provision-tools" \
PROVISION_REQUIRE_LOCAL_DOWNLOADS="true" \
PREPARE_OTELCOL="false" \
SPACETIME_ROOT="${TMP_ROOT}/missing-target-stdb" \
SPACETIME_ARCHIVE_PATH="${BARE_ARCHIVE_PATH}" \
"${REPO_ROOT}/scripts/prepare-server-provision-tools.sh" \
>"${BARE_ARCHIVE_LOG}" 2>&1
); then
echo "[check-server-provision-tools] 裸 v2.7.0 archive 不应通过 hotfix3 安装结果门禁。" >&2
cat "${BARE_ARCHIVE_LOG}" >&2
exit 1
fi
grep -q "安装结果 commit 不匹配" "${BARE_ARCHIVE_LOG}"
echo "[check-server-provision-tools] OK"
+1 -1
View File
@@ -759,7 +759,7 @@ function composeEnv() {
}
function localSpacetimeImageName() {
return `${projectName}-spacetimedb:2.6.1`;
return `${projectName}-spacetimedb:2.7.0`;
}
function spacetimeServerUrl(state) {
+77 -36
View File
@@ -569,7 +569,27 @@ function parseSpacetimeToolVersion(output) {
return match?.[1] ?? '';
}
function readSpacetimeToolVersion() {
function parseSpacetimeToolCommit(output) {
const match = /^Commit:\s*([0-9a-f]{40})\s*$/imu.exec(output);
return match?.[1]?.toLowerCase() ?? '';
}
function expectedSpacetimeToolCommit(workspaceVersion) {
if (workspaceVersion === '2.7.0') {
return 'd220349adb7af7eefa810eb08a185609356b83f6';
}
return '';
}
function buildSpacetimeUpgradeInstruction(workspaceVersion) {
const expectedCommit = expectedSpacetimeToolCommit(workspaceVersion);
if (expectedCommit) {
return `请安装官方 v${workspaceVersion}-hotfix3 发行包并确认 spacetime --version 的 Commit 为 ${expectedCommit},然后重新运行本命令。`;
}
return `请先直接升级并切换到锁定版本: spacetime version install ${workspaceVersion} && spacetime version use ${workspaceVersion},然后重新运行本命令。`;
}
function readSpacetimeToolProvenance() {
const result = spawnSync('spacetime', ['--version'], {
cwd: repoRoot,
encoding: 'utf8',
@@ -585,33 +605,43 @@ function readSpacetimeToolVersion() {
if (!version) {
throw new Error(`无法解析 spacetime 版本输出: ${trimPreview(output)}`);
}
return version;
return { version, commit: parseSpacetimeToolCommit(output) };
}
function assertSpacetimeToolVersionMatchesWorkspace({
toolVersion,
toolCommit = '',
workspaceVersion,
}) {
if (toolVersion === workspaceVersion) {
return;
if (toolVersion !== workspaceVersion) {
throw new Error(
[
`本机 spacetime CLI/standalone 版本 ${toolVersion} 与 server-rs 锁定的 SpacetimeDB ${workspaceVersion} 不一致。`,
'版本错位会导致 procedure 返回值 BSATN 反序列化失败,前端表现为 SpacetimeDB procedure 调用超时。',
buildSpacetimeUpgradeInstruction(workspaceVersion),
].join(''),
);
}
throw new Error(
[
`本机 spacetime CLI/standalone 版本 ${toolVersion} 与 server-rs 锁定的 SpacetimeDB ${workspaceVersion} 不一致。`,
'版本错位会导致 procedure 返回值 BSATN 反序列化失败,前端表现为 SpacetimeDB procedure 调用超时。',
`请先直接升级并切换到锁定版本: spacetime version install ${workspaceVersion} && spacetime version use ${workspaceVersion},然后重新运行本命令`,
].join(''),
);
const expectedCommit = expectedSpacetimeToolCommit(workspaceVersion);
if (expectedCommit && toolCommit.toLowerCase() !== expectedCommit) {
throw new Error(
[
`本机 spacetime CLI/standalone 虽报告 ${toolVersion},但构建 commit ${toolCommit || 'unknown'} 不是项目锁定的 ${expectedCommit}`,
'同版本号的裸 tag 缺少后续 hotfix,不能用于本地 SpacetimeDB。',
buildSpacetimeUpgradeInstruction(workspaceVersion),
].join(''),
);
}
}
function assertReusableSpacetimeProcessVersionMatchesWorkspace({
dataDir,
serverUrl,
}) {
const recordedVersion = readRecordedSpacetimeToolVersion(dataDir);
const recordedProvenance = readRecordedSpacetimeToolProvenance(dataDir);
const workspaceVersion = readWorkspaceSpacetimeVersion();
if (!recordedVersion) {
if (!recordedProvenance.version) {
throw new Error(
[
`检测到正在运行的本地 SpacetimeDB: ${serverUrl},但缺少 SpacetimeDB 版本记录。`,
@@ -620,26 +650,25 @@ function assertReusableSpacetimeProcessVersionMatchesWorkspace({
);
}
if (recordedVersion === workspaceVersion) {
return;
try {
assertSpacetimeToolVersionMatchesWorkspace({
toolVersion: recordedProvenance.version,
toolCommit: recordedProvenance.commit,
workspaceVersion,
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(
`正在运行的本地 SpacetimeDB standalone provenance 不符合项目锁定要求: ${message}请停止当前 SpacetimeDB 进程后重新运行 npm run dev:spacetime。`,
);
}
throw new Error(
[
`正在运行的本地 SpacetimeDB standalone 版本 ${recordedVersion} 与 server-rs 锁定的 SpacetimeDB ${workspaceVersion} 不一致。`,
'版本错位会导致 procedure 返回值 BSATN 反序列化失败,前端表现为 SpacetimeDB procedure 调用超时。',
'请停止当前 SpacetimeDB 进程,先直接升级并切换到锁定版本: spacetime version install ',
workspaceVersion,
' && spacetime version use ',
workspaceVersion,
',然后重新运行 npm run dev:spacetime。',
].join(''),
);
}
function ensureSpacetimeToolVersionMatchesWorkspace() {
const toolProvenance = readSpacetimeToolProvenance();
assertSpacetimeToolVersionMatchesWorkspace({
toolVersion: readSpacetimeToolVersion(),
toolVersion: toolProvenance.version,
toolCommit: toolProvenance.commit,
workspaceVersion: readWorkspaceSpacetimeVersion(),
});
}
@@ -1530,12 +1559,16 @@ class DevRunner {
encoding: 'utf8',
});
service.logStream = logStream;
const spacetimeToolVersion = readSpacetimeToolVersion();
const spacetimeToolProvenance = readSpacetimeToolProvenance();
assertSpacetimeToolVersionMatchesWorkspace({
toolVersion: spacetimeToolVersion,
toolVersion: spacetimeToolProvenance.version,
toolCommit: spacetimeToolProvenance.commit,
workspaceVersion: readWorkspaceSpacetimeVersion(),
});
recordSpacetimeToolVersion(options.spacetimeDataDir, spacetimeToolVersion);
recordSpacetimeToolVersion(
options.spacetimeDataDir,
spacetimeToolProvenance,
);
console.log(`[dev:spacetime] log: ${logFile}`);
service.updateRuntimeState({
@@ -2380,13 +2413,16 @@ function readRecordedSpacetimeUrl(dataDir) {
return '';
}
function readRecordedSpacetimeToolVersion(dataDir) {
function readRecordedSpacetimeToolProvenance(dataDir) {
const versionPath = resolve(dataDir, 'dev-spacetime-tool-version');
if (!existsSync(versionPath)) {
return '';
return { version: '', commit: '' };
}
return readFileSync(versionPath, 'utf8').split(/\r?\n/u)[0]?.trim() ?? '';
const [version = '', commit = ''] = readFileSync(versionPath, 'utf8').split(
/\r?\n/u,
);
return { version: version.trim(), commit: commit.trim().toLowerCase() };
}
function readRecordedSpacetimePidState(dataDir) {
@@ -2661,11 +2697,15 @@ function writeLocalSpacetimeApiIdentity({
}
}
function recordSpacetimeToolVersion(dataDir, version) {
function recordSpacetimeToolVersion(dataDir, provenance) {
const versionPath = resolve(dataDir, 'dev-spacetime-tool-version');
ensureParentDir(versionPath);
try {
writeFileSync(versionPath, `${version}\n`, 'utf8');
writeFileSync(
versionPath,
`${provenance.version}\n${provenance.commit}\n`,
'utf8',
);
} catch (error) {
console.warn(
`[dev:spacetime] 写入版本记录失败 ${versionPath}: ${error.message}`,
@@ -2977,6 +3017,7 @@ export {
normalizeCargoVersionRequirement,
parseArgs,
parseProcessEnvBlock,
parseSpacetimeToolCommit,
parseSpacetimeToolVersion,
resolveCurrentSpacetimeCliToken,
resolveDevStackStatePath,
+51 -6
View File
@@ -32,6 +32,7 @@ import {
normalizeCargoVersionRequirement,
parseArgs,
parseProcessEnvBlock,
parseSpacetimeToolCommit,
parseSpacetimeToolVersion,
resolveDevStackStatePath,
resolveLocalSpacetimeApiIdentityPath,
@@ -569,7 +570,7 @@ describe('dev scheduler spacetime reuse guard', () => {
writeFileSync(join(tempDir, 'spacetime.pid'), `${process.pid}\n`, 'utf8');
writeFileSync(
join(tempDir, 'dev-spacetime-tool-version'),
`${workspaceSpacetimeVersionForTest()}\n`,
`${workspaceSpacetimeVersionForTest()}\nd220349adb7af7eefa810eb08a185609356b83f6\n`,
'utf8',
);
globalThis.fetch = vi.fn(async () => ({
@@ -598,7 +599,7 @@ describe('dev scheduler spacetime reuse guard', () => {
writeFileSync(join(tempDir, 'spacetime.pid'), `${process.pid}\n`, 'utf8');
writeFileSync(
join(tempDir, 'dev-spacetime-tool-version'),
`${workspaceSpacetimeVersionForTest()}\n`,
`${workspaceSpacetimeVersionForTest()}\nd220349adb7af7eefa810eb08a185609356b83f6\n`,
'utf8',
);
globalThis.fetch = vi.fn(async () => ({
@@ -709,12 +710,34 @@ describe('dev scheduler spacetime refresh', () => {
});
test('解析 spacetime --version 输出里的 tool version', () => {
const version = parseSpacetimeToolVersion(`
const output = `
A new version of SpacetimeDB is available: v2.6.1 (current: v2.5.0)
spacetimedb tool version 2.6.0; spacetimedb-lib version 2.6.0;
`);
Commit: d220349adb7af7eefa810eb08a185609356b83f6
spacetimedb tool version 2.7.0; spacetimedb-lib version 2.7.0;
`;
expect(version).toBe('2.6.0');
expect(parseSpacetimeToolVersion(output)).toBe('2.7.0');
expect(parseSpacetimeToolCommit(output)).toBe(
'd220349adb7af7eefa810eb08a185609356b83f6',
);
});
test('同为 2.7.0 时拒绝裸 tag 并接受 hotfix3 commit', () => {
expect(() =>
assertSpacetimeToolVersionMatchesWorkspace({
toolVersion: '2.7.0',
toolCommit: 'a08663c7b94688a2542577532d472f751e641f5b',
workspaceVersion: '2.7.0',
}),
).toThrow('裸 tag');
expect(() =>
assertSpacetimeToolVersionMatchesWorkspace({
toolVersion: '2.7.0',
toolCommit: 'd220349adb7af7eefa810eb08a185609356b83f6',
workspaceVersion: '2.7.0',
}),
).not.toThrow();
});
test('本机 spacetime 版本和 workspace 锁定版本不一致时直接报清楚', () => {
@@ -748,6 +771,28 @@ spacetimedb tool version 2.6.0; spacetimedb-lib version 2.6.0;
}
});
test('复用本地 SpacetimeDB standalone 时拒绝同版本裸 tag 记录', () => {
const tempDir = mkdtempSync(
join(tmpdir(), 'genarrative-spacetime-commit-'),
);
try {
writeFileSync(
join(tempDir, 'dev-spacetime-tool-version'),
'2.7.0\na08663c7b94688a2542577532d472f751e641f5b\n',
'utf8',
);
expect(() =>
assertReusableSpacetimeProcessVersionMatchesWorkspace({
dataDir: tempDir,
serverUrl: 'http://127.0.0.1:3101',
}),
).toThrow('裸 tag');
} finally {
rmSync(tempDir, { recursive: true, force: true });
}
});
test('本地发布 403 时识别为身份权限问题,避免误杀 standalone', () => {
const error = new Error(
'Pre-publish check failed with status 403 Forbidden: c200... is not authorized to perform action on database c200...: update database',
+19 -2
View File
@@ -9,10 +9,11 @@ OTELCOL_DOWNLOAD_ROOT="${OTELCOL_DOWNLOAD_ROOT:-https://github.com/open-telemetr
OTELCOL_ARCHIVE_PATH="${OTELCOL_ARCHIVE_PATH:-}"
OTELCOL_TARGET_BIN="${OTELCOL_TARGET_BIN:-/usr/local/bin/otelcol-contrib}"
SPACETIME_INSTALLER_URL="${SPACETIME_INSTALLER_URL:-https://install.spacetimedb.com}"
SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.6.1}"
SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.7.0-hotfix3}"
SPACETIME_TARGET_HOST="${SPACETIME_TARGET_HOST:-x86_64-unknown-linux-gnu}"
SPACETIME_ROOT="${SPACETIME_ROOT:-/stdb}"
SPACETIME_EXPECTED_VERSION="${SPACETIME_EXPECTED_VERSION:-}"
SPACETIME_EXPECTED_COMMIT="${SPACETIME_EXPECTED_COMMIT:-d220349adb7af7eefa810eb08a185609356b83f6}"
SPACETIME_ARCHIVE_PATH="${SPACETIME_ARCHIVE_PATH:-}"
SPACETIME_INSTALLER_PATH="${SPACETIME_INSTALLER_PATH:-}"
SPACETIME_UPDATE_INSTALLER_PATH="${SPACETIME_UPDATE_INSTALLER_PATH:-}"
@@ -76,7 +77,7 @@ resolve_spacetime_expected_version() {
return
fi
if [[ "${download_root}" =~ /v([0-9]+(\.[0-9]+){1,2})$ ]]; then
if [[ "${download_root}" =~ /v([0-9]+(\.[0-9]+){1,2})(-hotfix[0-9]+)?$ ]]; then
printf "%s" "${BASH_REMATCH[1]}"
fi
}
@@ -117,6 +118,10 @@ target_spacetime_ready() {
echo "[prepare-provision-tools] 目标机 SpacetimeDB 版本不匹配,期望 ${expected_version},当前: ${version_output:-unknown}"
return 1
fi
if [[ -n "${SPACETIME_EXPECTED_COMMIT}" && "${version_output}" != *"Commit: ${SPACETIME_EXPECTED_COMMIT}"* ]]; then
echo "[prepare-provision-tools] 目标机 SpacetimeDB commit 不匹配,期望 ${SPACETIME_EXPECTED_COMMIT},当前: ${version_output:-unknown}"
return 1
fi
echo "[prepare-provision-tools] 目标机 SpacetimeDB 已满足要求: ${version_output:-version unknown}"
return 0
@@ -284,6 +289,18 @@ prepare_spacetime() {
exit 1
fi
local installed_version_output expected_version
expected_version="$(resolve_spacetime_expected_version)"
installed_version_output="$("${install_root}/bin/current/spacetimedb-cli" --version 2>/dev/null || true)"
if [[ -n "${expected_version}" && "${installed_version_output}" != *"${expected_version}"* ]]; then
echo "[prepare-provision-tools] SpacetimeDB 安装结果版本不匹配,期望 ${expected_version},当前: ${installed_version_output:-unknown}" >&2
exit 1
fi
if [[ -n "${SPACETIME_EXPECTED_COMMIT}" && "${installed_version_output}" != *"Commit: ${SPACETIME_EXPECTED_COMMIT}"* ]]; then
echo "[prepare-provision-tools] SpacetimeDB 安装结果 commit 不匹配,期望 ${SPACETIME_EXPECTED_COMMIT},当前: ${installed_version_output:-unknown}" >&2
exit 1
fi
mkdir -p "${target_dir}"
cp -a "${install_root}/bin" "${target_dir}/bin"
make_spacetime_wrapper "${target_dir}/spacetime"
+28 -28
View File
@@ -5348,9 +5348,9 @@ dependencies = [
[[package]]
name = "spacetimedb"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6eff5017248ff2e35e03564df947fdf3e963f7198be6ae1d9e894c2efb2ea15"
checksum = "f8ba4d29856a75aafc3c66fd47d39e11e20c5001ee323d90549ffe19980ef9ff"
dependencies = [
"anyhow",
"bytemuck",
@@ -5371,9 +5371,9 @@ dependencies = [
[[package]]
name = "spacetimedb-bindings-macro"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fce86c7657dcb42a33ce55f0100f98964dc15b64e79f06803a478676b74d6c82"
checksum = "4a9c2548accd66ba0444caf12916e60ca282054fe5701298f633aa6a2a90c38b"
dependencies = [
"heck 0.4.1",
"humantime",
@@ -5385,18 +5385,18 @@ dependencies = [
[[package]]
name = "spacetimedb-bindings-sys"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbe5f9d71d59bdb93d81a7a61eee75ac2f1f88f91e139a7e263261f9dbf316de"
checksum = "2fc1790a7705a2d83ee601c9b14e4fd543ee8fe777d5b6117d4c5d33fc6566d7"
dependencies = [
"spacetimedb-primitives",
]
[[package]]
name = "spacetimedb-client-api-messages"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1642404553853b56e521a12aa9849807d8e003433934c73eeebbc8671f1254f8"
checksum = "e2ef1840b2157a9487618ad360a078d7b5d86de5eb27494efa5bbbb2ca76b247"
dependencies = [
"bytes",
"bytestring",
@@ -5416,9 +5416,9 @@ dependencies = [
[[package]]
name = "spacetimedb-data-structures"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3407c90a3da48b1c421bbad6a2ee6de3855a77d73fae98773bcc058426f1318f"
checksum = "20df758e7067fb085e9393786b3b12289838eac9fd78601cb1aaf7e059904ccb"
dependencies = [
"ahash",
"crossbeam-queue",
@@ -5431,9 +5431,9 @@ dependencies = [
[[package]]
name = "spacetimedb-lib"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bceaf72bdbf1a624d55d17ebaa38f8cf78a4972e43641c6cbf94f82318b5581d"
checksum = "7a6b0417d7db37d991fd927a21298e09ad61cd5dc298eb9e1ac2433fe4a958a7"
dependencies = [
"anyhow",
"bitflags 2.13.0",
@@ -5456,9 +5456,9 @@ dependencies = [
[[package]]
name = "spacetimedb-memory-usage"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cc1e19f664b47f4b3b82fb69b2fc096c3d82dc659ea705d62bbbec2fa9c2e83"
checksum = "892d4ef38414498d687d765c4b0a9f6390f786c6fc5ca640a09c42f5da902f99"
dependencies = [
"decorum",
"ethnum",
@@ -5466,9 +5466,9 @@ dependencies = [
[[package]]
name = "spacetimedb-metrics"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c794455ed96245d52d837c8bbc3493d1c17d9f6382e6c5fee1c88926c9aa04a"
checksum = "de1ef3c1d55ec819953211e5ae645f1152e2b894ea770d59b039a7133b2ebf5f"
dependencies = [
"arrayvec",
"itertools 0.12.1",
@@ -5478,9 +5478,9 @@ dependencies = [
[[package]]
name = "spacetimedb-primitives"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7525fda46b21fffdc62805099dee853a79000e0673ff6df4b8355cb0b8dabe8"
checksum = "2adee8bd225009feb67ab329aa4eae6b7fe6c4c0165d9d65814c07a4252b2d20"
dependencies = [
"bitflags 2.13.0",
"either",
@@ -5492,18 +5492,18 @@ dependencies = [
[[package]]
name = "spacetimedb-query-builder"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f283c4797961d9a94f623ee4c66e6a94d30861b6380a49a27ac2d9568e17125"
checksum = "1d8476efc6c3c1d9def4499bbeedcc015d5f13c75565dd7136180265dd45708c"
dependencies = [
"spacetimedb-lib",
]
[[package]]
name = "spacetimedb-sats"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cefb87b7d5e760d43cb65855591e25af772bdcca19562e5796ae797240d1998"
checksum = "a6cfd92de752a8fd711ad2138ae79a80313be34061da6112fd46df1dd6365200"
dependencies = [
"anyhow",
"arrayvec",
@@ -5534,9 +5534,9 @@ dependencies = [
[[package]]
name = "spacetimedb-schema"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775cfdeb406e5628bf78b2221b0e0fd2fcba583f691bb89ba1c9338790ecaf7d"
checksum = "444649a34ca14d1535d03a375deacb8ad4668f692576bff7091b6d4160b1d346"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -5565,9 +5565,9 @@ dependencies = [
[[package]]
name = "spacetimedb-sdk"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "074a6d8828638176eb8e9bba7a3e6fb75dc659b260717306eb966c7e10575cd7"
checksum = "ed0e49e45ab4828e9bf51d1c93db553f496c2836f1b49174f4019dc8c42e6525"
dependencies = [
"anymap3",
"base64 0.21.7",
@@ -5597,9 +5597,9 @@ dependencies = [
[[package]]
name = "spacetimedb-sql-parser"
version = "2.6.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b978b6d76cfbe5782a7f0dae7e25f6be4e7e13cfad26c9211d4eb4cdf8c22da"
checksum = "2b9908b30e69222970fd955e30235fe977c8fa12010d630949c77f603abf54a2"
dependencies = [
"derive_more",
"spacetimedb-lib",
+3 -3
View File
@@ -116,9 +116,9 @@ serde_urlencoded = "0.7"
sha1 = "0.10"
sha2 = "0.10"
socket2 = "0.6"
spacetimedb = "=2.6.1"
spacetimedb-sdk = "=2.6.1"
spacetimedb-lib = { version = "=2.6.1", default-features = false }
spacetimedb = "=2.7.0"
spacetimedb-sdk = "=2.7.0"
spacetimedb-lib = { version = "=2.7.0", default-features = false }
time = "0.3"
tokio = "1"
tokio-stream = "0.1"
@@ -1,7 +1,7 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
// This was generated using spacetimedb cli version 2.6.1 (commit 052c83fe984a4c4eb7bb4f9afa5c6b1903891d87).
// This was generated using spacetimedb cli version 2.7.0 (commit d220349adb7af7eefa810eb08a185609356b83f6).
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
@@ -18,6 +18,18 @@ pub struct AdminAccountTableHandle<'ctx> {
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
/// Lifetime-aware accessor marker for the table `admin_account`.
pub struct AdminAccountTableAccessor;
impl __sdk::TableAccessor<super::RemoteTables> for AdminAccountTableAccessor {
type Row = AdminAccount;
type Handle<'db> = AdminAccountTableHandle<'db>;
fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> {
db.admin_account()
}
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `admin_account`.
///
@@ -40,6 +52,18 @@ impl AdminAccountTableAccess for super::RemoteTables {
pub struct AdminAccountInsertCallbackId(__sdk::CallbackId);
pub struct AdminAccountDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableLike for AdminAccountTableHandle<'ctx> {
type Row = AdminAccount;
type EventContext = super::EventContext;
fn count(&self) -> u64 {
self.imp.count()
}
fn iter(&self) -> impl Iterator<Item = AdminAccount> + '_ {
self.imp.iter()
}
}
impl<'ctx> __sdk::Table for AdminAccountTableHandle<'ctx> {
type Row = AdminAccount;
type EventContext = super::EventContext;
@@ -78,6 +102,36 @@ impl<'ctx> __sdk::Table for AdminAccountTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithInsert for AdminAccountTableHandle<'ctx> {
type InsertCallbackId = AdminAccountInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AdminAccountInsertCallbackId {
AdminAccountInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: AdminAccountInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
}
impl<'ctx> __sdk::WithDelete for AdminAccountTableHandle<'ctx> {
type DeleteCallbackId = AdminAccountDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AdminAccountDeleteCallbackId {
AdminAccountDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: AdminAccountDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct AdminAccountUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for AdminAccountTableHandle<'ctx> {
@@ -95,6 +149,21 @@ impl<'ctx> __sdk::TableWithPrimaryKey for AdminAccountTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithUpdate for AdminAccountTableHandle<'ctx> {
type UpdateCallbackId = AdminAccountUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> AdminAccountUpdateCallbackId {
AdminAccountUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: AdminAccountUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `account_id` unique index on the table `admin_account`,
/// which allows point queries on the field of the same name
/// via the [`AdminAccountAccountIdUnique::find`] method.
@@ -19,6 +19,18 @@ pub struct AiResultReferenceTableHandle<'ctx> {
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
/// Lifetime-aware accessor marker for the table `ai_result_reference`.
pub struct AiResultReferenceTableAccessor;
impl __sdk::TableAccessor<super::RemoteTables> for AiResultReferenceTableAccessor {
type Row = AiResultReference;
type Handle<'db> = AiResultReferenceTableHandle<'db>;
fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> {
db.ai_result_reference()
}
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `ai_result_reference`.
///
@@ -43,6 +55,18 @@ impl AiResultReferenceTableAccess for super::RemoteTables {
pub struct AiResultReferenceInsertCallbackId(__sdk::CallbackId);
pub struct AiResultReferenceDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableLike for AiResultReferenceTableHandle<'ctx> {
type Row = AiResultReference;
type EventContext = super::EventContext;
fn count(&self) -> u64 {
self.imp.count()
}
fn iter(&self) -> impl Iterator<Item = AiResultReference> + '_ {
self.imp.iter()
}
}
impl<'ctx> __sdk::Table for AiResultReferenceTableHandle<'ctx> {
type Row = AiResultReference;
type EventContext = super::EventContext;
@@ -81,6 +105,36 @@ impl<'ctx> __sdk::Table for AiResultReferenceTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithInsert for AiResultReferenceTableHandle<'ctx> {
type InsertCallbackId = AiResultReferenceInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AiResultReferenceInsertCallbackId {
AiResultReferenceInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: AiResultReferenceInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
}
impl<'ctx> __sdk::WithDelete for AiResultReferenceTableHandle<'ctx> {
type DeleteCallbackId = AiResultReferenceDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AiResultReferenceDeleteCallbackId {
AiResultReferenceDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: AiResultReferenceDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct AiResultReferenceUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for AiResultReferenceTableHandle<'ctx> {
@@ -98,6 +152,21 @@ impl<'ctx> __sdk::TableWithPrimaryKey for AiResultReferenceTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithUpdate for AiResultReferenceTableHandle<'ctx> {
type UpdateCallbackId = AiResultReferenceUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> AiResultReferenceUpdateCallbackId {
AiResultReferenceUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: AiResultReferenceUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `result_reference_row_id` unique index on the table `ai_result_reference`,
/// which allows point queries on the field of the same name
/// via the [`AiResultReferenceResultReferenceRowIdUnique::find`] method.
@@ -21,6 +21,18 @@ pub struct AiTaskEventTableHandle<'ctx> {
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
/// Lifetime-aware accessor marker for the table `ai_task_event`.
pub struct AiTaskEventTableAccessor;
impl __sdk::TableAccessor<super::RemoteTables> for AiTaskEventTableAccessor {
type Row = AiTaskEvent;
type Handle<'db> = AiTaskEventTableHandle<'db>;
fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> {
db.ai_task_event()
}
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `ai_task_event`.
///
@@ -42,6 +54,18 @@ impl AiTaskEventTableAccess for super::RemoteTables {
pub struct AiTaskEventInsertCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableLike for AiTaskEventTableHandle<'ctx> {
type Row = AiTaskEvent;
type EventContext = super::EventContext;
fn count(&self) -> u64 {
self.imp.count()
}
fn iter(&self) -> impl Iterator<Item = AiTaskEvent> + '_ {
self.imp.iter()
}
}
impl<'ctx> __sdk::EventTable for AiTaskEventTableHandle<'ctx> {
type Row = AiTaskEvent;
type EventContext = super::EventContext;
@@ -67,6 +91,21 @@ impl<'ctx> __sdk::EventTable for AiTaskEventTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithInsert for AiTaskEventTableHandle<'ctx> {
type InsertCallbackId = AiTaskEventInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AiTaskEventInsertCallbackId {
AiTaskEventInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: AiTaskEventInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
}
#[doc(hidden)]
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
let _table = client_cache.get_or_make_table::<AiTaskEvent>("ai_task_event");
@@ -20,6 +20,18 @@ pub struct AiTaskStageTableHandle<'ctx> {
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
/// Lifetime-aware accessor marker for the table `ai_task_stage`.
pub struct AiTaskStageTableAccessor;
impl __sdk::TableAccessor<super::RemoteTables> for AiTaskStageTableAccessor {
type Row = AiTaskStage;
type Handle<'db> = AiTaskStageTableHandle<'db>;
fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> {
db.ai_task_stage()
}
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `ai_task_stage`.
///
@@ -42,6 +54,18 @@ impl AiTaskStageTableAccess for super::RemoteTables {
pub struct AiTaskStageInsertCallbackId(__sdk::CallbackId);
pub struct AiTaskStageDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableLike for AiTaskStageTableHandle<'ctx> {
type Row = AiTaskStage;
type EventContext = super::EventContext;
fn count(&self) -> u64 {
self.imp.count()
}
fn iter(&self) -> impl Iterator<Item = AiTaskStage> + '_ {
self.imp.iter()
}
}
impl<'ctx> __sdk::Table for AiTaskStageTableHandle<'ctx> {
type Row = AiTaskStage;
type EventContext = super::EventContext;
@@ -80,6 +104,36 @@ impl<'ctx> __sdk::Table for AiTaskStageTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithInsert for AiTaskStageTableHandle<'ctx> {
type InsertCallbackId = AiTaskStageInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AiTaskStageInsertCallbackId {
AiTaskStageInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: AiTaskStageInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
}
impl<'ctx> __sdk::WithDelete for AiTaskStageTableHandle<'ctx> {
type DeleteCallbackId = AiTaskStageDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AiTaskStageDeleteCallbackId {
AiTaskStageDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: AiTaskStageDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct AiTaskStageUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for AiTaskStageTableHandle<'ctx> {
@@ -97,6 +151,21 @@ impl<'ctx> __sdk::TableWithPrimaryKey for AiTaskStageTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithUpdate for AiTaskStageTableHandle<'ctx> {
type UpdateCallbackId = AiTaskStageUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> AiTaskStageUpdateCallbackId {
AiTaskStageUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: AiTaskStageUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `task_stage_id` unique index on the table `ai_task_stage`,
/// which allows point queries on the field of the same name
/// via the [`AiTaskStageTaskStageIdUnique::find`] method.
@@ -20,6 +20,18 @@ pub struct AiTaskTableHandle<'ctx> {
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
/// Lifetime-aware accessor marker for the table `ai_task`.
pub struct AiTaskTableAccessor;
impl __sdk::TableAccessor<super::RemoteTables> for AiTaskTableAccessor {
type Row = AiTask;
type Handle<'db> = AiTaskTableHandle<'db>;
fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> {
db.ai_task()
}
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `ai_task`.
///
@@ -42,6 +54,18 @@ impl AiTaskTableAccess for super::RemoteTables {
pub struct AiTaskInsertCallbackId(__sdk::CallbackId);
pub struct AiTaskDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableLike for AiTaskTableHandle<'ctx> {
type Row = AiTask;
type EventContext = super::EventContext;
fn count(&self) -> u64 {
self.imp.count()
}
fn iter(&self) -> impl Iterator<Item = AiTask> + '_ {
self.imp.iter()
}
}
impl<'ctx> __sdk::Table for AiTaskTableHandle<'ctx> {
type Row = AiTask;
type EventContext = super::EventContext;
@@ -80,6 +104,36 @@ impl<'ctx> __sdk::Table for AiTaskTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithInsert for AiTaskTableHandle<'ctx> {
type InsertCallbackId = AiTaskInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AiTaskInsertCallbackId {
AiTaskInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: AiTaskInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
}
impl<'ctx> __sdk::WithDelete for AiTaskTableHandle<'ctx> {
type DeleteCallbackId = AiTaskDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AiTaskDeleteCallbackId {
AiTaskDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: AiTaskDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct AiTaskUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for AiTaskTableHandle<'ctx> {
@@ -97,6 +151,21 @@ impl<'ctx> __sdk::TableWithPrimaryKey for AiTaskTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithUpdate for AiTaskTableHandle<'ctx> {
type UpdateCallbackId = AiTaskUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> AiTaskUpdateCallbackId {
AiTaskUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: AiTaskUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `task_id` unique index on the table `ai_task`,
/// which allows point queries on the field of the same name
/// via the [`AiTaskTaskIdUnique::find`] method.
@@ -19,6 +19,18 @@ pub struct AiTextChunkTableHandle<'ctx> {
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
/// Lifetime-aware accessor marker for the table `ai_text_chunk`.
pub struct AiTextChunkTableAccessor;
impl __sdk::TableAccessor<super::RemoteTables> for AiTextChunkTableAccessor {
type Row = AiTextChunk;
type Handle<'db> = AiTextChunkTableHandle<'db>;
fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> {
db.ai_text_chunk()
}
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `ai_text_chunk`.
///
@@ -41,6 +53,18 @@ impl AiTextChunkTableAccess for super::RemoteTables {
pub struct AiTextChunkInsertCallbackId(__sdk::CallbackId);
pub struct AiTextChunkDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableLike for AiTextChunkTableHandle<'ctx> {
type Row = AiTextChunk;
type EventContext = super::EventContext;
fn count(&self) -> u64 {
self.imp.count()
}
fn iter(&self) -> impl Iterator<Item = AiTextChunk> + '_ {
self.imp.iter()
}
}
impl<'ctx> __sdk::Table for AiTextChunkTableHandle<'ctx> {
type Row = AiTextChunk;
type EventContext = super::EventContext;
@@ -79,6 +103,36 @@ impl<'ctx> __sdk::Table for AiTextChunkTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithInsert for AiTextChunkTableHandle<'ctx> {
type InsertCallbackId = AiTextChunkInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AiTextChunkInsertCallbackId {
AiTextChunkInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: AiTextChunkInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
}
impl<'ctx> __sdk::WithDelete for AiTextChunkTableHandle<'ctx> {
type DeleteCallbackId = AiTextChunkDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AiTextChunkDeleteCallbackId {
AiTextChunkDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: AiTextChunkDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct AiTextChunkUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for AiTextChunkTableHandle<'ctx> {
@@ -96,6 +150,21 @@ impl<'ctx> __sdk::TableWithPrimaryKey for AiTextChunkTableHandle<'ctx> {
}
}
impl<'ctx> __sdk::WithUpdate for AiTextChunkTableHandle<'ctx> {
type UpdateCallbackId = AiTextChunkUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> AiTextChunkUpdateCallbackId {
AiTextChunkUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: AiTextChunkUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `text_chunk_row_id` unique index on the table `ai_text_chunk`,
/// which allows point queries on the field of the same name
/// via the [`AiTextChunkTextChunkRowIdUnique::find`] method.

Some files were not shown because too many files have changed in this diff Show More