From fbeea2f85e08336763d8d329a443f6317a9eb76d Mon Sep 17 00:00:00 2001 From: mattheliu Date: Mon, 28 Sep 2026 22:25:18 +0800 Subject: [PATCH] feat: adapt session teleport to DSH 0.2 persistence handles --- .github/workflows/ci.yml | 51 +- .npmrc | 3 +- CONTRIBUTING.md | 8 +- README.md | 26 +- dist/authority.js | 41 +- dist/authority.js.map | 2 +- dist/client.d.ts | 8 +- dist/client.js | 33 +- dist/client.js.map | 2 +- dist/dsh-adapter.d.ts | 51 +- dist/dsh-adapter.js | 561 +++++++++------ dist/dsh-adapter.js.map | 2 +- dist/importer.d.ts | 20 +- dist/importer.js | 49 +- dist/importer.js.map | 2 +- dist/schema.d.ts | 2 +- dist/schema.js | 15 +- dist/schema.js.map | 2 +- dist/server.js | 3 +- dist/server.js.map | 2 +- dist/source-capture.d.ts | 2 +- dist/types.d.ts | 10 + dist/types.js.map | 2 +- docs/DSH_INTEGRATION.md | 32 +- docs/IMPORT_AND_CUTOVER.md | 10 +- docs/PLUGIN_LIFECYCLE.md | 4 +- docs/TESTING.md | 50 +- package.json | 26 +- pnpm-lock.yaml | 648 +++++++++++++----- scripts/check-release-artifacts.mjs | 31 +- scripts/compatibility.mjs | 23 + scripts/plugin-lifecycle-real.mjs | 33 +- scripts/plugin-profile-local.mjs | 25 +- src/authority.ts | 42 +- src/client.ts | 25 +- src/dsh-adapter.ts | 606 ++++++++-------- src/importer.ts | 59 +- src/schema.ts | 15 +- src/server.ts | 3 +- src/source-capture.ts | 2 +- src/types.ts | 10 + tests/dsh-adapter-loader.integration.spec.ts | 89 +++ tests/dsh-adapter.spec.ts | 224 ++++++ tests/dsh-capture.integration.spec.ts | 13 +- ...onl-migration.postgres.integration.spec.ts | 10 +- tests/schema.spec.ts | 20 + tests/server.spec.ts | 2 + 47 files changed, 1962 insertions(+), 937 deletions(-) create mode 100644 scripts/compatibility.mjs create mode 100644 tests/dsh-adapter-loader.integration.spec.ts create mode 100644 tests/dsh-adapter.spec.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9265b3..e456cfa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,20 +25,49 @@ jobs: cache: pnpm registry-url: https://registry.npmjs.org scope: '@deepseek-ai' - - name: Install the pinned npm-next compatibility matrix - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - test -n "$NPM_TOKEN" - pnpm install --frozen-lockfile --ignore-scripts + - name: Install pinned public compatibility packages + run: pnpm install --frozen-lockfile --ignore-scripts - run: pnpm check - env: - NPM_TOKEN: post-install-placeholder - name: Verify committed build output run: git diff --exit-code -- dist - run: pnpm audit --prod - name: Verify package contents - env: - NPM_TOKEN: post-install-placeholder run: pnpm pack:check + dsh-integration: + runs-on: ubuntu-latest + timeout-minutes: 15 + services: + postgres: + image: postgres:17 + env: + POSTGRES_PASSWORD: teleport-test + POSTGRES_DB: teleport_test + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready --health-interval 5s + --health-timeout 5s --health-retries 10 + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + persist-credentials: false + - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 + with: + version: 10.12.3 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: 24 + cache: pnpm + - run: pnpm install --frozen-lockfile --ignore-scripts + - name: Install the official DSH compatibility target + run: npm install --prefix "$RUNNER_TEMP/dsh-runtime" --ignore-scripts --no-audit --no-fund @deepseek-ai/dsh@0.2.0-rc.1 + - run: pnpm build + - name: Exercise the real DSH loader and PostgreSQL migration/recovery + env: + DSH_TELEPORT_TEST_DSH_BIN: ${{ runner.temp }}/dsh-runtime/node_modules/@deepseek-ai/dsh/lib/bin.js + POSTGRES_TEST_URL: postgresql://postgres:teleport-test@127.0.0.1:5432/teleport_test + run: pnpm vitest run --no-file-parallelism tests/dsh-adapter-loader.integration.spec.ts tests/dsh-capture.integration.spec.ts tests/postgres.recovery.integration.spec.ts tests/migration.postgres.integration.spec.ts tests/jsonl-migration.postgres.integration.spec.ts + - name: Exercise profile install, cutover and uninstall + env: + DSH_TELEPORT_TEST_DSH_BIN: ${{ runner.temp }}/dsh-runtime/node_modules/@deepseek-ai/dsh/lib/bin.js + run: node scripts/plugin-profile-local.mjs diff --git a/.npmrc b/.npmrc index 593509a..080ffd3 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,2 @@ -auto-install-peers=false +auto-install-peers=true @deepseek-ai:registry=https://registry.npmjs.org/ -//registry.npmjs.org/:_authToken=${NPM_TOKEN} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 533f8bc..bc4fb89 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,20 +6,18 @@ Use a supported Node.js version and the package-manager version declared in `package.json`: ```bash -export NPM_TOKEN pnpm install --frozen-lockfile --ignore-scripts pnpm check pnpm pack:check ``` -The committed `.npmrc` contains only the registry scope and the literal -`${NPM_TOKEN}` placeholder. Keep the concrete token in the process environment; -never write it into a repository file, log, issue or test fixture. +Dependencies are public npm packages; no npm token is required. Keep credentials +out of repository files, logs, issues and test fixtures. `pnpm build` updates the committed `dist/` output. A source change and its generated output belong in the same review. Source maps must remain relative and must not embed source text. `pnpm typecheck:adapter` checks -`src/dsh-adapter.ts` and `src/index.ts` strictly against the exact npm next +`src/dsh-adapter.ts` and `src/index.ts` strictly against the pinned published development baselines declared in `package.json`; declaration generation uses the same real package types. diff --git a/README.md b/README.md index 090ced4..5baeb97 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,20 @@ DSH peer packages 是外部依赖,保留各自许可,不在本仓库中复 本包保留 `private: true`,避免本地发布演练误触 npm 发布;受支持的插件源是 `https://github.com/omdsh-dev/session-teleport`,安装时必须固定到完整 commit。 -当前适配器使用 npm next 包做严格编译基线:`@deepseek-ai/cordis@4.0.1-rc.4`, +当前适配目标是 DSH `0.2.0-rc.1`(2026-09-28 的 npm `next` 预发布版本), +严格编译基线为:`@deepseek-ai/cordis@4.0.4`, 以及 `@deepseek-ai/dsh-session`、`@deepseek-ai/dsh-session-persistence`、 -`@deepseek-ai/dsh-session-persistence-jsonl` 的 `0.1.0-rc.6`。这些精确版本只用于 +`@deepseek-ai/dsh-session-persistence-jsonl` 的 `0.2.0-rc.1`。这些精确版本只用于 开发和验证;安装时仍由目标 DSH 环境按 `peerDependencies` 提供兼容版本。 +新版采用 `create/open → SessionHandle`,支持 `read/append/flush/close`、 +`stat/list` 和空会话持久化。`0.7.0-rc.1` 插件与 authority 服务应一起升级: +数据库自动迁移到 schema 5,保留 fork 的 `inheritedEventCount`。 +已有旧格式日志不会被自动改写成 format 4;应先通过兼容源后端迁移、读取并导出。 +直接保存的旧 Teleport 日志仍可归档,但新版 adapter 会拒绝打开非 format 4 日志。 +同一设备的所有 profile 必须共用 writer credential 目录;本地文件锁防止重复写者, +跨设备交接由 PostgreSQL epoch fencing 保证。当前文件锁路径面向 macOS/Linux。 + ## 能做什么 - 原样保存 JSON event envelope,包括扩展字段。 @@ -20,12 +29,12 @@ DSH peer packages 是外部依赖,保留各自许可,不在本仓库中复 - 生成一次性、限时 handoff code;接管后旧 writer token 被 fencing。 - 旧设备丢失时可由独立管理员凭据执行显式恢复接管,并审计每次 writer 变化。 - 可对既有 Session 做无写入 dry-run、单事务导入和受约束的回滚切换。 -- 可从旧 DSH Profile 临时挂载只读 overlay,经 `inspect()` 抓取 Session, +- 可从旧 DSH Profile 临时挂载只读 overlay,经 `open(id, "read")` / `handle.read()` 抓取 Session, 不必手写 TypeScript,也不解析 JSONL/SQLite 物理文件。 - 提供计划优先的 `install / upgrade / uninstall / doctor` 生命周期工具; 只接受完整 commit pin,结构校验失败会恢复旧依赖。 - 提供一致快照、增量读取与 SSE 观察端点。 -- 提供 DSH `PersistenceBackend` adapter 和 profile bundle patch。 +- 提供 DSH `SessionPersistence` / `SessionHandle` adapter 和 profile bundle patch。 - 将每个 Session 的 writer credential 保存为本机 0600 原子文件。 - 在非 loopback 监听时强制配置服务 Bearer token。 @@ -63,7 +72,7 @@ export DSH_TELEPORT_DEVICE_ID=office-mac export DSH_TELEPORT_HEALTH_TIMEOUT_MS=5000 ``` -仅安装 bundle 不会切换 Session authority:默认仍使用 RC.6 自带 JSONL,Teleport +仅安装 bundle 不会切换 Session authority:默认仍使用 DSH 0.2 自带 JSONL,Teleport adapter 保持禁用。先启动 Teleport 服务并验证 `/health`,再停止 profile、设置 `DSH_TELEPORT_ENABLE=1` 并重启,才会关闭 JSONL、启用 Teleport。显式启用后如果 服务不可达,profile 会拒绝启动,不会静默回退到另一份权威存储。 @@ -78,7 +87,6 @@ turn 完成并停止对应 profile,再重启;不要把它当成对运行中 需要 Node.js 22.19+ 和 PostgreSQL: ```bash -export NPM_TOKEN pnpm install --frozen-lockfile --ignore-scripts pnpm build @@ -140,7 +148,7 @@ pnpm admin writer-audit ## 导入既有 Session 先让旧 writer 完成当前 turn、flush 并停止对应 Profile。迁移工具会临时启动 -这个 Profile,挂载一次性只读 overlay,并把一致 `inspect()` 结果写成 `0600` +这个 Profile,挂载一次性只读 overlay,并把一致只读 handle 结果写成 `0600` bundle;它不修改旧 Profile 配置或旧存储,也不会覆盖已有输出文件: ```bash @@ -167,14 +175,12 @@ dsh-teleport-import rollback "cutover smoke check failed" ## 开发与验证 ```bash -export NPM_TOKEN pnpm install --frozen-lockfile --ignore-scripts pnpm check pnpm audit --prod ``` -只读 npm 令牌仅通过进程环境提供;仓库 `.npmrc` 只保存 `${NPM_TOKEN}` 占位符, -发布包检查会拒绝把 `.npmrc` 打进产物。 +依赖来自公共 npm registry,安装不需要 npm 令牌。发布包检查会拒绝把 `.npmrc` 打进产物。 仓库内的通用测试覆盖 authority 的 CAS/fencing/handoff/idempotency、HTTP API、schema 与 credential file。更多说明见 [测试边界](docs/TESTING.md)。 diff --git a/dist/authority.js b/dist/authority.js index 6db5676..aa69ba0 100644 --- a/dist/authority.js +++ b/dist/authority.js @@ -19,15 +19,16 @@ class TeleportAuthority { async createSession(request) { assertIdentifier(request.sessionId, "sessionId"); assertIdentifier(request.deviceId, "deviceId"); + if (request.inheritedEventCount !== void 0) safeNonNegative(request.inheritedEventCount, "inheritedEventCount"); const header = canonicalJson(request.header); const writerToken = secret(); const inserted = await this.database.query( `INSERT INTO teleport_sessions - (session_id, header, writer_epoch, writer_device_id, writer_token_hash) - VALUES ($1, $2::jsonb, 1, $3, $4) + (session_id, header, writer_epoch, writer_device_id, writer_token_hash, inherited_event_count) + VALUES ($1, $2::jsonb, 1, $3, $4, $5) ON CONFLICT (session_id) DO NOTHING RETURNING session_id`, - [request.sessionId, header, request.deviceId, sha256(writerToken)] + [request.sessionId, header, request.deviceId, sha256(writerToken), request.inheritedEventCount ?? null] ); if (inserted.rowCount !== 1) { throw new TeleportError("SESSION_EXISTS", `session "${request.sessionId}" already exists`); @@ -54,12 +55,14 @@ class TeleportAuthority { expectedNextSeq: 0, idempotencyKey: request.idempotencyKey, events: request.events - }); + }, true); + if (request.inheritedEventCount !== void 0) safeNonNegative(request.inheritedEventCount, "inheritedEventCount"); const header = canonicalJson(request.header); const digest = sha256( canonicalJson({ sessionId: request.sessionId, header: request.header, + ...request.inheritedEventCount === void 0 ? {} : { inheritedEventCount: request.inheritedEventCount }, deviceId: request.deviceId, events: request.events }) @@ -67,11 +70,11 @@ class TeleportAuthority { const result = await this.database.transaction(async (transaction) => { const inserted = await transaction.query( `INSERT INTO teleport_sessions - (session_id, header, writer_epoch, writer_device_id, writer_token_hash) - VALUES ($1, $2::jsonb, 1, $3, $4) + (session_id, header, writer_epoch, writer_device_id, writer_token_hash, inherited_event_count) + VALUES ($1, $2::jsonb, 1, $3, $4, $5) ON CONFLICT (session_id) DO NOTHING RETURNING session_id`, - [request.sessionId, header, request.deviceId, sha256(request.writerToken)] + [request.sessionId, header, request.deviceId, sha256(request.writerToken), request.inheritedEventCount ?? null] ); if (inserted.rowCount !== 1) { const session = await lockSession(transaction, request.sessionId); @@ -104,7 +107,7 @@ class TeleportAuthority { [request.sessionId, event.seq, eventJson(event)] ); } - const nextSeq = request.events.at(-1).seq + 1; + const nextSeq = request.events.length; await transaction.query( `UPDATE teleport_sessions SET revision = 1, next_seq = $2, updated_at = CURRENT_TIMESTAMP @@ -120,7 +123,7 @@ class TeleportAuthority { request.sessionId, request.idempotencyKey, digest, - request.events.at(-1).seq, + nextSeq - 1, nextSeq ] ); @@ -225,7 +228,7 @@ class TeleportAuthority { return this.database.transaction( async (transaction) => { const sessionResult = await transaction.query( - `SELECT session_id, header, revision, next_seq, writer_epoch, + `SELECT session_id, header, inherited_event_count, revision, next_seq, writer_epoch, writer_device_id, writer_token_hash FROM teleport_sessions WHERE session_id = $1`, [sessionId] @@ -243,6 +246,9 @@ class TeleportAuthority { return { sessionId, header: asJsonValue(session.header), + ...session.inherited_event_count == null ? {} : { + inheritedEventCount: integer(session.inherited_event_count, "inherited_event_count") + }, revision: integer(session.revision, "revision"), nextSeq: integer(session.next_seq, "next_seq"), writerEpoch: integer(session.writer_epoch, "writer_epoch"), @@ -256,7 +262,7 @@ class TeleportAuthority { async head(sessionId) { assertIdentifier(sessionId, "sessionId"); const result = await this.database.query( - `SELECT session_id, header, revision, next_seq, writer_epoch, + `SELECT session_id, header, inherited_event_count, revision, next_seq, writer_epoch, writer_device_id, writer_token_hash FROM teleport_sessions WHERE session_id = $1`, [sessionId] @@ -269,7 +275,7 @@ class TeleportAuthority { } async listHeads() { const result = await this.database.query( - `SELECT session_id, header, revision, next_seq, writer_epoch, + `SELECT session_id, header, inherited_event_count, revision, next_seq, writer_epoch, writer_device_id, writer_token_hash FROM teleport_sessions ORDER BY created_at, session_id` @@ -667,7 +673,7 @@ class TeleportAuthority { } async function lockSession(transaction, sessionId) { const result = await transaction.query( - `SELECT session_id, header, revision, next_seq, writer_epoch, + `SELECT session_id, header, inherited_event_count, revision, next_seq, writer_epoch, writer_device_id, writer_token_hash FROM teleport_sessions WHERE session_id = $1 @@ -694,13 +700,16 @@ function headFromRow(session) { return { sessionId: session.session_id, header: asJsonValue(session.header), + ...session.inherited_event_count == null ? {} : { + inheritedEventCount: integer(session.inherited_event_count, "inherited_event_count") + }, revision: integer(session.revision, "revision"), nextSeq: integer(session.next_seq, "next_seq"), writerEpoch: integer(session.writer_epoch, "writer_epoch"), ...session.writer_device_id === null ? {} : { writerDeviceId: session.writer_device_id } }; } -function validateAppend(request) { +function validateAppend(request, allowEmpty = false) { assertIdentifier(request.sessionId, "sessionId"); assertWriterCredentials(request.writer); assertIdentifier(request.writer.deviceId, "writer.deviceId"); @@ -709,7 +718,7 @@ function validateAppend(request) { safeNonNegative(request.writer.writerEpoch, "writer.writerEpoch"); safeNonNegative(request.expectedRevision, "expectedRevision"); safeNonNegative(request.expectedNextSeq, "expectedNextSeq"); - if (!Array.isArray(request.events) || request.events.length === 0) { + if (!Array.isArray(request.events) || !allowEmpty && request.events.length === 0) { throw new TeleportError("BAD_REQUEST", "append requires at least one event"); } for (const [index, value] of request.events.entries()) { @@ -769,7 +778,7 @@ function validateImportRollback(request) { assertIdentifier(request.importIdempotencyKey, "importIdempotencyKey"); assertIdentifier(request.actorId, "actorId"); safePositive(request.expectedRevision, "expectedRevision"); - safePositive(request.expectedNextSeq, "expectedNextSeq"); + safeNonNegative(request.expectedNextSeq, "expectedNextSeq"); safePositive(request.expectedWriterEpoch, "expectedWriterEpoch"); if (typeof request.reason !== "string" || request.reason.trim().length === 0) { throw new TeleportError("BAD_REQUEST", "rollback reason is required"); diff --git a/dist/authority.js.map b/dist/authority.js.map index 3958f5f..6a4894f 100644 --- a/dist/authority.js.map +++ b/dist/authority.js.map @@ -1,6 +1,6 @@ { "version": 3, "sources": ["../src/authority.ts"], - "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,aAAa,eAAe,QAAQ,cAAc;AAwB3D,SAAS,qBAAqB;AAwDvB,MAAM,kBAAkB;AAAA,EAM7B,YACmB,UACjB,UAAoC,CAAC,GACrC;AAFiB;AAGjB,SAAK,MAAM,QAAQ,OAAO,KAAK;AAC/B,SAAK,sBAAsB,QAAQ,uBAAuB,IAAI;AAC9D,SAAK,kBAAkB,QAAQ,mBAAmB,KAAK;AAAA,EACzD;AAAA,EANmB;AAAA,EANF,UAAU,IAAI,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EAWjB,MAAM,cAA6B;AACjC,UAAM,KAAK,SAAS,MAAM,UAAU;AAAA,EACtC;AAAA,EAEA,MAAM,cAAc,SAA6D;AAC/E,qBAAiB,QAAQ,WAAW,WAAW;AAC/C,qBAAiB,QAAQ,UAAU,UAAU;AAC7C,UAAM,SAAS,cAAc,QAAQ,MAAM;AAC3C,UAAM,cAAc,OAAO;AAC3B,UAAM,WAAW,MAAM,KAAK,SAAS;AAAA,MACnC;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,CAAC,QAAQ,WAAW,QAAQ,QAAQ,UAAU,OAAO,WAAW,CAAC;AAAA,IACnE;AACA,QAAI,SAAS,aAAa,GAAG;AAC3B,YAAM,IAAI,cAAc,kBAAkB,YAAY,QAAQ,SAAS,kBAAkB;AAAA,IAC3F;AACA,UAAM,SAAS;AAAA,MACb,WAAW,QAAQ;AAAA,MACnB,UAAU;AAAA,MACV,SAAS;AAAA,MACT,QAAQ,EAAE,UAAU,QAAQ,UAAU,aAAa,GAAG,YAAY;AAAA,IACpE;AACA,SAAK,KAAK,QAAQ,WAAW,SAAS;AACtC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,mBACJ,SACmC;AACnC,UAAM,SAA4B;AAAA,MAChC,UAAU,QAAQ;AAAA,MAClB,aAAa;AAAA,MACb,aAAa,QAAQ;AAAA,IACvB;AACA,mBAAe;AAAA,MACb,WAAW,QAAQ;AAAA,MACnB;AAAA,MACA,kBAAkB;AAAA,MAClB,iBAAiB;AAAA,MACjB,gBAAgB,QAAQ;AAAA,MACxB,QAAQ,QAAQ;AAAA,IAClB,CAAC;AACD,UAAM,SAAS,cAAc,QAAQ,MAAM;AAC3C,UAAM,SAAS;AAAA,MACb,cAAc;AAAA,QACZ,WAAW,QAAQ;AAAA,QACnB,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,QAAQ,QAAQ;AAAA,MAClB,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,MAAM,KAAK,SAAS,YAAY,OAAO,gBAAgB;AACpE,YAAM,WAAW,MAAM,YAAY;AAAA,QACjC;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA,CAAC,QAAQ,WAAW,QAAQ,QAAQ,UAAU,OAAO,QAAQ,WAAW,CAAC;AAAA,MAC3E;AAEA,UAAI,SAAS,aAAa,GAAG;AAC3B,cAAM,UAAU,MAAM,YAAY,aAAa,QAAQ,SAAS;AAChE,cAAM,WAAW,MAAM,YAAY;AAAA,UACjC;AAAA;AAAA;AAAA,UAGA,CAAC,QAAQ,WAAW,QAAQ,cAAc;AAAA,QAC5C;AACA,cAAM,WAAW,SAAS,KAAK,CAAC;AAChC,YAAI,aAAa,UAAa,SAAS,mBAAmB,QAAQ;AAChE,uBAAa,SAAS,MAAM;AAC5B,iBAAO;AAAA,YACL,WAAW,QAAQ;AAAA,YACnB,UAAU,QAAQ,SAAS,oBAAoB,oBAAoB;AAAA,YACnE,SAAS,QAAQ,SAAS,oBAAoB,oBAAoB;AAAA,YAClE;AAAA,YACA,kBAAkB;AAAA,UACpB;AAAA,QACF;AACA,cAAM,IAAI;AAAA,UACR;AAAA,UACA,YAAY,QAAQ,SAAS;AAAA,QAC/B;AAAA,MACF;AAEA,iBAAW,SAAS,QAAQ,QAAQ;AAClC,cAAM,YAAY;AAAA,UAChB;AAAA;AAAA,UAEA,CAAC,QAAQ,WAAW,MAAM,KAAK,UAAU,KAAK,CAAC;AAAA,QACjD;AAAA,MACF;AACA,YAAM,UAAU,QAAQ,OAAO,GAAG,EAAE,EAAG,MAAM;AAC7C,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA;AAAA,QAGA,CAAC,QAAQ,WAAW,OAAO;AAAA,MAC7B;AACA,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA;AAAA;AAAA,QAIA;AAAA,UACE,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ,OAAO,GAAG,EAAE,EAAG;AAAA,UACvB;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,QACL,WAAW,QAAQ;AAAA,QACnB,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA,kBAAkB;AAAA,MACpB;AAAA,IACF,CAAC;AACD,QAAI,CAAC,OAAO,iBAAkB,MAAK,KAAK,QAAQ,WAAW,SAAS;AACpE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,SAA+C;AAC1D,mBAAe,OAAO;AACtB,UAAM,SAAS;AAAA,MACb,cAAc;AAAA,QACZ,WAAW,QAAQ;AAAA,QACnB,kBAAkB,QAAQ;AAAA,QAC1B,iBAAiB,QAAQ;AAAA,QACzB,QAAQ,QAAQ;AAAA,MAClB,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,MAAM,KAAK,SAAS,YAAY,OAAO,gBAAgB;AACpE,YAAM,UAAU,MAAM,YAAY,aAAa,QAAQ,SAAS;AAEhE,YAAM,WAAW,MAAM,YAAY;AAAA,QACjC;AAAA;AAAA;AAAA,QAGA,CAAC,QAAQ,WAAW,QAAQ,cAAc;AAAA,MAC5C;AACA,YAAM,WAAW,SAAS,KAAK,CAAC;AAChC,UAAI,aAAa,QAAW;AAC1B,YAAI,SAAS,mBAAmB,QAAQ;AACtC,gBAAM,IAAI;AAAA,YACR;AAAA,YACA,oBAAoB,QAAQ,cAAc;AAAA,UAC5C;AAAA,QACF;AACA,eAAO;AAAA,UACL,UAAU,QAAQ,SAAS,oBAAoB,oBAAoB;AAAA,UACnE,SAAS,QAAQ,SAAS,oBAAoB,oBAAoB;AAAA,UAClE,kBAAkB;AAAA,QACpB;AAAA,MACF;AAKA,mBAAa,SAAS,QAAQ,MAAM;AAEpC,YAAM,WAAW,QAAQ,QAAQ,UAAU,UAAU;AACrD,YAAM,UAAU,QAAQ,QAAQ,UAAU,UAAU;AACpD,UAAI,aAAa,QAAQ,kBAAkB;AACzC,cAAM,IAAI;AAAA,UACR;AAAA,UACA,+BAA+B,QAAQ,gBAAgB,aAAa,QAAQ;AAAA,QAC9E;AAAA,MACF;AACA,UAAI,YAAY,QAAQ,iBAAiB;AACvC,cAAM,IAAI;AAAA,UACR;AAAA,UACA,+BAA+B,QAAQ,eAAe,aAAa,OAAO;AAAA,QAC5E;AAAA,MACF;AAEA,iBAAW,SAAS,QAAQ,QAAQ;AAClC,cAAM,YAAY;AAAA,UAChB;AAAA;AAAA,UAEA,CAAC,QAAQ,WAAW,MAAM,KAAK,UAAU,KAAK,CAAC;AAAA,QACjD;AAAA,MACF;AAEA,YAAM,oBAAoB,WAAW;AACrC,YAAM,mBAAmB,QAAQ,OAAO,GAAG,EAAE,EAAG,MAAM;AACtD,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA;AAAA,QAGA,CAAC,QAAQ,WAAW,mBAAmB,gBAAgB;AAAA,MACzD;AACA,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA;AAAA;AAAA,QAIA;AAAA,UACE,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ,OAAO,CAAC,EAAG;AAAA,UACnB,QAAQ,OAAO,GAAG,EAAE,EAAG;AAAA,UACvB;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,aAAO,EAAE,UAAU,mBAAmB,SAAS,kBAAkB,kBAAkB,MAAM;AAAA,IAC3F,CAAC;AAED,QAAI,CAAC,OAAO,iBAAkB,MAAK,KAAK,QAAQ,WAAW,QAAQ;AACnE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAS,WAAmB,WAAW,IAA8B;AACzE,qBAAiB,WAAW,WAAW;AACvC,QAAI,CAAC,OAAO,cAAc,QAAQ,KAAK,WAAW,IAAI;AACpD,YAAM,IAAI,cAAc,eAAe,uCAAuC;AAAA,IAChF;AACA,WAAO,KAAK,SAAS;AAAA,MACnB,OAAO,gBAAgB;AACrB,cAAM,gBAAgB,MAAM,YAAY;AAAA,UACtC;AAAA;AAAA;AAAA,UAGA,CAAC,SAAS;AAAA,QACZ;AACA,cAAM,UAAU,cAAc,KAAK,CAAC;AACpC,YAAI,YAAY,QAAW;AACzB,gBAAM,IAAI,cAAc,aAAa,YAAY,SAAS,aAAa;AAAA,QACzE;AACA,cAAM,cAAc,MAAM,YAAY;AAAA,UACpC;AAAA;AAAA;AAAA,UAGA,CAAC,WAAW,QAAQ;AAAA,QACtB;AACA,eAAO;AAAA,UACL;AAAA,UACA,QAAQ,YAAY,QAAQ,MAAM;AAAA,UAClC,UAAU,QAAQ,QAAQ,UAAU,UAAU;AAAA,UAC9C,SAAS,QAAQ,QAAQ,UAAU,UAAU;AAAA,UAC7C,aAAa,QAAQ,QAAQ,cAAc,cAAc;AAAA,UACzD,GAAI,QAAQ,qBAAqB,OAC7B,CAAC,IACD,EAAE,gBAAgB,QAAQ,iBAAiB;AAAA,UAC/C,QAAQ,YAAY,KAAK,IAAI,CAAC,QAAQ,KAAK,MAAM,IAAI,UAAU,CAAkB;AAAA,QACnF;AAAA,MACF;AAAA,MACA,EAAE,gBAAgB,mBAAmB,UAAU,KAAK;AAAA,IACtD;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,WAAyC;AAClD,qBAAiB,WAAW,WAAW;AACvC,UAAM,SAAS,MAAM,KAAK,SAAS;AAAA,MACjC;AAAA;AAAA;AAAA,MAGA,CAAC,SAAS;AAAA,IACZ;AACA,UAAM,UAAU,OAAO,KAAK,CAAC;AAC7B,QAAI,YAAY,QAAW;AACzB,YAAM,IAAI,cAAc,aAAa,YAAY,SAAS,aAAa;AAAA,IACzE;AACA,WAAO,YAAY,OAAO;AAAA,EAC5B;AAAA,EAEA,MAAM,YAAoC;AACxC,UAAM,SAAS,MAAM,KAAK,SAAS;AAAA,MACjC;AAAA;AAAA;AAAA;AAAA,IAIF;AACA,WAAO,OAAO,KAAK,IAAI,WAAW;AAAA,EACpC;AAAA,EAEA,MAAM,cAAc,SAA6D;AAC/E,qBAAiB,QAAQ,WAAW,WAAW;AAC/C,4BAAwB,QAAQ,MAAM;AACtC,UAAM,QAAQ,QAAQ,SAAS,KAAK;AACpC,QAAI,CAAC,OAAO,cAAc,KAAK,KAAK,SAAS,KAAK,QAAQ,KAAK,iBAAiB;AAC9E,YAAM,IAAI;AAAA,QACR;AAAA,QACA,4CAA4C,KAAK,eAAe;AAAA,MAClE;AAAA,IACF;AACA,UAAM,OAAO,OAAO,EAAE;AACtB,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,EAAE,YAAY;AAC3D,UAAM,KAAK,SAAS,YAAY,OAAO,gBAAgB;AACrD,YAAM,UAAU,MAAM,YAAY,aAAa,QAAQ,SAAS;AAChE,mBAAa,SAAS,QAAQ,MAAM;AACpC,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA,QAEA,CAAC,OAAO,IAAI,GAAG,QAAQ,WAAW,QAAQ,OAAO,aAAa,SAAS;AAAA,MACzE;AAAA,IACF,CAAC;AACD,WAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AAAA,EAEA,MAAM,cAAc,SAA6D;AAC/E,qBAAiB,QAAQ,MAAM,MAAM;AACrC,qBAAiB,QAAQ,UAAU,UAAU;AAC7C,UAAM,SAAS,MAAM,KAAK,SAAS,YAAY,OAAO,gBAAgB;AACpE,YAAM,gBAAgB,MAAM,YAAY;AAAA,QACtC;AAAA;AAAA;AAAA;AAAA,QAIA,CAAC,OAAO,QAAQ,IAAI,CAAC;AAAA,MACvB;AACA,YAAM,UAAU,cAAc,KAAK,CAAC;AACpC,UAAI,YAAY,QAAW;AACzB,cAAM,IAAI,cAAc,aAAa,wBAAwB;AAAA,MAC/D;AACA,UAAI,QAAQ,gBAAgB,MAAM;AAChC,cAAM,IAAI,cAAc,oBAAoB,mCAAmC;AAAA,MACjF;AACA,UAAI,IAAI,KAAK,QAAQ,UAAU,EAAE,QAAQ,KAAK,KAAK,IAAI,GAAG;AACxD,cAAM,IAAI,cAAc,mBAAmB,0BAA0B;AAAA,MACvE;AAEA,YAAM,UAAU,MAAM,YAAY,aAAa,QAAQ,UAAU;AACjE,YAAM,eAAe,QAAQ,QAAQ,cAAc,cAAc;AACjE,YAAM,YAAY,QAAQ,QAAQ,YAAY,YAAY;AAC1D,UAAI,iBAAiB,WAAW;AAC9B,cAAM,IAAI;AAAA,UACR;AAAA,UACA,uCAAuC,SAAS,sBAAsB,YAAY;AAAA,QACpF;AAAA,MACF;AAEA,YAAM,cAAc,OAAO;AAC3B,YAAM,kBAAkB,OAAO,WAAW;AAC1C,YAAM,cAAc,eAAe;AACnC,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA;AAAA;AAAA,QAIA,CAAC,QAAQ,YAAY,aAAa,QAAQ,UAAU,eAAe;AAAA,MACrE;AACA,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,CAAC,OAAO,QAAQ,IAAI,CAAC;AAAA,MACvB;AACA,YAAM,UAAU,WAAW,OAAO,QAAQ,IAAI,CAAC;AAC/C,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA;AAAA,UACE,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,YACE,cAAc;AAAA,cACZ,QAAQ;AAAA,cACR,WAAW,QAAQ;AAAA,cACnB,UAAU,OAAO,QAAQ,IAAI;AAAA,cAC7B,UAAU,QAAQ;AAAA,cAClB;AAAA,cACA,SAAS;AAAA,cACT;AAAA,YACF,CAAC;AAAA,UACH;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,UACA,QAAQ,QAAQ,UAAU,UAAU;AAAA,UACpC,QAAQ,QAAQ,UAAU,UAAU;AAAA,QACtC;AAAA,MACF;AACA,aAAO;AAAA,QACL,WAAW,QAAQ;AAAA,QACnB,UAAU,QAAQ,QAAQ,UAAU,UAAU;AAAA,QAC9C,SAAS,QAAQ,QAAQ,UAAU,UAAU;AAAA,QAC7C,QAAQ,EAAE,UAAU,QAAQ,UAAU,aAAa,YAAY;AAAA,MACjE;AAAA,IACF,CAAC;AACD,SAAK,KAAK,OAAO,WAAW,QAAQ;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,SAA6D;AAC/E,qBAAiB,OAAO;AACxB,UAAM,SAAS,QAAQ,OAAO,KAAK;AACnC,UAAM,kBAAkB,OAAO,QAAQ,WAAW;AAClD,UAAM,SAAS;AAAA,MACb,cAAc;AAAA,QACZ,QAAQ;AAAA,QACR,WAAW,QAAQ;AAAA,QACnB,kBAAkB,QAAQ;AAAA,QAC1B,qBAAqB,QAAQ;AAAA,QAC7B,UAAU,QAAQ;AAAA,QAClB;AAAA,QACA,SAAS,QAAQ;AAAA,QACjB;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,SAA4B;AAAA,MAChC,UAAU,QAAQ;AAAA,MAClB,aAAa,QAAQ,sBAAsB;AAAA,MAC3C,aAAa,QAAQ;AAAA,IACvB;AAEA,UAAM,SAAS,MAAM,KAAK,SAAS,YAAY,OAAO,gBAAgB;AACpE,YAAM,UAAU,MAAM,YAAY,aAAa,QAAQ,SAAS;AAChE,YAAM,WAAW,MAAM,YAAY;AAAA,QACjC;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA,CAAC,QAAQ,WAAW,QAAQ,cAAc;AAAA,MAC5C;AACA,YAAM,QAAQ,SAAS,KAAK,CAAC;AAC7B,UAAI,UAAU,QAAW;AACvB,YAAI,MAAM,WAAW,oBAAoB,MAAM,mBAAmB,QAAQ;AACxE,gBAAM,IAAI;AAAA,YACR;AAAA,YACA,6BAA6B,QAAQ,cAAc;AAAA,UACrD;AAAA,QACF;AACA,cAAMA,gBAAe,QAAQ,QAAQ,cAAc,cAAc;AACjE,cAAM,iBAAiB,QAAQ,MAAM,UAAU,UAAU;AACzD,YACEA,kBAAiB,kBACjB,QAAQ,qBAAqB,QAAQ,YACrC,QAAQ,sBAAsB,iBAC9B;AACA,gBAAM,IAAI;AAAA,YACR;AAAA,YACA,4CAA4CA,aAAY;AAAA,UAC1D;AAAA,QACF;AACA,eAAO;AAAA,UACL,WAAW,QAAQ;AAAA,UACnB,UAAU,QAAQ,QAAQ,UAAU,UAAU;AAAA,UAC9C,SAAS,QAAQ,QAAQ,UAAU,UAAU;AAAA,UAC7C,QAAQ,EAAE,GAAG,QAAQ,aAAa,eAAe;AAAA,UACjD,kBAAkB;AAAA,QACpB;AAAA,MACF;AAEA,YAAM,kBAAkB,QAAQ,QAAQ,UAAU,UAAU;AAC5D,YAAM,eAAe,QAAQ,QAAQ,cAAc,cAAc;AACjE,UAAI,oBAAoB,QAAQ,kBAAkB;AAChD,cAAM,IAAI;AAAA,UACR;AAAA,UACA,+BAA+B,QAAQ,gBAAgB,aAAa,eAAe;AAAA,QACrF;AAAA,MACF;AACA,UAAI,iBAAiB,QAAQ,qBAAqB;AAChD,cAAM,IAAI;AAAA,UACR;AAAA,UACA,mCAAmC,QAAQ,mBAAmB,aAAa,YAAY;AAAA,QACzF;AAAA,MACF;AAEA,YAAM,cAAc,eAAe;AACnC,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA;AAAA;AAAA,QAIA,CAAC,QAAQ,WAAW,aAAa,QAAQ,UAAU,eAAe;AAAA,MACpE;AACA,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA;AAAA,UACE,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,UACA,QAAQ,QAAQ,UAAU,UAAU;AAAA,QACtC;AAAA,MACF;AACA,aAAO;AAAA,QACL,WAAW,QAAQ;AAAA,QACnB,UAAU;AAAA,QACV,SAAS,QAAQ,QAAQ,UAAU,UAAU;AAAA,QAC7C,QAAQ,EAAE,GAAG,QAAQ,YAAY;AAAA,QACjC,kBAAkB;AAAA,MACpB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,OAAO,iBAAkB,MAAK,KAAK,QAAQ,WAAW,QAAQ;AACnE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eACJ,SACsC;AACtC,2BAAuB,OAAO;AAC9B,UAAM,SAAS,QAAQ,OAAO,KAAK;AACnC,UAAM,gBAAgB;AAAA,MACpB,cAAc;AAAA,QACZ,QAAQ;AAAA,QACR,WAAW,QAAQ;AAAA,QACnB,kBAAkB,QAAQ;AAAA,QAC1B,iBAAiB,QAAQ;AAAA,QACzB,qBAAqB,QAAQ;AAAA,QAC7B,sBAAsB,QAAQ;AAAA,QAC9B,SAAS,QAAQ;AAAA,QACjB;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,SAAS,MAAM,KAAK,SAAS,YAAY,OAAO,gBAAgB;AACpE,YAAM,WAAW,MAAM,YAAY;AAAA,QACjC;AAAA;AAAA;AAAA,QAGA,CAAC,QAAQ,WAAW,QAAQ,oBAAoB;AAAA,MAClD;AACA,YAAM,QAAQ,SAAS,KAAK,CAAC;AAC7B,UAAI,UAAU,QAAW;AACvB,YAAI,MAAM,mBAAmB,eAAe;AAC1C,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA,cAAM,SAAS,MAAM,YAAY;AAAA,UAC/B;AAAA,UACA,CAAC,QAAQ,SAAS;AAAA,QACpB;AACA,YAAI,OAAO,KAAK,WAAW,GAAG;AAC5B,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA,eAAO;AAAA,UACL,WAAW,QAAQ;AAAA,UACnB,YAAY;AAAA,UACZ,kBAAkB;AAAA,QACpB;AAAA,MACF;AAEA,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,YAAY,aAAa,QAAQ,SAAS;AAAA,MAC5D,SAAS,OAAgB;AACvB,YAAI,EAAE,iBAAiB,iBAAiB,MAAM,SAAS,aAAc,OAAM;AAI3E,cAAM,aAAa,MAAM,YAAY;AAAA,UACnC;AAAA;AAAA;AAAA,UAGA,CAAC,QAAQ,WAAW,QAAQ,oBAAoB;AAAA,QAClD;AACA,cAAM,YAAY,WAAW,KAAK,CAAC;AACnC,YAAI,cAAc,OAAW,OAAM;AACnC,YAAI,UAAU,mBAAmB,eAAe;AAC9C,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA,eAAO;AAAA,UACL,WAAW,QAAQ;AAAA,UACnB,YAAY;AAAA,UACZ,kBAAkB;AAAA,QACpB;AAAA,MACF;AACA,YAAM,WAAW,QAAQ,QAAQ,UAAU,UAAU;AACrD,YAAM,UAAU,QAAQ,QAAQ,UAAU,UAAU;AACpD,YAAM,cAAc,QAAQ,QAAQ,cAAc,cAAc;AAChE,UAAI,aAAa,QAAQ,oBAAoB,YAAY,QAAQ,iBAAiB;AAChF,cAAM,IAAI;AAAA,UACR;AAAA,UACA,2CAA2C,QAAQ,cAAc,OAAO;AAAA,QAC1E;AAAA,MACF;AACA,UAAI,gBAAgB,QAAQ,uBAAuB,gBAAgB,GAAG;AACpE,cAAM,IAAI;AAAA,UACR;AAAA,UACA,sDAAsD,WAAW;AAAA,QACnE;AAAA,MACF;AAEA,YAAM,YAAY,MAAM,YAAY;AAAA,QAClC;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA,CAAC,QAAQ,SAAS;AAAA,MACpB;AACA,YAAM,WAAW,UAAU,KAAK,CAAC;AACjC,YAAM,iBAAiB,QAAQ,kBAAkB;AACjD,UACE,UAAU,KAAK,WAAW,KAC1B,aAAa,UACb,CAAC,QAAQ,qBAAqB,WAAW,aAAa,KACtD,SAAS,oBAAoB,QAAQ,wBACrC,SAAS,cAAc,UACvB,QAAQ,SAAS,WAAW,WAAW,MAAM,KAC7C,QAAQ,SAAS,SAAS,SAAS,MAAM,kBACzC,QAAQ,SAAS,oBAAoB,oBAAoB,MACvD,QAAQ,oBACV,QAAQ,SAAS,oBAAoB,oBAAoB,MACvD,QAAQ,iBACV;AACA,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,YAAM,YAAY;AAAA,QAChB;AAAA;AAAA;AAAA;AAAA,QAIA;AAAA,UACE,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM,YAAY,MAAM,uDAAuD;AAAA,QAC7E,QAAQ;AAAA,MACV,CAAC;AACD,aAAO;AAAA,QACL,WAAW,QAAQ;AAAA,QACnB,YAAY;AAAA,QACZ,kBAAkB;AAAA,MACpB;AAAA,IACF,CAAC;AACD,SAAK,KAAK,QAAQ,WAAW,QAAQ;AACrC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,gBAAgB,WAAmB,QAAQ,KAAkC;AACjF,qBAAiB,WAAW,WAAW;AACvC,QAAI,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,KAAK,QAAQ,KAAK;AAC5D,YAAM,IAAI,cAAc,eAAe,kDAAkD;AAAA,IAC3F;AACA,UAAM,KAAK,KAAK,SAAS;AACzB,UAAM,SAAS,MAAM,KAAK,SAAS;AAAA,MACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,CAAC,WAAW,KAAK;AAAA,IACnB;AACA,WAAO,OAAO,KAAK,IAAI,CAAC,SAAS;AAAA,MAC/B,gBAAgB,IAAI;AAAA,MACpB,QAAQ,IAAI;AAAA,MACZ,SAAS,IAAI;AAAA,MACb,QAAQ,IAAI;AAAA,MACZ,GAAI,IAAI,mBAAmB,OAAO,CAAC,IAAI,EAAE,cAAc,IAAI,eAAe;AAAA,MAC1E,YAAY,IAAI;AAAA,MAChB,WAAW,QAAQ,IAAI,YAAY,YAAY;AAAA,MAC/C,SAAS,QAAQ,IAAI,UAAU,UAAU;AAAA,MACzC,UAAU,QAAQ,IAAI,oBAAoB,oBAAoB;AAAA,MAC9D,SAAS,QAAQ,IAAI,oBAAoB,oBAAoB;AAAA,MAC7D,WAAW,UAAU,IAAI,UAAU;AAAA,IACrC,EAAE;AAAA,EACJ;AAAA,EAEA,UAAU,WAAmB,UAAuE;AAClG,UAAM,YAAY,WAAW,SAAS;AACtC,SAAK,QAAQ,GAAG,WAAW,QAAQ;AACnC,WAAO,MAAM,KAAK,QAAQ,IAAI,WAAW,QAAQ;AAAA,EACnD;AAAA,EAEQ,KAAK,WAAmB,MAA6C;AAC3E,SAAK,QAAQ,KAAK,WAAW,SAAS,IAAI,IAAI;AAAA,EAChD;AACF;AAEA,eAAe,YAAY,aAA0B,WAAwC;AAC3F,QAAM,SAAS,MAAM,YAAY;AAAA,IAC/B;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,CAAC,SAAS;AAAA,EACZ;AACA,QAAM,UAAU,OAAO,KAAK,CAAC;AAC7B,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,cAAc,aAAa,YAAY,SAAS,aAAa;AAAA,EACzE;AACA,SAAO;AACT;AAEA,SAAS,aAAa,SAAqB,QAAiC;AAC1E,QAAM,eAAe,QAAQ,QAAQ,cAAc,cAAc;AACjE,QAAM,QACJ,QAAQ,qBAAqB,OAAO,YACpC,iBAAiB,OAAO,eACxB,QAAQ,sBAAsB,QAC9B,QAAQ,sBAAsB,OAAO,OAAO,WAAW;AACzD,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR;AAAA,MACA,0DAA0D,YAAY;AAAA,IACxE;AAAA,EACF;AACF;AAEA,SAAS,YAAY,SAAkC;AACrD,SAAO;AAAA,IACL,WAAW,QAAQ;AAAA,IACnB,QAAQ,YAAY,QAAQ,MAAM;AAAA,IAClC,UAAU,QAAQ,QAAQ,UAAU,UAAU;AAAA,IAC9C,SAAS,QAAQ,QAAQ,UAAU,UAAU;AAAA,IAC7C,aAAa,QAAQ,QAAQ,cAAc,cAAc;AAAA,IACzD,GAAI,QAAQ,qBAAqB,OAC7B,CAAC,IACD,EAAE,gBAAgB,QAAQ,iBAAiB;AAAA,EACjD;AACF;AAEA,SAAS,eAAe,SAA8B;AACpD,mBAAiB,QAAQ,WAAW,WAAW;AAC/C,0BAAwB,QAAQ,MAAM;AACtC,mBAAiB,QAAQ,OAAO,UAAU,iBAAiB;AAC3D,mBAAiB,QAAQ,OAAO,aAAa,oBAAoB;AACjE,mBAAiB,QAAQ,gBAAgB,gBAAgB;AACzD,kBAAgB,QAAQ,OAAO,aAAa,oBAAoB;AAChE,kBAAgB,QAAQ,kBAAkB,kBAAkB;AAC5D,kBAAgB,QAAQ,iBAAiB,iBAAiB;AAC1D,MAAI,CAAC,MAAM,QAAQ,QAAQ,MAAM,KAAK,QAAQ,OAAO,WAAW,GAAG;AACjE,UAAM,IAAI,cAAc,eAAe,oCAAoC;AAAA,EAC7E;AACA,aAAW,CAAC,OAAO,KAAK,KAAK,QAAQ,OAAO,QAAQ,GAAG;AACrD,QAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AACvE,YAAM,IAAI,cAAc,eAAe,UAAU,KAAK,qBAAqB;AAAA,IAC7E;AACA,UAAM,QAAQ;AACd,qBAAiB,MAAM,MAAgB,UAAU,KAAK,QAAQ;AAC9D,UAAM,MAAM,MAAM;AAClB,UAAM,OAAO,MAAM;AACnB,oBAAgB,KAAK,UAAU,KAAK,OAAO;AAC3C,oBAAgB,MAAM,UAAU,KAAK,QAAQ;AAC7C,QAAI,EAAE,UAAU,QAAQ;AACtB,YAAM,IAAI,cAAc,eAAe,UAAU,KAAK,oBAAoB;AAAA,IAC5E;AACA,QAAI,MAAM,oBAAoB,QAAW;AACvC,UAAI,CAAC,MAAM,QAAQ,MAAM,eAAe,GAAG;AACzC,cAAM,IAAI;AAAA,UACR;AAAA,UACA,UAAU,KAAK;AAAA,QACjB;AAAA,MACF;AACA,iBAAW,CAAC,aAAa,SAAS,KAAK,MAAM,gBAAgB,QAAQ,GAAG;AACtE;AAAA,UACE;AAAA,UACA,UAAU,KAAK,qBAAqB,WAAW;AAAA,QACjD;AAAA,MACF;AAAA,IACF;AACA,UAAM,WAAW,QAAQ,kBAAkB;AAC3C,QAAI,QAAQ,UAAU;AACpB,YAAM,IAAI;AAAA,QACR;AAAA,QACA,2CAA2C,QAAQ,SAAS,GAAG;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AACA,gBAAc,QAAQ,MAAM;AAC9B;AAEA,SAAS,iBAAiB,SAAqC;AAC7D,mBAAiB,QAAQ,WAAW,WAAW;AAC/C,mBAAiB,QAAQ,UAAU,UAAU;AAC7C,mBAAiB,QAAQ,aAAa,aAAa;AACnD,mBAAiB,QAAQ,gBAAgB,gBAAgB;AACzD,mBAAiB,QAAQ,SAAS,SAAS;AAC3C,kBAAgB,QAAQ,kBAAkB,kBAAkB;AAC5D,eAAa,QAAQ,qBAAqB,qBAAqB;AAC/D,MAAI,OAAO,QAAQ,WAAW,YAAY,QAAQ,OAAO,KAAK,EAAE,WAAW,GAAG;AAC5E,UAAM,IAAI,cAAc,eAAe,6BAA6B;AAAA,EACtE;AACA,MAAI,QAAQ,OAAO,SAAS,KAAK;AAC/B,UAAM,IAAI,cAAc,eAAe,sCAAsC;AAAA,EAC/E;AACF;AAEA,SAAS,uBAAuB,SAA6C;AAC3E,mBAAiB,QAAQ,WAAW,WAAW;AAC/C,mBAAiB,QAAQ,sBAAsB,sBAAsB;AACrE,mBAAiB,QAAQ,SAAS,SAAS;AAC3C,eAAa,QAAQ,kBAAkB,kBAAkB;AACzD,eAAa,QAAQ,iBAAiB,iBAAiB;AACvD,eAAa,QAAQ,qBAAqB,qBAAqB;AAC/D,MAAI,OAAO,QAAQ,WAAW,YAAY,QAAQ,OAAO,KAAK,EAAE,WAAW,GAAG;AAC5E,UAAM,IAAI,cAAc,eAAe,6BAA6B;AAAA,EACtE;AACA,MAAI,QAAQ,OAAO,SAAS,KAAK;AAC/B,UAAM,IAAI,cAAc,eAAe,sCAAsC;AAAA,EAC/E;AACF;AAGA,SAAS,UAAU,OAA8B;AAC/C,gBAAc,KAAK;AACnB,SAAO,KAAK,UAAU,KAAK;AAC7B;AAEA,SAAS,wBAAwB,OAAoD;AACnF,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,UAAM,IAAI,cAAc,eAAe,iCAAiC;AAAA,EAC1E;AACA,QAAM,SAAS;AACf,mBAAiB,OAAO,UAAoB,iBAAiB;AAC7D,mBAAiB,OAAO,aAAuB,oBAAoB;AACnE,kBAAgB,OAAO,aAAuB,oBAAoB;AACpE;AAEA,SAAS,iBAAiB,OAAe,MAAoB;AAC3D,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,KAAK,MAAM,SAAS,KAAK;AACzE,UAAM,IAAI,cAAc,eAAe,GAAG,IAAI,0CAA0C;AAAA,EAC1F;AACF;AAEA,SAAS,gBAAgB,OAAgB,MAAuC;AAC9E,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,GAAG;AAC1E,UAAM,IAAI,cAAc,eAAe,GAAG,IAAI,sCAAsC;AAAA,EACtF;AACF;AAEA,SAAS,aAAa,OAAgB,MAAuC;AAC3E,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,GAAG;AAC1E,UAAM,IAAI,cAAc,eAAe,GAAG,IAAI,kCAAkC;AAAA,EAClF;AACF;AAEA,SAAS,UAAU,OAA8B;AAC/C,QAAM,OAAO,iBAAiB,OAAO,QAAQ,IAAI,KAAK,KAAK;AAC3D,MAAI,CAAC,OAAO,SAAS,KAAK,QAAQ,CAAC,EAAG,OAAM,IAAI,MAAM,wCAAwC;AAC9F,SAAO,KAAK,YAAY;AAC1B;AAEA,SAAS,QAAQ,OAAwB,MAAsB;AAC7D,QAAM,SAAS,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK;AAC/D,MAAI,CAAC,OAAO,cAAc,MAAM,GAAG;AACjC,UAAM,IAAI,MAAM,YAAY,IAAI,wBAAwB;AAAA,EAC1D;AACA,SAAO;AACT;", + "mappings": "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", "names": ["currentEpoch"] } diff --git a/dist/client.d.ts b/dist/client.d.ts index bb2e677..adedfd6 100644 --- a/dist/client.d.ts +++ b/dist/client.d.ts @@ -10,12 +10,12 @@ export declare class TeleportClient { private readonly adminToken?; private readonly baseUrl; constructor(baseUrl: string, apiToken?: string | undefined, adminToken?: string | undefined); - health(signal?: AbortSignal): Promise; + health(signal?: AbortSignal, requiredSchemaVersion?: number): Promise; createSession(request: CreateSessionRequest): Promise; materializeSession(request: MaterializeSessionRequest): Promise; - listHeads(): Promise; - head(sessionId: string): Promise; - snapshot(sessionId: string, afterSeq?: number): Promise; + listHeads(signal?: AbortSignal): Promise; + head(sessionId: string, signal?: AbortSignal): Promise; + snapshot(sessionId: string, afterSeq?: number, signal?: AbortSignal): Promise; append(request: AppendRequest): Promise; createHandoff(request: CreateHandoffRequest): Promise; acceptHandoff(request: AcceptHandoffRequest): Promise; diff --git a/dist/client.js b/dist/client.js index 6ffa5ce..535f192 100644 --- a/dist/client.js +++ b/dist/client.js @@ -17,12 +17,23 @@ class TeleportClient { apiToken; adminToken; baseUrl; - async health(signal) { + async health(signal, requiredSchemaVersion) { const response = await fetch(`${this.baseUrl}/health`, { ...signal === void 0 ? {} : { signal } }); if (response.ok) { - await response.arrayBuffer(); + if (requiredSchemaVersion === void 0) { + await response.arrayBuffer(); + } else { + const body = await response.json(); + if (body.schemaVersion !== requiredSchemaVersion) { + throw new TeleportRemoteError( + 409, + "SCHEMA_INCOMPATIBLE", + `Teleport authority must run schema ${requiredSchemaVersion}; upgrade the service with the adapter` + ); + } + } return; } let message = `Teleport service returned HTTP ${response.status}`; @@ -39,16 +50,19 @@ class TeleportClient { materializeSession(request) { return this.request("POST", "/v1/sessions/materialize", request); } - listHeads() { - return this.request("GET", "/v1/sessions"); + listHeads(signal) { + return this.request("GET", "/v1/sessions", void 0, false, signal); } - head(sessionId) { - return this.request("GET", `/v1/sessions/${encodeURIComponent(sessionId)}/head`); + head(sessionId, signal) { + return this.request("GET", `/v1/sessions/${encodeURIComponent(sessionId)}/head`, void 0, false, signal); } - snapshot(sessionId, afterSeq = -1) { + snapshot(sessionId, afterSeq = -1, signal) { return this.request( "GET", - `/v1/sessions/${encodeURIComponent(sessionId)}?after=${afterSeq}` + `/v1/sessions/${encodeURIComponent(sessionId)}?after=${afterSeq}`, + void 0, + false, + signal ); } append(request) { @@ -104,12 +118,13 @@ class TeleportClient { watchUrl(sessionId, afterSeq = -1) { return `${this.baseUrl}/v1/sessions/${encodeURIComponent(sessionId)}/watch?after=${afterSeq}`; } - async request(method, path, body, admin = false) { + async request(method, path, body, admin = false, signal) { if (admin && this.adminToken === void 0) { throw new Error("Teleport admin token is required for this operation"); } const response = await fetch(`${this.baseUrl}${path}`, { method, + ...signal === void 0 ? {} : { signal }, headers: { ...this.apiToken === void 0 ? {} : { authorization: `Bearer ${this.apiToken}` }, ...admin ? { "x-teleport-admin-token": this.adminToken } : {}, diff --git a/dist/client.js.map b/dist/client.js.map index c3bcc1f..8044cac 100644 --- a/dist/client.js.map +++ b/dist/client.js.map @@ -1,6 +1,6 @@ { "version": 3, "sources": ["../src/client.ts"], - "mappings": "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", + "mappings": "AAoBO,MAAM,4BAA4B,MAAM;AAAA,EAC7C,YACW,QACA,MACT,SACA;AACA,UAAM,OAAO;AAJJ;AACA;AAIT,SAAK,OAAO;AAAA,EACd;AAAA,EANW;AAAA,EACA;AAMb;AAGO,MAAM,eAAe;AAAA,EAG1B,YACE,SACiB,UACA,YACjB;AAFiB;AACA;AAEjB,SAAK,UAAU,QAAQ,QAAQ,OAAO,EAAE;AAAA,EAC1C;AAAA,EAJmB;AAAA,EACA;AAAA,EALF;AAAA,EAUjB,MAAM,OAAO,QAAsB,uBAA+C;AAChF,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,WAAW;AAAA,MACrD,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;AAAA,IAC3C,CAAC;AACD,QAAI,SAAS,IAAI;AACf,UAAI,0BAA0B,QAAW;AACvC,cAAM,SAAS,YAAY;AAAA,MAC7B,OAAO;AACL,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAI,KAAK,kBAAkB,uBAAuB;AAChD,gBAAM,IAAI;AAAA,YAAoB;AAAA,YAAK;AAAA,YACjC,sCAAsC,qBAAqB;AAAA,UAAwC;AAAA,QACvG;AAAA,MACF;AACA;AAAA,IACF;AACA,QAAI,UAAU,kCAAkC,SAAS,MAAM;AAC/D,QAAI;AACF,YAAM,UAAW,MAAM,SAAS,KAAK;AACrC,gBAAU,QAAQ,OAAO,WAAW;AAAA,IACtC,QAAQ;AAAA,IAGR;AACA,UAAM,IAAI,oBAAoB,SAAS,QAAQ,uBAAuB,OAAO;AAAA,EAC/E;AAAA,EAEA,cAAc,SAA6D;AACzE,WAAO,KAAK,QAAQ,QAAQ,gBAAgB,OAAO;AAAA,EACrD;AAAA,EAEA,mBAAmB,SAAuE;AACxF,WAAO,KAAK,QAAQ,QAAQ,4BAA4B,OAAO;AAAA,EACjE;AAAA,EAEA,UAAU,QAA8C;AACtD,WAAO,KAAK,QAAQ,OAAO,gBAAgB,QAAW,OAAO,MAAM;AAAA,EACrE;AAAA,EAEA,KAAK,WAAmB,QAA4C;AAClE,WAAO,KAAK,QAAQ,OAAO,gBAAgB,mBAAmB,SAAS,CAAC,SAAS,QAAW,OAAO,MAAM;AAAA,EAC3G;AAAA,EAEA,SAAS,WAAmB,WAAW,IAAI,QAAgD;AACzF,WAAO,KAAK;AAAA,MACV;AAAA,MACA,gBAAgB,mBAAmB,SAAS,CAAC,UAAU,QAAQ;AAAA,MAC/D;AAAA,MAAW;AAAA,MAAO;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,OAAO,SAA+C;AACpD,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,gBAAgB,mBAAmB,SAAS,CAAC;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,cAAc,SAA6D;AACzE,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,gBAAgB,mBAAmB,SAAS,CAAC;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,cAAc,SAA6D;AACzE,UAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAC1B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,cAAc,SAA6D;AACzE,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sBAAsB,mBAAmB,SAAS,CAAC;AAAA,MACnD;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,YAAY,WAAmB,QAAQ,KAAkC;AACvE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sBAAsB,mBAAmB,SAAS,CAAC,uBAAuB,KAAK;AAAA,MAC/E;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,eACE,SACsC;AACtC,UAAM,EAAE,WAAW,GAAG,KAAK,IAAI;AAC/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sBAAsB,mBAAmB,SAAS,CAAC;AAAA,MACnD;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,SAAS,WAAmB,WAAW,IAAY;AACjD,WAAO,GAAG,KAAK,OAAO,gBAAgB,mBAAmB,SAAS,CAAC,gBAAgB,QAAQ;AAAA,EAC7F;AAAA,EAEA,MAAc,QACZ,QACA,MACA,MACA,QAAQ,OACR,QACY;AACZ,QAAI,SAAS,KAAK,eAAe,QAAW;AAC1C,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACvE;AACA,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI,IAAI;AAAA,MACrD;AAAA,MACA,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;AAAA,MACzC,SAAS;AAAA,QACP,GAAI,KAAK,aAAa,SAAY,CAAC,IAAI,EAAE,eAAe,UAAU,KAAK,QAAQ,GAAG;AAAA,QAClF,GAAI,QAAQ,EAAE,0BAA0B,KAAK,WAAY,IAAI,CAAC;AAAA,QAC9D,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,gBAAgB,mBAAmB;AAAA,MACrE;AAAA,MACA,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE;AAAA,IAC7D,CAAC;AACD,UAAM,UAAW,MAAM,SAAS,KAAK;AAGrC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,WAAY,UACrB,QAA4D,QAC7D;AACJ,YAAM,IAAI;AAAA,QACR,SAAS;AAAA,QACT,OAAO,QAAQ;AAAA,QACf,OAAO,WAAW,kCAAkC,SAAS,MAAM;AAAA,MACrE;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;", "names": [] } diff --git a/dist/dsh-adapter.d.ts b/dist/dsh-adapter.d.ts index a82962e..cb56ec2 100644 --- a/dist/dsh-adapter.d.ts +++ b/dist/dsh-adapter.d.ts @@ -1,6 +1,6 @@ import { Context, Service } from "@deepseek-ai/cordis"; -import { SessionPersistence, SessionPersistenceRevision, type PersistenceBackend, type SessionLocation, type SessionPersistenceSnapshot, type StoredPrefix, type StoredSuffix } from "@deepseek-ai/dsh-session-persistence"; -import type { SessionEvent, SessionHeader, SessionId, SessionPreparation } from "@deepseek-ai/dsh-session"; +import { SessionPersistence, type SessionAccess, type SessionHandle, type SessionPersistenceCreateOptions, type SessionPersistenceListOptions, type SessionPersistenceOpenOptions, type SessionPersistenceSnapshot, type SessionPersistenceStatOptions } from "@deepseek-ai/dsh-session-persistence"; +import { type SessionHeader, type SessionId } from "@deepseek-ai/dsh-session"; import { type WriterCredentialStore } from "./credential-store.js"; import { TeleportClient } from "./client.js"; import type { CreateHandoffResult, WriterCredentials } from "./types.js"; @@ -15,49 +15,30 @@ export interface SessionPersistenceTeleportDependencies { client?: TeleportClient; credentialStore?: WriterCredentialStore; } -/** DSH PersistenceBackend adapter over the Teleport HTTP authority. */ -export declare class SessionPersistenceTeleport extends SessionPersistence implements PersistenceBackend { +/** DSH 0.2 handle-based persistence over the PostgreSQL authority. */ +export declare class SessionPersistenceTeleport extends SessionPersistence { readonly config: SessionPersistenceTeleportConfig; static inject: string[]; readonly name = "session-persistence-teleport"; - readonly supportsRawArtifacts = false; private readonly client; private readonly credentials; - private readonly coordinator; - private readonly observedHeads; + private readonly writers; + private readonly handles; private readonly sourceIdentity; - private readonly deviceId; constructor(ctx: Context, config: SessionPersistenceTeleportConfig, dependencies?: SessionPersistenceTeleportDependencies); protected [Service.init](): Promise; - locate(_meta: SessionHeader): SessionLocation | undefined; - create(meta: SessionHeader): Promise; - append(id: SessionId, events: readonly SessionEvent[]): Promise; - prepare(id: SessionId, signal?: AbortSignal): Promise; - load(id: SessionId): Promise<{ - meta: SessionHeader; - events: readonly SessionEvent[]; - }>; - inspect(id: SessionId, signal?: AbortSignal): Promise<{ - meta: SessionHeader; - events: readonly SessionEvent[]; - }>; - readFrom(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise<{ - meta: SessionHeader; - events: SessionEvent[]; - }>; - loadStored(id: SessionId, signal?: AbortSignal): Promise | undefined>; - readStoredRevision(id: SessionId, signal?: AbortSignal): Promise; - loadStoredFrom(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise; - appendBatch(meta: SessionHeader, events: readonly SessionEvent[], isMaterialized: boolean): Promise; - commitRepair(meta: SessionHeader, _tornMarker: undefined, closers: readonly SessionEvent[]): Promise; - list(signal?: AbortSignal): Promise; - listSnapshots(signal?: AbortSignal): Promise; + create(header: SessionHeader, options?: SessionPersistenceCreateOptions): Promise; + open(id: SessionId, access: SessionAccess, options?: SessionPersistenceOpenOptions): Promise; + flush(): Promise; + stat(id: SessionId, options?: SessionPersistenceStatOptions): Promise; + list(options?: SessionPersistenceListOptions): Promise; createHandoff(id: SessionId, ttlMs?: number): Promise; acceptHandoff(code: string): Promise; - private appendExisting; + private snapshot; + private adopt; + private release; private requireWriter; - private assertLocalWriter; - private observe; - private revision; + private assertDevice; + private acquireLock; } export default SessionPersistenceTeleport; diff --git a/dist/dsh-adapter.js b/dist/dsh-adapter.js index d2f6e53..40fb3f4 100644 --- a/dist/dsh-adapter.js +++ b/dist/dsh-adapter.js @@ -1,261 +1,440 @@ +import { mkdir, open as openFile } from "node:fs/promises"; +import { join } from "node:path"; import { Service } from "@deepseek-ai/cordis"; +import { tryLockExclusive } from "@deepseek-ai/node-addon-system/flock"; import { - PersistenceCoordinator, + SessionAlreadyExistsError, + SessionAlreadyOwnedError, + SessionHandleClosedError, + SessionOwnershipLostError, SessionPersistence, - SessionPersistenceRevision + SessionPersistenceNotFoundError, + SessionPersistenceRevision, + SessionReadOnlyError, + assertContiguous, + assertStoredId, + assertVersion, + materializeAppendBatch, + materializeCreateHeader, + validateStoredEvents } from "@deepseek-ai/dsh-session-persistence"; -import { canonicalJson, secret, sha256 } from "./canonical.js"; import { - FileWriterCredentialStore -} from "./credential-store.js"; + SessionLogOffset +} from "@deepseek-ai/dsh-session"; +import { SCHEMA_VERSION } from "./schema.js"; +import { canonicalJson, secret, sha256 } from "./canonical.js"; +import { FileWriterCredentialStore } from "./credential-store.js"; import { TeleportClient, TeleportRemoteError } from "./client.js"; class SessionPersistenceTeleport extends SessionPersistence { constructor(ctx, config, dependencies = {}) { validateConfig(config); super(ctx); this.config = config; - this.deviceId = config.deviceId; - const baseUrl = config.baseUrl.replace(/\/$/, ""); - this.sourceIdentity = sha256(baseUrl); - this.client = dependencies.client ?? new TeleportClient(baseUrl, config.apiToken); + this.client = dependencies.client ?? new TeleportClient(config.baseUrl, config.apiToken); this.credentials = dependencies.credentialStore ?? new FileWriterCredentialStore(config.credentialDir); - this.coordinator = new PersistenceCoordinator(this.ctx, this); + this.ctx.on("session/event", (session, event) => { + this.writers.get(session.id)?.enqueue(event, (error) => { + this.ctx.logger.warn(`Teleport background write failed for ${session.id}; buffered events retained: ${String(error)}`); + }); + }); + this.ctx.on("session/flush", (session) => this.writers.get(session.id)?.flush()); + this.ctx.on("session/disposed", (session) => { + this.writers.get(session.id)?.close().catch((error) => { + this.ctx.logger.warn(`Teleport close failed for ${session.id}: ${String(error)}`); + }); + }); + this.ctx.effect(() => async () => { + const results = await Promise.allSettled([...this.handles].map((handle) => handle.close())); + throwFailures(results, "Teleport handle teardown failed"); + }, "Teleport open handles"); } config; static inject = ["sessions"]; name = "session-persistence-teleport"; - supportsRawArtifacts = false; client; credentials; - coordinator; - observedHeads = /* @__PURE__ */ new Map(); - sourceIdentity; - deviceId; + writers = /* @__PURE__ */ new Map(); + handles = /* @__PURE__ */ new Set(); + sourceIdentity = secret(); async [Service.init]() { - const timeoutMs = this.config.healthTimeoutMs ?? 5e3; + await this.client.health(AbortSignal.timeout(this.config.healthTimeoutMs ?? 5e3), SCHEMA_VERSION); + } + async create(header, options) { + options?.signal?.throwIfAborted(); + const meta = materializeCreateHeader(header); + assertVersion(meta); + const inheritedEventCount = inheritedCount(meta, options?.inheritedEventCount); + if (this.writers.has(meta.id)) throw new SessionAlreadyExistsError(meta.id); + this.writers.set(meta.id, null); + let lock; try { - await this.client.health(AbortSignal.timeout(timeoutMs)); + lock = await this.acquireLock(meta.id); + if (await this.stat(meta.id, options)) throw new SessionAlreadyExistsError(meta.id); + options?.signal?.throwIfAborted(); + let writer = await this.credentials.get(meta.id); + if (writer === void 0) { + writer = { deviceId: this.config.deviceId, writerEpoch: 1, writerToken: secret() }; + await this.credentials.put(meta.id, writer); + } + this.assertDevice(meta.id, writer); + const result = await this.client.materializeSession({ + sessionId: meta.id, + header: meta, + inheritedEventCount, + deviceId: writer.deviceId, + writerToken: writer.writerToken, + idempotencyKey: `dsh-create-${sha256(canonicalJson({ meta, inheritedEventCount, token: writer.writerToken }))}`, + events: [] + }); + return this.adopt(new TeleportHandle( + this.client, + meta, + inheritedEventCount, + "write", + result.revision, + 0, + writer, + lock, + (handle) => this.release(handle) + )); } catch (error) { - throw new Error( - `Teleport service health check failed for ${this.config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`, - { cause: error } - ); + this.writers.delete(meta.id); + await lock?.close(); + if (remoteCode(error, "SESSION_EXISTS")) throw new SessionAlreadyExistsError(meta.id); + throw error; } } - locate(_meta) { - return void 0; - } - create(meta) { - return this.coordinator.create(meta); - } - append(id, events) { - return this.coordinator.append(id, events); - } - prepare(id, signal) { - return this.coordinator.prepare(id, signal); - } - load(id) { - return this.coordinator.load(id); - } - inspect(id, signal) { - return this.coordinator.inspect(id, signal); + async open(id, access, options) { + options?.signal?.throwIfAborted(); + if (access !== "read" && access !== "write") throw new TypeError("invalid session access"); + if (access === "write") { + if (this.writers.has(id)) throw new SessionAlreadyOwnedError(id); + this.writers.set(id, null); + } + let lock; + try { + if (access === "write") lock = await this.acquireLock(id); + const stored = await this.client.snapshot(id, -1, options?.signal); + const meta = storedHeader(id, stored); + const cut = inheritedCount(meta, stored.inheritedEventCount); + validateStoredEvents(meta, cloneEvents(stored.events)); + assertContiguous(id, stored.events, 0); + if (stored.events.length !== stored.nextSeq) throw new Error(`Incomplete Teleport log for ${id}`); + options?.signal?.throwIfAborted(); + const writer = access === "write" ? await this.requireWriter(id) : void 0; + if (writer !== void 0 && (writer.writerEpoch !== stored.writerEpoch || writer.deviceId !== stored.writerDeviceId)) { + throw new SessionOwnershipLostError(id); + } + return this.adopt(new TeleportHandle( + this.client, + meta, + cut, + access, + stored.revision, + stored.nextSeq, + writer, + lock, + (handle) => this.release(handle) + )); + } catch (error) { + if (access === "write") this.writers.delete(id); + await lock?.close(); + if (remoteCode(error, "NOT_FOUND")) throw new SessionPersistenceNotFoundError(id); + throw error; + } } - readFrom(id, fromSeq, signal) { - return this.coordinator.readFrom(id, fromSeq, signal); + async flush() { + const results = await Promise.allSettled([...this.writers.values()].map(async (handle) => { + try { + await handle?.flush(); + } catch (error) { + if (error instanceof SessionHandleClosedError) await handle?.close(); + else throw error; + } + })); + throwFailures(results, "Teleport flush failed"); } - async loadStored(id, signal) { - signal?.throwIfAborted(); - let snapshot; + async stat(id, options) { try { - snapshot = await this.client.snapshot(id); + return this.snapshot(await this.client.head(id, options?.signal)); } catch (error) { - if (isNotFound(error)) return void 0; + if (remoteCode(error, "NOT_FOUND")) return void 0; throw error; } - signal?.throwIfAborted(); - this.observe(id, snapshot.revision, snapshot.nextSeq); + } + async list(options) { + return (await this.client.listHeads(options?.signal)).map((head) => this.snapshot(head)); + } + async createHandoff(id, ttlMs) { + await this.writers.get(id)?.flush(); + return this.client.createHandoff({ + sessionId: id, + writer: await this.requireWriter(id), + ...ttlMs === void 0 ? {} : { ttlMs } + }); + } + async acceptHandoff(code) { + const result = await this.client.acceptHandoff({ code, deviceId: this.config.deviceId }); + await this.credentials.put(result.sessionId, result.writer); + return structuredClone(result.writer); + } + snapshot(head) { return { - meta: cloneHeader(snapshot.header), - events: cloneEvents(snapshot.events), - revision: this.revision(id, snapshot.revision) + header: structuredClone(head.header), + revision: SessionPersistenceRevision(`teleport:${this.sourceIdentity}:${head.sessionId}:${head.revision}`), + eventCount: head.nextSeq }; } - async readStoredRevision(id, signal) { - signal?.throwIfAborted(); - let head; + adopt(handle) { + this.handles.add(handle); + if (handle.access === "write") this.writers.set(handle.id, handle); + return handle; + } + release(handle) { + this.handles.delete(handle); + if (this.writers.get(handle.id) === handle) this.writers.delete(handle.id); + } + async requireWriter(id) { + const writer = await this.credentials.get(id); + if (writer === void 0) throw new SessionAlreadyOwnedError(id); + this.assertDevice(id, writer); + return writer; + } + assertDevice(id, writer) { + if (writer.deviceId !== this.config.deviceId) throw new SessionOwnershipLostError(id); + } + async acquireLock(id) { + const directory = join(this.config.credentialDir, "locks"); + await mkdir(directory, { recursive: true, mode: 448 }); + const lock = await openFile(join(directory, `${sha256(id)}.lock`), "a", 384); try { - head = await this.client.head(id); + await tryLockExclusive(lock.fd); + return lock; } catch (error) { - if (isNotFound(error)) return void 0; + await lock.close(); + if (error instanceof Error && "code" in error && ["EAGAIN", "EWOULDBLOCK"].includes(String(error.code))) { + throw new SessionAlreadyOwnedError(id); + } throw error; } - signal?.throwIfAborted(); - return this.revision(id, head.revision); } - async loadStoredFrom(id, fromSeq, signal) { - signal?.throwIfAborted(); - let snapshot; +} +class TeleportHandle { + constructor(client, header, inheritedEventCount, access, revision, cursor, writer, lock, release) { + this.client = client; + this.inheritedEventCount = inheritedEventCount; + this.access = access; + this.revision = revision; + this.cursor = cursor; + this.writer = writer; + this.lock = lock; + this.release = release; + this.id = header.id; + this.header = freezeHeader(header); + this.observedLength = cursor; + } + client; + inheritedEventCount; + access; + revision; + cursor; + writer; + lock; + release; + id; + header; + chain = Promise.resolve(); + closing; + lost = false; + pending = []; + retryBatch; + timer; + automaticPaused = false; + reportBackgroundError; + observedLength; + read(offset = 0, length = Number.MAX_SAFE_INTEGER, options) { + return this.run("read", async () => { + if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(length) || length < 0) { + throw new TypeError("read offset and length must be non-negative safe integers"); + } + const stored = await this.client.snapshot(this.id, -1, options?.signal); + const meta = storedHeader(this.id, stored); + if (canonicalJson(meta) !== canonicalJson(this.header) || inheritedCount(meta, stored.inheritedEventCount) !== this.inheritedEventCount) { + throw new Error(`Teleport metadata changed for ${this.id}`); + } + const events = validateStoredEvents(meta, cloneEvents(stored.events)); + assertContiguous(this.id, events, 0); + if (events.length < this.observedLength || events.length !== stored.nextSeq) { + throw new Error(`Teleport log shrank or is incomplete for ${this.id}`); + } + this.observedLength = events.length; + return { events: events.slice(offset, offset + length), eventState: "detached" }; + }); + } + append(events, options) { + let batch; try { - snapshot = await this.client.snapshot(id, fromSeq - 1); + this.assertOpen("append"); + batch = materializeAppendBatch(events); } catch (error) { - if (isNotFound(error)) return void 0; - throw error; + return Promise.reject(error); } - signal?.throwIfAborted(); - return { - meta: cloneHeader(snapshot.header), - events: cloneEvents(snapshot.events) - }; + return this.run("append", async () => { + this.assertWritable("append"); + options?.signal?.throwIfAborted(); + await this.drain(); + await this.persist(batch); + }); } - async appendBatch(meta, events, isMaterialized) { - if (events.length === 0) return; - const teleportEvents = cloneTeleportEvents(events); - if (!isMaterialized) { - let writer = await this.credentials.get(meta.id); - if (writer === void 0) { - writer = { - deviceId: this.deviceId, - writerEpoch: 1, - writerToken: secret() - }; - await this.credentials.put(meta.id, writer); + flush(options) { + return this.run("flush", async () => { + this.assertWritable("flush"); + options?.signal?.throwIfAborted(); + await this.drain(); + const head = await this.client.head(this.id); + if (head.writerEpoch !== this.writer.writerEpoch || head.writerDeviceId !== this.writer.deviceId) { + this.lost = true; + throw new SessionOwnershipLostError(this.id); } - this.assertLocalWriter(meta.id, writer); - const result = await this.client.materializeSession({ - sessionId: meta.id, - header: structuredClone(meta), - deviceId: writer.deviceId, - writerToken: writer.writerToken, - idempotencyKey: mutationKey("materialize", meta.id, 0, 0, { - header: meta, - events: teleportEvents - }), - events: teleportEvents - }); - this.observe(meta.id, result.revision, result.nextSeq); - return; - } - await this.appendExisting(meta.id, teleportEvents); - } - async commitRepair(meta, _tornMarker, closers) { - if (closers.length === 0) return; - await this.appendExisting(meta.id, cloneTeleportEvents(closers)); + this.automaticPaused = false; + this.scheduleBackground(); + }); } - async list(signal) { - signal?.throwIfAborted(); - const heads = await this.client.listHeads(); - signal?.throwIfAborted(); - return heads.map((head) => cloneHeader(head.header)); + enqueue(event, onError) { + if (this.closing !== void 0 || this.lost) return; + this.pending.push(...materializeAppendBatch([event])); + this.reportBackgroundError = onError; + this.scheduleBackground(); } - async listSnapshots(signal) { - signal?.throwIfAborted(); - const heads = await this.client.listHeads(); - signal?.throwIfAborted(); - return heads.map((head) => ({ - header: cloneHeader(head.header), - revision: this.revision(head.sessionId, head.revision) - })); + scheduleBackground() { + if (this.pending.length === 0 || this.automaticPaused || this.closing !== void 0 || this.timer !== void 0) return; + this.timer = setTimeout(() => { + this.timer = void 0; + void this.flush().catch((error) => { + this.automaticPaused = true; + if (this.timer !== void 0) clearTimeout(this.timer); + this.timer = void 0; + this.reportBackgroundError?.(error); + }); + }, 200); + this.timer.unref(); } - async createHandoff(id, ttlMs) { - const writer = await this.requireWriter(id); - return this.client.createHandoff({ - sessionId: id, - writer, - ...ttlMs === void 0 ? {} : { ttlMs } + close() { + if (this.closing !== void 0) return this.closing; + if (this.timer !== void 0) clearTimeout(this.timer); + this.closing = this.chain.then(async () => { + try { + if (this.access === "write") await this.drain(); + } finally { + try { + await this.lock?.close(); + } finally { + this.release(this); + } + } }); + return this.closing; } - async acceptHandoff(code) { - const accepted = await this.client.acceptHandoff({ code, deviceId: this.deviceId }); - await this.credentials.put(accepted.sessionId, accepted.writer); - this.observe(accepted.sessionId, accepted.revision, accepted.nextSeq); - return structuredClone(accepted.writer); + [Symbol.asyncDispose]() { + return this.close(); } - async appendExisting(id, events) { - const writer = await this.requireWriter(id); - const observed = this.observedHeads.get(id); - if (observed === void 0) { - throw new Error( - `session "${id}" has no observed Teleport head; load it before appending` - ); - } - const nextSeq = events[0].seq; - if (observed.nextSeq !== nextSeq) { - throw new Error( - `Teleport head changed for "${id}": observed next seq ${observed.nextSeq}, append starts at ${nextSeq}` - ); + run(operation, work) { + try { + this.assertOpen(operation); + } catch (error) { + return Promise.reject(error); } - const result = await this.client.append({ - sessionId: id, - writer, - expectedRevision: observed.revision, - expectedNextSeq: observed.nextSeq, - idempotencyKey: mutationKey( - "append", - id, - observed.revision, - observed.nextSeq, - events - ), - events + const result = this.chain.then(work); + this.chain = result.then(() => { + }, () => { }); - this.observe(id, result.revision, result.nextSeq); + return result; } - async requireWriter(id) { - const writer = await this.credentials.get(id); - if (writer === void 0) { - throw new Error( - `this device has no writer credential for session "${id}"; accept a Teleport handoff before appending` - ); - } - this.assertLocalWriter(id, writer); - return writer; + assertOpen(operation) { + if (this.closing !== void 0) throw new SessionHandleClosedError(this.id, operation); } - assertLocalWriter(id, writer) { - if (writer.deviceId !== this.deviceId) { - throw new Error( - `writer credential for session "${id}" belongs to device "${writer.deviceId}", not "${this.deviceId}"` - ); - } + assertWritable(operation) { + if (this.access !== "write") throw new SessionReadOnlyError(this.id, operation); + if (this.lost) throw new SessionOwnershipLostError(this.id); } - observe(id, revision, nextSeq) { - this.observedHeads.set(id, { revision, nextSeq }); + async drain() { + while (this.pending.length > 0) { + const batch = this.retryBatch ??= this.pending.slice(); + await this.persist(batch); + this.pending.splice(0, batch.length); + this.retryBatch = void 0; + } } - revision(id, revision) { - return SessionPersistenceRevision( - `teleport:${this.sourceIdentity}:session:${id}:revision:${revision}` - ); + async persist(batch) { + this.assertWritable("append"); + if (batch.length === 0) return; + assertContiguous(this.id, batch, this.cursor); + validateStoredEvents(this.header, [...batch]); + try { + const result = await this.client.append({ + sessionId: this.id, + writer: this.writer, + expectedRevision: this.revision, + expectedNextSeq: this.cursor, + idempotencyKey: `dsh-append-${sha256(canonicalJson({ id: this.id, revision: this.revision, cursor: this.cursor, batch }))}`, + events: structuredClone(batch) + }); + this.revision = result.revision; + this.cursor = result.nextSeq; + this.observedLength = Math.max(this.observedLength, this.cursor); + } catch (error) { + if (remoteCode(error, "WRITER_FENCED") || remoteCode(error, "REVISION_CONFLICT") || remoteCode(error, "SEQ_CONFLICT")) { + this.lost = true; + throw new SessionOwnershipLostError(this.id); + } + throw error; + } } } -function mutationKey(kind, sessionId, revision, nextSeq, value) { - return `dsh-${kind}-${sha256(canonicalJson({ sessionId, revision, nextSeq, value }))}`; +function storedHeader(id, stored) { + const header = structuredClone(stored.header); + assertVersion(header); + const meta = materializeCreateHeader(header); + assertStoredId(id, meta); + return meta; } -function cloneHeader(value) { - return structuredClone(value); +function inheritedCount(header, value) { + if (typeof header.isSeeded !== "boolean") throw new TypeError("session header requires isSeeded"); + if (header.isSeeded && value === void 0) throw new TypeError("seeded sessions require inheritedEventCount"); + const count = SessionLogOffset(value ?? 0); + if (!header.isSeeded && count !== 0) throw new TypeError("unseeded sessions require inheritedEventCount=0"); + return count; } -function cloneEvents(value) { - return structuredClone(value); +function cloneEvents(events) { + return structuredClone(events); } -function cloneTeleportEvents(value) { - return structuredClone(value); +function remoteCode(error, code) { + return error instanceof TeleportRemoteError && error.code === code; } -function isNotFound(error) { - return error instanceof TeleportRemoteError && error.code === "NOT_FOUND"; +function throwFailures(results, message) { + const failures = results.filter((result) => result.status === "rejected").map((result) => result.reason); + if (failures.length) throw new AggregateError(failures, message); } function validateConfig(config) { - if (typeof config.baseUrl !== "string" || config.baseUrl.length === 0) { - throw new TypeError("Teleport baseUrl is required"); - } - if (typeof config.deviceId !== "string" || config.deviceId.length === 0) { - throw new TypeError("Teleport deviceId is required"); - } - if (typeof config.credentialDir !== "string" || config.credentialDir.length === 0) { - throw new TypeError("Teleport credentialDir is required"); + for (const key of ["baseUrl", "deviceId", "credentialDir"]) { + if (typeof config[key] !== "string" || config[key].trim().length === 0) throw new TypeError(`${key} must not be empty`); } if (config.healthTimeoutMs !== void 0 && (!Number.isSafeInteger(config.healthTimeoutMs) || config.healthTimeoutMs <= 0)) { - throw new TypeError("Teleport healthTimeoutMs must be a positive integer"); + throw new TypeError("healthTimeoutMs must be a positive safe integer"); } } var dsh_adapter_default = SessionPersistenceTeleport; +function freezeHeader(header) { + const pending = [header]; + while (pending.length) { + const value = pending.pop(); + for (const child of Object.values(value)) { + if (child !== null && typeof child === "object") pending.push(child); + } + Object.freeze(value); + } + return header; +} export { SessionPersistenceTeleport, dsh_adapter_default as default diff --git a/dist/dsh-adapter.js.map b/dist/dsh-adapter.js.map index cbfaa7e..4b1d156 100644 --- a/dist/dsh-adapter.js.map +++ b/dist/dsh-adapter.js.map @@ -1,6 +1,6 @@ { "version": 3, "sources": ["../src/dsh-adapter.ts"], - "mappings": "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", + "mappings": "AAAA,SAAS,OAAO,QAAQ,gBAAiC;AACzD,SAAS,YAAY;AACrB,SAAkB,eAAe;AACjC,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EAA2B;AAAA,EAA0B;AAAA,EACrD;AAAA,EAA2B;AAAA,EAAoB;AAAA,EAC/C;AAAA,EAA4B;AAAA,EAAsB;AAAA,EAAkB;AAAA,EACpE;AAAA,EAAe;AAAA,EAAwB;AAAA,EAAyB;AAAA,OAM3D;AACP;AAAA,EACE;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,eAAe,QAAQ,cAAc;AAC9C,SAAS,iCAA6D;AACtE,SAAS,gBAAgB,2BAA2B;AAiB7C,MAAM,mCAAmC,mBAAmB;AAAA,EASjE,YAAY,KAAuB,QACjC,eAAuD,CAAC,GAAG;AAC3D,mBAAe,MAAM;AACrB,UAAM,GAAG;AAHwB;AAIjC,SAAK,SAAS,aAAa,UAAU,IAAI,eAAe,OAAO,SAAS,OAAO,QAAQ;AACvF,SAAK,cAAc,aAAa,mBAAmB,IAAI,0BAA0B,OAAO,aAAa;AACrG,SAAK,IAAI,GAAG,iBAAiB,CAAC,SAAS,UAAU;AAC/C,WAAK,QAAQ,IAAI,QAAQ,EAAE,GAAG,QAAQ,OAAO,CAAC,UAAU;AACtD,aAAK,IAAI,OAAO,KAAK,wCAAwC,QAAQ,EAAE,+BAA+B,OAAO,KAAK,CAAC,EAAE;AAAA,MACvH,CAAC;AAAA,IACH,CAAC;AACD,SAAK,IAAI,GAAG,iBAAiB,CAAC,YAAY,KAAK,QAAQ,IAAI,QAAQ,EAAE,GAAG,MAAM,CAAC;AAC/E,SAAK,IAAI,GAAG,oBAAoB,CAAC,YAAY;AAC3C,WAAK,QAAQ,IAAI,QAAQ,EAAE,GAAG,MAAM,EAAE,MAAM,CAAC,UAAmB;AAC9D,aAAK,IAAI,OAAO,KAAK,6BAA6B,QAAQ,EAAE,KAAK,OAAO,KAAK,CAAC,EAAE;AAAA,MAClF,CAAC;AAAA,IACH,CAAC;AACD,SAAK,IAAI,OAAO,MAAM,YAAY;AAChC,YAAM,UAAU,MAAM,QAAQ,WAAW,CAAC,GAAG,KAAK,OAAO,EAAE,IAAI,CAAC,WAAW,OAAO,MAAM,CAAC,CAAC;AAC1F,oBAAc,SAAS,iCAAiC;AAAA,IAC1D,GAAG,uBAAuB;AAAA,EAC5B;AAAA,EArBmC;AAAA,EARnC,OAAO,SAAS,CAAC,UAAU;AAAA,EACT,OAAO;AAAA,EACR;AAAA,EACA;AAAA,EACA,UAAU,oBAAI,IAAsC;AAAA,EACpD,UAAU,oBAAI,IAAoB;AAAA,EAClC,iBAAiB,OAAO;AAAA,EAyBzC,OAAiB,QAAQ,IAAI,IAAmB;AAC9C,UAAM,KAAK,OAAO,OAAO,YAAY,QAAQ,KAAK,OAAO,mBAAmB,GAAK,GAAG,cAAc;AAAA,EACpG;AAAA,EAEA,MAAM,OAAO,QAAuB,SAAmE;AACrG,aAAS,QAAQ,eAAe;AAChC,UAAM,OAAO,wBAAwB,MAAM;AAC3C,kBAAc,IAAI;AAClB,UAAM,sBAAsB,eAAe,MAAM,SAAS,mBAAmB;AAC7E,QAAI,KAAK,QAAQ,IAAI,KAAK,EAAE,EAAG,OAAM,IAAI,0BAA0B,KAAK,EAAE;AAC1E,SAAK,QAAQ,IAAI,KAAK,IAAI,IAAI;AAC9B,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,KAAK,YAAY,KAAK,EAAE;AACrC,UAAI,MAAM,KAAK,KAAK,KAAK,IAAI,OAAO,EAAG,OAAM,IAAI,0BAA0B,KAAK,EAAE;AAClF,eAAS,QAAQ,eAAe;AAChC,UAAI,SAAS,MAAM,KAAK,YAAY,IAAI,KAAK,EAAE;AAC/C,UAAI,WAAW,QAAW;AACxB,iBAAS,EAAE,UAAU,KAAK,OAAO,UAAU,aAAa,GAAG,aAAa,OAAO,EAAE;AAEjF,cAAM,KAAK,YAAY,IAAI,KAAK,IAAI,MAAM;AAAA,MAC5C;AACA,WAAK,aAAa,KAAK,IAAI,MAAM;AACjC,YAAM,SAAS,MAAM,KAAK,OAAO,mBAAmB;AAAA,QAClD,WAAW,KAAK;AAAA,QAAI,QAAQ;AAAA,QAA8B;AAAA,QAC1D,UAAU,OAAO;AAAA,QAAU,aAAa,OAAO;AAAA,QAC/C,gBAAgB,cAAc,OAAO,cAAc,EAAE,MAAM,qBAAqB,OAAO,OAAO,YAAY,CAAC,CAAC,CAAC;AAAA,QAC7G,QAAQ,CAAC;AAAA,MACX,CAAC;AACD,aAAO,KAAK,MAAM,IAAI;AAAA,QAAe,KAAK;AAAA,QAAQ;AAAA,QAAM;AAAA,QAAqB;AAAA,QAC3E,OAAO;AAAA,QAAU;AAAA,QAAG;AAAA,QAAQ;AAAA,QAAM,CAAC,WAAW,KAAK,QAAQ,MAAM;AAAA,MAAC,CAAC;AAAA,IACvE,SAAS,OAAO;AACd,WAAK,QAAQ,OAAO,KAAK,EAAE;AAC3B,YAAM,MAAM,MAAM;AAClB,UAAI,WAAW,OAAO,gBAAgB,EAAG,OAAM,IAAI,0BAA0B,KAAK,EAAE;AACpF,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,IAAe,QAAuB,SAAiE;AAChH,aAAS,QAAQ,eAAe;AAChC,QAAI,WAAW,UAAU,WAAW,QAAS,OAAM,IAAI,UAAU,wBAAwB;AACzF,QAAI,WAAW,SAAS;AACtB,UAAI,KAAK,QAAQ,IAAI,EAAE,EAAG,OAAM,IAAI,yBAAyB,EAAE;AAC/D,WAAK,QAAQ,IAAI,IAAI,IAAI;AAAA,IAC3B;AACA,QAAI;AACJ,QAAI;AACF,UAAI,WAAW,QAAS,QAAO,MAAM,KAAK,YAAY,EAAE;AACxD,YAAM,SAAS,MAAM,KAAK,OAAO,SAAS,IAAI,IAAI,SAAS,MAAM;AACjE,YAAM,OAAO,aAAa,IAAI,MAAM;AACpC,YAAM,MAAM,eAAe,MAAM,OAAO,mBAAmB;AAC3D,2BAAqB,MAAM,YAAY,OAAO,MAAM,CAAC;AACrD,uBAAiB,IAAI,OAAO,QAAqC,CAAC;AAClE,UAAI,OAAO,OAAO,WAAW,OAAO,QAAS,OAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAChG,eAAS,QAAQ,eAAe;AAChC,YAAM,SAAS,WAAW,UAAU,MAAM,KAAK,cAAc,EAAE,IAAI;AACnE,UAAI,WAAW,WAAc,OAAO,gBAAgB,OAAO,eAAe,OAAO,aAAa,OAAO,iBAAiB;AACpH,cAAM,IAAI,0BAA0B,EAAE;AAAA,MACxC;AACA,aAAO,KAAK,MAAM,IAAI;AAAA,QAAe,KAAK;AAAA,QAAQ;AAAA,QAAM;AAAA,QAAK;AAAA,QAAQ,OAAO;AAAA,QAC1E,OAAO;AAAA,QAAS;AAAA,QAAQ;AAAA,QAAM,CAAC,WAAW,KAAK,QAAQ,MAAM;AAAA,MAAC,CAAC;AAAA,IACnE,SAAS,OAAO;AACd,UAAI,WAAW,QAAS,MAAK,QAAQ,OAAO,EAAE;AAC9C,YAAM,MAAM,MAAM;AAClB,UAAI,WAAW,OAAO,WAAW,EAAG,OAAM,IAAI,gCAAgC,EAAE;AAChF,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,UAAU,MAAM,QAAQ,WAAW,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,OAAO,WAAW;AACxF,UAAI;AAAE,cAAM,QAAQ,MAAM;AAAA,MAAG,SACtB,OAAO;AACZ,YAAI,iBAAiB,yBAA0B,OAAM,QAAQ,MAAM;AAAA,YAC9D,OAAM;AAAA,MACb;AAAA,IACF,CAAC,CAAC;AACF,kBAAc,SAAS,uBAAuB;AAAA,EAChD;AAAA,EAEA,MAAM,KAAK,IAAe,SAA0F;AAClH,QAAI;AAAE,aAAO,KAAK,SAAS,MAAM,KAAK,OAAO,KAAK,IAAI,SAAS,MAAM,CAAC;AAAA,IAAG,SAClE,OAAO;AAAE,UAAI,WAAW,OAAO,WAAW,EAAG,QAAO;AAAW,YAAM;AAAA,IAAO;AAAA,EACrF;AAAA,EAEA,MAAM,KAAK,SAAyF;AAClG,YAAQ,MAAM,KAAK,OAAO,UAAU,SAAS,MAAM,GAAG,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC;AAAA,EACzF;AAAA,EAEA,MAAM,cAAc,IAAe,OAA8C;AAC/E,UAAM,KAAK,QAAQ,IAAI,EAAE,GAAG,MAAM;AAClC,WAAO,KAAK,OAAO,cAAc;AAAA,MAAE,WAAW;AAAA,MAAI,QAAQ,MAAM,KAAK,cAAc,EAAE;AAAA,MACnF,GAAI,UAAU,SAAY,CAAC,IAAI,EAAE,MAAM;AAAA,IAAG,CAAC;AAAA,EAC/C;AAAA,EAEA,MAAM,cAAc,MAA0C;AAC5D,UAAM,SAAS,MAAM,KAAK,OAAO,cAAc,EAAE,MAAM,UAAU,KAAK,OAAO,SAAS,CAAC;AACvF,UAAM,KAAK,YAAY,IAAI,OAAO,WAAW,OAAO,MAAM;AAC1D,WAAO,gBAAgB,OAAO,MAAM;AAAA,EACtC;AAAA,EAEQ,SAAS,MAA+C;AAC9D,WAAO;AAAA,MAAE,QAAQ,gBAAgB,KAAK,MAAM;AAAA,MAC1C,UAAU,2BAA2B,YAAY,KAAK,cAAc,IAAI,KAAK,SAAS,IAAI,KAAK,QAAQ,EAAE;AAAA,MACzG,YAAY,KAAK;AAAA,IAAQ;AAAA,EAC7B;AAAA,EAEQ,MAAM,QAAwC;AACpD,SAAK,QAAQ,IAAI,MAAM;AACvB,QAAI,OAAO,WAAW,QAAS,MAAK,QAAQ,IAAI,OAAO,IAAI,MAAM;AACjE,WAAO;AAAA,EACT;AAAA,EAEQ,QAAQ,QAA8B;AAC5C,SAAK,QAAQ,OAAO,MAAM;AAC1B,QAAI,KAAK,QAAQ,IAAI,OAAO,EAAE,MAAM,OAAQ,MAAK,QAAQ,OAAO,OAAO,EAAE;AAAA,EAC3E;AAAA,EAEA,MAAc,cAAc,IAAwC;AAClE,UAAM,SAAS,MAAM,KAAK,YAAY,IAAI,EAAE;AAC5C,QAAI,WAAW,OAAW,OAAM,IAAI,yBAAyB,EAAe;AAC5E,SAAK,aAAa,IAAI,MAAM;AAC5B,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,IAAY,QAAiC;AAChE,QAAI,OAAO,aAAa,KAAK,OAAO,SAAU,OAAM,IAAI,0BAA0B,EAAe;AAAA,EACnG;AAAA,EAEA,MAAc,YAAY,IAAoC;AAI5D,UAAM,YAAY,KAAK,KAAK,OAAO,eAAe,OAAO;AACzD,UAAM,MAAM,WAAW,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACvD,UAAM,OAAO,MAAM,SAAS,KAAK,WAAW,GAAG,OAAO,EAAE,CAAC,OAAO,GAAG,KAAK,GAAK;AAC7E,QAAI;AAAE,YAAM,iBAAiB,KAAK,EAAE;AAAG,aAAO;AAAA,IAAM,SAC7C,OAAO;AACZ,YAAM,KAAK,MAAM;AACjB,UAAI,iBAAiB,SAAS,UAAU,SAAS,CAAC,UAAU,aAAa,EAAE,SAAS,OAAO,MAAM,IAAI,CAAC,GAAG;AACvG,cAAM,IAAI,yBAAyB,EAAE;AAAA,MACvC;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,MAAM,eAAwC;AAAA,EAa5C,YAA6B,QAAwB,QAC1C,qBAAgD,QACjD,UAA0B,QAAiC,QAClD,MAA+C,SAA2C;AAHhF;AAClB;AAAgD;AACjD;AAA0B;AAAiC;AAClD;AAA+C;AAChE,SAAK,KAAK,OAAO;AACjB,SAAK,SAAS,aAAa,MAAM;AACjC,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAP6B;AAAA,EAClB;AAAA,EAAgD;AAAA,EACjD;AAAA,EAA0B;AAAA,EAAiC;AAAA,EAClD;AAAA,EAA+C;AAAA,EAfzD;AAAA,EACA;AAAA,EACD,QAAuB,QAAQ,QAAQ;AAAA,EACvC;AAAA,EACA,OAAO;AAAA,EACP,UAA0B,CAAC;AAAA,EAC3B;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EAWR,KAAK,SAAS,GAAG,SAAS,OAAO,kBAAkB,SAAsE;AACvH,WAAO,KAAK,IAAI,QAAQ,YAAY;AAClC,UAAI,CAAC,OAAO,cAAc,MAAM,KAAK,SAAS,KAAK,CAAC,OAAO,cAAc,MAAM,KAAK,SAAS,GAAG;AAC9F,cAAM,IAAI,UAAU,2DAA2D;AAAA,MACjF;AACA,YAAM,SAAS,MAAM,KAAK,OAAO,SAAS,KAAK,IAAI,IAAI,SAAS,MAAM;AACtE,YAAM,OAAO,aAAa,KAAK,IAAI,MAAM;AACzC,UAAI,cAAc,IAAI,MAAM,cAAc,KAAK,MAAM,KAAK,eAAe,MAAM,OAAO,mBAAmB,MAAM,KAAK,qBAAqB;AACvI,cAAM,IAAI,MAAM,iCAAiC,KAAK,EAAE,EAAE;AAAA,MAC5D;AACA,YAAM,SAAS,qBAAqB,MAAM,YAAY,OAAO,MAAM,CAAC;AACpE,uBAAiB,KAAK,IAAI,QAAQ,CAAC;AACnC,UAAI,OAAO,SAAS,KAAK,kBAAkB,OAAO,WAAW,OAAO,SAAS;AAC3E,cAAM,IAAI,MAAM,4CAA4C,KAAK,EAAE,EAAE;AAAA,MACvE;AACA,WAAK,iBAAiB,OAAO;AAC7B,aAAO,EAAE,QAAQ,OAAO,MAAM,QAAQ,SAAS,MAAM,GAAG,YAAY,WAAW;AAAA,IACjF,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,QAAiC,SAAqD;AAE3F,QAAI;AACJ,QAAI;AAAE,WAAK,WAAW,QAAQ;AAAG,cAAQ,uBAAuB,MAAM;AAAA,IAAG,SAClE,OAAO;AAAE,aAAO,QAAQ,OAAO,KAAK;AAAA,IAAG;AAC9C,WAAO,KAAK,IAAI,UAAU,YAAY;AACpC,WAAK,eAAe,QAAQ;AAC5B,eAAS,QAAQ,eAAe;AAChC,YAAM,KAAK,MAAM;AACjB,YAAM,KAAK,QAAQ,KAAK;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,SAAoD;AACxD,WAAO,KAAK,IAAI,SAAS,YAAY;AACnC,WAAK,eAAe,OAAO;AAC3B,eAAS,QAAQ,eAAe;AAChC,YAAM,KAAK,MAAM;AAGjB,YAAM,OAAO,MAAM,KAAK,OAAO,KAAK,KAAK,EAAE;AAC3C,UAAI,KAAK,gBAAgB,KAAK,OAAQ,eAAe,KAAK,mBAAmB,KAAK,OAAQ,UAAU;AAClG,aAAK,OAAO;AACZ,cAAM,IAAI,0BAA0B,KAAK,EAAE;AAAA,MAC7C;AACA,WAAK,kBAAkB;AACvB,WAAK,mBAAmB;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,OAAqB,SAAyC;AACpE,QAAI,KAAK,YAAY,UAAa,KAAK,KAAM;AAC7C,SAAK,QAAQ,KAAK,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;AACpD,SAAK,wBAAwB;AAC7B,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEQ,qBAA2B;AACjC,QAAI,KAAK,QAAQ,WAAW,KAAK,KAAK,mBAAmB,KAAK,YAAY,UAAa,KAAK,UAAU,OAAW;AACjH,SAAK,QAAQ,WAAW,MAAM;AAC5B,WAAK,QAAQ;AAGb,WAAK,KAAK,MAAM,EAAE,MAAM,CAAC,UAAmB;AAC1C,aAAK,kBAAkB;AACvB,YAAI,KAAK,UAAU,OAAW,cAAa,KAAK,KAAK;AACrD,aAAK,QAAQ;AACb,aAAK,wBAAwB,KAAK;AAAA,MACpC,CAAC;AAAA,IACH,GAAG,GAAG;AACN,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA,EAEA,QAAuB;AACrB,QAAI,KAAK,YAAY,OAAW,QAAO,KAAK;AAC5C,QAAI,KAAK,UAAU,OAAW,cAAa,KAAK,KAAK;AACrD,SAAK,UAAU,KAAK,MAAM,KAAK,YAAY;AACzC,UAAI;AAAE,YAAI,KAAK,WAAW,QAAS,OAAM,KAAK,MAAM;AAAA,MAAG,UACvD;AAAU,YAAI;AAAE,gBAAM,KAAK,MAAM,MAAM;AAAA,QAAG,UAAE;AAAU,eAAK,QAAQ,IAAI;AAAA,QAAG;AAAA,MAAE;AAAA,IAC9E,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,CAAC,OAAO,YAAY,IAAmB;AAAE,WAAO,KAAK,MAAM;AAAA,EAAG;AAAA,EAEtD,IAAO,WAAmB,MAAoC;AACpE,QAAI;AAAE,WAAK,WAAW,SAAS;AAAA,IAAG,SAAS,OAAO;AAAE,aAAO,QAAQ,OAAO,KAAK;AAAA,IAAG;AAClF,UAAM,SAAS,KAAK,MAAM,KAAK,IAAI;AACnC,SAAK,QAAQ,OAAO,KAAK,MAAM;AAAA,IAAC,GAAG,MAAM;AAAA,IAAC,CAAC;AAC3C,WAAO;AAAA,EACT;AAAA,EAEQ,WAAW,WAAyB;AAC1C,QAAI,KAAK,YAAY,OAAW,OAAM,IAAI,yBAAyB,KAAK,IAAI,SAAS;AAAA,EACvF;AAAA,EAEQ,eAAe,WAAyB;AAC9C,QAAI,KAAK,WAAW,QAAS,OAAM,IAAI,qBAAqB,KAAK,IAAI,SAAS;AAC9E,QAAI,KAAK,KAAM,OAAM,IAAI,0BAA0B,KAAK,EAAE;AAAA,EAC5D;AAAA,EAEA,MAAc,QAAuB;AACnC,WAAO,KAAK,QAAQ,SAAS,GAAG;AAG9B,YAAM,QAAQ,KAAK,eAAe,KAAK,QAAQ,MAAM;AACrD,YAAM,KAAK,QAAQ,KAAK;AACxB,WAAK,QAAQ,OAAO,GAAG,MAAM,MAAM;AACnC,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAc,QAAQ,OAA+C;AACnE,SAAK,eAAe,QAAQ;AAC5B,QAAI,MAAM,WAAW,EAAG;AACxB,qBAAiB,KAAK,IAAI,OAAO,KAAK,MAAM;AAE5C,yBAAqB,KAAK,QAAQ,CAAC,GAAG,KAAK,CAAC;AAC5C,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,OAAO,OAAO;AAAA,QAAE,WAAW,KAAK;AAAA,QAAI,QAAQ,KAAK;AAAA,QACzE,kBAAkB,KAAK;AAAA,QAAU,iBAAiB,KAAK;AAAA,QACvD,gBAAgB,cAAc,OAAO,cAAc,EAAE,IAAI,KAAK,IAAI,UAAU,KAAK,UAAU,QAAQ,KAAK,QAAQ,MAAM,CAAC,CAAC,CAAC;AAAA,QACzH,QAAQ,gBAAgB,KAAK;AAAA,MAAgC,CAAC;AAChE,WAAK,WAAW,OAAO;AACvB,WAAK,SAAS,OAAO;AACrB,WAAK,iBAAiB,KAAK,IAAI,KAAK,gBAAgB,KAAK,MAAM;AAAA,IACjE,SAAS,OAAO;AACd,UAAI,WAAW,OAAO,eAAe,KAAK,WAAW,OAAO,mBAAmB,KAAK,WAAW,OAAO,cAAc,GAAG;AACrH,aAAK,OAAO;AACZ,cAAM,IAAI,0BAA0B,KAAK,EAAE;AAAA,MAC7C;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,SAAS,aAAa,IAAe,QAAoC;AACvE,QAAM,SAAS,gBAAgB,OAAO,MAAM;AAC5C,gBAAc,MAAM;AACpB,QAAM,OAAO,wBAAwB,MAAM;AAC3C,iBAAe,IAAI,IAAI;AACvB,SAAO;AACT;AAEA,SAAS,eAAe,QAAuB,OAAkC;AAC/E,MAAI,OAAO,OAAO,aAAa,UAAW,OAAM,IAAI,UAAU,kCAAkC;AAChG,MAAI,OAAO,YAAY,UAAU,OAAW,OAAM,IAAI,UAAU,6CAA6C;AAC7G,QAAM,QAAQ,iBAAiB,SAAS,CAAC;AACzC,MAAI,CAAC,OAAO,YAAY,UAAU,EAAG,OAAM,IAAI,UAAU,iDAAiD;AAC1G,SAAO;AACT;AAEA,SAAS,YAAY,QAAyC;AAC5D,SAAO,gBAAgB,MAAM;AAC/B;AAEA,SAAS,WAAW,OAAgB,MAAuB;AACzD,SAAO,iBAAiB,uBAAuB,MAAM,SAAS;AAChE;AAEA,SAAS,cAAc,SAA0C,SAAuB;AACtF,QAAM,WAAW,QAAQ,OAAO,CAAC,WAAW,OAAO,WAAW,UAAU,EAAE,IAAI,CAAC,WAAW,OAAO,MAAiB;AAClH,MAAI,SAAS,OAAQ,OAAM,IAAI,eAAe,UAAU,OAAO;AACjE;AAEA,SAAS,eAAe,QAAgD;AACtE,aAAW,OAAO,CAAC,WAAW,YAAY,eAAe,GAAY;AACnE,QAAI,OAAO,OAAO,GAAG,MAAM,YAAY,OAAO,GAAG,EAAE,KAAK,EAAE,WAAW,EAAG,OAAM,IAAI,UAAU,GAAG,GAAG,oBAAoB;AAAA,EACxH;AACA,MAAI,OAAO,oBAAoB,WAAc,CAAC,OAAO,cAAc,OAAO,eAAe,KAAK,OAAO,mBAAmB,IAAI;AAC1H,UAAM,IAAI,UAAU,iDAAiD;AAAA,EACvE;AACF;AAEA,IAAO,sBAAQ;AAEf,SAAS,aAAa,QAAsC;AAC1D,QAAM,UAAoB,CAAC,MAAM;AACjC,SAAO,QAAQ,QAAQ;AACrB,UAAM,QAAQ,QAAQ,IAAI;AAC1B,eAAW,SAAS,OAAO,OAAO,KAAK,GAAG;AACxC,UAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,SAAQ,KAAK,KAAK;AAAA,IACrE;AACA,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,SAAO;AACT;", "names": [] } diff --git a/dist/importer.d.ts b/dist/importer.d.ts index 5fdc10e..c4e30f2 100644 --- a/dist/importer.d.ts +++ b/dist/importer.d.ts @@ -6,7 +6,21 @@ export interface SessionImportClient { rollbackImport(request: RollbackSessionImportRequest): Promise; } export interface SessionSnapshotSource { - inspect(sessionId: string, signal?: AbortSignal): Promise<{ + /** Current DSH handle seam; kept structural so the overlay has no runtime peers. */ + open?(sessionId: string, access: "read", options?: { + signal?: AbortSignal; + }): Promise<{ + header: unknown; + inheritedEventCount: number; + read(offset?: number, length?: number, options?: { + signal?: AbortSignal; + }): Promise<{ + events: readonly unknown[]; + }>; + close(): Promise; + }>; + /** Legacy source profiles can still export an archival bundle. */ + inspect?(sessionId: string, signal?: AbortSignal): Promise<{ meta: unknown; events: readonly unknown[]; }>; @@ -21,8 +35,8 @@ export interface SessionImporterOptions { actorId?: string; now?: () => number; } -/** Build a portable import file from any existing backend's consistent inspect result. */ -export declare function createSessionImportBundle(header: unknown, events: readonly unknown[]): SessionImportBundle; +/** Build a portable import file from a consistent storage read. */ +export declare function createSessionImportBundle(header: unknown, events: readonly unknown[], inheritedEventCount?: number): SessionImportBundle; /** Read one consistent Session through the existing persistence seam. */ export declare function exportSessionImportBundle(source: SessionSnapshotSource, sessionId: string, signal?: AbortSignal): Promise; /** Strictly validate identity, JSON shape and the exact contiguous event prefix. */ diff --git a/dist/importer.js b/dist/importer.js index a21d949..d0a0851 100644 --- a/dist/importer.js +++ b/dist/importer.js @@ -6,19 +6,35 @@ import { SESSION_IMPORT_FORMAT, TeleportError } from "./types.js"; -function createSessionImportBundle(header, events) { +function createSessionImportBundle(header, events, inheritedEventCount) { return parseSessionImportBundle({ format: SESSION_IMPORT_FORMAT, header, - events + events, + ...inheritedEventCount === void 0 ? {} : { inheritedEventCount } }); } async function exportSessionImportBundle(source, sessionId, signal) { assertIdentifier(sessionId, "sessionId"); signal?.throwIfAborted(); - const snapshot = await source.inspect(sessionId, signal); - signal?.throwIfAborted(); - const bundle = createSessionImportBundle(snapshot.meta, snapshot.events); + let bundle; + if (source.open !== void 0) { + const options = signal === void 0 ? {} : { signal }; + const handle = await source.open(sessionId, "read", options); + try { + const snapshot = await handle.read(0, void 0, options); + signal?.throwIfAborted(); + bundle = createSessionImportBundle(handle.header, snapshot.events, handle.inheritedEventCount); + } finally { + await handle.close(); + } + } else if (source.inspect !== void 0) { + const snapshot = await source.inspect(sessionId, signal); + signal?.throwIfAborted(); + bundle = createSessionImportBundle(snapshot.meta, snapshot.events); + } else { + throw new TypeError("source persistence supports neither open nor inspect"); + } if (sessionIdOf(bundle) !== sessionId) { throw new TeleportError( "BAD_REQUEST", @@ -43,8 +59,8 @@ function parseSessionImportBundle(value) { } const sessionId = candidate.header.id; assertIdentifier(sessionId, "import bundle header.id"); - if (!Array.isArray(candidate.events) || candidate.events.length === 0) { - throw new TeleportError("BAD_REQUEST", "import bundle requires at least one event"); + if (!Array.isArray(candidate.events)) { + throw new TeleportError("BAD_REQUEST", "import bundle events must be an array"); } for (const [index, value2] of candidate.events.entries()) { if (value2 === null || typeof value2 !== "object" || Array.isArray(value2)) { @@ -75,12 +91,23 @@ function parseSessionImportBundle(value) { } } } + const seeded = candidate.header.isSeeded === true; + if (seeded && candidate.inheritedEventCount === void 0) { + throw new TeleportError("BAD_REQUEST", "seeded import requires inheritedEventCount"); + } + if (candidate.inheritedEventCount !== void 0) { + safeNonNegative(candidate.inheritedEventCount, "inheritedEventCount"); + if (!seeded && candidate.inheritedEventCount !== 0 || candidate.inheritedEventCount > candidate.events.length) { + throw new TeleportError("BAD_REQUEST", "inheritedEventCount does not match the imported prefix"); + } + } canonicalJson(candidate.header); canonicalJson(candidate.events); return structuredClone({ format: SESSION_IMPORT_FORMAT, header: candidate.header, - events: candidate.events + events: candidate.events, + ...seeded ? { inheritedEventCount: candidate.inheritedEventCount } : {} }); } function sessionImportDigest(bundle) { @@ -89,6 +116,7 @@ function sessionImportDigest(bundle) { canonicalJson({ format: parsed.format, header: parsed.header, + ...parsed.inheritedEventCount === void 0 ? {} : { inheritedEventCount: parsed.inheritedEventCount }, // PostgreSQL JSON preserves event-object key order. Bind the digest to // each original envelope encoding while keeping JSONB header order neutral. eventJson: parsed.events.map((event) => JSON.stringify(event)) @@ -178,6 +206,7 @@ class SessionImporter { const result = await this.client.materializeSession({ sessionId: plan.sessionId, header: bundle.header, + ...bundle.inheritedEventCount === void 0 ? {} : { inheritedEventCount: bundle.inheritedEventCount }, deviceId: writer.deviceId, writerToken: writer.writerToken, idempotencyKey, @@ -320,7 +349,7 @@ function sessionIdOf(bundle) { } function snapshotDigest(snapshot) { return sessionImportDigest( - createSessionImportBundle(snapshot.header, snapshot.events) + createSessionImportBundle(snapshot.header, snapshot.events, snapshot.inheritedEventCount) ); } function validateReceipt(value, expectedSessionId) { @@ -330,7 +359,7 @@ function validateReceipt(value, expectedSessionId) { const receipt = value; if (receipt.version !== 1 || receipt.sessionId !== expectedSessionId || typeof receipt.digest !== "string" || !/^[a-f0-9]{64}$/.test(receipt.digest) || !new RegExp(`^dsh-import-${receipt.digest}-[a-f0-9]{64}$`).test( receipt.idempotencyKey ?? "" - ) || receipt.revision !== 1 || !Number.isSafeInteger(receipt.nextSeq) || receipt.nextSeq < 1 || receipt.writerEpoch !== 1 || typeof receipt.deviceId !== "string" || receipt.deviceId.length === 0 || typeof receipt.createdAt !== "string" || !Number.isFinite(new Date(receipt.createdAt).getTime())) { + ) || receipt.revision !== 1 || !Number.isSafeInteger(receipt.nextSeq) || receipt.nextSeq < 0 || receipt.writerEpoch !== 1 || typeof receipt.deviceId !== "string" || receipt.deviceId.length === 0 || typeof receipt.createdAt !== "string" || !Number.isFinite(new Date(receipt.createdAt).getTime())) { throw new TypeError("receipt fields are invalid"); } return structuredClone(receipt); diff --git a/dist/importer.js.map b/dist/importer.js.map index 223a96a..0fb8582 100644 --- a/dist/importer.js.map +++ b/dist/importer.js.map @@ -1,6 +1,6 @@ { "version": 3, "sources": ["../src/importer.ts"], - "mappings": "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", + "mappings": "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", "names": ["value"] } diff --git a/dist/schema.d.ts b/dist/schema.d.ts index 85a4d58..3a8ab8b 100644 --- a/dist/schema.d.ts +++ b/dist/schema.d.ts @@ -1,3 +1,3 @@ import type { SqlDatabase } from "./database.js"; -export declare const SCHEMA_VERSION = 4; +export declare const SCHEMA_VERSION = 5; export declare function initializeSchema(database: SqlDatabase): Promise; diff --git a/dist/schema.js b/dist/schema.js index a51f781..5c79d1d 100644 --- a/dist/schema.js +++ b/dist/schema.js @@ -1,4 +1,4 @@ -const SCHEMA_VERSION = 4; +const SCHEMA_VERSION = 5; const STATEMENTS = [ `CREATE TABLE IF NOT EXISTS teleport_schema_meta ( key TEXT PRIMARY KEY, @@ -15,6 +15,8 @@ const STATEMENTS = [ created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP )`, + `ALTER TABLE teleport_sessions ADD COLUMN IF NOT EXISTS inherited_event_count BIGINT + CHECK (inherited_event_count >= 0)`, `CREATE TABLE IF NOT EXISTS teleport_events ( session_id TEXT NOT NULL REFERENCES teleport_sessions(session_id) ON DELETE CASCADE, seq BIGINT NOT NULL CHECK (seq >= 0), @@ -67,7 +69,7 @@ const STATEMENTS = [ actor_id TEXT NOT NULL, reason TEXT NOT NULL, rolled_back_revision BIGINT NOT NULL CHECK (rolled_back_revision >= 1), - rolled_back_next_seq BIGINT NOT NULL CHECK (rolled_back_next_seq >= 1), + rolled_back_next_seq BIGINT NOT NULL CHECK (rolled_back_next_seq >= 0), rolled_back_writer_epoch BIGINT NOT NULL CHECK (rolled_back_writer_epoch >= 1), created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (session_id, import_idempotency_key) @@ -87,6 +89,13 @@ async function initializeSchema(database) { ); return; } + if ([1, 2, 3, 4].includes(Number(version))) { + await transaction.query(`ALTER TABLE teleport_import_rollback_audit + DROP CONSTRAINT IF EXISTS teleport_import_rollback_audit_rolled_back_next_seq_check`); + await transaction.query(`ALTER TABLE teleport_import_rollback_audit + ADD CONSTRAINT teleport_import_rollback_audit_rolled_back_next_seq_check + CHECK (rolled_back_next_seq >= 0)`); + } if (Number(version) === 1) { const count = await transaction.query( `SELECT COUNT(*) AS count FROM teleport_events` @@ -112,7 +121,7 @@ async function initializeSchema(database) { ); return; } - if (Number(version) === 3) { + if (Number(version) === 3 || Number(version) === 4) { await transaction.query( `UPDATE teleport_schema_meta SET value = $1 WHERE key = 'schema_version'`, [String(SCHEMA_VERSION)] diff --git a/dist/schema.js.map b/dist/schema.js.map index 5ba3636..2573aca 100644 --- a/dist/schema.js.map +++ b/dist/schema.js.map @@ -1,6 +1,6 @@ { "version": 3, "sources": ["../src/schema.ts"], - "mappings": "AAEO,MAAM,iBAAiB;AAE9B,MAAM,aAAa;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYF;AAEA,eAAsB,iBAAiB,UAAsC;AAC3E,QAAM,SAAS,YAAY,OAAO,gBAAgB;AAChD,eAAW,aAAa,WAAY,OAAM,YAAY,MAAM,SAAS;AACrE,UAAM,SAAS,MAAM,YAAY;AAAA,MAC/B;AAAA,IACF;AACA,UAAM,UAAU,OAAO,KAAK,CAAC,GAAG;AAChC,QAAI,YAAY,QAAW;AACzB,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,CAAC,OAAO,cAAc,CAAC;AAAA,MACzB;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,MAAM,GAAG;AAIzB,YAAM,QAAQ,MAAM,YAAY;AAAA,QAC9B;AAAA,MACF;AACA,UAAI,OAAO,MAAM,KAAK,CAAC,GAAG,SAAS,CAAC,IAAI,GAAG;AACzC,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,YAAM,YAAY;AAAA,QAChB;AAAA,MACF;AACA,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,CAAC,OAAO,cAAc,CAAC;AAAA,MACzB;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,MAAM,GAAG;AACzB,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,CAAC,OAAO,cAAc,CAAC;AAAA,MACzB;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,MAAM,GAAG;AACzB,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,CAAC,OAAO,cAAc,CAAC;AAAA,MACzB;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,MAAM,gBAAgB;AACtC,YAAM,IAAI;AAAA,QACR,oCAAoC,OAAO,qCAAqC,cAAc;AAAA,MAChG;AAAA,IACF;AAAA,EACF,CAAC;AACH;", + "mappings": "AAEO,MAAM,iBAAiB;AAE9B,MAAM,aAAa;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYF;AAEA,eAAsB,iBAAiB,UAAsC;AAC3E,QAAM,SAAS,YAAY,OAAO,gBAAgB;AAChD,eAAW,aAAa,WAAY,OAAM,YAAY,MAAM,SAAS;AACrE,UAAM,SAAS,MAAM,YAAY;AAAA,MAC/B;AAAA,IACF;AACA,UAAM,UAAU,OAAO,KAAK,CAAC,GAAG;AAChC,QAAI,YAAY,QAAW;AACzB,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,CAAC,OAAO,cAAc,CAAC;AAAA,MACzB;AACA;AAAA,IACF;AACA,QAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,SAAS,OAAO,OAAO,CAAC,GAAG;AAC1C,YAAM,YAAY,MAAM;AAAA,4FAC8D;AACtF,YAAM,YAAY,MAAM;AAAA;AAAA,0CAEY;AAAA,IACtC;AACA,QAAI,OAAO,OAAO,MAAM,GAAG;AAIzB,YAAM,QAAQ,MAAM,YAAY;AAAA,QAC9B;AAAA,MACF;AACA,UAAI,OAAO,MAAM,KAAK,CAAC,GAAG,SAAS,CAAC,IAAI,GAAG;AACzC,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,YAAM,YAAY;AAAA,QAChB;AAAA,MACF;AACA,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,CAAC,OAAO,cAAc,CAAC;AAAA,MACzB;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,MAAM,GAAG;AACzB,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,CAAC,OAAO,cAAc,CAAC;AAAA,MACzB;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,MAAM,KAAK,OAAO,OAAO,MAAM,GAAG;AAClD,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,CAAC,OAAO,cAAc,CAAC;AAAA,MACzB;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,MAAM,gBAAgB;AACtC,YAAM,IAAI;AAAA,QACR,oCAAoC,OAAO,qCAAqC,cAAc;AAAA,MAChG;AAAA,IACF;AAAA,EACF,CAAC;AACH;", "names": [] } diff --git a/dist/server.js b/dist/server.js index 15ae799..85f9d58 100644 --- a/dist/server.js +++ b/dist/server.js @@ -1,3 +1,4 @@ +import { SCHEMA_VERSION } from "./schema.js"; import { createServer } from "node:http"; import { timingSafeEqual } from "node:crypto"; import { TeleportError } from "./types.js"; @@ -9,7 +10,7 @@ function createTeleportServer(authority, options = {}) { if (request.url === "/health") { try { await authority.checkHealth(); - sendJson(response, 200, { ok: true, database: "ready" }); + sendJson(response, 200, { ok: true, database: "ready", schemaVersion: SCHEMA_VERSION }); } catch { sendJson(response, 503, { ok: false, database: "unavailable" }); } diff --git a/dist/server.js.map b/dist/server.js.map index f532bd6..5a23c48 100644 --- a/dist/server.js.map +++ b/dist/server.js.map @@ -1,6 +1,6 @@ { "version": 3, "sources": ["../src/server.ts"], - "mappings": "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", + "mappings": "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", "names": [] } diff --git a/dist/source-capture.d.ts b/dist/source-capture.d.ts index efe8aa9..73a714f 100644 --- a/dist/source-capture.d.ts +++ b/dist/source-capture.d.ts @@ -25,7 +25,7 @@ export interface ProfileCaptureOptions { environment?: NodeJS.ProcessEnv; sourcePluginUrl?: string; } -/** Export one consistent inspect() result to a no-clobber owner-only file. */ +/** Export one consistent storage read to a no-clobber owner-only file. */ export declare function captureSessionBundle(source: SessionSnapshotSource, sessionId: string, outputPath: string, sourceBackend?: string, signal?: AbortSignal): Promise; /** Publish a sensitive bundle atomically without ever replacing an existing path. */ export declare function writeSessionImportBundle(outputPath: string, value: unknown): Promise; diff --git a/dist/types.d.ts b/dist/types.d.ts index c4d8d43..e66596e 100644 --- a/dist/types.d.ts +++ b/dist/types.d.ts @@ -15,6 +15,8 @@ export interface TeleportEvent { export declare const SESSION_IMPORT_FORMAT: "dsh-session-teleport/import-v1"; /** Portable, backend-neutral snapshot produced from an existing Session. */ export interface SessionImportBundle { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; format: typeof SESSION_IMPORT_FORMAT; header: JsonValue; events: TeleportEvent[]; @@ -63,6 +65,8 @@ export interface WriterCredentials { writerToken: string; } export interface CreateSessionRequest { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; sessionId: string; header: JsonValue; deviceId: string; @@ -75,6 +79,8 @@ export interface CreateSessionResult { } /** Atomic first materialization used by the lazy-create adapter. */ export interface MaterializeSessionRequest { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; sessionId: string; header: JsonValue; deviceId: string; @@ -99,6 +105,8 @@ export interface AppendResult { idempotentReplay: boolean; } export interface SessionSnapshot { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; sessionId: string; header: JsonValue; revision: number; @@ -108,6 +116,8 @@ export interface SessionSnapshot { events: TeleportEvent[]; } export interface SessionHead { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; sessionId: string; header: JsonValue; revision: number; diff --git a/dist/types.js.map b/dist/types.js.map index bb59d4f..8aadce9 100644 --- a/dist/types.js.map +++ b/dist/types.js.map @@ -1,6 +1,6 @@ { "version": 3, "sources": ["../src/types.ts"], - "mappings": "AAcO,MAAM,wBAAwB;AA8L9B,MAAM,sBAAsB,MAAM;AAAA,EACvC,YACW,MACT,SACA;AACA,UAAM,OAAO;AAHJ;AAIT,SAAK,OAAO;AAAA,EACd;AAAA,EALW;AAMb;", + "mappings": "AAcO,MAAM,wBAAwB;AAwM9B,MAAM,sBAAsB,MAAM;AAAA,EACvC,YACW,MACT,SACA;AACA,UAAM,OAAO;AAHJ;AAIT,SAAK,OAAO;AAAA,EACd;AAAA,EALW;AAMb;", "names": [] } diff --git a/docs/DSH_INTEGRATION.md b/docs/DSH_INTEGRATION.md index 09f6730..2f6fe7d 100644 --- a/docs/DSH_INTEGRATION.md +++ b/docs/DSH_INTEGRATION.md @@ -6,7 +6,6 @@ The Teleport service and the DSH adapter run separately. DSH clients call the HTTP API and never receive database credentials. ```bash -export NPM_TOKEN pnpm install --frozen-lockfile --ignore-scripts pnpm build @@ -42,9 +41,10 @@ install does not need to execute repository build scripts. Installation alone is fail-safe: the bundle leaves the base JSONL authority enabled and inserts a disabled Teleport adapter after the base bundles. -The published-package compatibility baseline is Cordis `4.0.1-rc.4` with DSH -Session, Session Persistence and Session Persistence JSONL `0.1.0-rc.6`. -Development checks compile against those exact npm next packages; no DSH source +The published-package compatibility baseline is Cordis `4.0.4` with DSH +Session, Session Persistence and Session Persistence JSONL `0.2.0-rc.1`. +This targets DSH `0.2.0-rc.1` (`next`, a prerelease as of 2026-09-28). +Development checks compile against these pinned public packages; no DSH source checkout or generated package snapshot is used by the adapter typecheck. Set these values on every device that runs the profile: @@ -66,6 +66,30 @@ Writer credentials live under `$DSH_HOME/session-teleport/writers`. Filenames are SHA-256 identifiers and files use mode 0600. This is OS file-permission protection, not hardware-backed or Keychain encryption. +All profiles on one device must share that credential directory. The adapter +holds an OS file lock per write handle (macOS/Linux); closing the handle or +exiting the process releases it. Never copy live writer credentials to a second +directory/device: use handoff instead. Independent read handles do not acquire +the writer lock. Cross-device ownership remains fenced by PostgreSQL epochs. + +### Upgrade from the previous adapter + +Upgrade the authority service and plugin together. Schema 5 adds nullable +`inherited_event_count` without rewriting existing event rows and permits empty +import rollback records. Old authority binaries cannot serve the new contract. +A seeded format 4 session requires its exact inherited count; missing metadata +is refused rather than inferred. The adapter only opens logical format 4 logs. +For historical JSONL, capture from a compatible source backend that performs +its supported migration; a legacy `inspect()` export remains archival and is +not automatically made resumable by importing it. Back up before changing +versions; do not downgrade the service after schema 5 is installed. + +The adapter now implements `create/open → SessionHandle`, `stat/list`, and +service `flush`. A write handle accepts contiguous appends, durably materializes +an empty session, flushes live `session/event` batches at `session/flush`, and +releases its lock on `close`. Reads return detached event values. Old coordinator +and backend methods are no longer exposed. + ### Restart boundary Plugin installation changes the selected profile's dependency and bundle diff --git a/docs/IMPORT_AND_CUTOVER.md b/docs/IMPORT_AND_CUTOVER.md index a7d26f8..de57c2d 100644 --- a/docs/IMPORT_AND_CUTOVER.md +++ b/docs/IMPORT_AND_CUTOVER.md @@ -16,7 +16,7 @@ dsh-teleport-import capture \ The command boots that profile once with a temporary absolute `file://` overlay. The overlay injects the profile's existing `sessionPersistence`, calls -`inspect(sessionId)` and writes into an owner-only staging directory. The +`open(sessionId, "read")` and `handle.read()` (legacy sources may use `inspect`) and writes into an owner-only staging directory. The parent validates the digest and shape, then atomically publishes the requested mode `0600` no-clobber file and requests normal DSH shutdown. A failed source boot therefore does not leave a final bundle. It never edits the @@ -103,3 +103,11 @@ Rollback deliberately fails with `IMPORT_NOT_ROLLBACKABLE` after any Teleport append, accepted handoff or writer recovery. At that point the old backend is a stale prefix, so silently switching back would lose history. Recovery then requires a deliberate export/migration operation, not this lightweight path. + +Format 4 fork bundles carry `inheritedEventCount` outside the replayable event +log. Capture always closes its read handle, including on error. Import digests +include a seeded session's inherited count; a changed boundary is a conflict. +Unseeded zero counts are normalized away to preserve older bundle digests. +Empty sessions can be imported and rolled back before any subsequent mutation. +Import preserves historical data verbatim; it does not upgrade a retired DSH +format or invent missing fork metadata. The 0.2 adapter refuses those logs. diff --git a/docs/PLUGIN_LIFECYCLE.md b/docs/PLUGIN_LIFECYCLE.md index 44f6851..a7ec3cc 100644 --- a/docs/PLUGIN_LIFECYCLE.md +++ b/docs/PLUGIN_LIFECYCLE.md @@ -14,8 +14,8 @@ The adapter has required peer dependencies on matching DSH Session, Session Persistence and Cordis packages. Configure the target DSH installation to resolve those peers through its supported software sources before install. The lifecycle tool does not create or persist package-manager configuration. The -current npm next validation baseline is Cordis `4.0.1-rc.4` and DSH Session, -Session Persistence and Session Persistence JSONL `0.1.0-rc.6`. +current npm next validation baseline is Cordis `4.0.4` and DSH Session, +Session Persistence and Session Persistence JSONL `0.2.0-rc.1`. ## Bootstrap diff --git a/docs/TESTING.md b/docs/TESTING.md index ca62eb1..5033d91 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -7,18 +7,19 @@ without copying DSH packages or deployment-specific compatibility fixtures. ## Repository checks ```bash -export NPM_TOKEN pnpm install --frozen-lockfile --ignore-scripts pnpm check pnpm audit --prod ``` -The concrete read token belongs only in the process environment. The repository -stores a literal `${NPM_TOKEN}` placeholder and the package gate rejects `.npmrc` -from the tarball. +Dependencies are public npm packages and CI needs no npm registry secret. The +package gate rejects `.npmrc` from the tarball. The tests cover: +- real DSH 0.2 handles and SessionStore event/flush routing, local writer locks, + read access, closure, aborts, handoff fencing and response-loss retries; +- real JSONL fork export/import with the inherited boundary and format 4 restore; - authority CAS, fencing, handoff, idempotent admin recovery, audit and exact event replay; - HTTP authentication, malformed requests, explicit errors and SSE; - schema creation, migrations and fail-loud incompatible stores; @@ -32,8 +33,8 @@ The tests cover: redaction and credential preservation across uninstall. `pnpm typecheck:adapter` strictly checks the adapter and public entry point -against exact npm next development packages: Cordis `4.0.1-rc.4`, plus DSH -Session, Session Persistence and Session Persistence JSONL `0.0.1-rc.5`. +against pinned published development packages: Cordis `4.0.4`, plus DSH +Session, Session Persistence and Session Persistence JSONL `0.2.0-rc.1`. `pnpm build` uses those real package types to regenerate declarations, JavaScript and source maps in `dist/`; it does not use a DSH source checkout or package snapshot. Repository installs use committed build output and deliberately @@ -60,13 +61,19 @@ Point the opt-in test at the built CLI from a compatible DSH installation: ```bash DSH_TELEPORT_TEST_DSH_BIN=/absolute/path/to/dsh/bin.js \ - pnpm vitest run tests/dsh-capture.integration.spec.ts + pnpm vitest run tests/dsh-adapter-loader.integration.spec.ts tests/dsh-capture.integration.spec.ts ``` -This boots a disposable Profile in the real DSH process, loads the temporary -absolute `file://` export overlay, executes the public `capture` CLI, verifies -the exact bundle and removes the fixture. No DSH package, fixture or snapshot is -copied into this repository. +These boot disposable Profiles in the real DSH process. The adapter probe loads +the packaged provider and flushes a live Session through the HTTP service; the +capture probe loads a temporary absolute `file://` export overlay, executes the +public `capture` CLI and verifies the exact bundle. Both remove their fixtures. +No DSH package, fixture or snapshot is copied into this repository. + +CI installs the official DSH `0.2.0-rc.1` CLI and runs these probes, the PostgreSQL +recovery and migration gates below, and the local profile lifecycle check. Its +PostgreSQL 17 service is disposable; integration files run sequentially to avoid +concurrent first-time schema initialization. The complete opt-in migration test also needs a disposable real PostgreSQL database and exercises every public CLI step plus authoritative readback: @@ -90,22 +97,22 @@ DSH_TELEPORT_TEST_DSH_BIN=/absolute/path/to/dsh/bin.js \ ## Real plugin lifecycle check First validate the package tarball and DSH plugin composition. Supply a built -DSH CLI plus the exact npm next baseline package specs: +DSH CLI plus the pinned published baseline package specs: ```bash DSH_TELEPORT_TEST_DSH_BIN=/absolute/path/to/dsh/bin.js \ -DSH_TELEPORT_TEST_SESSION_SPEC=0.0.1-rc.5 \ -DSH_TELEPORT_TEST_SESSION_PERSISTENCE_SPEC=0.0.1-rc.5 \ -DSH_TELEPORT_TEST_JSONL_SPEC=0.0.1-rc.5 \ -DSH_TELEPORT_TEST_CORDIS_SPEC=4.0.1-rc.4 \ +DSH_TELEPORT_TEST_SESSION_SPEC=0.2.0-rc.1 \ +DSH_TELEPORT_TEST_SESSION_PERSISTENCE_SPEC=0.2.0-rc.1 \ +DSH_TELEPORT_TEST_JSONL_SPEC=0.2.0-rc.1 \ +DSH_TELEPORT_TEST_CORDIS_SPEC=4.0.4 \ pnpm test:lifecycle:local ``` This packs the current source, installs it into a disposable profile, checks the adapter and every packaged binary, verifies the safe JSONL default and the explicit `DSH_TELEPORT_ENABLE=1` cutover, then removes it and verifies the -JSONL composition is restored. The script also installs the exact RC.5 peer -closure needed to import the official persistence packages. +JSONL composition is restored. The script defaults to the versions in `package.json`; the matching public transitive peer closure is installed explicitly because +the profile manager does not auto-install those peers. After that, validate repository install and upgrade pins. @@ -128,8 +135,7 @@ package-manager or Git configuration into the repository or test evidence. If the profile cannot resolve the peer packages through its normal software sources, supply the same four `DSH_TELEPORT_TEST_*_SPEC` variables used by the -local lifecycle check. The variables must be provided together and affect only -the disposable profile. +local lifecycle check. Overrides affect only the disposable profile; omitted values use `package.json`. ## Compatibility boundary @@ -151,3 +157,7 @@ The complete physical two-machine, TLS, network-fault, database-restart and backup/restore procedure is maintained in [Real-device acceptance](REAL_DEVICE_ACCEPTANCE.md). Those tests are required for a release candidate because simulation cannot prove deployment behavior. + +The default adapter tests use the official published DSH packages with PGlite +behind the real HTTP service. They do not certify physical multi-host operation +or replace the opt-in PostgreSQL connection-pool concurrency gates above. diff --git a/package.json b/package.json index f967b18..fb9a72c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mattheliu/session-teleport", - "version": "0.6.0-rc.2", + "version": "0.7.0-rc.1", "private": true, "description": "PostgreSQL-backed single-writer session handoff service for DeepSeek Harness", "license": "BSD-3-Clause", @@ -79,7 +79,7 @@ "capability": { "id": "session-persistence-teleport", "kind": "provider", - "invocation": "boot an RC.6 candidate Profile with DSH_TELEPORT_ENABLE=1 and run the Session persistence lifecycle", + "invocation": "boot a DSH 0.2.0-rc.1 Profile with DSH_TELEPORT_ENABLE=1 and run the Session persistence lifecycle", "expected": "the Teleport persistence provider becomes ready only after its PostgreSQL-backed health check passes" }, "evidence": { @@ -109,23 +109,27 @@ "node": "^22.19.0 || >=24.0.0" }, "dependencies": { - "pg": "^8.23.0" + "pg": "^8.23.0", + "@deepseek-ai/node-addon-system": "~0.1.2" }, "peerDependencies": { - "@deepseek-ai/dsh-session": "0.1.0-rc.6", - "@deepseek-ai/dsh-session-persistence": "0.1.0-rc.6", - "@deepseek-ai/cordis": "^4.0.1" + "@deepseek-ai/dsh-session": "0.2.0-rc.1", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.1", + "@deepseek-ai/cordis": "~4.0.4" }, "devDependencies": { - "@deepseek-ai/cordis": "4.0.1", - "@deepseek-ai/dsh-session": "0.1.0-rc.6", - "@deepseek-ai/dsh-session-persistence": "0.1.0-rc.6", - "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.0-rc.6", + "@deepseek-ai/cordis": "4.0.4", + "@deepseek-ai/dsh-session": "0.2.0-rc.1", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.1", + "@deepseek-ai/dsh-session-persistence-jsonl": "0.2.0-rc.1", "@electric-sql/pglite": "^0.5.4", "@types/node": "^24.0.0", "@types/pg": "^8.15.0", "esbuild": "^0.28.2", "typescript": "^6.0.0", - "vitest": "^4.1.0" + "vitest": "^4.1.0", + "@deepseek-ai/dsh-scope": "0.2.0-rc.1", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.1", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a03bd82..c664115 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,22 +8,34 @@ importers: .: dependencies: + '@deepseek-ai/node-addon-system': + specifier: ~0.1.2 + version: 0.1.2 pg: specifier: ^8.23.0 version: 8.23.0 devDependencies: '@deepseek-ai/cordis': - specifier: 4.0.1 - version: 4.0.1 + specifier: 4.0.4 + version: 4.0.4 + '@deepseek-ai/dsh-attachment': + specifier: 0.2.0-rc.1 + version: 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) + '@deepseek-ai/dsh-invariants': + specifier: 0.2.0-rc.1 + version: 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-scope': + specifier: 0.2.0-rc.1 + version: 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) '@deepseek-ai/dsh-session': - specifier: 0.1.0-rc.6 - version: 0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6) + specifier: 0.2.0-rc.1 + version: 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) '@deepseek-ai/dsh-session-persistence': - specifier: 0.1.0-rc.6 - version: 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6))(@deepseek-ai/dsh-timeout@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))) + specifier: 0.2.0-rc.1 + version: 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))(@deepseek-ai/dsh-timeout@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) '@deepseek-ai/dsh-session-persistence-jsonl': - specifier: 0.1.0-rc.6 - version: 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session-persistence@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6))(@deepseek-ai/dsh-timeout@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-session@0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6)) + specifier: 0.2.0-rc.1 + version: 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-agent@0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed))(@deepseek-ai/dsh-compaction@0.2.0-rc.1(3a346bff41f150ae5b4d06af0696936d))(@deepseek-ai/dsh-session-persistence@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))(@deepseek-ai/dsh-timeout@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))) '@electric-sql/pglite': specifier: ^0.5.4 version: 0.5.4 @@ -45,95 +57,213 @@ importers: packages: - '@deepseek-ai/cordis@4.0.1': - resolution: {integrity: sha512-YBdskTU2Po1kru3GgcUWUbkTsPMA9LkSQDAY8rBkFJeajdgcQad3QPJZE26JyK99Xb6HaASvoXg2DSUTeN/0Nw==} + '@deepseek-ai/cordis@4.0.4': + resolution: {integrity: sha512-obgyxqWAmFn3Re8kvsuUnyW+ihrz6eJCnJO4fh1cQzDtmPYz/zzVeUkH9R94I0OwSVOocK67Kgakm04j/oQXzg==} hasBin: true peerDependencies: - '@deepseek-ai/cordis-plugin-include': ^1.0.6 - '@deepseek-ai/cordis-plugin-loader': ^1.0.2 + '@deepseek-ai/cordis-plugin-include': ~1.0.9 + '@deepseek-ai/cordis-plugin-loader': ~1.0.5 peerDependenciesMeta: '@deepseek-ai/cordis-plugin-include': optional: true '@deepseek-ai/cordis-plugin-loader': optional: true - '@deepseek-ai/cosmokit@1.8.2': - resolution: {integrity: sha512-muBOKtSrUKU5m/xpq8ZXWL6hQ/jgd4PhU2PqH97bcxIiLEJfNwZOGQEx4t/aS/GgxRAR+ra9pMHPMtTHU4sqqA==} + '@deepseek-ai/cosmokit@1.8.5': + resolution: {integrity: sha512-LXsrlem9z8dq4sLflj2yuCuYX7KqhdzF5hZly3eZyuTo8d6oDSOXuEgC5DbQWKW+lksm6zmOutQLsP/ma6wR6A==} - '@deepseek-ai/dsh-attachment@0.1.0-rc.6': - resolution: {integrity: sha512-3P6N17NQ8jqSQGzeCs+svCIqArU8oq0YmgEAo+axN9aVuUDferWU4DLRSX59UGpmyldX4LQn81toA+c+DqMcHg==} + '@deepseek-ai/dsh-agent@0.2.0-rc.1': + resolution: {integrity: sha512-PQ4Qtu7QiI6j2n730p8RJ+u4l7ywwhVJ4NeIe/Tj86hBYYZNvNT8iMhViECn+GSepAk7GmM/1eb7e7hvmYhsKA==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 - '@deepseek-ai/dsh-brand': ^0.1.0-rc.6 - '@deepseek-ai/dsh-invariants': ^0.1.0-rc.6 + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1 + '@deepseek-ai/dsh-llm': 0.2.0-rc.1 + '@deepseek-ai/dsh-scope': 0.2.0-rc.1 + '@deepseek-ai/dsh-session': 0.2.0-rc.1 + '@deepseek-ai/dsh-session-projection': 0.2.0-rc.1 + '@deepseek-ai/dsh-system-prompt': 0.2.0-rc.1 + '@deepseek-ai/dsh-typert-protocol': 0.2.0-rc.1 + '@deepseek-ai/dsh-util-values': 0.2.0-rc.1 + '@deepseek-ai/dsh-workspace': 0.2.0-rc.1 + peerDependenciesMeta: + '@deepseek-ai/dsh-workspace': + optional: true + + '@deepseek-ai/dsh-attachment@0.2.0-rc.1': + resolution: {integrity: sha512-aKKFE9fGYYn1BCzDtun7IYkpiMANYt7s51vwPukkCnobNiLfxHrIyANLWNmMTSpq0iENfqREXPR805K/um8Hfw==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1 + + '@deepseek-ai/dsh-brand@0.2.0-rc.1': + resolution: {integrity: sha512-TPeMaUt/Xev0X2TfIf6pSVVGiWAbFHy+VWCIW+w8UkC0yH1ep9302JQOBqhUgefAM4s/3W1R8lra/PMbFhjx2w==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + + '@deepseek-ai/dsh-commands@0.2.0-rc.1': + resolution: {integrity: sha512-VZOWNwjBDBkX3kXVJcD24oAoKeGRpLnHZjRiPm0gq41ZClCYy9CzNnFdl6IVtJHfG+bz9/HDnONilpiRwBg2lQ==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-agent': 0.2.0-rc.1 + '@deepseek-ai/dsh-attachment': 0.2.0-rc.1 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1 + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1 + '@deepseek-ai/dsh-llm': 0.2.0-rc.1 + '@deepseek-ai/dsh-scope': 0.2.0-rc.1 + '@deepseek-ai/dsh-session': 0.2.0-rc.1 + '@deepseek-ai/dsh-typert-protocol': 0.2.0-rc.1 + + '@deepseek-ai/dsh-compaction-image-offload@0.2.0-rc.1': + resolution: {integrity: sha512-GM+Wk7dROfMllrm0gqbYpZY8MCef+Y+tK+vSLP426hd/hNRpSSOcPB72ZNfu05hZF+IUCkNSCF7x0gTAGtm7NQ==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-agent': 0.2.0-rc.1 + '@deepseek-ai/dsh-compaction': 0.2.0-rc.1 + '@deepseek-ai/dsh-llm': 0.2.0-rc.1 + '@deepseek-ai/dsh-session': 0.2.0-rc.1 + + '@deepseek-ai/dsh-compaction@0.2.0-rc.1': + resolution: {integrity: sha512-xtyT0MW45DIseej9fJ4HmkUlRK02IY0vC8AWPZ7ORQqaEHMV4lqX/mhTRFA937NOuOeLdLF/DKH5E4bpUeeshQ==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1 + '@deepseek-ai/dsh-commands': 0.2.0-rc.1 + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1 + '@deepseek-ai/dsh-llm': 0.2.0-rc.1 + '@deepseek-ai/dsh-session': 0.2.0-rc.1 + + '@deepseek-ai/dsh-invariants@0.2.0-rc.1': + resolution: {integrity: sha512-sEeO6sRPGxgHChQsiU/V3LvelbVaLt7kb4WHVQqljZGgoAv3VZK0rzSlQaGfTCYJrThcoJ/a9mCT9pcZEZ3aDg==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + + '@deepseek-ai/dsh-llm@0.2.0-rc.1': + resolution: {integrity: sha512-F5ZlBG8z8o5PfEWeEF/PN9t/A1N/oEErvqmpqE4J8f9mJR85DvBdV+rjDs7OjAbMJsJ8INjkbroruG5NNKDg5A==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + + '@deepseek-ai/dsh-scope@0.2.0-rc.1': + resolution: {integrity: sha512-D1JeWIz40A62/nJIi7HwLsddmuDwdcxV9Lbx5IgBveWDZHGqPIP0/CPJ4o6XWr+C1qI/GBtdMkN2Z3F20Rlt7w==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1 + + '@deepseek-ai/dsh-session-format-catalog@0.2.0-rc.1': + resolution: {integrity: sha512-Kacc7D3at1ifPlPbFD3t463/m+jg0RdERnuTWH1omv0hjT5ZkX/xM0TS37bhlyhLJdI+1TOqm9Jy3BpR15yR0Q==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-session': 0.2.0-rc.1 + + '@deepseek-ai/dsh-session-format-v0-to-v1@0.2.0-rc.1': + resolution: {integrity: sha512-bBf8YJKpolltz2vn03+mbT5IZ3mrAeN1GjgVQ5FwhU5ITWLV6jQqvtN7DWEWjTwKVVmUpl2XkmRcGBib+PH16Q==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + + '@deepseek-ai/dsh-session-format-v1-to-v2@0.2.0-rc.1': + resolution: {integrity: sha512-YXqkqnTqMUKUgdSZT4GXCEwWvfSZv7TEIG+wfYxtJBWQlzfuCf7iHjNIWVNBslQdxl0VxbaFThbwZUtBa3f2Tg==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 - '@deepseek-ai/dsh-brand@0.1.0-rc.6': - resolution: {integrity: sha512-E8j9Nby24qP4rfrdcfc7bpt1CHpGT3tYmycOJJkEOH4ptIdT1m2ro9nmnSd5CWYukTr64A77vjm2WGqHRI92UA==} + '@deepseek-ai/dsh-session-format-v2-to-v3@0.2.0-rc.1': + resolution: {integrity: sha512-f7QapRRmMstuTYVVORYWgZn2gngw8Vu/ls5iBYfyb+15FbgwYr8bIOKNMGQ660dg4PHsxzWprsTbsxBAe9QDNw==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 - '@deepseek-ai/dsh-invariants': ^0.1.0-rc.6 + '@deepseek-ai/cordis': ~4.0.4 - '@deepseek-ai/dsh-invariants@0.1.0-rc.6': - resolution: {integrity: sha512-WfEfOi99a4cpOugRAHTBSTnesLieu3ist1q9PXDXFBHX++K1rAl9+sB7YrdnbB8LH0UOY532gS9xJUYU6w0SLw==} + '@deepseek-ai/dsh-session-format-v3-to-v4@0.2.0-rc.1': + resolution: {integrity: sha512-vnplfHQOqTXpe7EMN/0h0VZyBS10+kzzjm5x/X01iu5lynbOQs2jRdi4Lrzp9fgnAUEJYaESZZLlWKY40arLCw==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 + '@deepseek-ai/cordis': ~4.0.4 - '@deepseek-ai/dsh-llm@0.1.0-rc.6': - resolution: {integrity: sha512-kuFGC8bHlzGTwlRxQhXjf3CYWl8M4NzH+EYIkrW8rri4iMc9W53xrdvkil5No/DUlMm8g1u7GdeiWYFy0TMvtA==} + '@deepseek-ai/dsh-session-format@0.2.0-rc.1': + resolution: {integrity: sha512-j2m+3FQeFPW9fgzRktL8E6J2UegpWPcc7nSFP+Ir7fdKYD5xDukcbdYDzzairbqQedntb0QMcp78rBQeJOmoYA==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 - '@deepseek-ai/dsh-attachment': ^0.1.0-rc.6 - '@deepseek-ai/dsh-brand': ^0.1.0-rc.6 - '@deepseek-ai/dsh-invariants': ^0.1.0-rc.6 - '@deepseek-ai/dsh-timeout': ^0.1.0-rc.6 - - '@deepseek-ai/dsh-scope@0.1.0-rc.6': - resolution: {integrity: sha512-UlDLV4syLoJinNg9imhXrSAHrdaTa5Ff8gg46rzjFJGPUOhAk3DZff0hryT5OhrBi0A5Tj92qVpg2pRVvxnUzQ==} + '@deepseek-ai/cordis': ~4.0.4 + + '@deepseek-ai/dsh-session-persistence-jsonl@0.2.0-rc.1': + resolution: {integrity: sha512-16hp5zx1Q1SIVJfQI/hrxASHMkE/r+pHeELn1b/GZCpKwCD1nwiQapqHhgq/+WEb9SRvRpWAxE5dQWEscZghEw==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-session': 0.2.0-rc.1 + '@deepseek-ai/dsh-session-persistence': 0.2.0-rc.1 + + '@deepseek-ai/dsh-session-persistence@0.2.0-rc.1': + resolution: {integrity: sha512-OAHmDpR3LasgEXzpmGyajlgcG5tOEzlUSclovllLtKaY402hcTn6Vm7W/EzRMwc+jvSfEQyXDY1g7wG3t3Ch+g==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 - '@deepseek-ai/dsh-invariants': ^0.1.0-rc.6 + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1 + '@deepseek-ai/dsh-session': 0.2.0-rc.1 + '@deepseek-ai/dsh-timeout': 0.2.0-rc.1 - '@deepseek-ai/dsh-session-persistence-jsonl@0.1.0-rc.6': - resolution: {integrity: sha512-US9Q4b5CZJPRRqa/M+WESL5VAOLjfYWjdzb3TQ/7zmpR4/+EQWCOFA9CtDSMh4t1oFOQBjz2+YJJcGu59MKHDA==} + '@deepseek-ai/dsh-session-projection@0.2.0-rc.1': + resolution: {integrity: sha512-6ymxQyycjXlxayjgVfxAsQv8POk3oKny/mrpxPcz30/Sv8FRsWnEnKaWf1pQvlBsGQcN6atOqXWsNyvHSyT/zw==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 - '@deepseek-ai/dsh-invariants': ^0.1.0-rc.6 - '@deepseek-ai/dsh-session': ^0.1.0-rc.6 - '@deepseek-ai/dsh-session-persistence': ^0.1.0-rc.6 + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-session': 0.2.0-rc.1 - '@deepseek-ai/dsh-session-persistence@0.1.0-rc.6': - resolution: {integrity: sha512-AbNBe+IYCbZqSHqOACVdj8QTynm2HZ0cThrEuI6nGMtlWLYLx6lzZ1rgO/56Av9mIScjyTBGJAIKhEYaMTBG9g==} + '@deepseek-ai/dsh-session@0.2.0-rc.1': + resolution: {integrity: sha512-KUDCUk8kmiJCwvV3gDbkUSpkyoGHdg36nIhKsEh6iBoYDuIQCuvX2htiVRXCm099XZO6rCBVInmm1193UoPYcA==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 - '@deepseek-ai/dsh-brand': ^0.1.0-rc.6 - '@deepseek-ai/dsh-invariants': ^0.1.0-rc.6 - '@deepseek-ai/dsh-session': ^0.1.0-rc.6 - '@deepseek-ai/dsh-timeout': ^0.1.0-rc.6 - - '@deepseek-ai/dsh-session@0.1.0-rc.6': - resolution: {integrity: sha512-8tu8I6VWC7050GAUXWhcEWQw4pakALQc8TlhKr52m7Y4+kIKeNt3FBgP86PaGPBtpK0p5zUPRQNkFpzZbBdxyw==} + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-scope': 0.2.0-rc.1 + + '@deepseek-ai/dsh-system-prompt@0.2.0-rc.1': + resolution: {integrity: sha512-AZC0HBWaiopkVcJXh/WEzyyF19+/yBPnbuLrZoD7h+UJYF8iG8tlDabauWfMw+dvgoYe9hIiTV2EcFRv4AgJhw==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 - '@deepseek-ai/dsh-brand': ^0.1.0-rc.6 - '@deepseek-ai/dsh-invariants': ^0.1.0-rc.6 - '@deepseek-ai/dsh-llm': ^0.1.0-rc.6 - '@deepseek-ai/dsh-scope': ^0.1.0-rc.6 - '@deepseek-ai/dsh-typert-protocol': ^0.1.0-rc.6 - - '@deepseek-ai/dsh-timeout@0.1.0-rc.6': - resolution: {integrity: sha512-CUean0fAnfsJVszFEip7PsU/S26W+JfDFfsza2dCtlw8n6xlkbHA9Gjxdk2aTwqDGCgXEPkRW7mYkdJ0n6FR7w==} + '@deepseek-ai/cordis': ~4.0.4 + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1 + '@deepseek-ai/dsh-llm': 0.2.0-rc.1 + '@deepseek-ai/dsh-scope': 0.2.0-rc.1 + + '@deepseek-ai/dsh-timeout@0.2.0-rc.1': + resolution: {integrity: sha512-SQpvDLIPU0EJP1lbphfuEkLrvnX+CE9u9ym1+L5z/8dYe9BCPbhgjQoRvDnyzKZqFyoXVvZFdqdAADlc6DX7Ig==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 - '@deepseek-ai/dsh-invariants': ^0.1.0-rc.6 + '@deepseek-ai/cordis': ~4.0.4 - '@deepseek-ai/dsh-typert-protocol@0.1.0-rc.6': - resolution: {integrity: sha512-weWzN8r01YCkoDCAM7BsKw2YhRrD4zL8N2SAZu9hovYtXSq8xHXsP4Zh8RLYIlYcuotjyff/6hic+0TJPd14YA==} + '@deepseek-ai/dsh-typert-protocol@0.2.0-rc.1': + resolution: {integrity: sha512-MhpeimGP6E3MqSESLm32OmPgx5aNUG7yCJCgcIFw7XBWhQmKB9fU3CWuUxxbWZeC7eWkdJ93AG2ww/Qu6QWW9A==} peerDependencies: - '@deepseek-ai/cordis': ^4.0.1 - '@deepseek-ai/dsh-invariants': ^0.1.0-rc.6 + '@deepseek-ai/cordis': ~4.0.4 + + '@deepseek-ai/dsh-util-crypto@0.2.0-rc.1': + resolution: {integrity: sha512-BLBQVRGBlzhNprSpREiMDi1JwX0X8jKdEPWiVRKBnttlG9d33j1pLsaiH9HHLY/D10lXX/NagGia/Zz9mW4FBA==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + + '@deepseek-ai/dsh-util-values@0.2.0-rc.1': + resolution: {integrity: sha512-Eh1HH0LFvztBwU2xotdfW5oCwLlWGjK2ygCC5+PnC3tkSDh9gvVQpEf0ezK+Kk6vpLz117V7VPehhR1+gs90+Q==} + peerDependencies: + '@deepseek-ai/cordis': ~4.0.4 + + '@deepseek-ai/node-addon-system-darwin-arm64@0.1.2': + resolution: {integrity: sha512-IR0cx8um19mLCZaJ+H5PLblKr6Eg3PWvVo8eTQBr/SwH2nh5tM9CD9/5fHweNS9Pjt15UdFlGqnvLSd/w+O6Rw==} + engines: {node: '>=20'} + cpu: [arm64] + os: [darwin] + + '@deepseek-ai/node-addon-system-darwin-x64@0.1.2': + resolution: {integrity: sha512-XDbmquNapk9aT28y4EKn9lbONVr9YNs1NM/GKH1Gi5gUhjOT9wgRaTv72FJdNaVIInbPAYbPoyn7/y+MzQMNNg==} + engines: {node: '>=20'} + cpu: [x64] + os: [darwin] + + '@deepseek-ai/node-addon-system-linux-arm64@0.1.2': + resolution: {integrity: sha512-Z/DQtqgEYzjBzb2ocHGjMzx51W7xDILkJKKj89nyErr8gZMNiLs+JNL1uKzJqc3VLZB+vYCPaHGyQ3oX6EzEmA==} + engines: {node: '>=20'} + cpu: [arm64] + os: [linux] + + '@deepseek-ai/node-addon-system-linux-x64@0.1.2': + resolution: {integrity: sha512-S2aPVHvYCpNCppCFyNlooMYuTB7ucK5lvD9oXQQ42v5Z2s5AoaiCdjz9r2l+ED2rI5oS1x0cUZmKjJH2dxV0pg==} + engines: {node: '>=20'} + cpu: [x64] + os: [linux] - '@deepseek-ai/schemastery@3.18.1': - resolution: {integrity: sha512-Qn0FCSwCQnpnj6SB31I6i2sIKgKWnkbJM8O0EU91Gv2UsYVvtZTl6IA0sCwk2e2MZf5S8w5hpq9QkeVvK9qwxg==} + '@deepseek-ai/node-addon-system@0.1.2': + resolution: {integrity: sha512-EFn8K+mXIXiw6s3rxX+cgp2hZTEAQdVIsURhrXnBxycSXvtQ1EQpsSVzoNKtKAQI0I0VqkEcVEjHzS/PeaGsvw==} + engines: {node: '>=20'} + + '@deepseek-ai/schemastery@3.18.4': + resolution: {integrity: sha512-SSXO6tYuyrIqKVbmOnIq0s+riUywYzouFMcnBluHF9n4KMo2G8HvEzhCYj6pj2617/glOjbJuVInJ9hfONsjkg==} '@electric-sql/pglite@0.5.4': resolution: {integrity: sha512-yYZUyyXrHU7tPlCjwZQJ6hIG9DscdCCn7Uk0mYKwC1FeHX286AbcmFveMiRBEak8e9iPupjsoVImN3yJZVed2g==} @@ -297,78 +427,78 @@ packages: '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@koromix/koffi-darwin-arm64@3.1.4': - resolution: {integrity: sha512-/9o0uahf25sNXz7CczfMAsgdHrrrkDK3/d1W5ygJUC7QnpWo80103yTYpYahWP3vTABK5yjzKtURgssv1paskA==} + '@koromix/koffi-darwin-arm64@3.1.1': + resolution: {integrity: sha512-+Dl0zQDh1Wb55AWOn9hp7K30qgkODvrvN+ZNkFOh81Q0oFX/rpJQtocgjAuYk2zFAcajSeVDumkcHMPwnKSXzA==} cpu: [arm64] os: [darwin] - '@koromix/koffi-darwin-x64@3.1.4': - resolution: {integrity: sha512-6IOhfAHbrySr6lYRU720Hg+IMQvtMpN08k9Ppf9WF8NxYRdHLnW1FJm7zCbClfrwudtjhS/piwDYwgAkO5u8cg==} + '@koromix/koffi-darwin-x64@3.1.1': + resolution: {integrity: sha512-cDFAKn1qdZBFLrp7dAc9QUDw3l4xAhTJbOdPWWb0LxssVicUdHcRCLZGrDsmPW2tpH6LGNNeLgqRpAoD2Mo8iA==} cpu: [x64] os: [darwin] - '@koromix/koffi-freebsd-arm64@3.1.4': - resolution: {integrity: sha512-JKCWC0awdVvq7Nd/etn4PXFTa7uvyHn7IzqtaOZ3r4dJRdwQVby7Ai/wsQo8UUrJfAYlALkLYgFgU8wgsnAE/A==} + '@koromix/koffi-freebsd-arm64@3.1.1': + resolution: {integrity: sha512-zaP7FJISI/scQW9Wa5QicY3a09WmtKBWSbmC+5nfCqPzwWe7Hx2so74Er7mPsDfCiMMR0Ya+evKbJQDkfyXicg==} cpu: [arm64] os: [freebsd] - '@koromix/koffi-freebsd-ia32@3.1.4': - resolution: {integrity: sha512-gU9pShDRLMZzftdGW+mTzyL8Cpa/7nzHPHe5vFakjGgtIzVFzdFBqwli4oB+tFsx44W1VqMMlvMMVlnz54ERiQ==} + '@koromix/koffi-freebsd-ia32@3.1.1': + resolution: {integrity: sha512-7GejVb688TLM8rbjfc0oezJrATxZc0dn801xWEDJekN2DgmRXu7HquGqWQ6z3NeSq7ZxEggz4T3xtlbCysQapA==} cpu: [ia32] os: [freebsd] - '@koromix/koffi-freebsd-x64@3.1.4': - resolution: {integrity: sha512-2kppLX97xBM3WoQET6noN4W02zT2fkFRXHYluAwcCcmkEax8AVJ1CYs6hxcZ3kaNPc+5P7yMw3V/b1lg2v3aMw==} + '@koromix/koffi-freebsd-x64@3.1.1': + resolution: {integrity: sha512-XLiCFP9OFCyOoGTjAimtDKLhzhfo34WcP1ShVWxRzNCWDGjfz8BYjwd69cp/cDSUXZbxamqs4+/6vmkePq9wxA==} cpu: [x64] os: [freebsd] - '@koromix/koffi-linux-arm64@3.1.4': - resolution: {integrity: sha512-yYbypuGVGqrNchkAMY59kj+7TZ1c1u9lXRG1+74X9T8G4rOaushoVONNYLuu+ygpbwsKzz/NvEDtRioRU/dQlQ==} + '@koromix/koffi-linux-arm64@3.1.1': + resolution: {integrity: sha512-HA9xINK7G4dRAkpfnBWD9VfuyIBgW1SuK+KPHjksUwRMOnhgqP8J/JqgrAzdzcDiefGBkqEacIP776OUwz7knQ==} cpu: [arm64] os: [linux] - '@koromix/koffi-linux-ia32@3.1.4': - resolution: {integrity: sha512-IoA/8Qfc6ZEmwMw2Nf4aSp9RfJnxh0UHhdqD4FsVXm0vC797kLMuzj744vv5tll+waVfjrU10jREqjtnMVFoQw==} + '@koromix/koffi-linux-ia32@3.1.1': + resolution: {integrity: sha512-jG7IFytmP8K5Qtbx0ro0ZeuX3JjSsLxmYhq+nmXDdrtOAlxIsWGynuiDLS6Jk3vOchVii2m6Y2f/L3GLG2fG5A==} cpu: [ia32] os: [linux] - '@koromix/koffi-linux-loong64@3.1.4': - resolution: {integrity: sha512-ZUTdea+9dg6CV9J9CIGbhTh0FtSBgvcGKqDrlp9BVQF71jEDKOri1by/TrDe8yQUyC5kzWN8vWnkzES5wT0xDg==} + '@koromix/koffi-linux-loong64@3.1.1': + resolution: {integrity: sha512-CIsT1cNnih8FuU52Me/IVlJBpH28SQfoDeYPctJswgJzaARktusF7m4MUbtR1PBDjuquCVM4/vFyNdOzfPonvA==} cpu: [loong64] os: [linux] - '@koromix/koffi-linux-riscv64@3.1.4': - resolution: {integrity: sha512-CINyyhNYV/8MX52MGhYcik2G6PXH+KEU2JEO7dOONlsGol4lSGyW40RvYA4RQgNYk8q8imGSEScL08X8eOXnaA==} + '@koromix/koffi-linux-riscv64@3.1.1': + resolution: {integrity: sha512-9D6RmqeKsSvs3U6jILJU9PcAjMwKKyn7yLxNBb5k6z9PCoUoGJ3/BrhXAX0qjrLLwEiIpP/hS/40RuXvH8Lc3Q==} cpu: [riscv64] os: [linux] - '@koromix/koffi-linux-x64@3.1.4': - resolution: {integrity: sha512-x3XnAy/tUTTCX/gMpV7VJNpOQIVQvzNhNYDrpyIeS9Q8/f1qLsE0vp0tj7A/YEDIfMVLqoJtyamfRJc04+vk4w==} + '@koromix/koffi-linux-x64@3.1.1': + resolution: {integrity: sha512-pyTcX5fePeYbt7TZAwRby69wdlRx3PT+g15ra5IYdat/Pgh3qAKEYeZ+uu7WpPGOy43p/oSRqqZoa2kORzozlA==} cpu: [x64] os: [linux] - '@koromix/koffi-openbsd-ia32@3.1.4': - resolution: {integrity: sha512-r9p/fffvmBm7+iT5BZ+c17gZJ280jvmbinrPZqjG14rF9I4lk7xrlV79YfsexkeN4mcPjF2hSPtbMNFBoQU3Dw==} + '@koromix/koffi-openbsd-ia32@3.1.1': + resolution: {integrity: sha512-iPnPzvG2HOfdzaiG1drdkt86sAqmTPDv9mAf+5gL7mRzkeeQC88EVGboRy7eXwdXn7R+v0ntA3iQxdHrBn6yXw==} cpu: [ia32] os: [openbsd] - '@koromix/koffi-openbsd-x64@3.1.4': - resolution: {integrity: sha512-SNp5AxOzheC2YaWPu3Y86wxRHHWf6V9NMl5Ot5nu9OpnP61Yinzug7JwsCeXtcZZTbKLsfsWoT7y4n17UYpOVA==} + '@koromix/koffi-openbsd-x64@3.1.1': + resolution: {integrity: sha512-/Xqc3R0SVoMCYjMPZnJ9bULtRo364+dKmnQhfDrI83tSpxUHRw7HRNf12vBeL+hPgKxSBjtMpWfQ/ZIyVyLFag==} cpu: [x64] os: [openbsd] - '@koromix/koffi-win32-arm64@3.1.4': - resolution: {integrity: sha512-oS8ETU35AelOD6DY7xmmz9qq26Xl38upXWiZbsdxbtH9UEIY0QpenQOuCK/0+q4CtfiLorRUlglGkO9YgPAIeA==} + '@koromix/koffi-win32-arm64@3.1.1': + resolution: {integrity: sha512-JhqHauEwQvdcWUERxrV5HH/DT9W7hY1A1eU6/o8tB+yck+D3kt5elpRDBt9KjpW6h+vHPy3V0sjDvO0CXyabTA==} cpu: [arm64] os: [win32] - '@koromix/koffi-win32-ia32@3.1.4': - resolution: {integrity: sha512-zd7Qh8s4fzblD9zzuDf44XCbujYg3QrffhgcNJg79/YC6ABT2m0CUtX4yFic9EWm2ps8NPAM25kCTCXPpt3eaw==} + '@koromix/koffi-win32-ia32@3.1.1': + resolution: {integrity: sha512-ZRuyYmlGS/rCc966qqs0qREXDW4FRdul7rDF1VgSWHbVmdc196PUgUT+blq/GjZgTwqzeEXtMRgM+cU8krHjvA==} cpu: [ia32] os: [win32] - '@koromix/koffi-win32-x64@3.1.4': - resolution: {integrity: sha512-BPeQXc1bRd0QBOklvsP+AjoRnUzKbPNE6rfx7VNxrebhh09MKld2ibstgKWn6ejQLEcfKEoUJ+WAWIhX4AOsIg==} + '@koromix/koffi-win32-x64@3.1.1': + resolution: {integrity: sha512-KqHPmvj6QILhNyI/To8QSihHsijeVGIYYPBOUnXEpcnH2LuLbargY4Hd6dDeTN3Z90uUUxN+1FWz1UnhVzFOiA==} cpu: [x64] os: [win32] @@ -553,8 +683,8 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - koffi@3.1.4: - resolution: {integrity: sha512-KHX39XIg7afe8ds+0MHPoLiKR9dCzsVK4oAmBUSaeJlcX0xur22f15C2DILbZ6GJ9eyqC+e6Sb1cTG7M17z+Tg==} + koffi@3.1.1: + resolution: {integrity: sha512-mRX6AMeeKCxSOeOopqAcLAl5jcNvge7NAG8l7rF/8gGJATI0tdHFYjteIdE0mGOtWdsrJOij+PjnP8Q9c1gwgA==} lightningcss-android-arm64@1.33.0: resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} @@ -840,84 +970,224 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + zod@4.6.5: + resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==} + snapshots: - '@deepseek-ai/cordis@4.0.1': + '@deepseek-ai/cordis@4.0.4': dependencies: - '@deepseek-ai/cosmokit': 1.8.2 + '@deepseek-ai/cosmokit': 1.8.5 '@standard-schema/spec': 1.1.0 - '@deepseek-ai/cosmokit@1.8.2': {} + '@deepseek-ai/cosmokit@1.8.5': {} - '@deepseek-ai/dsh-attachment@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))': + '@deepseek-ai/dsh-agent@0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed)': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-llm': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-scope': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) + '@deepseek-ai/dsh-session': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) + '@deepseek-ai/dsh-session-projection': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))) + '@deepseek-ai/dsh-system-prompt': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-llm@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) + '@deepseek-ai/dsh-typert-protocol': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-util-values': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + + '@deepseek-ai/dsh-attachment@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/dsh-brand': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)) - '@deepseek-ai/dsh-invariants': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) - '@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))': + '@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/dsh-invariants': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/cordis': 4.0.4 - '@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)': + '@deepseek-ai/dsh-commands@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-agent@0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed))(@deepseek-ai/dsh-attachment@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-llm@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))(@deepseek-ai/dsh-typert-protocol@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-agent': 0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed) + '@deepseek-ai/dsh-attachment': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) + '@deepseek-ai/dsh-brand': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-llm': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-scope': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) + '@deepseek-ai/dsh-session': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) + '@deepseek-ai/dsh-typert-protocol': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-util-crypto': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + zod: 4.6.5 + + '@deepseek-ai/dsh-compaction-image-offload@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-agent@0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed))(@deepseek-ai/dsh-compaction@0.2.0-rc.1(3a346bff41f150ae5b4d06af0696936d))(@deepseek-ai/dsh-llm@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-agent': 0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed) + '@deepseek-ai/dsh-compaction': 0.2.0-rc.1(3a346bff41f150ae5b4d06af0696936d) + '@deepseek-ai/dsh-llm': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) + '@deepseek-ai/dsh-util-values': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + + '@deepseek-ai/dsh-compaction@0.2.0-rc.1(3a346bff41f150ae5b4d06af0696936d)': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-commands': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-agent@0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed))(@deepseek-ai/dsh-attachment@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-llm@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))(@deepseek-ai/dsh-typert-protocol@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-llm': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) + + '@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/schemastery': 3.18.1 + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/schemastery': 3.18.4 - '@deepseek-ai/dsh-llm@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))': + '@deepseek-ai/dsh-llm@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/dsh-attachment': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)) - '@deepseek-ai/dsh-brand': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)) - '@deepseek-ai/dsh-invariants': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1) - '@deepseek-ai/dsh-timeout': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)) - '@deepseek-ai/schemastery': 3.18.1 - - '@deepseek-ai/dsh-scope@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))': + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-timeout': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-typert-protocol': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-util-crypto': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-util-values': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/schemastery': 3.18.4 + zod: 4.6.5 + + '@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/dsh-invariants': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) - '@deepseek-ai/dsh-session-persistence-jsonl@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session-persistence@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6))(@deepseek-ai/dsh-timeout@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))))(@deepseek-ai/dsh-session@0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6))': + '@deepseek-ai/dsh-session-format-catalog@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-agent@0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed))(@deepseek-ai/dsh-compaction@0.2.0-rc.1(3a346bff41f150ae5b4d06af0696936d))(@deepseek-ai/dsh-llm@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/dsh-invariants': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1) - '@deepseek-ai/dsh-session': 0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6) - '@deepseek-ai/dsh-session-persistence': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6))(@deepseek-ai/dsh-timeout@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))) - '@deepseek-ai/schemastery': 3.18.1 - koffi: 3.1.4 - - '@deepseek-ai/dsh-session-persistence@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-session@0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6))(@deepseek-ai/dsh-timeout@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))': + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-compaction-image-offload': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-agent@0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed))(@deepseek-ai/dsh-compaction@0.2.0-rc.1(3a346bff41f150ae5b4d06af0696936d))(@deepseek-ai/dsh-llm@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))) + '@deepseek-ai/dsh-session': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) + '@deepseek-ai/dsh-session-format': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format-v0-to-v1': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format-v1-to-v2': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format-v2-to-v3': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format-v3-to-v4': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + transitivePeerDependencies: + - '@deepseek-ai/dsh-agent' + - '@deepseek-ai/dsh-compaction' + - '@deepseek-ai/dsh-llm' + + '@deepseek-ai/dsh-session-format-v0-to-v1@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/dsh-brand': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)) - '@deepseek-ai/dsh-invariants': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1) - '@deepseek-ai/dsh-session': 0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6) - '@deepseek-ai/dsh-timeout': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-session-format': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-util-values': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) - '@deepseek-ai/dsh-session@0.1.0-rc.6(6fd26f59436a18b115f326d6060415e6)': + '@deepseek-ai/dsh-session-format-v1-to-v2@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/dsh-brand': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)) - '@deepseek-ai/dsh-invariants': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1) - '@deepseek-ai/dsh-llm': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-attachment@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-brand@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-timeout@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))) - '@deepseek-ai/dsh-scope': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)) - '@deepseek-ai/dsh-typert-protocol': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)) - - '@deepseek-ai/dsh-timeout@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))': + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-llm': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format-v0-to-v1': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-util-values': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + + '@deepseek-ai/dsh-session-format-v2-to-v3@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-session-format': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format-v0-to-v1': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format-v1-to-v2': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + + '@deepseek-ai/dsh-session-format-v3-to-v4@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/dsh-invariants': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-session-format': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format-v2-to-v3': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) - '@deepseek-ai/dsh-typert-protocol@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.0-rc.6(@deepseek-ai/cordis@4.0.1))': + '@deepseek-ai/dsh-session-format@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': dependencies: - '@deepseek-ai/cordis': 4.0.1 - '@deepseek-ai/dsh-invariants': 0.1.0-rc.6(@deepseek-ai/cordis@4.0.1) + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-util-values': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) - '@deepseek-ai/schemastery@3.18.1': + '@deepseek-ai/dsh-session-persistence-jsonl@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-agent@0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed))(@deepseek-ai/dsh-compaction@0.2.0-rc.1(3a346bff41f150ae5b4d06af0696936d))(@deepseek-ai/dsh-session-persistence@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))(@deepseek-ai/dsh-timeout@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))': dependencies: - '@deepseek-ai/cosmokit': 1.8.2 + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-llm': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) + '@deepseek-ai/dsh-session-format': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-format-catalog': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-agent@0.2.0-rc.1(d61f3b086328d5683f77296febd0cfed))(@deepseek-ai/dsh-compaction@0.2.0-rc.1(3a346bff41f150ae5b4d06af0696936d))(@deepseek-ai/dsh-llm@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))) + '@deepseek-ai/dsh-session-format-v3-to-v4': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session-persistence': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))(@deepseek-ai/dsh-timeout@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) + '@deepseek-ai/node-addon-system': 0.1.2 + '@deepseek-ai/schemastery': 3.18.4 + koffi: 3.1.1 + transitivePeerDependencies: + - '@deepseek-ai/dsh-agent' + - '@deepseek-ai/dsh-compaction' + + '@deepseek-ai/dsh-session-persistence@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-brand@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))(@deepseek-ai/dsh-timeout@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-session': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) + '@deepseek-ai/dsh-timeout': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-util-values': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + + '@deepseek-ai/dsh-session-projection@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))))': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-session': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))) + zod: 4.6.5 + + '@deepseek-ai/dsh-session@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-llm': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-scope': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) + '@deepseek-ai/dsh-util-values': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + + '@deepseek-ai/dsh-system-prompt@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-llm@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4))(@deepseek-ai/dsh-scope@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)))': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-invariants': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-llm': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + '@deepseek-ai/dsh-scope': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)(@deepseek-ai/dsh-invariants@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)) + '@deepseek-ai/schemastery': 3.18.4 + + '@deepseek-ai/dsh-timeout@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + + '@deepseek-ai/dsh-typert-protocol@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + '@deepseek-ai/dsh-brand': 0.2.0-rc.1(@deepseek-ai/cordis@4.0.4) + + '@deepseek-ai/dsh-util-crypto@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + + '@deepseek-ai/dsh-util-values@0.2.0-rc.1(@deepseek-ai/cordis@4.0.4)': + dependencies: + '@deepseek-ai/cordis': 4.0.4 + + '@deepseek-ai/node-addon-system-darwin-arm64@0.1.2': + optional: true + + '@deepseek-ai/node-addon-system-darwin-x64@0.1.2': + optional: true + + '@deepseek-ai/node-addon-system-linux-arm64@0.1.2': + optional: true + + '@deepseek-ai/node-addon-system-linux-x64@0.1.2': + optional: true + + '@deepseek-ai/node-addon-system@0.1.2': + optionalDependencies: + '@deepseek-ai/node-addon-system-darwin-arm64': 0.1.2 + '@deepseek-ai/node-addon-system-darwin-x64': 0.1.2 + '@deepseek-ai/node-addon-system-linux-arm64': 0.1.2 + '@deepseek-ai/node-addon-system-linux-x64': 0.1.2 + + '@deepseek-ai/schemastery@3.18.4': + dependencies: + '@deepseek-ai/cosmokit': 1.8.5 '@standard-schema/spec': 1.1.0 '@electric-sql/pglite@0.5.4': {} @@ -1002,49 +1272,49 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.5': {} - '@koromix/koffi-darwin-arm64@3.1.4': + '@koromix/koffi-darwin-arm64@3.1.1': optional: true - '@koromix/koffi-darwin-x64@3.1.4': + '@koromix/koffi-darwin-x64@3.1.1': optional: true - '@koromix/koffi-freebsd-arm64@3.1.4': + '@koromix/koffi-freebsd-arm64@3.1.1': optional: true - '@koromix/koffi-freebsd-ia32@3.1.4': + '@koromix/koffi-freebsd-ia32@3.1.1': optional: true - '@koromix/koffi-freebsd-x64@3.1.4': + '@koromix/koffi-freebsd-x64@3.1.1': optional: true - '@koromix/koffi-linux-arm64@3.1.4': + '@koromix/koffi-linux-arm64@3.1.1': optional: true - '@koromix/koffi-linux-ia32@3.1.4': + '@koromix/koffi-linux-ia32@3.1.1': optional: true - '@koromix/koffi-linux-loong64@3.1.4': + '@koromix/koffi-linux-loong64@3.1.1': optional: true - '@koromix/koffi-linux-riscv64@3.1.4': + '@koromix/koffi-linux-riscv64@3.1.1': optional: true - '@koromix/koffi-linux-x64@3.1.4': + '@koromix/koffi-linux-x64@3.1.1': optional: true - '@koromix/koffi-openbsd-ia32@3.1.4': + '@koromix/koffi-openbsd-ia32@3.1.1': optional: true - '@koromix/koffi-openbsd-x64@3.1.4': + '@koromix/koffi-openbsd-x64@3.1.1': optional: true - '@koromix/koffi-win32-arm64@3.1.4': + '@koromix/koffi-win32-arm64@3.1.1': optional: true - '@koromix/koffi-win32-ia32@3.1.4': + '@koromix/koffi-win32-ia32@3.1.1': optional: true - '@koromix/koffi-win32-x64@3.1.4': + '@koromix/koffi-win32-x64@3.1.1': optional: true '@oxc-project/types@0.143.0': {} @@ -1207,23 +1477,23 @@ snapshots: fsevents@2.3.3: optional: true - koffi@3.1.4: + koffi@3.1.1: optionalDependencies: - '@koromix/koffi-darwin-arm64': 3.1.4 - '@koromix/koffi-darwin-x64': 3.1.4 - '@koromix/koffi-freebsd-arm64': 3.1.4 - '@koromix/koffi-freebsd-ia32': 3.1.4 - '@koromix/koffi-freebsd-x64': 3.1.4 - '@koromix/koffi-linux-arm64': 3.1.4 - '@koromix/koffi-linux-ia32': 3.1.4 - '@koromix/koffi-linux-loong64': 3.1.4 - '@koromix/koffi-linux-riscv64': 3.1.4 - '@koromix/koffi-linux-x64': 3.1.4 - '@koromix/koffi-openbsd-ia32': 3.1.4 - '@koromix/koffi-openbsd-x64': 3.1.4 - '@koromix/koffi-win32-arm64': 3.1.4 - '@koromix/koffi-win32-ia32': 3.1.4 - '@koromix/koffi-win32-x64': 3.1.4 + '@koromix/koffi-darwin-arm64': 3.1.1 + '@koromix/koffi-darwin-x64': 3.1.1 + '@koromix/koffi-freebsd-arm64': 3.1.1 + '@koromix/koffi-freebsd-ia32': 3.1.1 + '@koromix/koffi-freebsd-x64': 3.1.1 + '@koromix/koffi-linux-arm64': 3.1.1 + '@koromix/koffi-linux-ia32': 3.1.1 + '@koromix/koffi-linux-loong64': 3.1.1 + '@koromix/koffi-linux-riscv64': 3.1.1 + '@koromix/koffi-linux-x64': 3.1.1 + '@koromix/koffi-openbsd-ia32': 3.1.1 + '@koromix/koffi-openbsd-x64': 3.1.1 + '@koromix/koffi-win32-arm64': 3.1.1 + '@koromix/koffi-win32-ia32': 3.1.1 + '@koromix/koffi-win32-x64': 3.1.1 lightningcss-android-arm64@1.33.0: optional: true @@ -1429,3 +1699,5 @@ snapshots: stackback: 0.0.2 xtend@4.0.2: {} + + zod@4.6.5: {} diff --git a/scripts/check-release-artifacts.mjs b/scripts/check-release-artifacts.mjs index 7ae47e1..18c32ab 100644 --- a/scripts/check-release-artifacts.mjs +++ b/scripts/check-release-artifacts.mjs @@ -23,13 +23,9 @@ const lifecycleGuide = await readFile( join(projectDir, "docs/PLUGIN_LIFECYCLE.md"), "utf8", ); -const localLifecycle = await readFile( - join(projectDir, "scripts/plugin-profile-local.mjs"), - "utf8", -); assert(packageJson.private === true, "package.json must retain private: true"); -assert(packageJson.version === "0.6.0-rc.2", "release version must be RC.6 migration rc.2"); +assert(packageJson.version === "0.7.0-rc.1", "release version must match the DSH 0.2 adapter candidate"); assert( packageJson.license === "BSD-3-Clause", "package.json license must be BSD-3-Clause", @@ -65,17 +61,16 @@ assert( assert( npmrc === [ - "auto-install-peers=false", + "auto-install-peers=true", "@deepseek-ai:registry=https://registry.npmjs.org/", - "//registry.npmjs.org/:_authToken=${NPM_TOKEN}", "", ].join("\n"), ".npmrc must contain only the approved registry template", ); const baselines = { - "@deepseek-ai/cordis": ["4.0.1", "^4.0.1"], - "@deepseek-ai/dsh-session": ["0.1.0-rc.6", "0.1.0-rc.6"], - "@deepseek-ai/dsh-session-persistence": ["0.1.0-rc.6", "0.1.0-rc.6"], + "@deepseek-ai/cordis": ["4.0.4", "~4.0.4"], + "@deepseek-ai/dsh-session": ["0.2.0-rc.1", "0.2.0-rc.1"], + "@deepseek-ai/dsh-session-persistence": ["0.2.0-rc.1", "0.2.0-rc.1"], }; for (const [name, [development, peer]] of Object.entries(baselines)) { assert( @@ -90,7 +85,7 @@ for (const [name, [development, peer]] of Object.entries(baselines)) { assert( packageJson.devDependencies?.[ "@deepseek-ai/dsh-session-persistence-jsonl" - ] === "0.1.0-rc.6", + ] === "0.2.0-rc.1", "JSONL development baseline changed", ); const workshop = packageJson.dshWorkshop; @@ -125,20 +120,6 @@ for (const [name, content] of [ `${name} omits the explicit cutover gate`, ); } -for (const name of [ - "@deepseek-ai/dsh-attachment", - "@deepseek-ai/dsh-brand", - "@deepseek-ai/dsh-invariants", - "@deepseek-ai/dsh-llm", - "@deepseek-ai/dsh-scope", - "@deepseek-ai/dsh-timeout", - "@deepseek-ai/dsh-typert-protocol", -]) { - assert( - localLifecycle.includes(`\"${name}\": \"0.1.0-rc.6\"`), - `local lifecycle peer closure omits ${name}@0.1.0-rc.6`, - ); -} for (const file of ["SECURITY.md", "CONTRIBUTING.md"]) { assert( packageJson.files?.includes(file), diff --git a/scripts/compatibility.mjs b/scripts/compatibility.mjs new file mode 100644 index 0000000..fee4122 --- /dev/null +++ b/scripts/compatibility.mjs @@ -0,0 +1,23 @@ +import { readFile } from "node:fs/promises"; +const manifest = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8")); +export function peerSpecs() { + const variables = { + "@deepseek-ai/dsh-session": "DSH_TELEPORT_TEST_SESSION_SPEC", + "@deepseek-ai/dsh-session-persistence": "DSH_TELEPORT_TEST_SESSION_PERSISTENCE_SPEC", + "@deepseek-ai/dsh-session-persistence-jsonl": "DSH_TELEPORT_TEST_JSONL_SPEC", + "@deepseek-ai/cordis": "DSH_TELEPORT_TEST_CORDIS_SPEC", + }; + const primary = Object.fromEntries(Object.entries(variables).map(([name, variable]) => [ + name, process.env[variable]?.trim() || manifest.devDependencies[name], + ])); + // The DSH profile manager does not automatically install transitive peers. + // Keep one matching host closure for adapter imports in either smoke test. + const version = manifest.devDependencies["@deepseek-ai/dsh-session"]; + return { + ...Object.fromEntries(["dsh-scope", "dsh-invariants", "dsh-attachment", "dsh-brand", + "dsh-llm", "dsh-timeout", "dsh-typert-protocol"].map((name) => [`@deepseek-ai/${name}`, version])), + "@deepseek-ai/cordis-plugin-include": "1.0.9", + "@deepseek-ai/cordis-plugin-loader": "1.0.5", + ...primary, + }; +} diff --git a/scripts/plugin-lifecycle-real.mjs b/scripts/plugin-lifecycle-real.mjs index c7afee3..0730362 100644 --- a/scripts/plugin-lifecycle-real.mjs +++ b/scripts/plugin-lifecycle-real.mjs @@ -1,3 +1,4 @@ +import { peerSpecs as compatibilityPeers } from "./compatibility.mjs"; import { spawnSync } from "node:child_process"; import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; @@ -9,7 +10,7 @@ const dshBin = requiredPath("DSH_TELEPORT_TEST_DSH_BIN"); const fromRevision = requiredRevision("DSH_TELEPORT_TEST_FROM_REVISION"); const toRevision = requiredRevision("DSH_TELEPORT_TEST_TO_REVISION"); if (fromRevision === toRevision) throw new Error("lifecycle test revisions must differ"); -const peerSpecs = optionalPeerSpecs(); +const peerSpecs = compatibilityPeers(); const root = await mkdtemp(join(tmpdir(), "session-teleport-real-lifecycle-")); const dshHome = join(root, "dsh-home"); @@ -117,36 +118,6 @@ async function profileManifest(home, profile) { return JSON.parse(await readFile(join(home, "profiles", profile, "package.json"), "utf8")); } -function optionalPeerSpecs() { - const variables = { - "@deepseek-ai/dsh-session": "DSH_TELEPORT_TEST_SESSION_SPEC", - "@deepseek-ai/dsh-session-persistence": "DSH_TELEPORT_TEST_SESSION_PERSISTENCE_SPEC", - "@deepseek-ai/dsh-session-persistence-jsonl": "DSH_TELEPORT_TEST_JSONL_SPEC", - "@deepseek-ai/cordis": "DSH_TELEPORT_TEST_CORDIS_SPEC", - }; - const entries = Object.entries(variables).map(([dependency, name]) => [ - dependency, - process.env[name]?.trim() ?? "", - ]); - if (entries.every(([, value]) => value.length === 0)) return undefined; - const missing = entries.filter(([, value]) => value.length === 0); - if (missing.length > 0) { - throw new Error(`peer package specs must be supplied together; missing ${missing.map(([name]) => name).join(", ")}`); - } - return { - ...Object.fromEntries(entries), - "@deepseek-ai/cordis-plugin-include": "1.0.6-rc.4", - "@deepseek-ai/cordis-plugin-loader": "1.0.2-rc.4", - "@deepseek-ai/dsh-attachment": "0.0.1-rc.5", - "@deepseek-ai/dsh-brand": "0.0.1-rc.5", - "@deepseek-ai/dsh-invariants": "0.0.1-rc.5", - "@deepseek-ai/dsh-llm": "0.0.1-rc.5", - "@deepseek-ai/dsh-scope": "0.0.1-rc.5", - "@deepseek-ai/dsh-timeout": "0.0.1-rc.5", - "@deepseek-ai/dsh-typert-protocol": "0.0.1-rc.5", - }; -} - async function installPeers(specs) { runDsh(["plugin", "--profile", profile, "install", "--ignore-scripts"]); const manifestPath = join(dshHome, "profiles", profile, "package.json"); diff --git a/scripts/plugin-profile-local.mjs b/scripts/plugin-profile-local.mjs index 71bade3..c0abeb7 100644 --- a/scripts/plugin-profile-local.mjs +++ b/scripts/plugin-profile-local.mjs @@ -1,3 +1,4 @@ +import { peerSpecs as compatibilityPeers } from "./compatibility.mjs"; import { spawnSync } from "node:child_process"; import { existsSync } from "node:fs"; import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises"; @@ -9,7 +10,7 @@ const projectDir = dirname(dirname(fileURLToPath(import.meta.url))); const projectPackage = JSON.parse(await readFile(join(projectDir, "package.json"), "utf8")); const dshBin = requiredPath("DSH_TELEPORT_TEST_DSH_BIN"); if (!existsSync(dshBin)) throw new Error("DSH_TELEPORT_TEST_DSH_BIN does not exist"); -const peerSpecs = requiredPeerSpecs(); +const peerSpecs = compatibilityPeers(); const root = await mkdtemp(join(tmpdir(), "session-teleport-local-profile-")); const packDir = join(root, "package"); @@ -122,28 +123,6 @@ function requiredPath(name) { return resolve(value); } -function requiredPeerSpecs() { - return { - "@deepseek-ai/dsh-session": requiredValue("DSH_TELEPORT_TEST_SESSION_SPEC"), - "@deepseek-ai/dsh-session-persistence": requiredValue( - "DSH_TELEPORT_TEST_SESSION_PERSISTENCE_SPEC", - ), - "@deepseek-ai/dsh-session-persistence-jsonl": requiredValue( - "DSH_TELEPORT_TEST_JSONL_SPEC", - ), - "@deepseek-ai/cordis": requiredValue("DSH_TELEPORT_TEST_CORDIS_SPEC"), - "@deepseek-ai/cordis-plugin-include": "1.0.6", - "@deepseek-ai/cordis-plugin-loader": "1.0.2", - "@deepseek-ai/dsh-attachment": "0.1.0-rc.6", - "@deepseek-ai/dsh-brand": "0.1.0-rc.6", - "@deepseek-ai/dsh-invariants": "0.1.0-rc.6", - "@deepseek-ai/dsh-llm": "0.1.0-rc.6", - "@deepseek-ai/dsh-scope": "0.1.0-rc.6", - "@deepseek-ai/dsh-timeout": "0.1.0-rc.6", - "@deepseek-ai/dsh-typert-protocol": "0.1.0-rc.6", - }; -} - function requiredValue(name) { const value = process.env[name]?.trim(); if (value === undefined || value.length === 0) throw new Error(`${name} is required`); diff --git a/src/authority.ts b/src/authority.ts index 2f68d6d..db40469 100644 --- a/src/authority.ts +++ b/src/authority.ts @@ -28,6 +28,7 @@ import { TeleportError } from "./types.js"; interface SessionRow { session_id: string; header: unknown; + inherited_event_count: string | number | null; revision: string | number; next_seq: string | number; writer_epoch: string | number; @@ -101,15 +102,16 @@ export class TeleportAuthority { async createSession(request: CreateSessionRequest): Promise { assertIdentifier(request.sessionId, "sessionId"); assertIdentifier(request.deviceId, "deviceId"); + if (request.inheritedEventCount !== undefined) safeNonNegative(request.inheritedEventCount, "inheritedEventCount"); const header = canonicalJson(request.header); const writerToken = secret(); const inserted = await this.database.query<{ session_id: string }>( `INSERT INTO teleport_sessions - (session_id, header, writer_epoch, writer_device_id, writer_token_hash) - VALUES ($1, $2::jsonb, 1, $3, $4) + (session_id, header, writer_epoch, writer_device_id, writer_token_hash, inherited_event_count) + VALUES ($1, $2::jsonb, 1, $3, $4, $5) ON CONFLICT (session_id) DO NOTHING RETURNING session_id`, - [request.sessionId, header, request.deviceId, sha256(writerToken)], + [request.sessionId, header, request.deviceId, sha256(writerToken), request.inheritedEventCount ?? null], ); if (inserted.rowCount !== 1) { throw new TeleportError("SESSION_EXISTS", `session "${request.sessionId}" already exists`); @@ -139,12 +141,14 @@ export class TeleportAuthority { expectedNextSeq: 0, idempotencyKey: request.idempotencyKey, events: request.events, - }); + }, true); + if (request.inheritedEventCount !== undefined) safeNonNegative(request.inheritedEventCount, "inheritedEventCount"); const header = canonicalJson(request.header); const digest = sha256( canonicalJson({ sessionId: request.sessionId, header: request.header, + ...(request.inheritedEventCount === undefined ? {} : { inheritedEventCount: request.inheritedEventCount }), deviceId: request.deviceId, events: request.events, }), @@ -153,11 +157,11 @@ export class TeleportAuthority { const result = await this.database.transaction(async (transaction) => { const inserted = await transaction.query<{ session_id: string }>( `INSERT INTO teleport_sessions - (session_id, header, writer_epoch, writer_device_id, writer_token_hash) - VALUES ($1, $2::jsonb, 1, $3, $4) + (session_id, header, writer_epoch, writer_device_id, writer_token_hash, inherited_event_count) + VALUES ($1, $2::jsonb, 1, $3, $4, $5) ON CONFLICT (session_id) DO NOTHING RETURNING session_id`, - [request.sessionId, header, request.deviceId, sha256(request.writerToken)], + [request.sessionId, header, request.deviceId, sha256(request.writerToken), request.inheritedEventCount ?? null], ); if (inserted.rowCount !== 1) { @@ -192,7 +196,7 @@ export class TeleportAuthority { [request.sessionId, event.seq, eventJson(event)], ); } - const nextSeq = request.events.at(-1)!.seq + 1; + const nextSeq = request.events.length; await transaction.query( `UPDATE teleport_sessions SET revision = 1, next_seq = $2, updated_at = CURRENT_TIMESTAMP @@ -208,7 +212,7 @@ export class TeleportAuthority { request.sessionId, request.idempotencyKey, digest, - request.events.at(-1)!.seq, + nextSeq - 1, nextSeq, ], ); @@ -325,7 +329,7 @@ export class TeleportAuthority { return this.database.transaction( async (transaction) => { const sessionResult = await transaction.query( - `SELECT session_id, header, revision, next_seq, writer_epoch, + `SELECT session_id, header, inherited_event_count, revision, next_seq, writer_epoch, writer_device_id, writer_token_hash FROM teleport_sessions WHERE session_id = $1`, [sessionId], @@ -343,6 +347,9 @@ export class TeleportAuthority { return { sessionId, header: asJsonValue(session.header), + ...(session.inherited_event_count == null ? {} : { + inheritedEventCount: integer(session.inherited_event_count, "inherited_event_count"), + }), revision: integer(session.revision, "revision"), nextSeq: integer(session.next_seq, "next_seq"), writerEpoch: integer(session.writer_epoch, "writer_epoch"), @@ -359,7 +366,7 @@ export class TeleportAuthority { async head(sessionId: string): Promise { assertIdentifier(sessionId, "sessionId"); const result = await this.database.query( - `SELECT session_id, header, revision, next_seq, writer_epoch, + `SELECT session_id, header, inherited_event_count, revision, next_seq, writer_epoch, writer_device_id, writer_token_hash FROM teleport_sessions WHERE session_id = $1`, [sessionId], @@ -373,7 +380,7 @@ export class TeleportAuthority { async listHeads(): Promise { const result = await this.database.query( - `SELECT session_id, header, revision, next_seq, writer_epoch, + `SELECT session_id, header, inherited_event_count, revision, next_seq, writer_epoch, writer_device_id, writer_token_hash FROM teleport_sessions ORDER BY created_at, session_id`, @@ -809,7 +816,7 @@ export class TeleportAuthority { async function lockSession(transaction: SqlExecutor, sessionId: string): Promise { const result = await transaction.query( - `SELECT session_id, header, revision, next_seq, writer_epoch, + `SELECT session_id, header, inherited_event_count, revision, next_seq, writer_epoch, writer_device_id, writer_token_hash FROM teleport_sessions WHERE session_id = $1 @@ -842,6 +849,9 @@ function headFromRow(session: SessionRow): SessionHead { return { sessionId: session.session_id, header: asJsonValue(session.header), + ...(session.inherited_event_count == null ? {} : { + inheritedEventCount: integer(session.inherited_event_count, "inherited_event_count"), + }), revision: integer(session.revision, "revision"), nextSeq: integer(session.next_seq, "next_seq"), writerEpoch: integer(session.writer_epoch, "writer_epoch"), @@ -851,7 +861,7 @@ function headFromRow(session: SessionRow): SessionHead { }; } -function validateAppend(request: AppendRequest): void { +function validateAppend(request: AppendRequest, allowEmpty = false): void { assertIdentifier(request.sessionId, "sessionId"); assertWriterCredentials(request.writer); assertIdentifier(request.writer.deviceId, "writer.deviceId"); @@ -860,7 +870,7 @@ function validateAppend(request: AppendRequest): void { safeNonNegative(request.writer.writerEpoch, "writer.writerEpoch"); safeNonNegative(request.expectedRevision, "expectedRevision"); safeNonNegative(request.expectedNextSeq, "expectedNextSeq"); - if (!Array.isArray(request.events) || request.events.length === 0) { + if (!Array.isArray(request.events) || (!allowEmpty && request.events.length === 0)) { throw new TeleportError("BAD_REQUEST", "append requires at least one event"); } for (const [index, value] of request.events.entries()) { @@ -922,7 +932,7 @@ function validateImportRollback(request: RollbackSessionImportRequest): void { assertIdentifier(request.importIdempotencyKey, "importIdempotencyKey"); assertIdentifier(request.actorId, "actorId"); safePositive(request.expectedRevision, "expectedRevision"); - safePositive(request.expectedNextSeq, "expectedNextSeq"); + safeNonNegative(request.expectedNextSeq, "expectedNextSeq"); safePositive(request.expectedWriterEpoch, "expectedWriterEpoch"); if (typeof request.reason !== "string" || request.reason.trim().length === 0) { throw new TeleportError("BAD_REQUEST", "rollback reason is required"); diff --git a/src/client.ts b/src/client.ts index b8b86ac..3c1f627 100644 --- a/src/client.ts +++ b/src/client.ts @@ -41,12 +41,20 @@ export class TeleportClient { this.baseUrl = baseUrl.replace(/\/$/, ""); } - async health(signal?: AbortSignal): Promise { + async health(signal?: AbortSignal, requiredSchemaVersion?: number): Promise { const response = await fetch(`${this.baseUrl}/health`, { ...(signal === undefined ? {} : { signal }), }); if (response.ok) { - await response.arrayBuffer(); + if (requiredSchemaVersion === undefined) { + await response.arrayBuffer(); + } else { + const body = await response.json() as { schemaVersion?: number }; + if (body.schemaVersion !== requiredSchemaVersion) { + throw new TeleportRemoteError(409, "SCHEMA_INCOMPATIBLE", + `Teleport authority must run schema ${requiredSchemaVersion}; upgrade the service with the adapter`); + } + } return; } let message = `Teleport service returned HTTP ${response.status}`; @@ -68,18 +76,19 @@ export class TeleportClient { return this.request("POST", "/v1/sessions/materialize", request); } - listHeads(): Promise { - return this.request("GET", "/v1/sessions"); + listHeads(signal?: AbortSignal): Promise { + return this.request("GET", "/v1/sessions", undefined, false, signal); } - head(sessionId: string): Promise { - return this.request("GET", `/v1/sessions/${encodeURIComponent(sessionId)}/head`); + head(sessionId: string, signal?: AbortSignal): Promise { + return this.request("GET", `/v1/sessions/${encodeURIComponent(sessionId)}/head`, undefined, false, signal); } - snapshot(sessionId: string, afterSeq = -1): Promise { + snapshot(sessionId: string, afterSeq = -1, signal?: AbortSignal): Promise { return this.request( "GET", `/v1/sessions/${encodeURIComponent(sessionId)}?after=${afterSeq}`, + undefined, false, signal, ); } @@ -150,12 +159,14 @@ export class TeleportClient { path: string, body?: unknown, admin = false, + signal?: AbortSignal, ): Promise { if (admin && this.adminToken === undefined) { throw new Error("Teleport admin token is required for this operation"); } const response = await fetch(`${this.baseUrl}${path}`, { method, + ...(signal === undefined ? {} : { signal }), headers: { ...(this.apiToken === undefined ? {} : { authorization: `Bearer ${this.apiToken}` }), ...(admin ? { "x-teleport-admin-token": this.adminToken! } : {}), diff --git a/src/dsh-adapter.ts b/src/dsh-adapter.ts index ee0e332..1083625 100644 --- a/src/dsh-adapter.ts +++ b/src/dsh-adapter.ts @@ -1,33 +1,26 @@ +import { mkdir, open as openFile, type FileHandle } from "node:fs/promises"; +import { join } from "node:path"; import { Context, Service } from "@deepseek-ai/cordis"; +import { tryLockExclusive } from "@deepseek-ai/node-addon-system/flock"; import { - PersistenceCoordinator, - SessionPersistence, - SessionPersistenceRevision, - type PersistenceBackend, - type SessionLocation, - type SessionPersistenceSnapshot, - type StoredPrefix, - type StoredSuffix, + SessionAlreadyExistsError, SessionAlreadyOwnedError, SessionHandleClosedError, + SessionOwnershipLostError, SessionPersistence, SessionPersistenceNotFoundError, + SessionPersistenceRevision, SessionReadOnlyError, assertContiguous, assertStoredId, + assertVersion, materializeAppendBatch, materializeCreateHeader, validateStoredEvents, + type SessionAccess, type SessionHandle, type SessionHandleAppendOptions, + type SessionHandleFlushOptions, type SessionHandleReadOptions, type SessionHandleReadResult, + type SessionPersistenceCreateOptions, type SessionPersistenceListOptions, + type SessionPersistenceOpenOptions, type SessionPersistenceSnapshot, + type SessionPersistenceStatOptions, } from "@deepseek-ai/dsh-session-persistence"; -import type { - SessionEvent, - SessionHeader, - SessionId, - SessionPreparation, +import { + SessionLogOffset, type SessionEvent, type SessionHeader, type SessionId, } from "@deepseek-ai/dsh-session"; +import { SCHEMA_VERSION } from "./schema.js"; import { canonicalJson, secret, sha256 } from "./canonical.js"; -import { - FileWriterCredentialStore, - type WriterCredentialStore, -} from "./credential-store.js"; +import { FileWriterCredentialStore, type WriterCredentialStore } from "./credential-store.js"; import { TeleportClient, TeleportRemoteError } from "./client.js"; -import type { - CreateHandoffResult, - SessionHead, - SessionSnapshot, - TeleportEvent, - WriterCredentials, -} from "./types.js"; +import type { CreateHandoffResult, JsonValue, SessionHead, TeleportEvent, WriterCredentials } from "./types.js"; export interface SessionPersistenceTeleportConfig { baseUrl: string; @@ -42,330 +35,393 @@ export interface SessionPersistenceTeleportDependencies { credentialStore?: WriterCredentialStore; } -interface ObservedHead { - revision: number; - nextSeq: number; -} - -/** DSH PersistenceBackend adapter over the Teleport HTTP authority. */ -export class SessionPersistenceTeleport - extends SessionPersistence - implements PersistenceBackend -{ +/** DSH 0.2 handle-based persistence over the PostgreSQL authority. */ +export class SessionPersistenceTeleport extends SessionPersistence { static inject = ["sessions"]; - override readonly name = "session-persistence-teleport"; - override readonly supportsRawArtifacts = false; - private readonly client: TeleportClient; private readonly credentials: WriterCredentialStore; - private readonly coordinator: PersistenceCoordinator; - private readonly observedHeads = new Map(); - private readonly sourceIdentity: string; - private readonly deviceId: string; - - constructor( - ctx: Context, - readonly config: SessionPersistenceTeleportConfig, - dependencies: SessionPersistenceTeleportDependencies = {}, - ) { + private readonly writers = new Map(); + private readonly handles = new Set(); + private readonly sourceIdentity = secret(); + + constructor(ctx: Context, readonly config: SessionPersistenceTeleportConfig, + dependencies: SessionPersistenceTeleportDependencies = {}) { validateConfig(config); super(ctx); - this.deviceId = config.deviceId; - const baseUrl = config.baseUrl.replace(/\/$/, ""); - this.sourceIdentity = sha256(baseUrl); - this.client = dependencies.client ?? new TeleportClient(baseUrl, config.apiToken); - this.credentials = - dependencies.credentialStore ?? new FileWriterCredentialStore(config.credentialDir); - this.coordinator = new PersistenceCoordinator(this.ctx, this); + this.client = dependencies.client ?? new TeleportClient(config.baseUrl, config.apiToken); + this.credentials = dependencies.credentialStore ?? new FileWriterCredentialStore(config.credentialDir); + this.ctx.on("session/event", (session, event) => { + this.writers.get(session.id)?.enqueue(event, (error) => { + this.ctx.logger.warn(`Teleport background write failed for ${session.id}; buffered events retained: ${String(error)}`); + }); + }); + this.ctx.on("session/flush", (session) => this.writers.get(session.id)?.flush()); + this.ctx.on("session/disposed", (session) => { + this.writers.get(session.id)?.close().catch((error: unknown) => { + this.ctx.logger.warn(`Teleport close failed for ${session.id}: ${String(error)}`); + }); + }); + this.ctx.effect(() => async () => { + const results = await Promise.allSettled([...this.handles].map((handle) => handle.close())); + throwFailures(results, "Teleport handle teardown failed"); + }, "Teleport open handles"); } protected async [Service.init](): Promise { - const timeoutMs = this.config.healthTimeoutMs ?? 5_000; + await this.client.health(AbortSignal.timeout(this.config.healthTimeoutMs ?? 5_000), SCHEMA_VERSION); + } + + async create(header: SessionHeader, options?: SessionPersistenceCreateOptions): Promise { + options?.signal?.throwIfAborted(); + const meta = materializeCreateHeader(header); + assertVersion(meta); + const inheritedEventCount = inheritedCount(meta, options?.inheritedEventCount); + if (this.writers.has(meta.id)) throw new SessionAlreadyExistsError(meta.id); + this.writers.set(meta.id, null); + let lock: FileHandle | undefined; try { - await this.client.health(AbortSignal.timeout(timeoutMs)); - } catch (error: unknown) { - throw new Error( - `Teleport service health check failed for ${this.config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`, - { cause: error }, - ); + lock = await this.acquireLock(meta.id); + if (await this.stat(meta.id, options)) throw new SessionAlreadyExistsError(meta.id); + options?.signal?.throwIfAborted(); + let writer = await this.credentials.get(meta.id); + if (writer === undefined) { + writer = { deviceId: this.config.deviceId, writerEpoch: 1, writerToken: secret() }; + // Save retry/recovery material before the remote transaction commits. + await this.credentials.put(meta.id, writer); + } + this.assertDevice(meta.id, writer); + const result = await this.client.materializeSession({ + sessionId: meta.id, header: meta as unknown as JsonValue, inheritedEventCount, + deviceId: writer.deviceId, writerToken: writer.writerToken, + idempotencyKey: `dsh-create-${sha256(canonicalJson({ meta, inheritedEventCount, token: writer.writerToken }))}`, + events: [], + }); + return this.adopt(new TeleportHandle(this.client, meta, inheritedEventCount, "write", + result.revision, 0, writer, lock, (handle) => this.release(handle))); + } catch (error) { + this.writers.delete(meta.id); + await lock?.close(); + if (remoteCode(error, "SESSION_EXISTS")) throw new SessionAlreadyExistsError(meta.id); + throw error; } } - locate(_meta: SessionHeader): SessionLocation | undefined { - return undefined; + async open(id: SessionId, access: SessionAccess, options?: SessionPersistenceOpenOptions): Promise { + options?.signal?.throwIfAborted(); + if (access !== "read" && access !== "write") throw new TypeError("invalid session access"); + if (access === "write") { + if (this.writers.has(id)) throw new SessionAlreadyOwnedError(id); + this.writers.set(id, null); + } + let lock: FileHandle | undefined; + try { + if (access === "write") lock = await this.acquireLock(id); + const stored = await this.client.snapshot(id, -1, options?.signal); + const meta = storedHeader(id, stored); + const cut = inheritedCount(meta, stored.inheritedEventCount); + validateStoredEvents(meta, cloneEvents(stored.events)); + assertContiguous(id, stored.events as unknown as SessionEvent[], 0); + if (stored.events.length !== stored.nextSeq) throw new Error(`Incomplete Teleport log for ${id}`); + options?.signal?.throwIfAborted(); + const writer = access === "write" ? await this.requireWriter(id) : undefined; + if (writer !== undefined && (writer.writerEpoch !== stored.writerEpoch || writer.deviceId !== stored.writerDeviceId)) { + throw new SessionOwnershipLostError(id); + } + return this.adopt(new TeleportHandle(this.client, meta, cut, access, stored.revision, + stored.nextSeq, writer, lock, (handle) => this.release(handle))); + } catch (error) { + if (access === "write") this.writers.delete(id); + await lock?.close(); + if (remoteCode(error, "NOT_FOUND")) throw new SessionPersistenceNotFoundError(id); + throw error; + } } - create(meta: SessionHeader): Promise { - return this.coordinator.create(meta); + async flush(): Promise { + const results = await Promise.allSettled([...this.writers.values()].map(async (handle) => { + try { await handle?.flush(); } + catch (error) { + if (error instanceof SessionHandleClosedError) await handle?.close(); + else throw error; + } + })); + throwFailures(results, "Teleport flush failed"); } - append(id: SessionId, events: readonly SessionEvent[]): Promise { - return this.coordinator.append(id, events); + async stat(id: SessionId, options?: SessionPersistenceStatOptions): Promise { + try { return this.snapshot(await this.client.head(id, options?.signal)); } + catch (error) { if (remoteCode(error, "NOT_FOUND")) return undefined; throw error; } } - override prepare(id: SessionId, signal?: AbortSignal): Promise { - return this.coordinator.prepare(id, signal); + async list(options?: SessionPersistenceListOptions): Promise { + return (await this.client.listHeads(options?.signal)).map((head) => this.snapshot(head)); } - load(id: SessionId): Promise<{ meta: SessionHeader; events: readonly SessionEvent[] }> { - return this.coordinator.load(id); + async createHandoff(id: SessionId, ttlMs?: number): Promise { + await this.writers.get(id)?.flush(); + return this.client.createHandoff({ sessionId: id, writer: await this.requireWriter(id), + ...(ttlMs === undefined ? {} : { ttlMs }) }); } - inspect( - id: SessionId, - signal?: AbortSignal, - ): Promise<{ meta: SessionHeader; events: readonly SessionEvent[] }> { - return this.coordinator.inspect(id, signal); + async acceptHandoff(code: string): Promise { + const result = await this.client.acceptHandoff({ code, deviceId: this.config.deviceId }); + await this.credentials.put(result.sessionId, result.writer); + return structuredClone(result.writer); } - readFrom( - id: SessionId, - fromSeq: number, - signal?: AbortSignal, - ): Promise<{ meta: SessionHeader; events: SessionEvent[] }> { - return this.coordinator.readFrom(id, fromSeq, signal); + private snapshot(head: SessionHead): SessionPersistenceSnapshot { + return { header: structuredClone(head.header) as unknown as SessionHeader, + revision: SessionPersistenceRevision(`teleport:${this.sourceIdentity}:${head.sessionId}:${head.revision}`), + eventCount: head.nextSeq }; } - async loadStored( - id: SessionId, - signal?: AbortSignal, - ): Promise | undefined> { - signal?.throwIfAborted(); - let snapshot: SessionSnapshot; - try { - snapshot = await this.client.snapshot(id); - } catch (error: unknown) { - if (isNotFound(error)) return undefined; - throw error; - } - signal?.throwIfAborted(); - this.observe(id, snapshot.revision, snapshot.nextSeq); - return { - meta: cloneHeader(snapshot.header), - events: cloneEvents(snapshot.events), - revision: this.revision(id, snapshot.revision), - }; + private adopt(handle: TeleportHandle): TeleportHandle { + this.handles.add(handle); + if (handle.access === "write") this.writers.set(handle.id, handle); + return handle; } - async readStoredRevision( - id: SessionId, - signal?: AbortSignal, - ): Promise { - signal?.throwIfAborted(); - let head: SessionHead; - try { - head = await this.client.head(id); - } catch (error: unknown) { - if (isNotFound(error)) return undefined; - throw error; - } - signal?.throwIfAborted(); - return this.revision(id, head.revision); + private release(handle: TeleportHandle): void { + this.handles.delete(handle); + if (this.writers.get(handle.id) === handle) this.writers.delete(handle.id); } - async loadStoredFrom( - id: SessionId, - fromSeq: number, - signal?: AbortSignal, - ): Promise { - signal?.throwIfAborted(); - let snapshot: SessionSnapshot; - try { - snapshot = await this.client.snapshot(id, fromSeq - 1); - } catch (error: unknown) { - if (isNotFound(error)) return undefined; - throw error; - } - signal?.throwIfAborted(); - return { - meta: cloneHeader(snapshot.header), - events: cloneEvents(snapshot.events), - }; + private async requireWriter(id: string): Promise { + const writer = await this.credentials.get(id); + if (writer === undefined) throw new SessionAlreadyOwnedError(id as SessionId); + this.assertDevice(id, writer); + return writer; } - async appendBatch( - meta: SessionHeader, - events: readonly SessionEvent[], - isMaterialized: boolean, - ): Promise { - if (events.length === 0) return; - const teleportEvents = cloneTeleportEvents(events); - if (!isMaterialized) { - let writer = await this.credentials.get(meta.id); - if (writer === undefined) { - writer = { - deviceId: this.deviceId, - writerEpoch: 1, - writerToken: secret(), - }; - // Persist the retry material before the remote commit. If the response - // is lost, the next coordinator retry can reproduce the same authority. - await this.credentials.put(meta.id, writer); + private assertDevice(id: string, writer: WriterCredentials): void { + if (writer.deviceId !== this.config.deviceId) throw new SessionOwnershipLostError(id as SessionId); + } + + private async acquireLock(id: SessionId): Promise { + // The OS releases this lock on process exit. Never unlink its stable inode. + // All profiles on one device must share credentialDir; device authority is + // separately fenced by PostgreSQL when a handoff changes the writer epoch. + const directory = join(this.config.credentialDir, "locks"); + await mkdir(directory, { recursive: true, mode: 0o700 }); + const lock = await openFile(join(directory, `${sha256(id)}.lock`), "a", 0o600); + try { await tryLockExclusive(lock.fd); return lock; } + catch (error) { + await lock.close(); + if (error instanceof Error && "code" in error && ["EAGAIN", "EWOULDBLOCK"].includes(String(error.code))) { + throw new SessionAlreadyOwnedError(id); } - this.assertLocalWriter(meta.id, writer); - const result = await this.client.materializeSession({ - sessionId: meta.id, - header: structuredClone(meta) as never, - deviceId: writer.deviceId, - writerToken: writer.writerToken, - idempotencyKey: mutationKey("materialize", meta.id, 0, 0, { - header: meta, - events: teleportEvents, - }), - events: teleportEvents, - }); - this.observe(meta.id, result.revision, result.nextSeq); - return; + throw error; } - await this.appendExisting(meta.id, teleportEvents); } +} - async commitRepair( - meta: SessionHeader, - _tornMarker: undefined, - closers: readonly SessionEvent[], - ): Promise { - if (closers.length === 0) return; - await this.appendExisting(meta.id, cloneTeleportEvents(closers)); +class TeleportHandle implements SessionHandle { + readonly id: SessionId; + readonly header: SessionHeader; + private chain: Promise = Promise.resolve(); + private closing: Promise | undefined; + private lost = false; + private pending: SessionEvent[] = []; + private retryBatch: SessionEvent[] | undefined; + private timer: ReturnType | undefined; + private automaticPaused = false; + private reportBackgroundError: ((error: unknown) => void) | undefined; + private observedLength: number; + + constructor(private readonly client: TeleportClient, header: SessionHeader, + readonly inheritedEventCount: SessionLogOffset, readonly access: SessionAccess, + private revision: number, private cursor: number, private readonly writer: WriterCredentials | undefined, + private readonly lock: FileHandle | undefined, private readonly release: (handle: TeleportHandle) => void) { + this.id = header.id; + this.header = freezeHeader(header); + this.observedLength = cursor; } - async list(signal?: AbortSignal): Promise { - signal?.throwIfAborted(); - const heads = await this.client.listHeads(); - signal?.throwIfAborted(); - return heads.map((head) => cloneHeader(head.header)); + read(offset = 0, length = Number.MAX_SAFE_INTEGER, options?: SessionHandleReadOptions): Promise { + return this.run("read", async () => { + if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(length) || length < 0) { + throw new TypeError("read offset and length must be non-negative safe integers"); + } + const stored = await this.client.snapshot(this.id, -1, options?.signal); + const meta = storedHeader(this.id, stored); + if (canonicalJson(meta) !== canonicalJson(this.header) || inheritedCount(meta, stored.inheritedEventCount) !== this.inheritedEventCount) { + throw new Error(`Teleport metadata changed for ${this.id}`); + } + const events = validateStoredEvents(meta, cloneEvents(stored.events)); + assertContiguous(this.id, events, 0); + if (events.length < this.observedLength || events.length !== stored.nextSeq) { + throw new Error(`Teleport log shrank or is incomplete for ${this.id}`); + } + this.observedLength = events.length; + return { events: events.slice(offset, offset + length), eventState: "detached" }; + }); } - async listSnapshots(signal?: AbortSignal): Promise { - signal?.throwIfAborted(); - const heads = await this.client.listHeads(); - signal?.throwIfAborted(); - return heads.map((head) => ({ - header: cloneHeader(head.header), - revision: this.revision(head.sessionId, head.revision), - })); + append(events: readonly SessionEvent[], options?: SessionHandleAppendOptions): Promise { + // Snapshot synchronously, before the queued write can observe caller mutation. + let batch: readonly SessionEvent[]; + try { this.assertOpen("append"); batch = materializeAppendBatch(events); } + catch (error) { return Promise.reject(error); } + return this.run("append", async () => { + this.assertWritable("append"); + options?.signal?.throwIfAborted(); + await this.drain(); + await this.persist(batch); + }); } - async createHandoff(id: SessionId, ttlMs?: number): Promise { - const writer = await this.requireWriter(id); - return this.client.createHandoff({ - sessionId: id, - writer, - ...(ttlMs === undefined ? {} : { ttlMs }), + flush(options?: SessionHandleFlushOptions): Promise { + return this.run("flush", async () => { + this.assertWritable("flush"); + options?.signal?.throwIfAborted(); + await this.drain(); + // Every append already commits a PostgreSQL transaction. Check that this + // handle still owns the writer even when the barrier has no events. + const head = await this.client.head(this.id); + if (head.writerEpoch !== this.writer!.writerEpoch || head.writerDeviceId !== this.writer!.deviceId) { + this.lost = true; + throw new SessionOwnershipLostError(this.id); + } + this.automaticPaused = false; + this.scheduleBackground(); }); } - async acceptHandoff(code: string): Promise { - const accepted = await this.client.acceptHandoff({ code, deviceId: this.deviceId }); - await this.credentials.put(accepted.sessionId, accepted.writer); - this.observe(accepted.sessionId, accepted.revision, accepted.nextSeq); - return structuredClone(accepted.writer); + enqueue(event: SessionEvent, onError: (error: unknown) => void): void { + if (this.closing !== undefined || this.lost) return; + this.pending.push(...materializeAppendBatch([event])); + this.reportBackgroundError = onError; + this.scheduleBackground(); } - private async appendExisting(id: SessionId, events: TeleportEvent[]): Promise { - const writer = await this.requireWriter(id); - const observed = this.observedHeads.get(id); - if (observed === undefined) { - throw new Error( - `session "${id}" has no observed Teleport head; load it before appending`, - ); - } - const nextSeq = events[0]!.seq; - if (observed.nextSeq !== nextSeq) { - throw new Error( - `Teleport head changed for "${id}": observed next seq ${observed.nextSeq}, append starts at ${nextSeq}`, - ); - } - const result = await this.client.append({ - sessionId: id, - writer, - expectedRevision: observed.revision, - expectedNextSeq: observed.nextSeq, - idempotencyKey: mutationKey( - "append", - id, - observed.revision, - observed.nextSeq, - events, - ), - events, + private scheduleBackground(): void { + if (this.pending.length === 0 || this.automaticPaused || this.closing !== undefined || this.timer !== undefined) return; + this.timer = setTimeout(() => { + this.timer = undefined; + // Pause automatic retries on failure; an explicit flush retries the exact + // retained batch and resumes the automatic path only after success. + void this.flush().catch((error: unknown) => { + this.automaticPaused = true; + if (this.timer !== undefined) clearTimeout(this.timer); + this.timer = undefined; + this.reportBackgroundError?.(error); + }); + }, 200); + this.timer.unref(); + } + + close(): Promise { + if (this.closing !== undefined) return this.closing; + if (this.timer !== undefined) clearTimeout(this.timer); + this.closing = this.chain.then(async () => { + try { if (this.access === "write") await this.drain(); } + finally { try { await this.lock?.close(); } finally { this.release(this); } } }); - this.observe(id, result.revision, result.nextSeq); + return this.closing; } - private async requireWriter(id: SessionId): Promise { - const writer = await this.credentials.get(id); - if (writer === undefined) { - throw new Error( - `this device has no writer credential for session "${id}"; accept a Teleport handoff before appending`, - ); - } - this.assertLocalWriter(id, writer); - return writer; + [Symbol.asyncDispose](): Promise { return this.close(); } + + private run(operation: string, work: () => Promise): Promise { + try { this.assertOpen(operation); } catch (error) { return Promise.reject(error); } + const result = this.chain.then(work); + this.chain = result.then(() => {}, () => {}); + return result; } - private assertLocalWriter(id: SessionId, writer: WriterCredentials): void { - if (writer.deviceId !== this.deviceId) { - throw new Error( - `writer credential for session "${id}" belongs to device "${writer.deviceId}", not "${this.deviceId}"`, - ); - } + private assertOpen(operation: string): void { + if (this.closing !== undefined) throw new SessionHandleClosedError(this.id, operation); } - private observe(id: string, revision: number, nextSeq: number): void { - this.observedHeads.set(id, { revision, nextSeq }); + private assertWritable(operation: string): void { + if (this.access !== "write") throw new SessionReadOnlyError(this.id, operation); + if (this.lost) throw new SessionOwnershipLostError(this.id); + } + + private async drain(): Promise { + while (this.pending.length > 0) { + // Preserve a failed request's exact batch and idempotency identity, even + // if more live events arrive after a commit whose response was lost. + const batch = this.retryBatch ??= this.pending.slice(); + await this.persist(batch); + this.pending.splice(0, batch.length); + this.retryBatch = undefined; + } } - private revision(id: string, revision: number): SessionPersistenceRevision { - return SessionPersistenceRevision( - `teleport:${this.sourceIdentity}:session:${id}:revision:${revision}`, - ); + private async persist(batch: readonly SessionEvent[]): Promise { + this.assertWritable("append"); + if (batch.length === 0) return; + assertContiguous(this.id, batch, this.cursor); + // Validate required vocabulary and the exact records being written, too. + validateStoredEvents(this.header, [...batch]); + try { + const result = await this.client.append({ sessionId: this.id, writer: this.writer!, + expectedRevision: this.revision, expectedNextSeq: this.cursor, + idempotencyKey: `dsh-append-${sha256(canonicalJson({ id: this.id, revision: this.revision, cursor: this.cursor, batch }))}`, + events: structuredClone(batch) as unknown as TeleportEvent[] }); + this.revision = result.revision; + this.cursor = result.nextSeq; + this.observedLength = Math.max(this.observedLength, this.cursor); + } catch (error) { + if (remoteCode(error, "WRITER_FENCED") || remoteCode(error, "REVISION_CONFLICT") || remoteCode(error, "SEQ_CONFLICT")) { + this.lost = true; + throw new SessionOwnershipLostError(this.id); + } + throw error; + } } } -function mutationKey( - kind: "materialize" | "append", - sessionId: string, - revision: number, - nextSeq: number, - value: unknown, -): string { - return `dsh-${kind}-${sha256(canonicalJson({ sessionId, revision, nextSeq, value }))}`; +function storedHeader(id: SessionId, stored: SessionHead): SessionHeader { + const header = structuredClone(stored.header) as unknown as SessionHeader; + assertVersion(header); + const meta = materializeCreateHeader(header); + assertStoredId(id, meta); + return meta; } -function cloneHeader(value: unknown): SessionHeader { - return structuredClone(value) as SessionHeader; +function inheritedCount(header: SessionHeader, value?: number): SessionLogOffset { + if (typeof header.isSeeded !== "boolean") throw new TypeError("session header requires isSeeded"); + if (header.isSeeded && value === undefined) throw new TypeError("seeded sessions require inheritedEventCount"); + const count = SessionLogOffset(value ?? 0); + if (!header.isSeeded && count !== 0) throw new TypeError("unseeded sessions require inheritedEventCount=0"); + return count; } -function cloneEvents(value: readonly TeleportEvent[]): SessionEvent[] { - return structuredClone(value) as unknown as SessionEvent[]; +function cloneEvents(events: TeleportEvent[]): SessionEvent[] { + return structuredClone(events) as unknown as SessionEvent[]; } -function cloneTeleportEvents(value: readonly SessionEvent[]): TeleportEvent[] { - return structuredClone(value) as unknown as TeleportEvent[]; +function remoteCode(error: unknown, code: string): boolean { + return error instanceof TeleportRemoteError && error.code === code; } -function isNotFound(error: unknown): boolean { - return error instanceof TeleportRemoteError && error.code === "NOT_FOUND"; +function throwFailures(results: PromiseSettledResult[], message: string): void { + const failures = results.filter((result) => result.status === "rejected").map((result) => result.reason as unknown); + if (failures.length) throw new AggregateError(failures, message); } function validateConfig(config: SessionPersistenceTeleportConfig): void { - if (typeof config.baseUrl !== "string" || config.baseUrl.length === 0) { - throw new TypeError("Teleport baseUrl is required"); - } - if (typeof config.deviceId !== "string" || config.deviceId.length === 0) { - throw new TypeError("Teleport deviceId is required"); + for (const key of ["baseUrl", "deviceId", "credentialDir"] as const) { + if (typeof config[key] !== "string" || config[key].trim().length === 0) throw new TypeError(`${key} must not be empty`); } - if (typeof config.credentialDir !== "string" || config.credentialDir.length === 0) { - throw new TypeError("Teleport credentialDir is required"); - } - if ( - config.healthTimeoutMs !== undefined && - (!Number.isSafeInteger(config.healthTimeoutMs) || config.healthTimeoutMs <= 0) - ) { - throw new TypeError("Teleport healthTimeoutMs must be a positive integer"); + if (config.healthTimeoutMs !== undefined && (!Number.isSafeInteger(config.healthTimeoutMs) || config.healthTimeoutMs <= 0)) { + throw new TypeError("healthTimeoutMs must be a positive safe integer"); } } export default SessionPersistenceTeleport; + +function freezeHeader(header: SessionHeader): SessionHeader { + const pending: object[] = [header]; + while (pending.length) { + const value = pending.pop()!; + for (const child of Object.values(value)) { + if (child !== null && typeof child === "object") pending.push(child); + } + Object.freeze(value); + } + return header; +} diff --git a/src/importer.ts b/src/importer.ts index 2fa264d..00c146a 100644 --- a/src/importer.ts +++ b/src/importer.ts @@ -26,10 +26,15 @@ export interface SessionImportClient { } export interface SessionSnapshotSource { - inspect( - sessionId: string, - signal?: AbortSignal, - ): Promise<{ meta: unknown; events: readonly unknown[] }>; + /** Current DSH handle seam; kept structural so the overlay has no runtime peers. */ + open?(sessionId: string, access: "read", options?: { signal?: AbortSignal }): Promise<{ + header: unknown; + inheritedEventCount: number; + read(offset?: number, length?: number, options?: { signal?: AbortSignal }): Promise<{ events: readonly unknown[] }>; + close(): Promise; + }>; + /** Legacy source profiles can still export an archival bundle. */ + inspect?(sessionId: string, signal?: AbortSignal): Promise<{ meta: unknown; events: readonly unknown[] }>; } export interface ImportReceiptStore { @@ -44,15 +49,17 @@ export interface SessionImporterOptions { now?: () => number; } -/** Build a portable import file from any existing backend's consistent inspect result. */ +/** Build a portable import file from a consistent storage read. */ export function createSessionImportBundle( header: unknown, events: readonly unknown[], + inheritedEventCount?: number, ): SessionImportBundle { return parseSessionImportBundle({ format: SESSION_IMPORT_FORMAT, header, events, + ...(inheritedEventCount === undefined ? {} : { inheritedEventCount }), }); } @@ -64,9 +71,24 @@ export async function exportSessionImportBundle( ): Promise { assertIdentifier(sessionId, "sessionId"); signal?.throwIfAborted(); - const snapshot = await source.inspect(sessionId, signal); - signal?.throwIfAborted(); - const bundle = createSessionImportBundle(snapshot.meta, snapshot.events); + let bundle: SessionImportBundle; + if (source.open !== undefined) { + const options = signal === undefined ? {} : { signal }; + const handle = await source.open(sessionId, "read", options); + try { + const snapshot = await handle.read(0, undefined, options); + signal?.throwIfAborted(); + bundle = createSessionImportBundle(handle.header, snapshot.events, handle.inheritedEventCount); + } finally { + await handle.close(); + } + } else if (source.inspect !== undefined) { + const snapshot = await source.inspect(sessionId, signal); + signal?.throwIfAborted(); + bundle = createSessionImportBundle(snapshot.meta, snapshot.events); + } else { + throw new TypeError("source persistence supports neither open nor inspect"); + } if (sessionIdOf(bundle) !== sessionId) { throw new TeleportError( "BAD_REQUEST", @@ -97,8 +119,8 @@ export function parseSessionImportBundle(value: unknown): SessionImportBundle { } const sessionId = (candidate.header as Record).id; assertIdentifier(sessionId, "import bundle header.id"); - if (!Array.isArray(candidate.events) || candidate.events.length === 0) { - throw new TeleportError("BAD_REQUEST", "import bundle requires at least one event"); + if (!Array.isArray(candidate.events)) { + throw new TeleportError("BAD_REQUEST", "import bundle events must be an array"); } for (const [index, value] of candidate.events.entries()) { if (value === null || typeof value !== "object" || Array.isArray(value)) { @@ -129,12 +151,23 @@ export function parseSessionImportBundle(value: unknown): SessionImportBundle { } } } + const seeded = (candidate.header as Record).isSeeded === true; + if (seeded && candidate.inheritedEventCount === undefined) { + throw new TeleportError("BAD_REQUEST", "seeded import requires inheritedEventCount"); + } + if (candidate.inheritedEventCount !== undefined) { + safeNonNegative(candidate.inheritedEventCount, "inheritedEventCount"); + if ((!seeded && candidate.inheritedEventCount !== 0) || candidate.inheritedEventCount > candidate.events.length) { + throw new TeleportError("BAD_REQUEST", "inheritedEventCount does not match the imported prefix"); + } + } canonicalJson(candidate.header); canonicalJson(candidate.events); return structuredClone({ format: SESSION_IMPORT_FORMAT, header: candidate.header, events: candidate.events, + ...(seeded ? { inheritedEventCount: candidate.inheritedEventCount! } : {}), }); } @@ -144,6 +177,7 @@ export function sessionImportDigest(bundle: SessionImportBundle): string { canonicalJson({ format: parsed.format, header: parsed.header, + ...(parsed.inheritedEventCount === undefined ? {} : { inheritedEventCount: parsed.inheritedEventCount }), // PostgreSQL JSON preserves event-object key order. Bind the digest to // each original envelope encoding while keeping JSONB header order neutral. eventJson: parsed.events.map((event) => JSON.stringify(event)), @@ -243,6 +277,7 @@ export class SessionImporter { const result = await this.client.materializeSession({ sessionId: plan.sessionId, header: bundle.header, + ...(bundle.inheritedEventCount === undefined ? {} : { inheritedEventCount: bundle.inheritedEventCount }), deviceId: writer.deviceId, writerToken: writer.writerToken, idempotencyKey, @@ -398,7 +433,7 @@ function sessionIdOf(bundle: SessionImportBundle): string { function snapshotDigest(snapshot: SessionSnapshot): string { return sessionImportDigest( - createSessionImportBundle(snapshot.header, snapshot.events), + createSessionImportBundle(snapshot.header, snapshot.events, snapshot.inheritedEventCount), ); } @@ -417,7 +452,7 @@ function validateReceipt(value: unknown, expectedSessionId: string): SessionImpo ) || receipt.revision !== 1 || !Number.isSafeInteger(receipt.nextSeq) || - receipt.nextSeq! < 1 || + receipt.nextSeq! < 0 || receipt.writerEpoch !== 1 || typeof receipt.deviceId !== "string" || receipt.deviceId.length === 0 || diff --git a/src/schema.ts b/src/schema.ts index b979b2f..74bef3e 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -1,6 +1,6 @@ import type { SqlDatabase } from "./database.js"; -export const SCHEMA_VERSION = 4; +export const SCHEMA_VERSION = 5; const STATEMENTS = [ `CREATE TABLE IF NOT EXISTS teleport_schema_meta ( @@ -18,6 +18,8 @@ const STATEMENTS = [ created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP )`, + `ALTER TABLE teleport_sessions ADD COLUMN IF NOT EXISTS inherited_event_count BIGINT + CHECK (inherited_event_count >= 0)`, `CREATE TABLE IF NOT EXISTS teleport_events ( session_id TEXT NOT NULL REFERENCES teleport_sessions(session_id) ON DELETE CASCADE, seq BIGINT NOT NULL CHECK (seq >= 0), @@ -70,7 +72,7 @@ const STATEMENTS = [ actor_id TEXT NOT NULL, reason TEXT NOT NULL, rolled_back_revision BIGINT NOT NULL CHECK (rolled_back_revision >= 1), - rolled_back_next_seq BIGINT NOT NULL CHECK (rolled_back_next_seq >= 1), + rolled_back_next_seq BIGINT NOT NULL CHECK (rolled_back_next_seq >= 0), rolled_back_writer_epoch BIGINT NOT NULL CHECK (rolled_back_writer_epoch >= 1), created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (session_id, import_idempotency_key) @@ -91,6 +93,13 @@ export async function initializeSchema(database: SqlDatabase): Promise { ); return; } + if ([1, 2, 3, 4].includes(Number(version))) { + await transaction.query(`ALTER TABLE teleport_import_rollback_audit + DROP CONSTRAINT IF EXISTS teleport_import_rollback_audit_rolled_back_next_seq_check`); + await transaction.query(`ALTER TABLE teleport_import_rollback_audit + ADD CONSTRAINT teleport_import_rollback_audit_rolled_back_next_seq_check + CHECK (rolled_back_next_seq >= 0)`); + } if (Number(version) === 1) { // v1 used JSONB, which reorders object keys. JSON preserves the DSH event // envelope's insertion order for byte-stable HMR prefix comparison. Rows @@ -119,7 +128,7 @@ export async function initializeSchema(database: SqlDatabase): Promise { ); return; } - if (Number(version) === 3) { + if (Number(version) === 3 || Number(version) === 4) { await transaction.query( `UPDATE teleport_schema_meta SET value = $1 WHERE key = 'schema_version'`, [String(SCHEMA_VERSION)], diff --git a/src/server.ts b/src/server.ts index 42392fc..ce0a571 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,3 +1,4 @@ +import { SCHEMA_VERSION } from "./schema.js"; import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http"; import { timingSafeEqual } from "node:crypto"; import type { AddressInfo } from "node:net"; @@ -36,7 +37,7 @@ export function createTeleportServer( if (request.url === "/health") { try { await authority.checkHealth(); - sendJson(response, 200, { ok: true, database: "ready" }); + sendJson(response, 200, { ok: true, database: "ready", schemaVersion: SCHEMA_VERSION }); } catch { sendJson(response, 503, { ok: false, database: "unavailable" }); } diff --git a/src/source-capture.ts b/src/source-capture.ts index 2c6e422..06febf9 100644 --- a/src/source-capture.ts +++ b/src/source-capture.ts @@ -51,7 +51,7 @@ export interface ProfileCaptureOptions { sourcePluginUrl?: string; } -/** Export one consistent inspect() result to a no-clobber owner-only file. */ +/** Export one consistent storage read to a no-clobber owner-only file. */ export async function captureSessionBundle( source: SessionSnapshotSource, sessionId: string, diff --git a/src/types.ts b/src/types.ts index 2b122ee..abb2e54 100644 --- a/src/types.ts +++ b/src/types.ts @@ -16,6 +16,8 @@ export const SESSION_IMPORT_FORMAT = "dsh-session-teleport/import-v1" as const; /** Portable, backend-neutral snapshot produced from an existing Session. */ export interface SessionImportBundle { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; format: typeof SESSION_IMPORT_FORMAT; header: JsonValue; events: TeleportEvent[]; @@ -72,6 +74,8 @@ export interface WriterCredentials { } export interface CreateSessionRequest { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; sessionId: string; header: JsonValue; deviceId: string; @@ -86,6 +90,8 @@ export interface CreateSessionResult { /** Atomic first materialization used by the lazy-create adapter. */ export interface MaterializeSessionRequest { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; sessionId: string; header: JsonValue; deviceId: string; @@ -114,6 +120,8 @@ export interface AppendResult { } export interface SessionSnapshot { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; sessionId: string; header: JsonValue; revision: number; @@ -124,6 +132,8 @@ export interface SessionSnapshot { } export interface SessionHead { + /** Exact fork prefix length, separate from the immutable DSH header. */ + inheritedEventCount?: number; sessionId: string; header: JsonValue; revision: number; diff --git a/tests/dsh-adapter-loader.integration.spec.ts b/tests/dsh-adapter-loader.integration.spec.ts new file mode 100644 index 0000000..2cd9f24 --- /dev/null +++ b/tests/dsh-adapter-loader.integration.spec.ts @@ -0,0 +1,89 @@ +import { spawn } from "node:child_process"; +import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { pathToFileURL } from "node:url"; +import { it, expect } from "vitest"; +import { PgliteDatabase } from "./pglite.js"; +import { initializeSchema } from "../src/schema.js"; +import { TeleportAuthority } from "../src/authority.js"; +import { createTeleportServer } from "../src/server.js"; + +const dshBin = process.env.DSH_TELEPORT_TEST_DSH_BIN; + +it.skipIf(dshBin === undefined)("boots the packaged adapter inside the real DSH loader and flushes a live Session", async () => { + const directory = await mkdtemp(join(tmpdir(), "teleport-loader-")); + const database = new PgliteDatabase(); + await initializeSchema(database); + const authority = new TeleportAuthority(database); + const app = createTeleportServer(authority, { apiToken: "loader-test-token" }); + const { url } = await app.listen(); + const profile = join(directory, "profiles", "teleport-loader"); + const statusPath = join(directory, "result.json"); + const probe = join(directory, "probe.mjs"); + let output = ""; + let child: ReturnType | undefined; + try { + await mkdir(profile, { recursive: true }); + await writeFile(join(profile, "package.json"), JSON.stringify({ name: "dsh-profile-loader", private: true, + dependencies: {}, dsh: { profile: { bundles: [] } } })); + await writeFile(probe, ` +import { writeFile } from "node:fs/promises"; +export const inject = ["sessions", "sessionPersistence"]; +export async function apply(ctx) { + const session = ctx.sessions.create(); + const handle = await ctx.sessionPersistence.create(session.header); + try { + session.append("turn/start", { turn: 1 }); + session.append("turn/end", { turn: 1, reason: { kind: "completed" } }); + await ctx.sessions.flush(session); + const read = await handle.read(); + await writeFile(${JSON.stringify(statusPath)}, JSON.stringify({ id: session.id, events: read.events })); + } finally { await handle.close(); } +} +`); + await writeFile(join(profile, "cordis.patch.yml"), [ + "- insert:", + " - id: sessions", + " name: '@deepseek-ai/dsh-session'", + " - id: session-persistence-teleport", + ` name: '${new URL("../dist/dsh-adapter.js", import.meta.url).href}'`, + " config:", + ` baseUrl: '${url}'`, + " apiToken: 'loader-test-token'", + " deviceId: 'loader-device'", + ` credentialDir: '${join(directory, "writers")}'`, + " - id: probe", + ` name: '${pathToFileURL(probe).href}'`, + ].join("\n")); + child = spawn(process.execPath, [dshBin!, "--profile", "teleport-loader"], { + env: { ...process.env, DSH_HOME: directory, DSH_TELEMETRY_DISABLED: "1" }, + stdio: ["ignore", "pipe", "pipe"], + }); + child.stdout?.on("data", (data) => { output += String(data); }); + child.stderr?.on("data", (data) => { output += String(data); }); + const deadline = Date.now() + 15_000; + let result: { id: string; events: unknown[] } | undefined; + while (Date.now() < deadline) { + try { result = JSON.parse(await readFile(statusPath, "utf8")); break; } + catch (error) { + if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) throw error; + } + if (child.exitCode !== null) throw new Error(`DSH exited before probe: ${output}`); + await new Promise((resolve) => setTimeout(resolve, 25)); + } + if (result === undefined) throw new Error(`DSH loader probe timed out: ${output}`); + expect(result.events).toHaveLength(2); + expect((await authority.snapshot(result.id)).events).toEqual(result.events); + } finally { + if (child && child.exitCode === null && child.signalCode === null) { + const exited = new Promise((resolve) => child!.once("close", resolve)); + child.kill("SIGTERM"); + const timer = setTimeout(() => child!.kill("SIGKILL"), 2_000); + try { await exited; } finally { clearTimeout(timer); } + } + await app.close(); + await database.close(); + await rm(directory, { recursive: true, force: true }); + } +}, 25_000); diff --git a/tests/dsh-adapter.spec.ts b/tests/dsh-adapter.spec.ts new file mode 100644 index 0000000..4cb1534 --- /dev/null +++ b/tests/dsh-adapter.spec.ts @@ -0,0 +1,224 @@ +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { Context } from "@deepseek-ai/cordis"; +import { Session, SessionStore, SessionId, SessionSeq, SESSION_FORMAT_VERSION, + type SessionHeader, type SessionEvent } from "@deepseek-ai/dsh-session"; +import { SessionAlreadyExistsError, SessionAlreadyOwnedError, SessionHandleClosedError, + SessionReadOnlyError, SessionOwnershipLostError, SessionFormatUnsupportedError } from "@deepseek-ai/dsh-session-persistence"; +import JsonlPersistence from "@deepseek-ai/dsh-session-persistence-jsonl"; +import { beforeEach, afterEach, describe, it, expect, vi } from "vitest"; +import { SessionPersistenceTeleport } from "../src/dsh-adapter.js"; +import { TeleportAuthority } from "../src/authority.js"; +import { TeleportClient } from "../src/client.js"; +import { MemoryWriterCredentialStore } from "../src/credential-store.js"; +import { SessionImporter, MemoryImportReceiptStore, exportSessionImportBundle } from "../src/importer.js"; +import { initializeSchema } from "../src/schema.js"; +import { createTeleportServer, type RunningTeleportServer } from "../src/server.js"; +import { PgliteDatabase } from "./pglite.js"; + +const id = SessionId("adapter-session"); +const header: SessionHeader = { id, version: SESSION_FORMAT_VERSION, createdAt: 1, isSeeded: false }; +const event = (seq: number): SessionEvent => ({ type: "turn/start", seq: SessionSeq(seq), time: seq + 1, data: { turn: seq } }); + +describe("DSH 0.2 handle contract over HTTP authority", () => { + let database: PgliteDatabase; + let app: RunningTeleportServer; + let root: string; + let client: TeleportClient; + let credentials: MemoryWriterCredentialStore; + let backend: SessionPersistenceTeleport; + let ctx: Context; + const contexts: Context[] = []; + + beforeEach(async () => { + root = await mkdtemp(join(tmpdir(), "teleport-adapter-")); + database = new PgliteDatabase(); + await initializeSchema(database); + app = createTeleportServer(new TeleportAuthority(database), { apiToken: "test-token", adminToken: "admin-token" }); + client = new TeleportClient((await app.listen()).url, "test-token", "admin-token"); + credentials = new MemoryWriterCredentialStore(); + ({ ctx, backend } = setup("device-a", credentials)); + }); + afterEach(async () => { + // Close through Cordis effects as production teardown does. + await Promise.allSettled(contexts.splice(0).map((context) => context.fiber.dispose())); + await app.close(); + await database.close(); + await rm(root, { recursive: true, force: true }); + }); + function setup(deviceId: string, store = new MemoryWriterCredentialStore()) { + const context = new Context(); + new SessionStore(context); + const persistence = new SessionPersistenceTeleport(context, { + baseUrl: "http://unused.invalid", deviceId, credentialDir: join(root, deviceId), + }, { client, credentialStore: store }); + contexts.push(context); + return { ctx: context, backend: persistence }; + } + + it("materializes an empty session, returns immutable slices, and enforces handle lifetime", async () => { + const writer = await backend.create(header); + await writer.flush(); + expect(await backend.stat(id)).toMatchObject({ header, eventCount: 0 }); + const initial = (await backend.stat(id))!.revision; + const reader = await backend.open(id, "read"); + await expect(backend.create(header)).rejects.toBeInstanceOf(SessionAlreadyExistsError); + await expect(backend.open(id, "write")).rejects.toBeInstanceOf(SessionAlreadyOwnedError); + await expect(reader.append([])).rejects.toBeInstanceOf(SessionReadOnlyError); + await expect(reader.flush()).rejects.toBeInstanceOf(SessionReadOnlyError); + const batch = [event(0), event(1)]; + const append = writer.append(batch); + (batch[0]!.data as { turn: number }).turn = 999; + await append; + expect((await reader.read()).events).toEqual([event(0), event(1)]); + expect((await reader.read(1, 1)).events).toEqual([event(1)]); + expect((await reader.read(99)).events).toEqual([]); + const detached = await reader.read(); + expect(detached.eventState).toBe("detached"); + (detached.events[0]!.data as { turn: number }).turn = 42; + expect((await reader.read()).events).toEqual([event(0), event(1)]); + expect((await backend.stat(id))!.revision).not.toBe(initial); + expect(await backend.list()).toHaveLength(1); + await expect(reader.read(-1)).rejects.toThrow(); + await reader.close(); + await reader.close(); + await expect(reader.read()).rejects.toBeInstanceOf(SessionHandleClosedError); + await writer.close(); + const reopened = await backend.open(id, "write"); + await reopened.append([event(2)]); + await reopened.close(); + }); + + it("routes real SessionStore events and flush, retaining an exact response-loss batch", async () => { + const writer = await backend.create(header); + const session = ctx.sessions.create(id, { meta: { createdAt: 1 } }); + const append = client.append.bind(client); + const spy = vi.spyOn(client, "append").mockImplementationOnce(async (request) => { + await append(request); + throw new Error("response lost after commit"); + }); + session.append("turn/start", { turn: 1 }); + await expect(ctx.sessions.flush(session)).rejects.toThrow("response lost"); + session.append("turn/end", { turn: 1, reason: { kind: "completed" } }); + await expect(ctx.sessions.flush(session)).resolves.toBe(true); + expect((await writer.read()).events.map((e) => e.type)).toEqual(["turn/start", "turn/end"]); + expect(spy.mock.calls[0]![0].idempotencyKey).toBe(spy.mock.calls[1]![0].idempotencyKey); + expect(spy).toHaveBeenCalledTimes(3); + await writer.close(); + }); + + it("drains accepted live events on Cordis disposal and releases the OS writer lock", async () => { + await backend.create(header); + const session = ctx.sessions.create(id, { meta: { createdAt: 1 } }); + session.append("turn/start", { turn: 1 }); + await ctx.fiber.dispose(); + expect((await client.snapshot(id)).events).toHaveLength(1); + const replacement = setup("device-a", credentials).backend; + const handle = await replacement.open(id, "write"); + await handle.close(); + }); + + it("finishes a durability barrier when cancellation arrives after its write starts", async () => { + const writer = await backend.create(header); + const session = ctx.sessions.create(id, { meta: { createdAt: 1 } }); + const controller = new AbortController(); + const append = client.append.bind(client); + vi.spyOn(client, "append").mockImplementationOnce(async (request) => { + const result = await append(request); + controller.abort(new Error("cancelled after commit")); + return result; + }); + session.append("turn/start", { turn: 1 }); + await expect(writer.flush({ signal: controller.signal })).resolves.toBeUndefined(); + expect((await writer.read()).events).toHaveLength(1); + await writer.close(); + }); + + it("pauses automatic writes after failure until an explicit flush retries the retained batch", async () => { + const writer = await backend.create(header); + const session = ctx.sessions.create(id, { meta: { createdAt: 1 } }); + const spy = vi.spyOn(client, "append").mockRejectedValueOnce(new Error("temporary network failure")); + session.append("turn/start", { turn: 1 }); + await vi.waitFor(() => expect(spy).toHaveBeenCalledTimes(1)); + session.append("turn/end", { turn: 1, reason: { kind: "completed" } }); + await new Promise((resolve) => setTimeout(resolve, 300)); + expect(spy).toHaveBeenCalledTimes(1); + await ctx.sessions.flush(session); + expect((await writer.read()).events).toHaveLength(2); + expect(spy.mock.calls[0]![0].idempotencyKey).toBe(spy.mock.calls[1]![0].idempotencyKey); + await writer.close(); + }); + + it("blocks a second writer with the same credential directory and fences the old device on handoff", async () => { + const writer = await backend.create(header); + const duplicate = setup("device-a", credentials).backend; + await expect(duplicate.open(id, "write")).rejects.toBeInstanceOf(SessionAlreadyOwnedError); + const remote = setup("device-b").backend; + await expect(remote.open(id, "write")).rejects.toBeInstanceOf(SessionAlreadyOwnedError); + const before = (await backend.stat(id))!.revision; + const handoff = await backend.createHandoff(id); + await remote.acceptHandoff(handoff.code); + expect((await backend.stat(id))!.revision).toBe(before); + await expect(writer.flush()).rejects.toBeInstanceOf(SessionOwnershipLostError); + await expect(writer.append([event(0)])).rejects.toBeInstanceOf(SessionOwnershipLostError); + const current = await remote.open(id, "write"); + await current.append([event(0)]); + expect((await writer.read()).events).toEqual([event(0)]); + await current.close(); + await writer.close(); + await expect(backend.open(id, "write")).rejects.toBeInstanceOf(SessionOwnershipLostError); + }); + + it("preserves a real JSONL fork's inherited cut through export, import, and restore", async () => { + const jsonlContext = new Context(); + new SessionStore(jsonlContext); + contexts.push(jsonlContext); + const jsonl = new JsonlPersistence(jsonlContext, { root: join(root, "jsonl") }); + const parent = jsonlContext.sessions.create(SessionId("parent")); + parent.append("turn/start", { turn: 1 }); + parent.append("turn/end", { turn: 1, reason: { kind: "completed" } }); + const child = jsonlContext.sessions.fork(parent, SessionSeq(1), SessionId("fork")); + const handle = await jsonl.create(child.header, { inheritedEventCount: child.inheritedEventCount }); + await handle.append(child.snapshotEvents()); + await handle.flush(); + await handle.close(); + const bundle = await exportSessionImportBundle(jsonl, child.id); + expect(bundle.inheritedEventCount).toBe(2); + const importer = new SessionImporter(client, credentials, new MemoryImportReceiptStore(), { deviceId: "device-a" }); + await importer.apply(bundle); + expect(await importer.dryRun(bundle)).toMatchObject({ targetStatus: "already-present" }); + const restored = await backend.open(child.id, "write"); + expect(restored.inheritedEventCount).toBe(child.inheritedEventCount); + const read = await restored.read(); + expect(Session.fromRestore(child.id, [...read.events], restored.header, restored.inheritedEventCount, read.eventState).inheritedEventCount).toBe(2); + await restored.close(); + }); + + it("supports empty imports and rollback and closes capture handles even after a failed read", async () => { + const writer = await backend.create(header); + await writer.close(); + const bundle = await exportSessionImportBundle(backend, id); + bundle.header = { ...header, id: "empty-import" }; + const importer = new SessionImporter(client, credentials, new MemoryImportReceiptStore(), { deviceId: "device-a" }); + await expect(importer.apply(bundle)).resolves.toMatchObject({ nextSeq: 0 }); + await expect(importer.rollback("empty-import", "test rollback")).resolves.toMatchObject({ rolledBack: true }); + const close = vi.fn(async () => {}); + await expect(exportSessionImportBundle({ open: async () => ({ header, inheritedEventCount: 0, + read: async () => { throw new Error("capture read failed"); }, close }) }, id)).rejects.toThrow("capture read failed"); + expect(close).toHaveBeenCalledOnce(); + }); + + it("refuses retired formats and unknown required events, and honors pre-aborted operations", async () => { + await expect(backend.create({ ...header, version: 0 } as unknown as SessionHeader)).rejects.toBeInstanceOf(SessionFormatUnsupportedError); + const writer = await backend.create(header); + const unknown = { ...event(0), type: "future/required" } as unknown as SessionEvent; + await expect(writer.append([unknown])).rejects.toBeInstanceOf(SessionFormatUnsupportedError); + const signal = AbortSignal.abort(new Error("cancelled")); + await expect(writer.append([event(0)], { signal })).rejects.toThrow("cancelled"); + await expect(backend.open(id, "read", { signal })).rejects.toThrow("cancelled"); + expect((await writer.read()).events).toEqual([]); + await writer.append([{ ...unknown, ignorable: true }]); + await writer.close(); + }); +}); diff --git a/tests/dsh-capture.integration.spec.ts b/tests/dsh-capture.integration.spec.ts index 59e9771..d94d955 100644 --- a/tests/dsh-capture.integration.spec.ts +++ b/tests/dsh-capture.integration.spec.ts @@ -16,7 +16,7 @@ afterEach(async () => { }); describe.skipIf(dshTestBin === undefined)("real DSH source capture", () => { - it("loads the temporary file URL overlay and exports through inspect()", async () => { + it("loads the temporary file URL overlay and exports through a read handle", async () => { const dshHome = await mkdtemp(join(tmpdir(), "session-teleport-dsh-home-")); temporaryRoots.push(dshHome); await chmod(dshHome, 0o700); @@ -90,13 +90,16 @@ export function apply(ctx) { } ctx.provide("sessionPersistence", { name: "session-persistence-fixture", - async inspect(sessionId) { + async open(sessionId, access) { + if (access !== "read") throw new Error("capture must be read-only"); return { - meta: { id: sessionId, version: 0, createdAt: 1 }, - events: [ + header: { id: sessionId, version: 4, createdAt: 1, isSeeded: false }, + inheritedEventCount: 0, + async close() {}, + async read() { return { events: [ { type: "user/message", seq: 0, time: 1, data: { text: "fixture input" } }, { type: "assistant/message", seq: 1, time: 2, data: { text: "fixture output" } }, - ], + ] }; }, }; }, }); diff --git a/tests/jsonl-migration.postgres.integration.spec.ts b/tests/jsonl-migration.postgres.integration.spec.ts index db84324..e515173 100644 --- a/tests/jsonl-migration.postgres.integration.spec.ts +++ b/tests/jsonl-migration.postgres.integration.spec.ts @@ -101,7 +101,7 @@ integration("migration from real DSH JSONL to real PostgreSQL", () => { header: Record; events: unknown[]; }; - expect(bundle.header).toMatchObject({ id: sessionId, version: 0 }); + expect(bundle.header).toMatchObject({ id: sessionId, version: 4 }); expect(bundle.events).toEqual(sourceEvents()); await expect(runCli(cliPath, ["dry-run", bundlePath], environment)).resolves.toMatchObject({ @@ -154,8 +154,10 @@ export const inject = ["sessionPersistence"]; export async function apply(ctx) { const id = process.env.DSH_TELEPORT_JSONL_SEED_SESSION_ID; const ready = process.env.DSH_TELEPORT_JSONL_SEED_READY_PATH; - await ctx.sessionPersistence.create({ version: 0, id, createdAt: 1000 }); - await ctx.sessionPersistence.append(id, ${JSON.stringify(sourceEvents())}); + const handle = await ctx.sessionPersistence.create({ version: 4, id, createdAt: 1000, isSeeded: false }); + await handle.append(${JSON.stringify(sourceEvents())}); + await handle.flush(); + await handle.close(); await writeFile(ready, JSON.stringify({ ok: true, id }) + "\\n", { mode: 0o600, flag: "wx" }); } `, { mode: 0o600 }); @@ -195,12 +197,14 @@ function sourceEvents(): Array> { return [ { type: "plugin/session-teleport-test", + ignorable: true, seq: 0, time: 1, data: { text: "from real JSONL", extension: { exact: true } }, }, { type: "plugin/session-teleport-test", + ignorable: true, seq: 1, time: 2, data: { text: "second event" }, diff --git a/tests/schema.spec.ts b/tests/schema.spec.ts index 3ee2e0c..8be8091 100644 --- a/tests/schema.spec.ts +++ b/tests/schema.spec.ts @@ -78,6 +78,26 @@ describe("Teleport schema lifecycle", () => { expect(Number(auditTable.rows[0]?.count)).toBe(1); }); + it("migrates v4 without rewriting existing metadata or event bytes", async () => { + const database = trackedDatabase(); + await initializeSchema(database); + await database.query("ALTER TABLE teleport_sessions DROP COLUMN inherited_event_count"); + await database.query("ALTER TABLE teleport_import_rollback_audit DROP CONSTRAINT teleport_import_rollback_audit_rolled_back_next_seq_check"); + await database.query("ALTER TABLE teleport_import_rollback_audit ADD CONSTRAINT teleport_import_rollback_audit_rolled_back_next_seq_check CHECK (rolled_back_next_seq >= 1)"); + await database.query("UPDATE teleport_schema_meta SET value = '4' WHERE key = 'schema_version'"); + await database.query("INSERT INTO teleport_sessions (session_id, header) VALUES ('v4-row', '{\"version\":0}'::jsonb)"); + const raw = '{"z":1,"a":2}'; + await database.query("INSERT INTO teleport_events (session_id, seq, event) VALUES ('v4-row', 0, $1::json)", [raw]); + await initializeSchema(database); + await initializeSchema(database); + const row = await database.query<{ header: unknown; inherited_event_count: number | null; raw: string }>( + "SELECT header, inherited_event_count, event::text AS raw FROM teleport_sessions JOIN teleport_events USING (session_id)"); + expect(row.rows[0]).toEqual({ header: { version: 0 }, inherited_event_count: null, raw }); + await database.query(`INSERT INTO teleport_import_rollback_audit + (session_id, import_idempotency_key, request_digest, actor_id, reason, rolled_back_revision, rolled_back_next_seq, rolled_back_writer_epoch) + VALUES ('empty', 'key', 'digest', 'actor', 'reason', 1, 0, 1)`); + }); + it("refuses a populated v1 JSONB store because key order cannot be recovered", async () => { const database = trackedDatabase(); await initializeSchema(database); diff --git a/tests/server.spec.ts b/tests/server.spec.ts index e7d9846..8d5a9fd 100644 --- a/tests/server.spec.ts +++ b/tests/server.spec.ts @@ -30,6 +30,8 @@ describe("Teleport HTTP API", () => { it("exposes create, append, snapshot and handoff as one authenticated vertical slice", async () => { expect((await fetch(`${baseUrl}/health`)).status).toBe(200); await expect(new TeleportClient(baseUrl).health()).resolves.toBeUndefined(); + await expect(new TeleportClient(baseUrl).health(undefined, 5)).resolves.toBeUndefined(); + await expect(new TeleportClient(baseUrl).health(undefined, 4)).rejects.toMatchObject({ code: "SCHEMA_INCOMPATIBLE" }); expect((await fetch(`${baseUrl}/v1/sessions/demo`)).status).toBe(401); const headers = { authorization: "Bearer test-token", "content-type": "application/json" };