UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

96 lines (95 loc) • 5.7 kB
import { o as racePromiseWithAbortSignal } from "./src-D1BHGNTj.mjs"; import "./abort-signal-QqAmLWTl.mjs"; import { O as NODE_WORKER_WORKSPACE_PREPARE_COMMAND } from "./node-commands-BLhGKTZa.mjs"; import { n as parseNodeWorkerPreparedWorkspaceResult } from "./node-workspace-prepared-protocol-DVXWVN71.mjs"; import { n as readWorkerProjectPreparation } from "./preparation-identity-E2cX74EF.mjs"; //#region src/gateway/worker-environments/node-worker-prepared-workspace-transport.ts /** Register and bind only while the durable owner and paired node still authorize the operation. */ function createNodeWorkerPreparedWorkspaceTransport(options) { const invokePreparedWorkspace = async (request) => { const { input, signal } = request; const assertCurrent = () => { signal?.throwIfAborted(); request.assertCurrent(); }; assertCurrent(); const transport = options.getNodeTransport(); if (!transport) throw new Error("Prepared workspace node transport is unavailable"); const node = await racePromiseWithAbortSignal(transport.getCurrentNode(request.deviceId), signal); assertCurrent(); if (!node || !transport.isCurrent(node)) throw new Error("Prepared workspace node protocol is unavailable"); const timeoutMs = input.action === "register" ? 605e3 : 3e4; const result = await transport.invoke({ node, command: NODE_WORKER_WORKSPACE_PREPARE_COMMAND, params: input, signal, timeoutMs, idempotencyKey: `${input.environmentId}:${input.preparationKey}:${input.action}`, isDispatchAuthorized: () => { assertCurrent(); return transport.isCurrent(node); } }); assertCurrent(); if (!result.ok) throw new Error(`Prepared workspace ${input.action} failed${result.error?.message ? `: ${result.error.message}` : ""}`); const payload = result.payloadJSON ? JSON.parse(result.payloadJSON) : result.payload; const registered = parseNodeWorkerPreparedWorkspaceResult(payload); if (!registered || registered.gatewayNamespace !== input.gatewayNamespace || registered.environmentId !== input.environmentId || registered.preparationKey !== input.preparationKey || registered.cacheKey !== input.cacheKey || input.action === "register" && (registered.workspaceDir !== input.workspaceDir || registered.homeDir !== input.homeDir || registered.sourceManifestRef !== input.sourceManifestRef || registered.preparedManifestRef !== input.preparedManifestRef)) throw new Error("Node did not acknowledge the exact prepared workspace"); return registered; }; return { registerPreparedWorkspace: async ({ record, deviceId, workspace, assertCurrent, signal }) => { const enrollment = options.store.get(record.environmentId); const assertRegistrationCurrent = () => { signal?.throwIfAborted(); assertCurrent(); const current = options.store.get(record.environmentId); const preparation = current && readWorkerProjectPreparation(current.profileSnapshot.project); if (current?.state !== "provisioning" || current.ownerEpoch !== record.ownerEpoch || current.provisionOperationId !== record.provisionOperationId || !enrollment?.nodeSetupId || current.nodeSetupId !== enrollment.nodeSetupId || current.nodeDeviceId !== deviceId || current.attachedSessionIds.length !== 0 || current.destroyRequestedAtMs !== null || preparation?.key !== workspace.preparationKey || preparation.cacheKey !== workspace.cacheKey) throw new Error("Prepared workspace lost its exact provisioning owner"); }; await invokePreparedWorkspace({ deviceId, assertCurrent: assertRegistrationCurrent, signal, input: { action: "register", gatewayNamespace: options.gatewayNamespace, environmentId: record.environmentId, ...workspace } }); }, bindPreparedWorkspace: async ({ assertCurrent, signal, ...binding }) => { const record = options.store.get(binding.environmentId); const placement = options.placementStore.get(binding.sessionId); const assertBindingCurrent = () => { signal?.throwIfAborted(); assertCurrent(); const current = options.store.get(binding.environmentId); const currentPlacement = options.placementStore.get(binding.sessionId); const credential = options.store.getCredential(binding.environmentId); const preparation = current && readWorkerProjectPreparation(current.profileSnapshot.project); if (!record?.nodeDeviceId || current?.nodeDeviceId !== record.nodeDeviceId || current.state !== "attached" || current.sharedHost !== false || current.ownerEpoch !== binding.ownerEpoch || current.attachedSessionIds.length !== 1 || current.attachedSessionIds[0] !== binding.sessionId || current.destroyRequestedAtMs !== null || credential?.ownerEpoch !== binding.ownerEpoch || credential.sessionId !== binding.sessionId || preparation?.key !== binding.preparationKey || preparation.cacheKey !== binding.cacheKey || !placement || !currentPlacement || currentPlacement.generation !== placement.generation || currentPlacement.sessionKey !== binding.sessionKey || currentPlacement.environmentId !== binding.environmentId || ![ "syncing", "starting", "active" ].includes(currentPlacement.state) || currentPlacement.state === "active" && currentPlacement.activeOwnerEpoch !== binding.ownerEpoch) throw new Error("Prepared workspace lost its exact attached placement owner"); return record.nodeDeviceId; }; const deviceId = assertBindingCurrent(); return await invokePreparedWorkspace({ deviceId, assertCurrent: assertBindingCurrent, signal, input: { action: "bind", gatewayNamespace: options.gatewayNamespace, ...binding } }); } }; } //#endregion export { createNodeWorkerPreparedWorkspaceTransport };