UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

117 lines (116 loc) • 6.04 kB
import { a as getNodeSqliteKysely, i as executeSqliteQueryTakeFirstSync, r as executeSqliteQuerySync } from "./kysely-sync-K7ftY-g4.mjs"; import { i as tableExists } from "./openclaw-state-db-schema-helpers-BlZefrPy.mjs"; import { i as requestSqliteWorkerOperationAdmission } from "./sqlite-worker-operation-admission-cNGSH5v0.mjs"; import { f as withExistingOpenClawStateDatabaseReadOnly } from "./openclaw-state-db-readonly-CC57AD_q.mjs"; import { l as runOpenClawStateWriteTransaction } from "./openclaw-state-db-D1jWDzK3.mjs"; import { f as ensureNodeWorkerPreparedWorkspaceSchema } from "./openclaw-state-db-schema-additive-CzAgdzE5.mjs"; //#region src/node-host/node-worker-prepared-workspace-store.kernel.ts const TABLE = "node_worker_prepared_workspaces"; function query(db) { return getNodeSqliteKysely(db); } function selectRow(db, preparationKey) { return executeSqliteQueryTakeFirstSync(db, query(db).selectFrom(TABLE).selectAll().where("preparation_key", "=", preparationKey)); } function requireUnchanged(row, expected) { if (!row || JSON.stringify(row) !== JSON.stringify(expected)) throw new Error("INVALID_REQUEST: prepared workspace ownership changed"); return row; } /** One fresh dedicated node owns one immutable registration and one session binding. */ var NodeWorkerPreparedWorkspaceKernel = class { constructor(options) { this.options = options; } write(operationLabel, operation) { return runOpenClawStateWriteTransaction(({ db }) => { requestSqliteWorkerOperationAdmission({ stage: "transaction", facts: { kind: "node-worker-journal" } }); return operation(db); }, this.options, { operationLabel }); } find(environmentId) { return withExistingOpenClawStateDatabaseReadOnly(({ db }) => { if (!tableExists(db, TABLE)) return; const rows = executeSqliteQuerySync(db, query(db).selectFrom(TABLE).selectAll().limit(2)).rows; if (rows.length > 1 || rows[0] && rows[0].environment_id !== environmentId) throw new Error("INVALID_REQUEST: this prepared node belongs to another environment"); return rows[0]; }, this.options); } list(gatewayNamespace) { return withExistingOpenClawStateDatabaseReadOnly(({ db }) => { if (!tableExists(db, TABLE)) return []; return executeSqliteQuerySync(db, query(db).selectFrom(TABLE).selectAll().where("gateway_namespace", "=", gatewayNamespace)).rows; }, this.options) ?? []; } register(input) { return this.write("prepared-workspace.register", (db) => { ensureNodeWorkerPreparedWorkspaceSchema(db); const existing = executeSqliteQueryTakeFirstSync(db, query(db).selectFrom(TABLE).selectAll().limit(1)); if (existing) { if (existing.state !== "available" || existing.preparation_key !== input.preparationKey || existing.cache_key !== input.cacheKey || existing.gateway_namespace !== input.gatewayNamespace || existing.environment_id !== input.environmentId || existing.workspace_dir !== input.workspaceDir || existing.home_dir !== input.homeDir || existing.source_manifest_ref !== input.sourceManifestRef || existing.prepared_manifest_ref !== input.preparedManifestRef) throw new Error("INVALID_REQUEST: this node already owns a prepared workspace"); return existing; } const row = { preparation_key: input.preparationKey, cache_key: input.cacheKey, gateway_namespace: input.gatewayNamespace, environment_id: input.environmentId, workspace_dir: input.workspaceDir, home_dir: input.homeDir, source_manifest_ref: input.sourceManifestRef, prepared_manifest_ref: input.preparedManifestRef, state: "available", session_id: null, session_key: null, owner_epoch: null, created_at_ms: Date.now(), bound_at_ms: null, retired_at_ms: null }; executeSqliteQuerySync(db, query(db).insertInto(TABLE).values(row)); return selectRow(db, input.preparationKey); }); } bind(input) { return this.write("prepared-workspace.bind", (db) => { if (!tableExists(db, TABLE)) throw new Error("INVALID_REQUEST: prepared workspace registration is missing"); const row = selectRow(db, input.preparationKey); if (!row || row.cache_key !== input.cacheKey || row.gateway_namespace !== input.gatewayNamespace || row.environment_id !== input.environmentId) throw new Error("INVALID_REQUEST: prepared workspace registration does not match this environment"); if (row.state === "bound" && row.session_id === input.sessionId && row.session_key === input.sessionKey && row.owner_epoch === input.ownerEpoch) return row; if (row.state !== "available" || row.session_id !== null || row.session_key !== null || row.owner_epoch !== null || row.bound_at_ms !== null) throw new Error("INVALID_REQUEST: prepared workspace has already been consumed"); const bound = { ...row, state: "bound", session_id: input.sessionId, session_key: input.sessionKey, owner_epoch: input.ownerEpoch, bound_at_ms: Math.max(Date.now(), row.created_at_ms) }; executeSqliteQuerySync(db, query(db).updateTable(TABLE).set(bound).where("preparation_key", "=", input.preparationKey)); return bound; }); } completeMutation(retiring) { this.write("prepared-workspace.finish-mutation", (db) => { requireUnchanged(selectRow(db, retiring.preparation_key), retiring); executeSqliteQuerySync(db, query(db).updateTable(TABLE).set({ state: "bound" }).where("preparation_key", "=", retiring.preparation_key)); }); } retire(expected, completed = false) { return this.write("prepared-workspace.retire", (db) => { const row = requireUnchanged(selectRow(db, expected.preparation_key), expected); if (row.state === "retired") return row; const retired = { ...row, state: completed ? "retired" : "retiring", retired_at_ms: completed ? Math.max(Date.now(), row.bound_at_ms ?? row.created_at_ms) : null }; executeSqliteQuerySync(db, query(db).updateTable(TABLE).set(retired).where("preparation_key", "=", row.preparation_key)); return retired; }); } }; //#endregion export { NodeWorkerPreparedWorkspaceKernel as t };