@opengeni/db 6.0.1 → 6.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-sessions.d.ts +26 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-reconciliation.js +2 -2
- package/dist/{chunk-4RDUZ5UV.js → chunk-4ZQFT5II.js} +2 -2
- package/dist/{chunk-6ORJPCYW.js → chunk-5UOWNKPP.js} +2 -2
- package/dist/{chunk-4CCFFLDZ.js → chunk-BG46J5HF.js} +13 -2
- package/dist/chunk-BG46J5HF.js.map +1 -0
- package/dist/{chunk-CSVHCF3R.js → chunk-IB3SW3JW.js} +11 -4
- package/dist/{chunk-CSVHCF3R.js.map → chunk-IB3SW3JW.js.map} +1 -1
- package/dist/{chunk-GSB4ISHE.js → chunk-IIPWNNVR.js} +4 -1
- package/dist/chunk-IIPWNNVR.js.map +1 -0
- package/dist/{chunk-MAMBI2HR.js → chunk-JPYN5XKV.js} +39 -3
- package/dist/chunk-JPYN5XKV.js.map +1 -0
- package/dist/{chunk-LSLNMENV.js → chunk-KZXWUXWV.js} +4 -4
- package/dist/{chunk-LO6BVXXH.js → chunk-LD52IFS3.js} +2 -2
- package/dist/{chunk-JILAWE26.js → chunk-M5Z6II2P.js} +2 -2
- package/dist/{chunk-PGIFHEBA.js → chunk-RVEOGRMF.js} +2 -2
- package/dist/{chunk-H7BC444C.js → chunk-SRAMNVHT.js} +17 -1
- package/dist/chunk-SRAMNVHT.js.map +1 -0
- package/dist/{chunk-XK6HXON2.js → chunk-UXFBXCHM.js} +2 -2
- package/dist/{chunk-RXH5CFG3.js → chunk-VE2XK2KD.js} +12 -8
- package/dist/{chunk-RXH5CFG3.js.map → chunk-VE2XK2KD.js.map} +1 -1
- package/dist/{chunk-FULLE5CF.js → chunk-WT7HG43Y.js} +3 -3
- package/dist/{chunk-I7HQL6FK.js → chunk-ZM5BA3TD.js} +3 -3
- package/dist/connect-attempts.js +3 -3
- package/dist/database.d.ts +8 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +69 -20
- package/dist/index.js +633 -202
- package/dist/index.js.map +1 -1
- package/dist/knowledge-entries.d.ts +2 -0
- package/dist/knowledge-indexing.d.ts +17 -0
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/managed-user-setup.d.ts +1 -0
- package/dist/mcp-operations.js +2 -2
- package/dist/migrate.d.ts +10 -1
- package/dist/migrate.js +3 -1
- package/dist/organization-integration-policy.js +3 -3
- package/dist/organization-membership-lifecycle.d.ts +1 -0
- package/dist/provision-roles.js +1 -1
- package/dist/retained-provider-commands.d.ts +4 -2
- package/dist/retained-provider-commands.js +6 -6
- package/dist/runtime-posture.d.ts +1 -1
- package/dist/schema.d.ts +25 -8
- package/dist/schema.js +1 -1
- package/dist/session-background-commands.js +4 -4
- package/dist/session-command-output.js +5 -5
- package/dist/session-event-slices.js +3 -3
- package/dist/session-mcp-credential-rotation.js +4 -4
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/dist/workspace-tool-defaults.js +4 -4
- package/drizzle/0508_deadline_command_workspace_capture.sql +75 -0
- package/drizzle/0509_verified_signup_trial_credits.sql +76 -0
- package/drizzle/0510_knowledge_index_funding_wait.sql +174 -0
- package/drizzle/0511_knowledge_visible_index_status.sql +56 -0
- package/drizzle/0512_insights_fact_reads_hash_join.sql +31 -0
- package/drizzle/0513_message_fork_prefix_compaction.sql +85 -0
- package/drizzle/0514_failed_session_variable_set_attach.sql +25 -0
- package/package.json +5 -5
- package/src/browser-sessions.ts +71 -1
- package/src/database.ts +18 -0
- package/src/index.ts +706 -252
- package/src/insights.ts +44 -36
- package/src/knowledge-entries.ts +43 -2
- package/src/knowledge-indexing.ts +79 -1
- package/src/managed-user-setup.ts +18 -1
- package/src/migrate.ts +58 -1
- package/src/organization-membership-lifecycle.ts +11 -0
- package/src/provision-roles.ts +12 -0
- package/src/retained-provider-commands.ts +16 -6
- package/src/runtime-posture.ts +4 -0
- package/src/schema.ts +3 -0
- package/dist/chunk-4CCFFLDZ.js.map +0 -1
- package/dist/chunk-GSB4ISHE.js.map +0 -1
- package/dist/chunk-H7BC444C.js.map +0 -1
- package/dist/chunk-MAMBI2HR.js.map +0 -1
- /package/dist/{chunk-4RDUZ5UV.js.map → chunk-4ZQFT5II.js.map} +0 -0
- /package/dist/{chunk-6ORJPCYW.js.map → chunk-5UOWNKPP.js.map} +0 -0
- /package/dist/{chunk-LSLNMENV.js.map → chunk-KZXWUXWV.js.map} +0 -0
- /package/dist/{chunk-LO6BVXXH.js.map → chunk-LD52IFS3.js.map} +0 -0
- /package/dist/{chunk-JILAWE26.js.map → chunk-M5Z6II2P.js.map} +0 -0
- /package/dist/{chunk-PGIFHEBA.js.map → chunk-RVEOGRMF.js.map} +0 -0
- /package/dist/{chunk-XK6HXON2.js.map → chunk-UXFBXCHM.js.map} +0 -0
- /package/dist/{chunk-FULLE5CF.js.map → chunk-WT7HG43Y.js.map} +0 -0
- /package/dist/{chunk-I7HQL6FK.js.map → chunk-ZM5BA3TD.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
rawRows,
|
|
3
3
|
withWorkspaceSubjectRls
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BG46J5HF.js";
|
|
5
5
|
|
|
6
6
|
// src/connect-attempts.ts
|
|
7
7
|
import { createHash } from "crypto";
|
|
@@ -216,4 +216,4 @@ export {
|
|
|
216
216
|
claimConnectOperation,
|
|
217
217
|
finishConnectOperation
|
|
218
218
|
};
|
|
219
|
-
//# sourceMappingURL=chunk-
|
|
219
|
+
//# sourceMappingURL=chunk-UXFBXCHM.js.map
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appendSessionCommandOutput
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KZXWUXWV.js";
|
|
4
4
|
import {
|
|
5
5
|
lockSessionEventWriteRows
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IB3SW3JW.js";
|
|
7
7
|
import {
|
|
8
8
|
withRlsContext,
|
|
9
9
|
withSessionActivityRlsContext
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-BG46J5HF.js";
|
|
11
11
|
import {
|
|
12
12
|
sandboxRetainedProcesses
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-IIPWNNVR.js";
|
|
14
14
|
|
|
15
15
|
// src/retained-provider-commands.ts
|
|
16
16
|
import { and, eq, sql } from "drizzle-orm";
|
|
@@ -242,7 +242,7 @@ async function retainedProcessCancellationRequested(db, scope) {
|
|
|
242
242
|
async function requestRetainedProcessDeadlineCancellation(db, scope) {
|
|
243
243
|
return withRlsContext(db, scope, async (tx) => {
|
|
244
244
|
const [row] = await tx.select().from(sandboxRetainedProcesses).where(processWhere(scope)).for("update").limit(1);
|
|
245
|
-
if (!row || row.state !== "active" ||
|
|
245
|
+
if (!row || row.state !== "active" || row.providerBackend !== "modal" || row.routeTargetId !== null)
|
|
246
246
|
return false;
|
|
247
247
|
const [lease] = await tx.execute(sql`
|
|
248
248
|
select id from sandbox_leases where id = ${row.leaseId}
|
|
@@ -252,8 +252,12 @@ async function requestRetainedProcessDeadlineCancellation(db, scope) {
|
|
|
252
252
|
and rotation_requested_at is not null and rotation_reason = 'provider_deadline' for update
|
|
253
253
|
`);
|
|
254
254
|
if (!lease) return false;
|
|
255
|
-
if (!row.cancellationRequestedAt)
|
|
256
|
-
await tx.update(sandboxRetainedProcesses).set({
|
|
255
|
+
if (!row.deadlineCancellationRequestedAt || !row.cancellationRequestedAt) {
|
|
256
|
+
await tx.update(sandboxRetainedProcesses).set({
|
|
257
|
+
...!row.cancellationRequestedAt ? { cancellationRequestedAt: sql`now()`, cancellationReason: "provider_deadline" } : {},
|
|
258
|
+
...!row.deadlineCancellationRequestedAt ? { deadlineCancellationRequestedAt: sql`now()` } : {}
|
|
259
|
+
}).where(processWhere(scope));
|
|
260
|
+
}
|
|
257
261
|
return true;
|
|
258
262
|
});
|
|
259
263
|
}
|
|
@@ -273,4 +277,4 @@ export {
|
|
|
273
277
|
retainedProcessCancellationRequested,
|
|
274
278
|
requestRetainedProcessDeadlineCancellation
|
|
275
279
|
};
|
|
276
|
-
//# sourceMappingURL=chunk-
|
|
280
|
+
//# sourceMappingURL=chunk-VE2XK2KD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/retained-provider-commands.ts"],"sourcesContent":["import { and, eq, sql } from \"drizzle-orm\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport {\n SandboxProviderCommand,\n ModalRouterProviderCommand,\n CommandSupervisionReceipt,\n type SessionEvent,\n} from \"@opengeni/contracts\";\nimport { withRlsContext, withSessionActivityRlsContext, type Database } from \"./database\";\nimport { lockSessionEventWriteRows } from \"./session-control\";\nimport { appendSessionCommandOutput } from \"./session-command-output\";\nimport * as schema from \"./schema\";\n\nexport type ProcessScope = {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n processId: string;\n};\n\n/** Bound to an already-authorized exact process scope by runtime wiring. */\nexport function retainedProviderCommandPersistence(\n db: Database,\n scope: ProcessScope,\n publish?: (events: SessionEvent[]) => Promise<void>,\n) {\n return {\n recordSupervisionReceipt: (receipt: SupervisionReceipt) =>\n recordRetainedSupervisionReceipt(db, scope, receipt),\n loadSupervisionReceipt: () => loadRetainedSupervisionReceipt(db, scope),\n requestCancellation: (reason: \"provider_deadline\" | \"explicit_stop\") =>\n requestRetainedProcessCancellation(db, scope, reason),\n cancellationRequested: () => retainedProcessCancellationRequested(db, scope),\n load: () => getRetainedProviderCommand(db, scope),\n acknowledge: (command: SandboxProviderCommand) =>\n acknowledgeRetainedProviderOutput(db, scope, command),\n reserveInput: (byteLength?: number) => reserveRetainedProviderInput(db, scope, byteLength),\n captureRouterPage: async (page: RetainedRouterOutputPage) => {\n const result = await captureRetainedRouterOutput(db, scope, page);\n // A committed capture is authoritative even if live fanout fails.\n if (result.events.length && publish) await publish(result.events).catch(() => undefined);\n return { command: result.command, captured: result.captured };\n },\n };\n}\n\nfunction processWhere(scope: ProcessScope) {\n return and(\n eq(schema.sandboxRetainedProcesses.accountId, scope.accountId),\n eq(schema.sandboxRetainedProcesses.workspaceId, scope.workspaceId),\n eq(schema.sandboxRetainedProcesses.sessionId, scope.sessionId),\n eq(schema.sandboxRetainedProcesses.id, scope.processId),\n );\n}\n\nfunction sameExecution(a: SandboxProviderCommand, b: SandboxProviderCommand): boolean {\n return (\n a.kind === b.kind &&\n a.sandboxId === b.sandboxId &&\n a.taskId === b.taskId &&\n a.execId === b.execId &&\n Boolean(a.pty) === Boolean(b.pty) &&\n isDeepStrictEqual(supervisionDescriptor(a), supervisionDescriptor(b))\n );\n}\n\n/** Promotion and the opaque provider locator commit together. Preserve the\n * existing durable-but-output-rejected promotion contract: its typed rejection\n * is rethrown only AFTER this outer transaction has committed the locator. */\nexport function createProviderCommandRetainer<Input extends ProcessScope, Process>(\n promote: (db: Database, input: Input) => Promise<Process>,\n recoverDurablePromotion: (error: unknown) => Process | null,\n) {\n return async function retainWorkspaceProviderCommand(\n db: Database,\n input: Input & { providerCommand?: SandboxProviderCommand | null },\n ): Promise<Process> {\n if (!input.providerCommand) return promote(db, input);\n const command = SandboxProviderCommand.parse(input.providerCommand);\n const result = await withRlsContext(db, input, async (tx) => {\n let process: Process;\n let rejection: unknown = null;\n try {\n process = await promote(tx, input);\n } catch (error) {\n const durable = recoverDurablePromotion(error);\n if (durable === null) throw error;\n process = durable;\n rejection = error;\n }\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(input))\n .for(\"update\")\n .limit(1);\n if (!row || row.providerBackend !== \"modal\" || row.providerInstanceId !== command.sandboxId)\n throw new Error(\"Provider command does not match its retained sandbox\");\n if (row.providerCommand) {\n if (!sameExecution(SandboxProviderCommand.parse(row.providerCommand), command))\n throw new Error(\"Retained process already has a different provider execution\");\n } else {\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ providerCommand: command })\n .where(processWhere(input));\n }\n return { process, rejection };\n });\n if (result.rejection) throw result.rejection;\n return result.process;\n };\n}\n\nexport async function getRetainedProviderCommand(\n db: Database,\n scope: ProcessScope,\n): Promise<SandboxProviderCommand | null> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select({ command: schema.sandboxRetainedProcesses.providerCommand })\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .limit(1);\n return row?.command ? SandboxProviderCommand.parse(row.command) : null;\n });\n}\n\n/** Call only after all output in this provider page has been durably captured.\n * A stale acknowledgment cannot roll back a cursor or erase terminal evidence. */\nexport async function acknowledgeRetainedProviderOutput(\n db: Database,\n scope: ProcessScope,\n candidate: SandboxProviderCommand,\n): Promise<SandboxProviderCommand> {\n const next = SandboxProviderCommand.parse(candidate);\n if (next.kind !== \"modal-control-v1\")\n throw new Error(\"Byte-offset command output requires atomic capture\");\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row?.providerCommand) throw new Error(\"Retained provider command is unavailable\");\n const previous = SandboxProviderCommand.parse(row.providerCommand);\n if (previous.kind !== \"modal-control-v1\")\n throw new Error(\"Legacy acknowledgment cannot advance byte-offset output\");\n if (!sameExecution(previous, next))\n throw new Error(\"Output acknowledgment changed provider execution identity\");\n const merged = structuredClone(previous);\n for (const stream of [\"stdout\", \"stderr\"] as const) {\n const oldCursor = previous.streams[stream];\n const newCursor = next.streams[stream];\n if (newCursor.batchIndex < oldCursor.batchIndex) continue;\n if (\n (newCursor.batchIndex === oldCursor.batchIndex || oldCursor.exitCode !== null) &&\n !isDeepStrictEqual(oldCursor, newCursor)\n )\n throw new Error(\"Provider output acknowledgment conflicts with retained evidence\");\n merged.streams[stream] = newCursor;\n }\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ providerCommand: merged })\n .where(processWhere(scope));\n return merged;\n });\n}\n\nexport type RetainedRouterOutputPage = {\n expected: ModalRouterProviderCommand;\n command: ModalRouterProviderCommand;\n stdout: string;\n stderr: string;\n};\n\nexport function validateRouterOutputAdvance(page: RetainedRouterOutputPage): void {\n const before = ModalRouterProviderCommand.parse(page.expected);\n const after = ModalRouterProviderCommand.parse(page.command);\n if (!sameExecution(before, after)) throw new Error(\"Output capture changed execution identity\");\n for (const stream of [\"stdout\", \"stderr\"] as const) {\n const oldCursor = before.streams[stream],\n cursor = after.streams[stream];\n if (\n cursor.byteOffset < oldCursor.byteOffset ||\n (oldCursor.eof && (!cursor.eof || cursor.byteOffset !== oldCursor.byteOffset)) ||\n (oldCursor.exitCode !== null && !isDeepStrictEqual(oldCursor, cursor))\n )\n throw new Error(\"Output capture cannot regress or rewrite terminal evidence\");\n if (\n cursor.byteOffset === oldCursor.byteOffset &&\n !(!oldCursor.eof && cursor.eof) &&\n (page[stream].length > 0 || cursor.utf8Remainder !== oldCursor.utf8Remainder)\n )\n throw new Error(\"Output without byte advancement requires the first EOF\");\n if (cursor.eof && cursor.utf8Remainder !== \"\")\n throw new Error(\"EOF must flush pending UTF-8 bytes\");\n if (Buffer.byteLength(page[stream]) > 4 * 1024 * 1024)\n throw new Error(\"Command output page exceeds its capture bound\");\n }\n}\n\n/** Capture and offsets commit atomically. The session lock is acquired before\n * the process lock, matching the event-write lock order. A concurrent reader\n * with a stale cursor discards its page and reloads; it never appends overlapping\n * output or silently advances the other reader's cursor. */\nexport async function captureRetainedRouterOutput(\n db: Database,\n scope: ProcessScope,\n page: RetainedRouterOutputPage,\n): Promise<{ command: ModalRouterProviderCommand; events: SessionEvent[]; captured: boolean }> {\n validateRouterOutputAdvance(page);\n return await withSessionActivityRlsContext(db, scope, async (tx) => {\n const locks = await lockSessionEventWriteRows(tx, {\n workspaceId: scope.workspaceId,\n sessionIds: [scope.sessionId],\n controlLock: \"share\",\n });\n if (locks.sessions[0]?.accountId !== scope.accountId)\n throw new Error(\"Command output session not found\");\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row?.providerCommand || row.providerBackend !== \"modal\")\n throw new Error(\"Retained provider command is unavailable\");\n const current = ModalRouterProviderCommand.parse(row.providerCommand);\n if (!sameExecution(current, page.expected))\n throw new Error(\"Output capture does not own this execution\");\n if (!isDeepStrictEqual(current, page.expected))\n return { command: current, events: [], captured: false };\n const events: SessionEvent[] = [];\n for (const stream of [\"stdout\", \"stderr\"] as const) {\n const before = current.streams[stream],\n after = page.command.streams[stream];\n if (page[stream])\n events.push(\n ...(await appendSessionCommandOutput(tx, {\n ...scope,\n commandId: scope.processId,\n stream,\n streamFidelity: current.pty ? \"merged\" : \"separate\",\n chunkId: `modal-router:${current.execId}:${stream}:${before.byteOffset}:${after.byteOffset}:${after.eof ? 1 : 0}`,\n chunk: page[stream],\n })),\n );\n }\n if (supervisionDescriptor(page.command)) {\n await tx.execute(\n sql`select set_config('opengeni.supervised_output_capture_process_id', ${scope.processId}, true)`,\n );\n }\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({\n providerCommand: page.command,\n ...(supervisionDescriptor(page.command) &&\n page.command.streams.stdout.eof &&\n page.command.streams.stderr.eof &&\n page.command.streams.stdout.exitCode === 0 &&\n page.command.streams.stderr.exitCode === 0\n ? { supervisionOutputCaptured: true }\n : {}),\n })\n .where(processWhere(scope));\n if (supervisionDescriptor(page.command)) {\n await tx.execute(\n sql`select set_config('opengeni.supervised_output_capture_process_id', '', true)`,\n );\n }\n return { command: page.command, events, captured: true };\n });\n}\n\n/** Reserve a strictly increasing provider stdin index before dispatch. An\n * ambiguous send consumes its index and is never silently replayed. */\nexport async function reserveRetainedProviderInput(\n db: Database,\n scope: ProcessScope,\n byteLength?: number,\n): Promise<number> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row?.providerCommand || row.state !== \"active\")\n throw new Error(\"Active retained provider command is unavailable\");\n if (row.cancellationRequestedAt || row.supervisionReceipt)\n throw new Error(\"Retained command input is closed\");\n const router = row.providerCommand.kind === \"modal-router-v1\";\n if (router && (!Number.isSafeInteger(byteLength) || byteLength! <= 0))\n throw new Error(\"Byte-offset stdin requires a positive byte reservation\");\n const index = row.providerCommandInputIndex + (router ? byteLength! : 1);\n if (!Number.isSafeInteger(index)) throw new Error(\"Provider stdin sequence exhausted\");\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ providerCommandInputIndex: index })\n .where(processWhere(scope));\n return router ? row.providerCommandInputIndex : index;\n });\n}\n\nexport type SupervisionReceipt = CommandSupervisionReceipt;\n\nfunction supervisionDescriptor(command: SandboxProviderCommand) {\n return command.kind === \"modal-router-v1\" ? command.supervision : undefined;\n}\n\n/** Fail before provider start, not after discovering an unprotected DB at retention. */\nexport async function supervisedCommandProtocolReady(db: Database): Promise<boolean> {\n const [row] = await db.execute<{ ready: boolean }>(sql`\n select count(*) = 5 as ready from pg_catalog.pg_trigger\n where (tgrelid, tgname) in (\n ('sandbox_retained_processes'::regclass, 'supervised_command_guard'),\n ('sandbox_retained_processes'::regclass, 'supervised_provider_loss_commit_guard'),\n ('sandbox_workspace_mutation_admissions'::regclass, 'supervised_command_admission_guard'),\n ('sandbox_lease_holders'::regclass, 'supervised_command_holder_guard'),\n ('sandbox_leases'::regclass, 'supervised_command_capture_guard')\n ) and tgenabled in ('O', 'A') and not tgisinternal\n `);\n return row?.ready === true;\n}\n\n/** Only an authenticated control-channel receipt; never parsed stdout/stderr.\n * ACK the supervisor only after this transaction returns successfully. */\nexport async function recordRetainedSupervisionReceipt(\n db: Database,\n scope: ProcessScope,\n receipt: SupervisionReceipt,\n): Promise<void> {\n const proof = CommandSupervisionReceipt.parse(receipt);\n await withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row?.providerCommand || !supervisionDescriptor(row.providerCommand))\n throw new Error(\"Supervised retained command is unavailable\");\n // Trigger validates invocation binding, immutable replay and unsettled input.\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ supervisionReceipt: proof })\n .where(processWhere(scope));\n });\n}\n\nexport async function loadRetainedSupervisionReceipt(\n db: Database,\n scope: ProcessScope,\n): Promise<SupervisionReceipt | null> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select({ receipt: schema.sandboxRetainedProcesses.supervisionReceipt })\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .limit(1);\n if (!row) throw new Error(\"Retained command is unavailable\");\n return row.receipt ? CommandSupervisionReceipt.parse(row.receipt) : null;\n });\n}\n\nexport async function requestRetainedProcessCancellation(\n db: Database,\n scope: ProcessScope,\n reason: \"provider_deadline\" | \"explicit_stop\",\n): Promise<void> {\n if (reason !== \"provider_deadline\" && reason !== \"explicit_stop\")\n throw new Error(\"Invalid cancellation reason\");\n await withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row) throw new Error(\"Retained command is unavailable\");\n if (row.cancellationRequestedAt || row.state !== \"active\") return;\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ cancellationRequestedAt: new Date(), cancellationReason: reason })\n .where(processWhere(scope));\n });\n}\n\nexport async function retainedProcessCancellationRequested(\n db: Database,\n scope: ProcessScope,\n): Promise<boolean> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select({ at: schema.sandboxRetainedProcesses.cancellationRequestedAt })\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .limit(1);\n if (!row) throw new Error(\"Retained command is unavailable\");\n return row.at !== null;\n });\n}\n\n/** Called by the reaper for an exact retained command. Ordinary completed turns\n * are intentionally irrelevant. Lock order remains process -> lease. */\nexport async function requestRetainedProcessDeadlineCancellation(\n db: Database,\n scope: ProcessScope,\n): Promise<boolean> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (\n !row ||\n row.state !== \"active\" ||\n !row.providerCommand ||\n !supervisionDescriptor(row.providerCommand)\n )\n return false;\n const [lease] = await tx.execute<{ id: string }>(sql`\n select id from sandbox_leases where id = ${row.leaseId}\n and account_id = ${row.accountId} and workspace_id = ${row.workspaceId}\n and sandbox_group_id = ${row.sandboxGroupId} and lease_epoch = ${row.leaseEpoch}\n and backend = ${row.providerBackend} and instance_id = ${row.providerInstanceId}\n and rotation_requested_at is not null and rotation_reason = 'provider_deadline' for update\n `);\n if (!lease) return false;\n if (!row.cancellationRequestedAt)\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ cancellationRequestedAt: new Date(), cancellationReason: \"provider_deadline\" })\n .where(processWhere(scope));\n return true;\n });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/retained-provider-commands.ts"],"sourcesContent":["import { and, eq, sql } from \"drizzle-orm\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport {\n SandboxProviderCommand,\n ModalRouterProviderCommand,\n CommandSupervisionReceipt,\n type SessionEvent,\n} from \"@opengeni/contracts\";\nimport { withRlsContext, withSessionActivityRlsContext, type Database } from \"./database\";\nimport { lockSessionEventWriteRows } from \"./session-control\";\nimport { appendSessionCommandOutput } from \"./session-command-output\";\nimport * as schema from \"./schema\";\n\nexport type ProcessScope = {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n processId: string;\n};\n\n/** Bound to an already-authorized exact process scope by runtime wiring. */\nexport function retainedProviderCommandPersistence(\n db: Database,\n scope: ProcessScope,\n publish?: (events: SessionEvent[]) => Promise<void>,\n) {\n return {\n recordSupervisionReceipt: (receipt: SupervisionReceipt) =>\n recordRetainedSupervisionReceipt(db, scope, receipt),\n loadSupervisionReceipt: () => loadRetainedSupervisionReceipt(db, scope),\n requestCancellation: (reason: \"provider_deadline\" | \"explicit_stop\") =>\n requestRetainedProcessCancellation(db, scope, reason),\n cancellationRequested: () => retainedProcessCancellationRequested(db, scope),\n load: () => getRetainedProviderCommand(db, scope),\n acknowledge: (command: SandboxProviderCommand) =>\n acknowledgeRetainedProviderOutput(db, scope, command),\n reserveInput: (byteLength?: number) => reserveRetainedProviderInput(db, scope, byteLength),\n captureRouterPage: async (page: RetainedRouterOutputPage) => {\n const result = await captureRetainedRouterOutput(db, scope, page);\n // A committed capture is authoritative even if live fanout fails.\n if (result.events.length && publish) await publish(result.events).catch(() => undefined);\n return { command: result.command, captured: result.captured };\n },\n };\n}\n\nfunction processWhere(scope: ProcessScope) {\n return and(\n eq(schema.sandboxRetainedProcesses.accountId, scope.accountId),\n eq(schema.sandboxRetainedProcesses.workspaceId, scope.workspaceId),\n eq(schema.sandboxRetainedProcesses.sessionId, scope.sessionId),\n eq(schema.sandboxRetainedProcesses.id, scope.processId),\n );\n}\n\nfunction sameExecution(a: SandboxProviderCommand, b: SandboxProviderCommand): boolean {\n return (\n a.kind === b.kind &&\n a.sandboxId === b.sandboxId &&\n a.taskId === b.taskId &&\n a.execId === b.execId &&\n Boolean(a.pty) === Boolean(b.pty) &&\n isDeepStrictEqual(supervisionDescriptor(a), supervisionDescriptor(b))\n );\n}\n\n/** Promotion and the opaque provider locator commit together. Preserve the\n * existing durable-but-output-rejected promotion contract: its typed rejection\n * is rethrown only AFTER this outer transaction has committed the locator. */\nexport function createProviderCommandRetainer<Input extends ProcessScope, Process>(\n promote: (db: Database, input: Input) => Promise<Process>,\n recoverDurablePromotion: (error: unknown) => Process | null,\n) {\n return async function retainWorkspaceProviderCommand(\n db: Database,\n input: Input & { providerCommand?: SandboxProviderCommand | null },\n ): Promise<Process> {\n if (!input.providerCommand) return promote(db, input);\n const command = SandboxProviderCommand.parse(input.providerCommand);\n const result = await withRlsContext(db, input, async (tx) => {\n let process: Process;\n let rejection: unknown = null;\n try {\n process = await promote(tx, input);\n } catch (error) {\n const durable = recoverDurablePromotion(error);\n if (durable === null) throw error;\n process = durable;\n rejection = error;\n }\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(input))\n .for(\"update\")\n .limit(1);\n if (!row || row.providerBackend !== \"modal\" || row.providerInstanceId !== command.sandboxId)\n throw new Error(\"Provider command does not match its retained sandbox\");\n if (row.providerCommand) {\n if (!sameExecution(SandboxProviderCommand.parse(row.providerCommand), command))\n throw new Error(\"Retained process already has a different provider execution\");\n } else {\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ providerCommand: command })\n .where(processWhere(input));\n }\n return { process, rejection };\n });\n if (result.rejection) throw result.rejection;\n return result.process;\n };\n}\n\nexport async function getRetainedProviderCommand(\n db: Database,\n scope: ProcessScope,\n): Promise<SandboxProviderCommand | null> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select({ command: schema.sandboxRetainedProcesses.providerCommand })\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .limit(1);\n return row?.command ? SandboxProviderCommand.parse(row.command) : null;\n });\n}\n\n/** Call only after all output in this provider page has been durably captured.\n * A stale acknowledgment cannot roll back a cursor or erase terminal evidence. */\nexport async function acknowledgeRetainedProviderOutput(\n db: Database,\n scope: ProcessScope,\n candidate: SandboxProviderCommand,\n): Promise<SandboxProviderCommand> {\n const next = SandboxProviderCommand.parse(candidate);\n if (next.kind !== \"modal-control-v1\")\n throw new Error(\"Byte-offset command output requires atomic capture\");\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row?.providerCommand) throw new Error(\"Retained provider command is unavailable\");\n const previous = SandboxProviderCommand.parse(row.providerCommand);\n if (previous.kind !== \"modal-control-v1\")\n throw new Error(\"Legacy acknowledgment cannot advance byte-offset output\");\n if (!sameExecution(previous, next))\n throw new Error(\"Output acknowledgment changed provider execution identity\");\n const merged = structuredClone(previous);\n for (const stream of [\"stdout\", \"stderr\"] as const) {\n const oldCursor = previous.streams[stream];\n const newCursor = next.streams[stream];\n if (newCursor.batchIndex < oldCursor.batchIndex) continue;\n if (\n (newCursor.batchIndex === oldCursor.batchIndex || oldCursor.exitCode !== null) &&\n !isDeepStrictEqual(oldCursor, newCursor)\n )\n throw new Error(\"Provider output acknowledgment conflicts with retained evidence\");\n merged.streams[stream] = newCursor;\n }\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ providerCommand: merged })\n .where(processWhere(scope));\n return merged;\n });\n}\n\nexport type RetainedRouterOutputPage = {\n expected: ModalRouterProviderCommand;\n command: ModalRouterProviderCommand;\n stdout: string;\n stderr: string;\n};\n\nexport function validateRouterOutputAdvance(page: RetainedRouterOutputPage): void {\n const before = ModalRouterProviderCommand.parse(page.expected);\n const after = ModalRouterProviderCommand.parse(page.command);\n if (!sameExecution(before, after)) throw new Error(\"Output capture changed execution identity\");\n for (const stream of [\"stdout\", \"stderr\"] as const) {\n const oldCursor = before.streams[stream],\n cursor = after.streams[stream];\n if (\n cursor.byteOffset < oldCursor.byteOffset ||\n (oldCursor.eof && (!cursor.eof || cursor.byteOffset !== oldCursor.byteOffset)) ||\n (oldCursor.exitCode !== null && !isDeepStrictEqual(oldCursor, cursor))\n )\n throw new Error(\"Output capture cannot regress or rewrite terminal evidence\");\n if (\n cursor.byteOffset === oldCursor.byteOffset &&\n !(!oldCursor.eof && cursor.eof) &&\n (page[stream].length > 0 || cursor.utf8Remainder !== oldCursor.utf8Remainder)\n )\n throw new Error(\"Output without byte advancement requires the first EOF\");\n if (cursor.eof && cursor.utf8Remainder !== \"\")\n throw new Error(\"EOF must flush pending UTF-8 bytes\");\n if (Buffer.byteLength(page[stream]) > 4 * 1024 * 1024)\n throw new Error(\"Command output page exceeds its capture bound\");\n }\n}\n\n/** Capture and offsets commit atomically. The session lock is acquired before\n * the process lock, matching the event-write lock order. A concurrent reader\n * with a stale cursor discards its page and reloads; it never appends overlapping\n * output or silently advances the other reader's cursor. */\nexport async function captureRetainedRouterOutput(\n db: Database,\n scope: ProcessScope,\n page: RetainedRouterOutputPage,\n): Promise<{ command: ModalRouterProviderCommand; events: SessionEvent[]; captured: boolean }> {\n validateRouterOutputAdvance(page);\n return await withSessionActivityRlsContext(db, scope, async (tx) => {\n const locks = await lockSessionEventWriteRows(tx, {\n workspaceId: scope.workspaceId,\n sessionIds: [scope.sessionId],\n controlLock: \"share\",\n });\n if (locks.sessions[0]?.accountId !== scope.accountId)\n throw new Error(\"Command output session not found\");\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row?.providerCommand || row.providerBackend !== \"modal\")\n throw new Error(\"Retained provider command is unavailable\");\n const current = ModalRouterProviderCommand.parse(row.providerCommand);\n if (!sameExecution(current, page.expected))\n throw new Error(\"Output capture does not own this execution\");\n if (!isDeepStrictEqual(current, page.expected))\n return { command: current, events: [], captured: false };\n const events: SessionEvent[] = [];\n for (const stream of [\"stdout\", \"stderr\"] as const) {\n const before = current.streams[stream],\n after = page.command.streams[stream];\n if (page[stream])\n events.push(\n ...(await appendSessionCommandOutput(tx, {\n ...scope,\n commandId: scope.processId,\n stream,\n streamFidelity: current.pty ? \"merged\" : \"separate\",\n chunkId: `modal-router:${current.execId}:${stream}:${before.byteOffset}:${after.byteOffset}:${after.eof ? 1 : 0}`,\n chunk: page[stream],\n })),\n );\n }\n if (supervisionDescriptor(page.command)) {\n await tx.execute(\n sql`select set_config('opengeni.supervised_output_capture_process_id', ${scope.processId}, true)`,\n );\n }\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({\n providerCommand: page.command,\n ...(supervisionDescriptor(page.command) &&\n page.command.streams.stdout.eof &&\n page.command.streams.stderr.eof &&\n page.command.streams.stdout.exitCode === 0 &&\n page.command.streams.stderr.exitCode === 0\n ? { supervisionOutputCaptured: true }\n : {}),\n })\n .where(processWhere(scope));\n if (supervisionDescriptor(page.command)) {\n await tx.execute(\n sql`select set_config('opengeni.supervised_output_capture_process_id', '', true)`,\n );\n }\n return { command: page.command, events, captured: true };\n });\n}\n\n/** Reserve a strictly increasing provider stdin index before dispatch. An\n * ambiguous send consumes its index and is never silently replayed. */\nexport async function reserveRetainedProviderInput(\n db: Database,\n scope: ProcessScope,\n byteLength?: number,\n): Promise<number> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row?.providerCommand || row.state !== \"active\")\n throw new Error(\"Active retained provider command is unavailable\");\n if (row.cancellationRequestedAt || row.supervisionReceipt)\n throw new Error(\"Retained command input is closed\");\n const router = row.providerCommand.kind === \"modal-router-v1\";\n if (router && (!Number.isSafeInteger(byteLength) || byteLength! <= 0))\n throw new Error(\"Byte-offset stdin requires a positive byte reservation\");\n const index = row.providerCommandInputIndex + (router ? byteLength! : 1);\n if (!Number.isSafeInteger(index)) throw new Error(\"Provider stdin sequence exhausted\");\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ providerCommandInputIndex: index })\n .where(processWhere(scope));\n return router ? row.providerCommandInputIndex : index;\n });\n}\n\nexport type SupervisionReceipt = CommandSupervisionReceipt;\n\nfunction supervisionDescriptor(command: SandboxProviderCommand) {\n return command.kind === \"modal-router-v1\" ? command.supervision : undefined;\n}\n\n/** Fail before provider start, not after discovering an unprotected DB at retention. */\nexport async function supervisedCommandProtocolReady(db: Database): Promise<boolean> {\n const [row] = await db.execute<{ ready: boolean }>(sql`\n select count(*) = 5 as ready from pg_catalog.pg_trigger\n where (tgrelid, tgname) in (\n ('sandbox_retained_processes'::regclass, 'supervised_command_guard'),\n ('sandbox_retained_processes'::regclass, 'supervised_provider_loss_commit_guard'),\n ('sandbox_workspace_mutation_admissions'::regclass, 'supervised_command_admission_guard'),\n ('sandbox_lease_holders'::regclass, 'supervised_command_holder_guard'),\n ('sandbox_leases'::regclass, 'supervised_command_capture_guard')\n ) and tgenabled in ('O', 'A') and not tgisinternal\n `);\n return row?.ready === true;\n}\n\n/** Only an authenticated control-channel receipt; never parsed stdout/stderr.\n * ACK the supervisor only after this transaction returns successfully. */\nexport async function recordRetainedSupervisionReceipt(\n db: Database,\n scope: ProcessScope,\n receipt: SupervisionReceipt,\n): Promise<void> {\n const proof = CommandSupervisionReceipt.parse(receipt);\n await withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row?.providerCommand || !supervisionDescriptor(row.providerCommand))\n throw new Error(\"Supervised retained command is unavailable\");\n // Trigger validates invocation binding, immutable replay and unsettled input.\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ supervisionReceipt: proof })\n .where(processWhere(scope));\n });\n}\n\nexport async function loadRetainedSupervisionReceipt(\n db: Database,\n scope: ProcessScope,\n): Promise<SupervisionReceipt | null> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select({ receipt: schema.sandboxRetainedProcesses.supervisionReceipt })\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .limit(1);\n if (!row) throw new Error(\"Retained command is unavailable\");\n return row.receipt ? CommandSupervisionReceipt.parse(row.receipt) : null;\n });\n}\n\nexport async function requestRetainedProcessCancellation(\n db: Database,\n scope: ProcessScope,\n reason: \"provider_deadline\" | \"explicit_stop\",\n): Promise<void> {\n if (reason !== \"provider_deadline\" && reason !== \"explicit_stop\")\n throw new Error(\"Invalid cancellation reason\");\n await withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (!row) throw new Error(\"Retained command is unavailable\");\n if (row.cancellationRequestedAt || row.state !== \"active\") return;\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({ cancellationRequestedAt: new Date(), cancellationReason: reason })\n .where(processWhere(scope));\n });\n}\n\nexport async function retainedProcessCancellationRequested(\n db: Database,\n scope: ProcessScope,\n): Promise<boolean> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select({ at: schema.sandboxRetainedProcesses.cancellationRequestedAt })\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .limit(1);\n if (!row) throw new Error(\"Retained command is unavailable\");\n return row.at !== null;\n });\n}\n\n/** Record deadline cancellation for an exact retained Modal command. Legacy\n * PTY callers send Ctrl-C first because cancellation fences stdin; non-PTY\n * callers only probe, since Ctrl-C would be data. An earlier explicit stop\n * remains immutable; the deadline uses its own clock. Lock order: process -> lease. */\nexport async function requestRetainedProcessDeadlineCancellation(\n db: Database,\n scope: ProcessScope,\n): Promise<boolean> {\n return withRlsContext(db, scope, async (tx) => {\n const [row] = await tx\n .select()\n .from(schema.sandboxRetainedProcesses)\n .where(processWhere(scope))\n .for(\"update\")\n .limit(1);\n if (\n !row ||\n row.state !== \"active\" ||\n row.providerBackend !== \"modal\" ||\n row.routeTargetId !== null\n )\n return false;\n const [lease] = await tx.execute<{ id: string }>(sql`\n select id from sandbox_leases where id = ${row.leaseId}\n and account_id = ${row.accountId} and workspace_id = ${row.workspaceId}\n and sandbox_group_id = ${row.sandboxGroupId} and lease_epoch = ${row.leaseEpoch}\n and backend = ${row.providerBackend} and instance_id = ${row.providerInstanceId}\n and rotation_requested_at is not null and rotation_reason = 'provider_deadline' for update\n `);\n if (!lease) return false;\n if (!row.deadlineCancellationRequestedAt || !row.cancellationRequestedAt) {\n await tx\n .update(schema.sandboxRetainedProcesses)\n .set({\n ...(!row.cancellationRequestedAt\n ? { cancellationRequestedAt: sql`now()`, cancellationReason: \"provider_deadline\" }\n : {}),\n ...(!row.deadlineCancellationRequestedAt\n ? { deadlineCancellationRequestedAt: sql`now()` }\n : {}),\n })\n .where(processWhere(scope));\n }\n return true;\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
rawRows,
|
|
3
3
|
withWorkspaceRls
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BG46J5HF.js";
|
|
5
5
|
import {
|
|
6
6
|
sessionEvents,
|
|
7
7
|
sessionTurns
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-IIPWNNVR.js";
|
|
9
9
|
import {
|
|
10
10
|
LOSSLESS_JSON_STRING_PREFIX,
|
|
11
11
|
fromPostgresLosslessJson
|
|
@@ -244,4 +244,4 @@ export {
|
|
|
244
244
|
readSessionMessageSliceInScope,
|
|
245
245
|
listSessionEventSlices
|
|
246
246
|
};
|
|
247
|
-
//# sourceMappingURL=chunk-
|
|
247
|
+
//# sourceMappingURL=chunk-WT7HG43Y.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
rawRows,
|
|
3
3
|
withRlsContext,
|
|
4
4
|
withWorkspaceRls
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BG46J5HF.js";
|
|
6
6
|
import {
|
|
7
7
|
connections,
|
|
8
8
|
creditLedgerEntries,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
workspaceVideoGenerationPolicies,
|
|
15
15
|
workspaceVideoGenerationQuotas,
|
|
16
16
|
workspaces
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-IIPWNNVR.js";
|
|
18
18
|
|
|
19
19
|
// src/video-generation.ts
|
|
20
20
|
import {
|
|
@@ -1006,4 +1006,4 @@ export {
|
|
|
1006
1006
|
mediaGenerationResultForStoredOperation,
|
|
1007
1007
|
getVideoGenerationOperationSummary
|
|
1008
1008
|
};
|
|
1009
|
-
//# sourceMappingURL=chunk-
|
|
1009
|
+
//# sourceMappingURL=chunk-ZM5BA3TD.js.map
|
package/dist/connect-attempts.js
CHANGED
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
getConnectAttempt,
|
|
8
8
|
getConnectBeginReplay,
|
|
9
9
|
listPendingConnectAttempts
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-UXFBXCHM.js";
|
|
11
|
+
import "./chunk-BG46J5HF.js";
|
|
12
|
+
import "./chunk-IIPWNNVR.js";
|
|
13
13
|
import "./chunk-S2TZ3F4L.js";
|
|
14
14
|
import "./chunk-PZ5AY32C.js";
|
|
15
15
|
export {
|
package/dist/database.d.ts
CHANGED
|
@@ -31,6 +31,14 @@ export type SessionRlsActorContext = {
|
|
|
31
31
|
initiatingHumanSubjectId?: string | null;
|
|
32
32
|
};
|
|
33
33
|
export declare function currentSessionAttachmentReadAccess(): SessionAttachmentReadAccess | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Stable identity of the ambient session RLS actor: every field that
|
|
36
|
+
* `setRlsContext` turns into database-visible GUCs or that scoped reads
|
|
37
|
+
* consult. Two callers with equal keys see exactly the same rows, so the key
|
|
38
|
+
* is safe for sharing a read result between them; `null` means no actor, in
|
|
39
|
+
* which case the subject GUC stays empty for every such caller.
|
|
40
|
+
*/
|
|
41
|
+
export declare function currentSessionRlsActorIdentityKey(): string | null;
|
|
34
42
|
export declare function withSessionRlsActorContext<T>(actor: SessionRlsActorContext, fn: () => Promise<T>): Promise<T>;
|
|
35
43
|
/**
|
|
36
44
|
* RLS posture for the connection OpenGeni's query layer runs over (Step I, §7.7).
|
|
@@ -9,9 +9,9 @@ import {
|
|
|
9
9
|
listEditableArtifactIdsForSession,
|
|
10
10
|
touchEditableArtifactSessionLink,
|
|
11
11
|
transactionallyAuthorizeEditableArtifactActor
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-5UOWNKPP.js";
|
|
13
|
+
import "./chunk-BG46J5HF.js";
|
|
14
|
+
import "./chunk-IIPWNNVR.js";
|
|
15
15
|
import "./chunk-S2TZ3F4L.js";
|
|
16
16
|
import "./chunk-PZ5AY32C.js";
|
|
17
17
|
export {
|
package/dist/index.d.ts
CHANGED
|
@@ -122,7 +122,7 @@ export * from "./memory-domain.js";
|
|
|
122
122
|
export * from "./model-catalog.js";
|
|
123
123
|
import { type Database, type SessionActivityDatabase } from "./database.js";
|
|
124
124
|
export { createDb, registerDbBinding, retrySessionActivityRls, rlsContextForWorkspace, rlsStrategyFor, setRlsContext, setSubjectRlsContext, withAccountRls, withDatabaseStatementTimeout, withRlsContext, withSessionActivityRlsContext, withSessionActivitySavepoint, withWorkspaceRls, withWorkspaceSessionActivityRls, withWorkspaceSubjectRls, withWorkspaceSubjectSessionActivityRls, withWorkspaceUsageLock, withSandboxProviderReadLock, SandboxProviderReadLockUnavailableError, type CreateDbOptions, type Database, type DbClient, type SessionActivityDatabase, type RlsContext, type SessionRlsActorContext, type RlsStrategy, type SandboxProviderReadLockIdentity, type ManagedUserProfile, type UserLookup, type UserProfileLookup, } from "./database.js";
|
|
125
|
-
export { withSessionRlsActorContext } from "./database.js";
|
|
125
|
+
export { currentSessionRlsActorIdentityKey, withSessionRlsActorContext } from "./database.js";
|
|
126
126
|
export { withDatabaseTimingObserver, type DatabaseTimingObservation } from "./database-timing.js";
|
|
127
127
|
export { normalizedCredentialHeaders } from "./connection-token-resolver.js";
|
|
128
128
|
import { buildCodexTokenResolver as buildCodexTokenResolverCore, fetchCodexRateLimitResetCreditsForAccount as fetchCodexRateLimitResetCreditsForAccountCore, fetchCodexUsageForAccount as fetchCodexUsageForAccountCore, type CodexAccountUsageSnapshot, type CodexAuthDeps, type CodexCredentialCooldownKind, type CodexCredentialForRun } from "./codex-token-resolver.js";
|
|
@@ -843,6 +843,26 @@ export declare function applyCreditDebitUpToBalance(db: Database, input: {
|
|
|
843
843
|
balance: BillingBalance;
|
|
844
844
|
debitedMicros: number;
|
|
845
845
|
}>;
|
|
846
|
+
/**
|
|
847
|
+
* Settle an already-consumed, OpenGeni-funded resource for its full cost.
|
|
848
|
+
* Admission happens before use; an in-flight operation can take the account
|
|
849
|
+
* below zero. Future grants and purchased top-ups net against that balance.
|
|
850
|
+
* Never use this helper to admit a new operation or for externally paid use.
|
|
851
|
+
*/
|
|
852
|
+
export declare function applyCreditDebitAfterUse(db: Database, input: {
|
|
853
|
+
accountId: string;
|
|
854
|
+
workspaceId?: string | null;
|
|
855
|
+
type: string;
|
|
856
|
+
amountMicros: number;
|
|
857
|
+
sourceType: string;
|
|
858
|
+
sourceId: string;
|
|
859
|
+
idempotencyKey: string;
|
|
860
|
+
metadata?: Record<string, unknown>;
|
|
861
|
+
occurredAt?: Date;
|
|
862
|
+
}): Promise<{
|
|
863
|
+
balance: BillingBalance;
|
|
864
|
+
debitedMicros: number;
|
|
865
|
+
}>;
|
|
846
866
|
export declare function hasCreditLedgerEntry(db: Database, accountId: string, idempotencyKey: string): Promise<boolean>;
|
|
847
867
|
export declare function getBillingCustomer(db: Database, accountId: string, provider?: string): Promise<{
|
|
848
868
|
accountId: string;
|
|
@@ -1820,6 +1840,9 @@ export declare function recordRetainedScreenshotArtifactError(db: Database, inpu
|
|
|
1820
1840
|
}): Promise<void>;
|
|
1821
1841
|
/** Session-qualified lookup: a screenshot from another session is indistinguishable from absent. */
|
|
1822
1842
|
export declare function getRetainedScreenshotArtifact(db: Database, workspaceId: string, sessionId: string, artifactId: string): Promise<RetainedScreenshotArtifact | null>;
|
|
1843
|
+
/** Recover a legacy damaged receipt only when its tool call has one exact
|
|
1844
|
+
* screenshot in this session. Never infer an artifact across fork ancestry. */
|
|
1845
|
+
export declare function getRetainedScreenshotArtifactForToolCall(db: Database, workspaceId: string, sessionId: string, toolCallId: string): Promise<RetainedScreenshotArtifact | null>;
|
|
1823
1846
|
export type RetainedScreenshotMaintenanceClaim = {
|
|
1824
1847
|
action: "reconcile" | "delete";
|
|
1825
1848
|
claimId: string;
|
|
@@ -6111,6 +6134,8 @@ export type PendingSessionToolCallInput = {
|
|
|
6111
6134
|
* The receipt belongs to the logical turn so an approval resume can
|
|
6112
6135
|
* settle it from a newer attempt. Duplicate SDK delivery converges on the
|
|
6113
6136
|
* unique (turn, call) identity.
|
|
6137
|
+
* Pass the root database handle so each rollback retry starts a fresh
|
|
6138
|
+
* transaction, not a savepoint in a caller-owned transaction.
|
|
6114
6139
|
*/
|
|
6115
6140
|
export declare function registerPendingSessionToolCall(db: Database, input: PendingSessionToolCallInput): Promise<{
|
|
6116
6141
|
accepted: boolean;
|
|
@@ -6756,6 +6781,12 @@ export interface AcquireLeaseInput {
|
|
|
6756
6781
|
* attach, mirrored into the scoped stream token's claims. */
|
|
6757
6782
|
viewerAuthorityEpoch?: number;
|
|
6758
6783
|
backend: string;
|
|
6784
|
+
/** Explicit compute policy at this admission boundary. Omission is legacy
|
|
6785
|
+
* usage-only; only a priced credits backend needs prepaid admission. */
|
|
6786
|
+
warmBilling?: {
|
|
6787
|
+
mode: "usage_only" | "shadow" | "credits";
|
|
6788
|
+
rateMicrosPerSecond: number;
|
|
6789
|
+
};
|
|
6759
6790
|
os?: string;
|
|
6760
6791
|
image?: string | null;
|
|
6761
6792
|
rigVersionId?: string | null;
|
|
@@ -6872,6 +6903,24 @@ export declare class SandboxViewerAdmissionBlockedError extends Error {
|
|
|
6872
6903
|
readonly name = "SandboxViewerAdmissionBlockedError";
|
|
6873
6904
|
constructor(workspaceId: string, sandboxGroupId: string, reason: SandboxViewerForceDrainReason);
|
|
6874
6905
|
}
|
|
6906
|
+
export declare class SandboxPaidComputeAdmissionError extends Error {
|
|
6907
|
+
readonly workspaceId: string;
|
|
6908
|
+
readonly sandboxGroupId: string;
|
|
6909
|
+
readonly name = "SandboxPaidComputeAdmissionError";
|
|
6910
|
+
constructor(workspaceId: string, sandboxGroupId: string);
|
|
6911
|
+
}
|
|
6912
|
+
/**
|
|
6913
|
+
* Fence the warm-time meter BEFORE requesting provider stop, including free
|
|
6914
|
+
* and shadow usage. The immutable cutoff survives a stop-success/settlement-
|
|
6915
|
+
* failure retry. A failed stop can undercount an idle retry, never count time
|
|
6916
|
+
* after the provider stopped.
|
|
6917
|
+
*/
|
|
6918
|
+
export declare function markWarmBillingStopCutoff(db: Database, input: {
|
|
6919
|
+
accountId: string;
|
|
6920
|
+
workspaceId: string;
|
|
6921
|
+
sandboxGroupId: string;
|
|
6922
|
+
expectedEpoch: number;
|
|
6923
|
+
}): Promise<Date | null>;
|
|
6875
6924
|
export declare class SandboxLeaseRecoveryBlockedError extends Error {
|
|
6876
6925
|
readonly sandboxGroupId: string;
|
|
6877
6926
|
readonly leaseEpoch: number;
|
|
@@ -7475,7 +7524,7 @@ export type LeaseHolderHeartbeatStatus = {
|
|
|
7475
7524
|
} | {
|
|
7476
7525
|
holderAlive: true;
|
|
7477
7526
|
leaseExtended: false;
|
|
7478
|
-
fence: "epoch" | "liveness" | "rotation_requested";
|
|
7527
|
+
fence: "epoch" | "liveness" | "rotation_requested" | "funding";
|
|
7479
7528
|
};
|
|
7480
7529
|
export declare function heartbeatLeaseHolderStatus(db: Database, input: {
|
|
7481
7530
|
accountId: string;
|
|
@@ -7485,6 +7534,7 @@ export declare function heartbeatLeaseHolderStatus(db: Database, input: {
|
|
|
7485
7534
|
holderId: string;
|
|
7486
7535
|
leaseTtlMs: number;
|
|
7487
7536
|
expectedEpoch: number;
|
|
7537
|
+
billingMode?: "usage_only" | "shadow" | "credits";
|
|
7488
7538
|
}): Promise<LeaseHolderHeartbeatStatus>;
|
|
7489
7539
|
export declare function heartbeatLeaseHolder(db: Database, input: {
|
|
7490
7540
|
accountId: string;
|
|
@@ -7494,6 +7544,7 @@ export declare function heartbeatLeaseHolder(db: Database, input: {
|
|
|
7494
7544
|
holderId: string;
|
|
7495
7545
|
leaseTtlMs: number;
|
|
7496
7546
|
expectedEpoch: number;
|
|
7547
|
+
billingMode?: "usage_only" | "shadow" | "credits";
|
|
7497
7548
|
}): Promise<boolean>;
|
|
7498
7549
|
export type ReinstateTurnLeaseHolderResult = {
|
|
7499
7550
|
status: "present" | "reinstated";
|
|
@@ -7620,6 +7671,7 @@ export declare function reArmDrainingLease(db: Database, input: {
|
|
|
7620
7671
|
workspaceId: string;
|
|
7621
7672
|
sandboxGroupId: string;
|
|
7622
7673
|
leaseTtlMs: number;
|
|
7674
|
+
warmBilling?: AcquireLeaseInput["warmBilling"];
|
|
7623
7675
|
}): Promise<{
|
|
7624
7676
|
rearmed: boolean;
|
|
7625
7677
|
}>;
|
|
@@ -7713,6 +7765,9 @@ export type SandboxRetainedProcess = {
|
|
|
7713
7765
|
reconcileClaimedAt: string | null;
|
|
7714
7766
|
reconcileAttempts: number;
|
|
7715
7767
|
lastReconcileOutcome: string | null;
|
|
7768
|
+
cancellationRequestedAt: string | null;
|
|
7769
|
+
cancellationReason: string | null;
|
|
7770
|
+
deadlineCancellationRequestedAt: string | null;
|
|
7716
7771
|
reconcileProofOutcome: "exited" | "lost" | null;
|
|
7717
7772
|
reconcileProofExitCode: number | null;
|
|
7718
7773
|
reconcileProofReason: "provider_exit_banner" | "provider_session_lost_banner" | "provider_instance_not_found" | "provider_instance_terminated" | null;
|
|
@@ -9293,22 +9348,17 @@ export interface AccrueWarmSecondsResult {
|
|
|
9293
9348
|
seconds: number;
|
|
9294
9349
|
/** The monotonic tick index this accrual was recorded under. */
|
|
9295
9350
|
tick: number;
|
|
9296
|
-
/** usd_micros
|
|
9351
|
+
/** Internal usd_micros estimate for this tick (0 in usage_only mode). */
|
|
9297
9352
|
costMicros: number;
|
|
9298
9353
|
}
|
|
9299
9354
|
/**
|
|
9300
9355
|
* Accrue warm-seconds for the elapsed wall-clock since the lease's last meter
|
|
9301
9356
|
* cursor, idempotent on (sandbox_group_id, lease_epoch, tick). EPOCH-FENCED +
|
|
9302
|
-
* liveness-guarded (warm
|
|
9303
|
-
*
|
|
9304
|
-
*
|
|
9305
|
-
*
|
|
9306
|
-
*
|
|
9307
|
-
* sandbox.warm_cost event (cost = seconds x rate) AND debits the same micros from
|
|
9308
|
-
* the credit balance via applyCreditDebitUpToBalance (the model-cost precedent),
|
|
9309
|
-
* idempotent on the SAME (group, epoch, tick) key. The usage event is the
|
|
9310
|
-
* REQUESTED cost; the ledger is the ACTUAL debit (they legitimately differ when
|
|
9311
|
-
* balance is low — M2). Set debitCredits:false to meter without debiting.
|
|
9357
|
+
* liveness-guarded (warm, or draining for a final provider-stop tick). The first
|
|
9358
|
+
* interval begins at the warm transition's recovery timestamp. A draining tick
|
|
9359
|
+
* is only allowed by the provider-stop path, never by the periodic reaper list.
|
|
9360
|
+
* In credits mode the signed full-cost ledger debit, both usage rows and cursor
|
|
9361
|
+
* commit together; a settlement failure rolls back the tick for retry.
|
|
9312
9362
|
*/
|
|
9313
9363
|
export declare function accrueWarmSeconds(db: Database, input: {
|
|
9314
9364
|
accountId: string;
|
|
@@ -9321,16 +9371,16 @@ export declare function accrueWarmSeconds(db: Database, input: {
|
|
|
9321
9371
|
/** Optional attribution: the founding/observing session (visibility only — the
|
|
9322
9372
|
* group meter key makes the workspace charge correct regardless). */
|
|
9323
9373
|
subjectId?: string | null;
|
|
9324
|
-
|
|
9325
|
-
|
|
9326
|
-
|
|
9374
|
+
billingMode?: "usage_only" | "shadow" | "credits";
|
|
9375
|
+
/** Final provider-stop tick, after provider termination and before cold CAS. */
|
|
9376
|
+
finalDrain?: boolean;
|
|
9327
9377
|
}): Promise<AccrueWarmSecondsResult>;
|
|
9328
9378
|
export interface ForceDrainResult {
|
|
9329
|
-
/** Whether the workspace
|
|
9379
|
+
/** Whether the workspace exceeded its optional warm cap. */
|
|
9330
9380
|
overLimit: boolean;
|
|
9331
9381
|
/** The reason, for observability. */
|
|
9332
9382
|
reason: SandboxViewerForceDrainReason | null;
|
|
9333
|
-
/** The (workspaceId, sandboxGroupId)
|
|
9383
|
+
/** The (workspaceId, sandboxGroupId) holderless boxes CASed warm->draining. */
|
|
9334
9384
|
drained: {
|
|
9335
9385
|
workspaceId: string;
|
|
9336
9386
|
sandboxGroupId: string;
|
|
@@ -9338,8 +9388,7 @@ export interface ForceDrainResult {
|
|
|
9338
9388
|
}
|
|
9339
9389
|
export declare function forceDrainOverLimitViewerOnlyBoxes(db: Database, input: {
|
|
9340
9390
|
workspaceId: string;
|
|
9341
|
-
/**
|
|
9342
|
-
balanceMicros: number;
|
|
9391
|
+
/** Legacy caller option; balance belongs to paid admission, not draining. */
|
|
9343
9392
|
enforceBalance: boolean;
|
|
9344
9393
|
/** warm-second cap (cumulative this UTC month). 0 = unbounded (no cap gate). */
|
|
9345
9394
|
maxWarmSecondsPerWorkspace: number;
|