/** * [ref] A9 域模块 —— 2c session-sync 面(sema-internal server/docs/DESIGN-session-sync.md §15 + §5–§10)。 * * 路由:`/v1/sessions/:id/sync/{manifest,entries,import,plan,blobs,snapshots/:k/blobs/:b,import/:staging/entries}`。 * 每条都像 fork/delete 一样 owner-gated;无持久 session store 时 501(能力面与路由解析同真值)。 * * 单域独占状态(lens1 §C2 的 12 条里的 4 条)全在 `SessionSyncLocal`,每个 server 实例一份: * `pendingStagings`(Phase A→B 的 staging 绑定)、`importLeases`(per-session 导入租约)与它的两个操作。 */ import type { IncomingMessage, ServerResponse } from "node:http"; import { type SessionRulesRecord, type FileHistoryExport } from "@sema-agent/core"; import { type StagingHandle } from "../../session-sync-kernel.js"; import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js"; export type PendingStaging = { handle: StagingHandle; realSessionId: string; owner: string | null; resolution?: "overwrite-dst"; operatorOk: boolean; /** [ref]: the session's file-history envelope (or null — no history travelled). Replaces the E19 per-key manifests. */ fileHistory: FileHistoryExport | null; policy: SessionRulesRecord[]; anchors: Array<{ eventId: string; entryId: string; owner: string | null; }>; /** 交叉复查 A-3(HIGH):Phase A's DECLARED entry-id set — Phase B verifies the streamed NDJSON matches it * (a different tree under the same staging would otherwise commit while the parked snapshots/anchors * still reference the DECLARED one). */ declaredEntryIds: string[]; /** The principal that opened this staging — a different caller may not drive it (404, no oracle). */ openedBy: string | null; /** Fleet-wide caller (ops on-behalf) — bypasses the openedBy identity check (like the route's owner gates). */ openedFleetWide: boolean; }; /** 单域独占状态 + 它的两个操作。每个 server 实例一份。 */ export interface SessionSyncLocal { pendingStagings: Map; importLeases: Map; touchImportLease(sessionId: string): void; cleanupStaging(stagingId: string): void; } export declare function createSessionSyncLocal(): SessionSyncLocal; /** 路由体 = 从 `server.ts` 的 `handle()` 里**整段剪切**过来的原文(唯一改动:统一去缩进两格)。 */ export declare function handleSessionSync(req: IncomingMessage, res: ServerResponse, match: RouteMatch, ctx: RouteCtx): Promise; export declare const SESSION_SYNC_ROUTES: readonly [{ readonly id: "session-sync-manifest"; readonly pattern: RegExp; readonly label: "/v1/sessions/:id/sync/$verb"; readonly methods: readonly ["GET"]; }, { readonly id: "session-sync-entries"; readonly pattern: RegExp; readonly label: "/v1/sessions/:id/sync/$verb"; readonly methods: readonly ["GET"]; }, { readonly id: "session-sync-plan"; readonly pattern: RegExp; readonly label: "/v1/sessions/:id/sync/$verb"; readonly methods: readonly ["POST"]; }, { readonly id: "session-sync-import"; readonly pattern: RegExp; readonly label: "/v1/sessions/:id/sync/import"; readonly methods: readonly ["POST"]; }, { readonly id: "session-sync-import-entries"; readonly pattern: RegExp; readonly label: "/v1/sessions/:id/sync/import"; readonly methods: readonly ["POST"]; }, { readonly id: "session-sync-blob-put"; readonly pattern: RegExp; readonly label: "/v1/sessions/:id/sync/blobs"; readonly methods: readonly ["PUT"]; }, { readonly id: "session-sync-history-blob"; readonly pattern: RegExp; readonly label: "/v1/sessions/:id/sync/history/blobs/:hash"; readonly methods: readonly ["GET"]; }]; /** 本域可分派行的 `id` 闭集 —— handler 的 `switch` 按它判穷尽(漏一口 = 编译红)。 */ export type SessionSyncRouteId = RouteIdsOf; //# sourceMappingURL=session-sync.d.ts.map