@lamplitisles/dsh-nanocodex 0.1.0-beta.0
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/LICENSE +65 -0
- package/NOTICE +2 -0
- package/README.md +182 -0
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/cordis.patch.yml +52 -0
- package/dist/index.d.ts +435 -0
- package/dist/index.js +3405 -0
- package/dist/standard-preset.d.ts +7 -0
- package/dist/standard-preset.js +25 -0
- package/engine-release.json +14 -0
- package/package.json +119 -0
- package/presets/standard/agent.cordis.yml +6 -0
- package/presets/standard/preset.yml +2 -0
- package/vendor/nanocodex/README.md +1344 -0
- package/vendor/nanocodex/actions/events.d.mts +10 -0
- package/vendor/nanocodex/actions/events.mjs +163 -0
- package/vendor/nanocodex/actions/index.d.mts +13 -0
- package/vendor/nanocodex/actions/index.mjs +35 -0
- package/vendor/nanocodex/actions/session.d.mts +66 -0
- package/vendor/nanocodex/actions/session.mjs +59 -0
- package/vendor/nanocodex/actions/turn.d.mts +59 -0
- package/vendor/nanocodex/actions/turn.mjs +37 -0
- package/vendor/nanocodex/actions/voice.d.mts +22 -0
- package/vendor/nanocodex/actions/voice.mjs +50 -0
- package/vendor/nanocodex/browser/Agent.d.mts +55 -0
- package/vendor/nanocodex/browser/Agent.mjs +11 -0
- package/vendor/nanocodex/browser/ChatGptSubscription.d.mts +7 -0
- package/vendor/nanocodex/browser/ChatGptSubscription.mjs +19 -0
- package/vendor/nanocodex/browser/InlineAgent.mjs +266 -0
- package/vendor/nanocodex/browser/Transport.d.mts +74 -0
- package/vendor/nanocodex/browser/Transport.mjs +61 -0
- package/vendor/nanocodex/browser/Voice.d.mts +71 -0
- package/vendor/nanocodex/browser/Voice.mjs +291 -0
- package/vendor/nanocodex/browser/VoiceSession.mjs +688 -0
- package/vendor/nanocodex/browser/WorkerAgent.d.mts +65 -0
- package/vendor/nanocodex/browser/WorkerAgent.mjs +1472 -0
- package/vendor/nanocodex/browser/agent.worker.mjs +3 -0
- package/vendor/nanocodex/browser/config.d.mts +36 -0
- package/vendor/nanocodex/browser/config.mjs +439 -0
- package/vendor/nanocodex/browser/engine.mjs +13 -0
- package/vendor/nanocodex/browser/harness.mjs +55 -0
- package/vendor/nanocodex/browser/host.d.mts +83 -0
- package/vendor/nanocodex/browser/host.mjs +555 -0
- package/vendor/nanocodex/browser/hostManagedWebSocket.d.mts +14 -0
- package/vendor/nanocodex/browser/hostManagedWebSocket.mjs +110 -0
- package/vendor/nanocodex/browser/index.d.mts +92 -0
- package/vendor/nanocodex/browser/index.mjs +23 -0
- package/vendor/nanocodex/browser/indexeddb-durability-store.mjs +197 -0
- package/vendor/nanocodex/browser/workspace.d.mts +16 -0
- package/vendor/nanocodex/browser/workspace.mjs +107 -0
- package/vendor/nanocodex/cloud/Client.d.mts +83 -0
- package/vendor/nanocodex/cloud/Client.mjs +231 -0
- package/vendor/nanocodex/cloud/Decorator.d.mts +31 -0
- package/vendor/nanocodex/cloud/Decorator.mjs +37 -0
- package/vendor/nanocodex/cloud/Dialog.d.mts +113 -0
- package/vendor/nanocodex/cloud/Dialog.mjs +366 -0
- package/vendor/nanocodex/cloud/Errors.d.mts +22 -0
- package/vendor/nanocodex/cloud/Errors.mjs +39 -0
- package/vendor/nanocodex/cloud/Principal.d.mts +26 -0
- package/vendor/nanocodex/cloud/Principal.mjs +88 -0
- package/vendor/nanocodex/cloud/RemoteProvider.mjs +88 -0
- package/vendor/nanocodex/cloud/Transport.d.mts +47 -0
- package/vendor/nanocodex/cloud/Transport.mjs +454 -0
- package/vendor/nanocodex/cloud/actions/account.d.mts +9 -0
- package/vendor/nanocodex/cloud/actions/account.mjs +19 -0
- package/vendor/nanocodex/cloud/actions/agent.d.mts +18 -0
- package/vendor/nanocodex/cloud/actions/agent.mjs +428 -0
- package/vendor/nanocodex/cloud/actions/connection.d.mts +133 -0
- package/vendor/nanocodex/cloud/actions/connection.mjs +580 -0
- package/vendor/nanocodex/cloud/actions/grant.d.mts +10 -0
- package/vendor/nanocodex/cloud/actions/grant.mjs +12 -0
- package/vendor/nanocodex/cloud/actions/index.d.mts +7 -0
- package/vendor/nanocodex/cloud/actions/index.mjs +7 -0
- package/vendor/nanocodex/cloud/actions/machineUsd.d.mts +23 -0
- package/vendor/nanocodex/cloud/actions/machineUsd.mjs +37 -0
- package/vendor/nanocodex/cloud/actions/model.d.mts +12 -0
- package/vendor/nanocodex/cloud/actions/model.mjs +50 -0
- package/vendor/nanocodex/cloud/actions/mpp.d.mts +28 -0
- package/vendor/nanocodex/cloud/actions/mpp.mjs +39 -0
- package/vendor/nanocodex/cloud/index.d.mts +30 -0
- package/vendor/nanocodex/cloud/index.mjs +9 -0
- package/vendor/nanocodex/cloud/internal.mjs +533 -0
- package/vendor/nanocodex/cloud/mercator.mjs +108 -0
- package/vendor/nanocodex/cloud/server/HostPrincipal.d.mts +34 -0
- package/vendor/nanocodex/cloud/server/HostPrincipal.mjs +202 -0
- package/vendor/nanocodex/cloud/server/index.d.mts +1 -0
- package/vendor/nanocodex/cloud/server/index.mjs +1 -0
- package/vendor/nanocodex/cloud/types.d.mts +211 -0
- package/vendor/nanocodex/cloudflare/Agent.d.mts +133 -0
- package/vendor/nanocodex/cloudflare/Agent.mjs +811 -0
- package/vendor/nanocodex/cloudflare/egress-subject.mjs +19 -0
- package/vendor/nanocodex/cloudflare/egress.d.mts +41 -0
- package/vendor/nanocodex/cloudflare/egress.mjs +119 -0
- package/vendor/nanocodex/cloudflare/event-socket.mjs +316 -0
- package/vendor/nanocodex/cloudflare/index.d.mts +7 -0
- package/vendor/nanocodex/cloudflare/index.mjs +6 -0
- package/vendor/nanocodex/host/Agent.d.mts +55 -0
- package/vendor/nanocodex/host/Agent.mjs +1 -0
- package/vendor/nanocodex/host/index.d.mts +82 -0
- package/vendor/nanocodex/host/index.mjs +10 -0
- package/vendor/nanocodex/index.d.mts +81 -0
- package/vendor/nanocodex/index.mjs +12 -0
- package/vendor/nanocodex/internal.mjs +1275 -0
- package/vendor/nanocodex/managed/Agent.d.mts +380 -0
- package/vendor/nanocodex/managed/Agent.mjs +1694 -0
- package/vendor/nanocodex/managed/ManagedError.d.mts +9 -0
- package/vendor/nanocodex/managed/ManagedError.mjs +8 -0
- package/vendor/nanocodex/managed/README.md +241 -0
- package/vendor/nanocodex/managed/Voice.mjs +202 -0
- package/vendor/nanocodex/managed/index.d.mts +20 -0
- package/vendor/nanocodex/managed/index.mjs +2 -0
- package/vendor/nanocodex/managed/internal.mjs +119 -0
- package/vendor/nanocodex/node/Agent.d.mts +50 -0
- package/vendor/nanocodex/node/Agent.mjs +203 -0
- package/vendor/nanocodex/node/ChatGptSubscription.d.mts +9 -0
- package/vendor/nanocodex/node/ChatGptSubscription.mjs +17 -0
- package/vendor/nanocodex/node/Transport.d.mts +44 -0
- package/vendor/nanocodex/node/Transport.mjs +46 -0
- package/vendor/nanocodex/node/host.mjs +731 -0
- package/vendor/nanocodex/node/index.d.mts +73 -0
- package/vendor/nanocodex/node/index.mjs +17 -0
- package/vendor/nanocodex/node/workspace.d.mts +10 -0
- package/vendor/nanocodex/node/workspace.mjs +198 -0
- package/vendor/nanocodex/package.json +200 -0
- package/vendor/nanocodex/pkg-node/nanocodex.d.ts +675 -0
- package/vendor/nanocodex/pkg-node/nanocodex.js +2628 -0
- package/vendor/nanocodex/pkg-node/nanocodex_bg.wasm.d.ts +105 -0
- package/vendor/nanocodex/pkg-node/package.json +1 -0
- package/vendor/nanocodex/pkg-web/.nanocodex-bindgen-stamp +6 -0
- package/vendor/nanocodex/pkg-web/nanocodex-build.json +1 -0
- package/vendor/nanocodex/pkg-web/nanocodex.d.ts +805 -0
- package/vendor/nanocodex/pkg-web/nanocodex.js +2714 -0
- package/vendor/nanocodex/pkg-web/nanocodex_bg.js +2615 -0
- package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm +0 -0
- package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm.d.ts +105 -0
- package/vendor/nanocodex/pkg-web/nanocodex_worker.js +9 -0
- package/vendor/nanocodex/pkg-web/package.json +1 -0
- package/vendor/nanocodex/runtime/chatgpt-subscription.mjs +212 -0
- package/vendor/nanocodex/runtime/cloudflare-durability-store.d.mts +26 -0
- package/vendor/nanocodex/runtime/cloudflare-durability-store.mjs +168 -0
- package/vendor/nanocodex/runtime/code-evaluator.worker.mjs +137 -0
- package/vendor/nanocodex/runtime/code-runtime.mjs +1 -0
- package/vendor/nanocodex/runtime/durability-store.d.mts +85 -0
- package/vendor/nanocodex/runtime/durability-store.mjs +631 -0
- package/vendor/nanocodex/runtime/durability.mjs +153 -0
- package/vendor/nanocodex/runtime/managed-transport.mjs +460 -0
- package/vendor/nanocodex/runtime/mcp-runtime.mjs +534 -0
- package/vendor/nanocodex/runtime/postgres-durability-store.d.mts +64 -0
- package/vendor/nanocodex/runtime/postgres-durability-store.mjs +532 -0
- package/vendor/nanocodex/runtime/quickjs-evaluator.d.mts +17 -0
- package/vendor/nanocodex/runtime/quickjs-evaluator.mjs +236 -0
- package/vendor/nanocodex/runtime/responses-transport.mjs +22 -0
- package/vendor/nanocodex/runtime/subagents.d.mts +107 -0
- package/vendor/nanocodex/runtime/subagents.mjs +54 -0
- package/vendor/nanocodex/runtime/subscription-store.d.mts +8 -0
- package/vendor/nanocodex/runtime/subscription-store.mjs +42 -0
- package/vendor/nanocodex/runtime/tempo-provider.d.mts +125 -0
- package/vendor/nanocodex/runtime/tempo-provider.mjs +264 -0
- package/vendor/nanocodex/runtime/tool-configuration.mjs +1 -0
- package/vendor/nanocodex/runtime/tool-router.mjs +1 -0
- package/vendor/nanocodex/runtime/utf8.mjs +1 -0
- package/vendor/nanocodex/runtime/worker-evaluator.mjs +162 -0
- package/vendor/nanocodex/runtime/workspace.d.mts +1 -0
- package/vendor/nanocodex/runtime/workspace.mjs +1 -0
- package/vendor/nanocodex/tools/Tools.d.mts +56 -0
- package/vendor/nanocodex/tools/Tools.mjs +136 -0
- package/vendor/nanocodex/tools/artifact.d.mts +1 -0
- package/vendor/nanocodex/tools/artifact.mjs +1 -0
- package/vendor/nanocodex/tools/attachment.mjs +1 -0
- package/vendor/nanocodex/tools/bash.d.mts +1 -0
- package/vendor/nanocodex/tools/bash.mjs +1 -0
- package/vendor/nanocodex/tools/browser/accountInfo.mjs +795 -0
- package/vendor/nanocodex/tools/browser/browserBuffer.mjs +18 -0
- package/vendor/nanocodex/tools/browser/browserCompiler.mjs +155 -0
- package/vendor/nanocodex/tools/browser/browserEgress.mjs +161 -0
- package/vendor/nanocodex/tools/browser/browserPython.mjs +133 -0
- package/vendor/nanocodex/tools/browser/browserShell.mjs +1075 -0
- package/vendor/nanocodex/tools/browser/browserSprintf.mjs +4 -0
- package/vendor/nanocodex/tools/browser/browserSsh.mjs +201 -0
- package/vendor/nanocodex/tools/browser/browserZlib.mjs +136 -0
- package/vendor/nanocodex/tools/browser/compiler.worker.mjs +160 -0
- package/vendor/nanocodex/tools/browser/devTunnelsSshBrowser.mjs +13 -0
- package/vendor/nanocodex/tools/browser/index.d.mts +209 -0
- package/vendor/nanocodex/tools/browser/index.mjs +174 -0
- package/vendor/nanocodex/tools/browser/opfsGit.mjs +248 -0
- package/vendor/nanocodex/tools/browser/python.worker.mjs +114 -0
- package/vendor/nanocodex/tools/browser/threadGit.mjs +197 -0
- package/vendor/nanocodex/tools/browser/unsupportedNodeRsa.mjs +5 -0
- package/vendor/nanocodex/tools/browser/workspace.mjs +83 -0
- package/vendor/nanocodex/tools/dataset.d.mts +1 -0
- package/vendor/nanocodex/tools/dataset.mjs +1 -0
- package/vendor/nanocodex/tools/datasetContract.mjs +1 -0
- package/vendor/nanocodex/tools/datasetEngine.mjs +1 -0
- package/vendor/nanocodex/tools/hostedCatalog.d.mts +1 -0
- package/vendor/nanocodex/tools/hostedCatalog.mjs +1 -0
- package/vendor/nanocodex/tools/index.d.mts +49 -0
- package/vendor/nanocodex/tools/index.mjs +19 -0
- package/vendor/nanocodex/tools/namedTool.mjs +1 -0
- package/vendor/nanocodex/tools/repository-workspace.d.mts +1 -0
- package/vendor/nanocodex/tools/repository-workspace.mjs +1 -0
- package/vendor/nanocodex/tools/ssh.d.mts +1 -0
- package/vendor/nanocodex/tools/ssh.mjs +1 -0
- package/vendor/nanocodex/tools/standard.mjs +1 -0
- package/vendor/nanocodex/tools/standardDescriptions.mjs +1 -0
- package/vendor/nanocodex/types.d.mts +663 -0
- package/vendor/nanocodex/wasm.d.mts +4 -0
- package/vendor/nanocodex/worker/ChatGptSubscription.d.mts +9 -0
- package/vendor/nanocodex/worker/ChatGptSubscription.mjs +29 -0
- package/vendor/nanocodex/worker/index.d.mts +18 -0
- package/vendor/nanocodex/worker/index.mjs +5 -0
- package/vendor/nanocodex-tools/README.md +65 -0
- package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.d.ts +7 -0
- package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.js +14 -0
- package/vendor/nanocodex-tools/dist/hosted/broker-core.d.ts +172 -0
- package/vendor/nanocodex-tools/dist/hosted/broker-core.js +1278 -0
- package/vendor/nanocodex-tools/dist/hosted/index.d.ts +3 -0
- package/vendor/nanocodex-tools/dist/hosted/index.js +3 -0
- package/vendor/nanocodex-tools/dist/hosted/protocol.d.ts +120 -0
- package/vendor/nanocodex-tools/dist/hosted/protocol.js +415 -0
- package/vendor/nanocodex-tools/dist/index.d.ts +19 -0
- package/vendor/nanocodex-tools/dist/index.js +14 -0
- package/vendor/nanocodex-tools/dist/memory.d.ts +204 -0
- package/vendor/nanocodex-tools/dist/memory.js +411 -0
- package/vendor/nanocodex-tools/dist/namespace.d.ts +87 -0
- package/vendor/nanocodex-tools/dist/namespace.js +338 -0
- package/vendor/nanocodex-tools/dist/repository-archive.d.ts +4 -0
- package/vendor/nanocodex-tools/dist/repository-archive.js +104 -0
- package/vendor/nanocodex-tools/dist/runtime.d.ts +30 -0
- package/vendor/nanocodex-tools/dist/runtime.js +37 -0
- package/vendor/nanocodex-tools/dist/session.d.ts +167 -0
- package/vendor/nanocodex-tools/dist/session.js +286 -0
- package/vendor/nanocodex-tools/dist/shell.d.ts +51 -0
- package/vendor/nanocodex-tools/dist/shell.js +553 -0
- package/vendor/nanocodex-tools/dist/ssh.d.ts +29 -0
- package/vendor/nanocodex-tools/dist/ssh.js +66 -0
- package/vendor/nanocodex-tools/dist/workspace.d.ts +45 -0
- package/vendor/nanocodex-tools/dist/workspace.js +237 -0
- package/vendor/nanocodex-tools/package.json +122 -0
- package/vendor/nanocodex-tools/runtime/code-runtime.mjs +817 -0
- package/vendor/nanocodex-tools/runtime/tool-configuration.mjs +50 -0
- package/vendor/nanocodex-tools/runtime/tool-router.mjs +730 -0
- package/vendor/nanocodex-tools/runtime/utf8.d.mts +2 -0
- package/vendor/nanocodex-tools/runtime/utf8.mjs +25 -0
- package/vendor/nanocodex-tools/tools/artifact.d.mts +69 -0
- package/vendor/nanocodex-tools/tools/artifact.mjs +270 -0
- package/vendor/nanocodex-tools/tools/attachment.mjs +603 -0
- package/vendor/nanocodex-tools/tools/bash.d.mts +90 -0
- package/vendor/nanocodex-tools/tools/bash.mjs +742 -0
- package/vendor/nanocodex-tools/tools/dataset.d.mts +9 -0
- package/vendor/nanocodex-tools/tools/dataset.mjs +47 -0
- package/vendor/nanocodex-tools/tools/datasetContract.mjs +54 -0
- package/vendor/nanocodex-tools/tools/datasetEngine.mjs +1167 -0
- package/vendor/nanocodex-tools/tools/execution-contract.d.mts +5 -0
- package/vendor/nanocodex-tools/tools/execution-contract.mjs +63 -0
- package/vendor/nanocodex-tools/tools/hostedCatalog.d.mts +20 -0
- package/vendor/nanocodex-tools/tools/hostedCatalog.mjs +67 -0
- package/vendor/nanocodex-tools/tools/hostedMachine.d.mts +10 -0
- package/vendor/nanocodex-tools/tools/hostedMachine.mjs +56 -0
- package/vendor/nanocodex-tools/tools/just-bash-browser.d.mts +1 -0
- package/vendor/nanocodex-tools/tools/just-bash-browser.mjs +1 -0
- package/vendor/nanocodex-tools/tools/namedTool.d.mts +3 -0
- package/vendor/nanocodex-tools/tools/namedTool.mjs +3 -0
- package/vendor/nanocodex-tools/tools/nodeProcess.d.mts +10 -0
- package/vendor/nanocodex-tools/tools/nodeProcess.mjs +314 -0
- package/vendor/nanocodex-tools/tools/processOutput.mjs +56 -0
- package/vendor/nanocodex-tools/tools/repository-workspace.d.mts +55 -0
- package/vendor/nanocodex-tools/tools/repository-workspace.mjs +397 -0
- package/vendor/nanocodex-tools/tools/ssh.d.mts +56 -0
- package/vendor/nanocodex-tools/tools/ssh.mjs +503 -0
- package/vendor/nanocodex-tools/tools/standard.mjs +458 -0
- package/vendor/nanocodex-tools/tools/standardDescriptions.mjs +3 -0
- package/vendor/nanocodex-tools/tools/types.d.mts +83 -0
- package/vendor/nanocodex-tools/tools/workspace.d.mts +25 -0
- package/vendor/nanocodex-tools/tools/workspace.mjs +282 -0
- package/vendor/nanocodex-tools/tools/x.d.mts +30 -0
- package/vendor/nanocodex-tools/tools/x.mjs +91 -0
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DurabilityImportConflictError,
|
|
3
|
+
durabilityRevision,
|
|
4
|
+
} from "./durability-store.mjs";
|
|
5
|
+
|
|
6
|
+
const MAX_REVISION = "18446744073709551615";
|
|
7
|
+
const PORTABLE_IMPORT_OWNER = "nanocodex-portable-import";
|
|
8
|
+
const VERIFY_ATTEMPTS = 3;
|
|
9
|
+
const SCHEMA = [
|
|
10
|
+
`CREATE TABLE IF NOT EXISTS nanocodex_durable_owners (
|
|
11
|
+
state_id TEXT PRIMARY KEY,
|
|
12
|
+
owner_id TEXT NOT NULL,
|
|
13
|
+
fence NUMERIC(20, 0) NOT NULL
|
|
14
|
+
CHECK (fence >= 1 AND fence <= 18446744073709551615)
|
|
15
|
+
)`,
|
|
16
|
+
`CREATE TABLE IF NOT EXISTS nanocodex_durable_states (
|
|
17
|
+
state_id TEXT PRIMARY KEY,
|
|
18
|
+
revision NUMERIC(20, 0) NOT NULL
|
|
19
|
+
CHECK (revision >= 1 AND revision <= 18446744073709551615),
|
|
20
|
+
payload TEXT NOT NULL
|
|
21
|
+
)`,
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
export class PostgresDurabilityUnavailableError extends Error {
|
|
25
|
+
constructor(stateId, cause) {
|
|
26
|
+
super(`PostgreSQL durability could not verify state ${JSON.stringify(stateId)}; retrying the identical request is safe`, {
|
|
27
|
+
cause,
|
|
28
|
+
});
|
|
29
|
+
this.name = "PostgresDurabilityUnavailableError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class CommitVerificationRequired extends Error {}
|
|
34
|
+
|
|
35
|
+
class InvalidPostgresDurabilityRequestError extends Error {
|
|
36
|
+
constructor(cause) {
|
|
37
|
+
super("invalid PostgreSQL durability replacement request", { cause });
|
|
38
|
+
this.name = "InvalidPostgresDurabilityRequestError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Creates a concrete PostgreSQL-backed Nanocodex durability store. */
|
|
43
|
+
export function createPostgresDurabilityStore(pool) {
|
|
44
|
+
if (!pool || typeof pool.connect !== "function" || typeof pool.query !== "function") {
|
|
45
|
+
throw new TypeError("PostgreSQL durability requires a connection pool");
|
|
46
|
+
}
|
|
47
|
+
let initialized;
|
|
48
|
+
const ready = () => {
|
|
49
|
+
initialized ??= initialize(pool).catch((error) => {
|
|
50
|
+
initialized = undefined;
|
|
51
|
+
throw error;
|
|
52
|
+
});
|
|
53
|
+
return initialized;
|
|
54
|
+
};
|
|
55
|
+
return Object.freeze({
|
|
56
|
+
async load(stateId) {
|
|
57
|
+
requireId(stateId);
|
|
58
|
+
await ready();
|
|
59
|
+
return loadState(pool, stateId);
|
|
60
|
+
},
|
|
61
|
+
async acquire(stateId, request) {
|
|
62
|
+
requireId(stateId);
|
|
63
|
+
const ownerId = requireOwner(request?.ownerId);
|
|
64
|
+
await ready();
|
|
65
|
+
return acquireState(pool, stateId, ownerId);
|
|
66
|
+
},
|
|
67
|
+
async replace(stateId, request) {
|
|
68
|
+
requireId(stateId);
|
|
69
|
+
const ownerId = requireOwner(request?.ownerId);
|
|
70
|
+
const fence = durabilityRevision(request?.fence);
|
|
71
|
+
await ready();
|
|
72
|
+
return replaceState(pool, stateId, {
|
|
73
|
+
ownerId,
|
|
74
|
+
fence,
|
|
75
|
+
expectedRevision: request?.expectedRevision,
|
|
76
|
+
payload: request?.payload,
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
async importState(stateId, imported, options) {
|
|
80
|
+
requireId(stateId);
|
|
81
|
+
const state = importedState(imported);
|
|
82
|
+
const expectedRevision = options?.expectedRevision === undefined
|
|
83
|
+
? undefined
|
|
84
|
+
: durabilityRevision(options.expectedRevision);
|
|
85
|
+
const expectedPayload = expectedImportPayload(options, expectedRevision);
|
|
86
|
+
await ready();
|
|
87
|
+
return restoreState(pool, stateId, state, expectedRevision, expectedPayload);
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function initialize(pool) {
|
|
93
|
+
const client = await pool.connect();
|
|
94
|
+
let begun = false;
|
|
95
|
+
let discard = false;
|
|
96
|
+
try {
|
|
97
|
+
await client.query("BEGIN");
|
|
98
|
+
begun = true;
|
|
99
|
+
await client.query(
|
|
100
|
+
`SELECT pg_advisory_xact_lock(hashtextextended(
|
|
101
|
+
current_database() || ':' || current_schema() || ':nanocodex-durability-v2', 0
|
|
102
|
+
))`,
|
|
103
|
+
);
|
|
104
|
+
for (const statement of SCHEMA) await client.query(statement);
|
|
105
|
+
const columns = await client.query(
|
|
106
|
+
`SELECT table_name, column_name, data_type, is_nullable,
|
|
107
|
+
numeric_precision, numeric_scale
|
|
108
|
+
FROM information_schema.columns
|
|
109
|
+
WHERE table_schema = current_schema()
|
|
110
|
+
AND table_name IN ('nanocodex_durable_owners', 'nanocodex_durable_states')
|
|
111
|
+
ORDER BY table_name, ordinal_position`,
|
|
112
|
+
);
|
|
113
|
+
if (!validColumns(columns.rows)) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
"incompatible Postgres durability schema; recreate the two nanocodex_durable_* tables",
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
const primaryKeys = await client.query(
|
|
119
|
+
`SELECT tc.table_name, kcu.column_name, kcu.ordinal_position
|
|
120
|
+
FROM information_schema.table_constraints AS tc
|
|
121
|
+
JOIN information_schema.key_column_usage AS kcu
|
|
122
|
+
ON tc.constraint_catalog = kcu.constraint_catalog
|
|
123
|
+
AND tc.constraint_schema = kcu.constraint_schema
|
|
124
|
+
AND tc.constraint_name = kcu.constraint_name
|
|
125
|
+
WHERE tc.table_schema = current_schema()
|
|
126
|
+
AND tc.constraint_type = 'PRIMARY KEY'
|
|
127
|
+
AND tc.table_name IN ('nanocodex_durable_owners', 'nanocodex_durable_states')
|
|
128
|
+
ORDER BY tc.table_name, kcu.ordinal_position`,
|
|
129
|
+
);
|
|
130
|
+
if (!validPrimaryKeys(primaryKeys.rows)) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
"incompatible Postgres durability primary keys; each state_id must be the sole primary key",
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
await client.query("COMMIT");
|
|
137
|
+
begun = false;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
discard = true;
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
} catch (error) {
|
|
143
|
+
if (begun) {
|
|
144
|
+
try {
|
|
145
|
+
await client.query("ROLLBACK");
|
|
146
|
+
} catch (rollbackError) {
|
|
147
|
+
discard = true;
|
|
148
|
+
throw new AggregateError(
|
|
149
|
+
[error, rollbackError],
|
|
150
|
+
"PostgreSQL durability initialization and rollback both failed",
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
throw error;
|
|
155
|
+
} finally {
|
|
156
|
+
client.release(discard);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function validPrimaryKeys(rows) {
|
|
161
|
+
const expected = [
|
|
162
|
+
["nanocodex_durable_owners", "state_id", 1],
|
|
163
|
+
["nanocodex_durable_states", "state_id", 1],
|
|
164
|
+
];
|
|
165
|
+
return rows.length === expected.length && rows.every((row, index) =>
|
|
166
|
+
row.table_name === expected[index][0]
|
|
167
|
+
&& row.column_name === expected[index][1]
|
|
168
|
+
&& row.ordinal_position === expected[index][2]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function validColumns(rows) {
|
|
172
|
+
const expected = [
|
|
173
|
+
["nanocodex_durable_owners", "state_id", "text", "NO", null, null],
|
|
174
|
+
["nanocodex_durable_owners", "owner_id", "text", "NO", null, null],
|
|
175
|
+
["nanocodex_durable_owners", "fence", "numeric", "NO", 20, 0],
|
|
176
|
+
["nanocodex_durable_states", "state_id", "text", "NO", null, null],
|
|
177
|
+
["nanocodex_durable_states", "revision", "numeric", "NO", 20, 0],
|
|
178
|
+
["nanocodex_durable_states", "payload", "text", "NO", null, null],
|
|
179
|
+
];
|
|
180
|
+
return rows.length === expected.length && rows.every((row, index) => {
|
|
181
|
+
const shape = expected[index];
|
|
182
|
+
return row.table_name === shape[0]
|
|
183
|
+
&& row.column_name === shape[1]
|
|
184
|
+
&& row.data_type === shape[2]
|
|
185
|
+
&& row.is_nullable === shape[3]
|
|
186
|
+
&& (row.numeric_precision ?? null) === shape[4]
|
|
187
|
+
&& (row.numeric_scale ?? null) === shape[5];
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function loadState(queryable, stateId) {
|
|
192
|
+
const result = await queryable.query(
|
|
193
|
+
`SELECT revision::text, payload FROM nanocodex_durable_states WHERE state_id = $1`,
|
|
194
|
+
[stateId],
|
|
195
|
+
);
|
|
196
|
+
if (result.rows.length === 0) return Object.freeze({ revision: "0", payload: null });
|
|
197
|
+
if (result.rows.length !== 1 || typeof result.rows[0].payload !== "string") {
|
|
198
|
+
throw new Error(`PostgreSQL returned invalid durability state ${JSON.stringify(stateId)}`);
|
|
199
|
+
}
|
|
200
|
+
return Object.freeze({
|
|
201
|
+
revision: durabilityRevision(result.rows[0].revision),
|
|
202
|
+
payload: result.rows[0].payload,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async function acquireState(pool, stateId, ownerId) {
|
|
207
|
+
return verifyCommit(stateId, () => acquireStateOnce(pool, stateId, ownerId));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function acquireStateOnce(pool, stateId, ownerId) {
|
|
211
|
+
const client = await pool.connect();
|
|
212
|
+
let begun = false;
|
|
213
|
+
let discard = false;
|
|
214
|
+
try {
|
|
215
|
+
await client.query("BEGIN");
|
|
216
|
+
begun = true;
|
|
217
|
+
const owner = await client.query(
|
|
218
|
+
`INSERT INTO nanocodex_durable_owners (state_id, owner_id, fence)
|
|
219
|
+
VALUES ($1, $2, 1)
|
|
220
|
+
ON CONFLICT (state_id) DO UPDATE
|
|
221
|
+
SET owner_id = excluded.owner_id,
|
|
222
|
+
fence = CASE
|
|
223
|
+
WHEN nanocodex_durable_owners.owner_id = excluded.owner_id
|
|
224
|
+
THEN nanocodex_durable_owners.fence
|
|
225
|
+
ELSE nanocodex_durable_owners.fence + 1
|
|
226
|
+
END
|
|
227
|
+
WHERE nanocodex_durable_owners.owner_id = excluded.owner_id
|
|
228
|
+
OR nanocodex_durable_owners.fence < 18446744073709551615
|
|
229
|
+
RETURNING fence::text`,
|
|
230
|
+
[stateId, ownerId],
|
|
231
|
+
);
|
|
232
|
+
if (owner.rows.length !== 1) {
|
|
233
|
+
throw new RangeError("PostgreSQL durability fence overflow");
|
|
234
|
+
}
|
|
235
|
+
const fence = durabilityRevision(owner.rows[0].fence);
|
|
236
|
+
const state = await loadState(client, stateId);
|
|
237
|
+
try {
|
|
238
|
+
await client.query("COMMIT");
|
|
239
|
+
begun = false;
|
|
240
|
+
} catch (error) {
|
|
241
|
+
discard = true;
|
|
242
|
+
throw new CommitVerificationRequired("acquire commit response was lost", { cause: error });
|
|
243
|
+
}
|
|
244
|
+
return Object.freeze({ ownerId, fence, ...state });
|
|
245
|
+
} catch (error) {
|
|
246
|
+
if (error instanceof CommitVerificationRequired) throw error;
|
|
247
|
+
if (begun) {
|
|
248
|
+
try {
|
|
249
|
+
await client.query("ROLLBACK");
|
|
250
|
+
} catch (rollbackError) {
|
|
251
|
+
discard = true;
|
|
252
|
+
throw new AggregateError(
|
|
253
|
+
[error, rollbackError],
|
|
254
|
+
"PostgreSQL durability acquire and rollback both failed",
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
throw error;
|
|
259
|
+
} finally {
|
|
260
|
+
client.release(discard);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function replaceState(pool, stateId, request) {
|
|
265
|
+
return verifyCommit(stateId, () => replaceStateOnce(pool, stateId, request));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function replaceStateOnce(pool, stateId, request) {
|
|
269
|
+
const client = await pool.connect();
|
|
270
|
+
let begun = false;
|
|
271
|
+
let discard = false;
|
|
272
|
+
try {
|
|
273
|
+
await client.query("BEGIN");
|
|
274
|
+
begun = true;
|
|
275
|
+
const owner = await client.query(
|
|
276
|
+
`SELECT owner_id, fence::text FROM nanocodex_durable_owners
|
|
277
|
+
WHERE state_id = $1 FOR UPDATE`,
|
|
278
|
+
[stateId],
|
|
279
|
+
);
|
|
280
|
+
const retained = owner.rows[0];
|
|
281
|
+
if (retained?.owner_id !== request.ownerId
|
|
282
|
+
|| durabilityRevision(retained?.fence ?? "0") !== request.fence) {
|
|
283
|
+
await client.query("ROLLBACK");
|
|
284
|
+
begun = false;
|
|
285
|
+
return { status: "fenced" };
|
|
286
|
+
}
|
|
287
|
+
const expectedRevision = requestRevision(request.expectedRevision);
|
|
288
|
+
const state = await loadStateForUpdate(client, stateId);
|
|
289
|
+
if (state.revision !== expectedRevision) {
|
|
290
|
+
await client.query("ROLLBACK");
|
|
291
|
+
begun = false;
|
|
292
|
+
if (state.revision === nextRevision(expectedRevision)
|
|
293
|
+
&& typeof request.payload === "string"
|
|
294
|
+
&& state.payload === request.payload) {
|
|
295
|
+
return { status: "replaced", revision: state.revision };
|
|
296
|
+
}
|
|
297
|
+
return { status: "conflict", actualRevision: state.revision };
|
|
298
|
+
}
|
|
299
|
+
if (state.revision === MAX_REVISION) {
|
|
300
|
+
await client.query("ROLLBACK");
|
|
301
|
+
begun = false;
|
|
302
|
+
return { status: "not_committed", message: "PostgreSQL durability revision overflow" };
|
|
303
|
+
}
|
|
304
|
+
const payload = requestPayload(request.payload);
|
|
305
|
+
const revision = durabilityRevision(BigInt(state.revision) + 1n);
|
|
306
|
+
await client.query(
|
|
307
|
+
`INSERT INTO nanocodex_durable_states (state_id, revision, payload)
|
|
308
|
+
VALUES ($1, $2::numeric, $3)
|
|
309
|
+
ON CONFLICT (state_id) DO UPDATE
|
|
310
|
+
SET revision = excluded.revision, payload = excluded.payload`,
|
|
311
|
+
[stateId, revision, payload],
|
|
312
|
+
);
|
|
313
|
+
try {
|
|
314
|
+
await client.query("COMMIT");
|
|
315
|
+
begun = false;
|
|
316
|
+
} catch (error) {
|
|
317
|
+
discard = true;
|
|
318
|
+
throw new CommitVerificationRequired("replace commit response was lost", { cause: error });
|
|
319
|
+
}
|
|
320
|
+
return { status: "replaced", revision };
|
|
321
|
+
} catch (error) {
|
|
322
|
+
if (error instanceof CommitVerificationRequired) throw error;
|
|
323
|
+
if (begun) {
|
|
324
|
+
try {
|
|
325
|
+
await client.query("ROLLBACK");
|
|
326
|
+
} catch (rollbackError) {
|
|
327
|
+
discard = true;
|
|
328
|
+
throw new AggregateError([error, rollbackError], "PostgreSQL durability replace and rollback both failed");
|
|
329
|
+
}
|
|
330
|
+
begun = false;
|
|
331
|
+
if (error instanceof InvalidPostgresDurabilityRequestError) throw error.cause;
|
|
332
|
+
return { status: "not_committed", message: message(error) };
|
|
333
|
+
}
|
|
334
|
+
throw error;
|
|
335
|
+
} finally {
|
|
336
|
+
client.release(discard);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async function restoreState(pool, stateId, state, expectedRevision, expectedPayload) {
|
|
341
|
+
return verifyCommit(
|
|
342
|
+
stateId,
|
|
343
|
+
(attempt) => restoreStateOnce(
|
|
344
|
+
pool,
|
|
345
|
+
stateId,
|
|
346
|
+
state,
|
|
347
|
+
expectedRevision,
|
|
348
|
+
expectedPayload,
|
|
349
|
+
attempt > 0,
|
|
350
|
+
),
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async function restoreStateOnce(
|
|
355
|
+
pool,
|
|
356
|
+
stateId,
|
|
357
|
+
state,
|
|
358
|
+
expectedRevision,
|
|
359
|
+
expectedPayload,
|
|
360
|
+
reconciling,
|
|
361
|
+
) {
|
|
362
|
+
const client = await pool.connect();
|
|
363
|
+
let begun = false;
|
|
364
|
+
let discard = false;
|
|
365
|
+
try {
|
|
366
|
+
await client.query("BEGIN");
|
|
367
|
+
begun = true;
|
|
368
|
+
await client.query(
|
|
369
|
+
`SELECT pg_advisory_xact_lock(hashtextextended(
|
|
370
|
+
current_schema() || ':nanocodex-durability-v2:state:' || $1, 0
|
|
371
|
+
))`,
|
|
372
|
+
[stateId],
|
|
373
|
+
);
|
|
374
|
+
const retainedOwner = await client.query(
|
|
375
|
+
`SELECT owner_id, fence::text FROM nanocodex_durable_owners
|
|
376
|
+
WHERE state_id = $1 FOR UPDATE`,
|
|
377
|
+
[stateId],
|
|
378
|
+
);
|
|
379
|
+
const retainedState = await loadStateForUpdate(client, stateId);
|
|
380
|
+
const owner = retainedOwner.rows[0];
|
|
381
|
+
if (reconciling
|
|
382
|
+
&& owner?.owner_id === PORTABLE_IMPORT_OWNER
|
|
383
|
+
&& retainedState.revision === state.revision
|
|
384
|
+
&& retainedState.payload === state.payload) {
|
|
385
|
+
await client.query("ROLLBACK");
|
|
386
|
+
begun = false;
|
|
387
|
+
return state;
|
|
388
|
+
}
|
|
389
|
+
if (expectedRevision === undefined
|
|
390
|
+
? owner !== undefined || retainedState.revision !== "0"
|
|
391
|
+
: retainedState.revision !== expectedRevision
|
|
392
|
+
|| expectedPayload.present && retainedState.payload !== expectedPayload.value) {
|
|
393
|
+
throw new DurabilityImportConflictError(stateId, expectedRevision, retainedState.revision);
|
|
394
|
+
}
|
|
395
|
+
const claimed = await client.query(
|
|
396
|
+
`INSERT INTO nanocodex_durable_owners (state_id, owner_id, fence)
|
|
397
|
+
VALUES ($1, $2, 1)
|
|
398
|
+
ON CONFLICT (state_id) DO UPDATE
|
|
399
|
+
SET owner_id = excluded.owner_id, fence = nanocodex_durable_owners.fence + 1
|
|
400
|
+
WHERE nanocodex_durable_owners.fence < 18446744073709551615
|
|
401
|
+
RETURNING fence::text`,
|
|
402
|
+
[stateId, PORTABLE_IMPORT_OWNER],
|
|
403
|
+
);
|
|
404
|
+
if (claimed.rows.length !== 1) throw new RangeError("PostgreSQL durability fence overflow");
|
|
405
|
+
if (state.revision !== "0") {
|
|
406
|
+
await client.query(
|
|
407
|
+
`INSERT INTO nanocodex_durable_states (state_id, revision, payload)
|
|
408
|
+
VALUES ($1, $2::numeric, $3)
|
|
409
|
+
ON CONFLICT (state_id) DO UPDATE
|
|
410
|
+
SET revision = excluded.revision, payload = excluded.payload`,
|
|
411
|
+
[stateId, state.revision, state.payload],
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
try {
|
|
415
|
+
await client.query("COMMIT");
|
|
416
|
+
begun = false;
|
|
417
|
+
} catch (error) {
|
|
418
|
+
discard = true;
|
|
419
|
+
throw new CommitVerificationRequired("import commit response was lost", { cause: error });
|
|
420
|
+
}
|
|
421
|
+
return state;
|
|
422
|
+
} catch (error) {
|
|
423
|
+
if (error instanceof CommitVerificationRequired) throw error;
|
|
424
|
+
if (begun) {
|
|
425
|
+
try {
|
|
426
|
+
await client.query("ROLLBACK");
|
|
427
|
+
} catch (rollbackError) {
|
|
428
|
+
discard = true;
|
|
429
|
+
throw new AggregateError(
|
|
430
|
+
[error, rollbackError],
|
|
431
|
+
"PostgreSQL durability import and rollback both failed",
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
throw error;
|
|
436
|
+
} finally {
|
|
437
|
+
client.release(discard);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
async function verifyCommit(stateId, operation) {
|
|
442
|
+
let retained;
|
|
443
|
+
for (let attempt = 0; attempt < VERIFY_ATTEMPTS; attempt += 1) {
|
|
444
|
+
try {
|
|
445
|
+
return await operation(attempt);
|
|
446
|
+
} catch (error) {
|
|
447
|
+
if (!(error instanceof CommitVerificationRequired)) throw error;
|
|
448
|
+
retained = error;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
throw new PostgresDurabilityUnavailableError(stateId, retained?.cause ?? retained);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function nextRevision(revision) {
|
|
455
|
+
return revision === MAX_REVISION ? undefined : durabilityRevision(BigInt(revision) + 1n);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function requestRevision(value) {
|
|
459
|
+
try {
|
|
460
|
+
return durabilityRevision(value);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
throw new InvalidPostgresDurabilityRequestError(error);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function requestPayload(value) {
|
|
467
|
+
if (typeof value !== "string") {
|
|
468
|
+
throw new InvalidPostgresDurabilityRequestError(
|
|
469
|
+
new TypeError("durability payload must be a string"),
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
return value;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function importedState(value) {
|
|
476
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
477
|
+
throw new TypeError("imported durability state must be an object");
|
|
478
|
+
}
|
|
479
|
+
const keys = Object.keys(value).sort();
|
|
480
|
+
if (keys.length !== 2 || keys[0] !== "payload" || keys[1] !== "revision") {
|
|
481
|
+
throw new TypeError("imported durability state must contain exactly payload and revision");
|
|
482
|
+
}
|
|
483
|
+
const revision = durabilityRevision(value.revision);
|
|
484
|
+
const payload = value.payload;
|
|
485
|
+
if ((revision === "0") !== (payload === null)) {
|
|
486
|
+
throw new TypeError("imported durability payload must be null exactly at revision zero");
|
|
487
|
+
}
|
|
488
|
+
if (payload !== null && typeof payload !== "string") {
|
|
489
|
+
throw new TypeError("imported durability payload must be a string");
|
|
490
|
+
}
|
|
491
|
+
return Object.freeze({ revision, payload });
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function expectedImportPayload(options, expectedRevision) {
|
|
495
|
+
const present = options?.expectedPayload !== undefined;
|
|
496
|
+
if (!present) return { present: false, value: undefined };
|
|
497
|
+
if (expectedRevision === undefined) {
|
|
498
|
+
throw new TypeError("durability import expected payload requires an expected revision");
|
|
499
|
+
}
|
|
500
|
+
const expected = importedState({ revision: expectedRevision, payload: options.expectedPayload });
|
|
501
|
+
return { present: true, value: expected.payload };
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async function loadStateForUpdate(client, stateId) {
|
|
505
|
+
const result = await client.query(
|
|
506
|
+
`SELECT revision::text, payload FROM nanocodex_durable_states
|
|
507
|
+
WHERE state_id = $1 FOR UPDATE`,
|
|
508
|
+
[stateId],
|
|
509
|
+
);
|
|
510
|
+
if (result.rows.length === 0) return { revision: "0", payload: null };
|
|
511
|
+
if (result.rows.length !== 1 || typeof result.rows[0].payload !== "string") {
|
|
512
|
+
throw new Error("PostgreSQL returned invalid durable state");
|
|
513
|
+
}
|
|
514
|
+
return { revision: durabilityRevision(result.rows[0].revision), payload: result.rows[0].payload };
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function requireId(value) {
|
|
518
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
519
|
+
throw new TypeError("durability state ID must be a non-empty string");
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function requireOwner(value) {
|
|
524
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
525
|
+
throw new TypeError("durability owner ID must be a non-empty string");
|
|
526
|
+
}
|
|
527
|
+
return value;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function message(error) {
|
|
531
|
+
return error instanceof Error ? error.message : String(error);
|
|
532
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CodeEvaluator } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
export type QuickJsEvaluatorOptions = {
|
|
4
|
+
memoryLimitBytes?: number | undefined;
|
|
5
|
+
stackLimitBytes?: number | undefined;
|
|
6
|
+
maxInterruptCycles?: number | undefined;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type AsyncQuickJsModule = {
|
|
10
|
+
newContext(): unknown;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/** Builds a serialized, sandboxed Code Mode evaluator for CSP-restricted runtimes. */
|
|
14
|
+
export function createQuickJsEvaluator(
|
|
15
|
+
quickJs: AsyncQuickJsModule,
|
|
16
|
+
options?: QuickJsEvaluatorOptions,
|
|
17
|
+
): CodeEvaluator;
|