@lostgradient/weft 0.11.0 → 0.12.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/README.md +1 -1
- package/dist/cli/generated/operation-catalog.snapshot.json +4671 -0
- package/dist/cli/generated/operation-client.generated.d.ts +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/cli-main.js +227 -401
- package/dist/client/http-operations.js +7 -1
- package/dist/client/http-request.d.ts +23 -1
- package/dist/client/http-request.js +12 -3
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +7 -0
- package/dist/connection.d.ts +8 -0
- package/dist/connection.js +41 -17
- package/dist/core/engine/callback-creators-core.js +2 -1
- package/dist/core/engine/index.d.ts +43 -0
- package/dist/core/engine/lifecycle/shared.d.ts +25 -0
- package/dist/core/engine/lifecycle/transition.js +19 -9
- package/dist/core/types/definition-schema-to-json.d.ts +11 -0
- package/dist/core/types/definition-schema-to-json.js +11 -2
- package/dist/http.js +2 -0
- package/dist/indexeddb.js +1 -0
- package/dist/json-schema.js +3 -3
- package/dist/mcp/cli.js +63 -61
- package/dist/mcp/http.d.ts +7 -2
- package/dist/mcp/session.d.ts +3 -3
- package/dist/mcp/session.js +3 -2
- package/dist/mcp/stdio.d.ts +7 -2
- package/dist/observability/index.js +2 -2
- package/dist/runtime/portable.d.ts +33 -0
- package/dist/runtime/portable.js +17 -6
- package/dist/server/engine-event-feed-backend.d.ts +22 -3
- package/dist/server/fleet-event-feed.d.ts +65 -0
- package/dist/server/handler/index.d.ts +11 -2
- package/dist/server/handler/index.js +7 -0
- package/dist/server/handler.js +1 -56
- package/dist/server/index.d.ts +12 -1
- package/dist/server/index.js +87 -64
- package/dist/server/operations/submit-review-decision.d.ts +2 -0
- package/dist/server/operations/submit-review-decision.js +19 -2
- package/dist/server/replay-live-feed-internals.d.ts +19 -0
- package/dist/server/replay-live-feed-internals.js +76 -0
- package/dist/server/runtime/authentication-bridge.d.ts +2 -2
- package/dist/server/serve-internals.js +3 -3
- package/dist/server/workflow-event-feed.d.ts +100 -11
- package/dist/server/workflow-event-feed.js +1 -140
- package/dist/service-worker/index.d.ts +8 -2
- package/dist/service-worker/index.js +37 -56
- package/dist/service-worker/setup.d.ts +6 -2
- package/dist/storage/auto.js +1 -1
- package/dist/storage/bun-sql.js +3 -3
- package/dist/storage/cloudflare-durable-object-sql.d.ts +75 -0
- package/dist/storage/cloudflare-durable-object-sql.js +0 -0
- package/dist/storage/cloudflare-value-codec.d.ts +65 -0
- package/dist/storage/cloudflare-value-codec.js +46 -0
- package/dist/storage/cloudflare.d.ts +140 -0
- package/dist/storage/cloudflare.js +127 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/http.js +200 -2
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/indexeddb.js +311 -1
- package/dist/storage/interface.js +1 -1
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +4 -4
- package/dist/storage/node-sqlite.js +3 -3
- package/dist/storage/postgres-key-value-queries.d.ts +6 -0
- package/dist/storage/postgres-key-value-queries.js +2 -3
- package/dist/storage/postgres.js +4 -4
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/sql-identifier.d.ts +35 -0
- package/dist/storage/sql-identifier.js +5 -0
- package/dist/storage/sqlite-key-value-queries.d.ts +11 -6
- package/dist/storage/sqlite-key-value-queries.js +3 -3
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/storage/typed-storage.js +138 -2
- package/dist/storage/web-extension.js +298 -1
- package/dist/testing/index.js +21 -60
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -0
- package/dist/worker/protocol.js +1 -1
- package/package.json +8 -3
|
@@ -6,6 +6,9 @@ function isJsonRpcFailure(value) {
|
|
|
6
6
|
function isJsonRpcSuccess(value) {
|
|
7
7
|
return typeof value === "object" && value !== null && "result" in value;
|
|
8
8
|
}
|
|
9
|
+
function isRecord(value) {
|
|
10
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
+
}
|
|
9
12
|
export function httpClientCatalogTransport(baseUrl, headers) {
|
|
10
13
|
const endpoint = `${baseUrl}/jsonrpc`;
|
|
11
14
|
return async (operationName, input) => {
|
|
@@ -27,7 +30,10 @@ export function httpClientCatalogTransport(baseUrl, headers) {
|
|
|
27
30
|
}
|
|
28
31
|
if (isJsonRpcFailure(body)) {
|
|
29
32
|
const { message, data } = body.error, httpStatus = typeof data?.httpStatus === "number" ? data.httpStatus : response.status, faultCode = isFaultCode(data?.weftCode) ? data.weftCode : void 0;
|
|
30
|
-
throw new HttpClientError(httpStatus, message, {
|
|
33
|
+
throw new HttpClientError(httpStatus, message, {
|
|
34
|
+
faultCode,
|
|
35
|
+
data: isRecord(data) ? data : void 0
|
|
36
|
+
});
|
|
31
37
|
}
|
|
32
38
|
if (isJsonRpcSuccess(body))
|
|
33
39
|
return body.result;
|
|
@@ -67,7 +67,11 @@ export declare function resolveHttpClientConnection(options: HttpClientOptions):
|
|
|
67
67
|
* the wire fault `code` is surfaced as {@link HttpClientError.faultCode} and a
|
|
68
68
|
* derived {@link HttpClientError.category} so callers can branch programmatically
|
|
69
69
|
* instead of string-matching `message`. Both are `undefined` when the body is a
|
|
70
|
-
* plain `{ error: string }` or carries no recognized code.
|
|
70
|
+
* plain `{ error: string }` or carries no recognized code. The fault's typed
|
|
71
|
+
* `data` payload (e.g. `InvalidParams`'s `issues`, `NotFound`/`Conflict`'s
|
|
72
|
+
* `resource`/`identifier`) is surfaced verbatim as {@link HttpClientError.data}
|
|
73
|
+
* when the body carries a structured `data` object; `undefined` otherwise —
|
|
74
|
+
* including for a masked `EngineFailure`, whose flat body carries no `data`.
|
|
71
75
|
*
|
|
72
76
|
* @example
|
|
73
77
|
* ```ts
|
|
@@ -110,9 +114,27 @@ export declare class HttpClientError extends WeftError<'HttpClientError'> {
|
|
|
110
114
|
* carried only the coarse {@link faultCode} (most faults) or no structured body.
|
|
111
115
|
*/
|
|
112
116
|
readonly weftCode?: WeftErrorCode | undefined;
|
|
117
|
+
/**
|
|
118
|
+
* The fault's wire `data` payload, when the response carried a structured
|
|
119
|
+
* body (`{ error: { data } }` for REST, `error.data` for JSON-RPC). Shape is
|
|
120
|
+
* fault-code-dependent — see {@link FaultCode} and the server's
|
|
121
|
+
* `OperationFault` per-code `data` union for what each code carries (e.g.
|
|
122
|
+
* `InvalidParams.data.issues`, `NotFound.data.resource`). `undefined` for
|
|
123
|
+
* plain-string error bodies, bodies with no `data` field, or a `data` field
|
|
124
|
+
* that is not a JSON object.
|
|
125
|
+
*
|
|
126
|
+
* Over JSON-RPC-over-HTTP this is the raw envelope `error.data` verbatim
|
|
127
|
+
* (see `httpClientCatalogTransport` in `http-operations.ts`), so it also
|
|
128
|
+
* carries the envelope's own `weftCode` (the coarse {@link FaultCode}, not
|
|
129
|
+
* a fine-grained {@link WeftErrorCode}) and `httpStatus` keys alongside the
|
|
130
|
+
* per-code payload — those two are not part of the `OperationFault` data
|
|
131
|
+
* union.
|
|
132
|
+
*/
|
|
133
|
+
readonly data?: Readonly<Record<string, unknown>> | undefined;
|
|
113
134
|
constructor(status: number, message: string, options?: {
|
|
114
135
|
faultCode?: FaultCode | undefined;
|
|
115
136
|
weftCode?: WeftErrorCode | undefined;
|
|
137
|
+
data?: Readonly<Record<string, unknown>> | undefined;
|
|
116
138
|
});
|
|
117
139
|
}
|
|
118
140
|
export declare function request<T>(baseUrl: string, path: string, baseHeaders: Record<string, string>, options?: RequestInit): Promise<T>;
|
|
@@ -17,12 +17,14 @@ export class HttpClientError extends WeftError {
|
|
|
17
17
|
faultCode;
|
|
18
18
|
category;
|
|
19
19
|
weftCode;
|
|
20
|
+
data;
|
|
20
21
|
constructor(status, message, options) {
|
|
21
22
|
super("HttpClientError", message);
|
|
22
23
|
this.status = status;
|
|
23
24
|
this.faultCode = options?.faultCode;
|
|
24
25
|
this.category = options?.faultCode === void 0 ? void 0 : failureCategoryForFaultCode(options.faultCode);
|
|
25
26
|
this.weftCode = options?.weftCode;
|
|
27
|
+
this.data = options?.data;
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
function buildRequestHeaders(baseHeaders, options) {
|
|
@@ -53,11 +55,18 @@ function weftCodeFromData(data) {
|
|
|
53
55
|
const candidate = data.weftCode;
|
|
54
56
|
return isWeftErrorCode(candidate) ? candidate : void 0;
|
|
55
57
|
}
|
|
58
|
+
function isRecord(value) {
|
|
59
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
60
|
+
}
|
|
56
61
|
async function parseErrorBody(response) {
|
|
57
62
|
try {
|
|
58
63
|
const body = await response.json();
|
|
59
64
|
if (isStructuredErrorBody(body)) {
|
|
60
|
-
const { code, message, data } = body.error, weftCode = weftCodeFromData(data), base =
|
|
65
|
+
const { code, message, data } = body.error, weftCode = weftCodeFromData(data), base = { message };
|
|
66
|
+
if (weftCode !== void 0)
|
|
67
|
+
base.weftCode = weftCode;
|
|
68
|
+
if (isRecord(data))
|
|
69
|
+
base.data = data;
|
|
61
70
|
return isFaultCode(code) ? { ...base, faultCode: code } : base;
|
|
62
71
|
}
|
|
63
72
|
if (isFlatErrorBody(body) && body.error) {
|
|
@@ -74,8 +83,8 @@ export async function request(baseUrl, path, baseHeaders, options) {
|
|
|
74
83
|
if (response.status === 404 && (!options?.method || options.method === "GET"))
|
|
75
84
|
return null;
|
|
76
85
|
if (!response.ok) {
|
|
77
|
-
const { message, faultCode, weftCode } = await parseErrorBody(response);
|
|
78
|
-
throw new HttpClientError(response.status, message, { faultCode, weftCode });
|
|
86
|
+
const { message, faultCode, weftCode, data } = await parseErrorBody(response);
|
|
87
|
+
throw new HttpClientError(response.status, message, { faultCode, weftCode, data });
|
|
79
88
|
}
|
|
80
89
|
if (response.status === 204)
|
|
81
90
|
return;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module client/index
|
|
9
9
|
*/
|
|
10
|
+
export { isWeftError, isWeftErrorCode, isWeftErrorLike, isWeftFault, WeftError, } from '../core/weft-error.ts';
|
|
11
|
+
export type { WeftErrorCode } from '../core/weft-error.ts';
|
|
10
12
|
export type { WorkflowEventStreamOptions, WorkflowEventTransport } from './event-stream-options.ts';
|
|
11
13
|
export type { WorkflowEventTail } from './event-tail.ts';
|
|
12
14
|
export { HttpClient } from './http-client.ts';
|
package/dist/client/index.js
CHANGED
package/dist/connection.d.ts
CHANGED
|
@@ -14,6 +14,14 @@
|
|
|
14
14
|
* A profile token is only applied when neither an explicit `server` option nor
|
|
15
15
|
* `WEFT_ADDR` redirected the request to a different destination.
|
|
16
16
|
*
|
|
17
|
+
* This module is imported from `@lostgradient/weft/client` (browser-reachable),
|
|
18
|
+
* so it must stay statically free of `node:*` and Bun-only imports. Environment
|
|
19
|
+
* variables go through {@link readEnvironmentVariable}; `~/.weft/config` and the
|
|
20
|
+
* run lockfile are read through {@link tryLoadNodeBuiltin}, which resolves
|
|
21
|
+
* `node:fs`/`node:fs/promises` via `process.getBuiltinModule` instead of a
|
|
22
|
+
* static import. Both return `undefined` outside Bun/Node, so a browser caller
|
|
23
|
+
* that supplies explicit `server`/`token` never touches either.
|
|
24
|
+
*
|
|
17
25
|
* @module connection
|
|
18
26
|
*/
|
|
19
27
|
/**
|
package/dist/connection.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mkdir, rm } from "node:fs/promises";
|
|
1
|
+
import { isBunRuntime, readEnvironmentVariable, tryLoadNodeBuiltin } from "./runtime/portable.js";
|
|
3
2
|
export const DEFAULT_WEFT_ADDRESS = "http://localhost:7233";
|
|
4
3
|
|
|
5
4
|
export class ConnectionConfigurationError extends Error {
|
|
@@ -9,7 +8,7 @@ export class ConnectionConfigurationError extends Error {
|
|
|
9
8
|
}
|
|
10
9
|
}
|
|
11
10
|
export function resolveConnection(options = {}) {
|
|
12
|
-
const context = resolveConnectionContext(options), server = resolveServerString(context), fallbackProfile = profileForToken(context, server), token = resolveToken(options.token ??
|
|
11
|
+
const context = resolveConnectionContext(options), server = resolveServerString(context), fallbackProfile = profileForToken(context, server), token = resolveToken(options.token ?? readEnvironmentVariable("WEFT_TOKEN"), fallbackProfile);
|
|
13
12
|
return {
|
|
14
13
|
server: parseServerUrl(server),
|
|
15
14
|
...token === void 0 ? {} : { token }
|
|
@@ -26,7 +25,7 @@ function parseServerUrl(server) {
|
|
|
26
25
|
function profileForToken(context, resolvedServer) {
|
|
27
26
|
if (context.profile === void 0)
|
|
28
27
|
return;
|
|
29
|
-
if (!(context.options.server !== void 0 ||
|
|
28
|
+
if (!(context.options.server !== void 0 || readEnvironmentVariable("WEFT_ADDR") !== void 0))
|
|
30
29
|
return context.profile;
|
|
31
30
|
const profileServer = context.profile.server;
|
|
32
31
|
if (profileServer === void 0)
|
|
@@ -44,7 +43,7 @@ function sameDestination(a, b) {
|
|
|
44
43
|
return left.origin === right.origin && left.pathname.replace(/\/+$/, "") === right.pathname.replace(/\/+$/, "");
|
|
45
44
|
}
|
|
46
45
|
function resolveConnectionContext(options) {
|
|
47
|
-
const configuration = readWeftConfiguration(), profileName = options.profile ??
|
|
46
|
+
const configuration = readWeftConfiguration(), profileName = options.profile ?? readEnvironmentVariable("WEFT_PROFILE") ?? configuration.defaultProfile, profile = profileName === void 0 ? void 0 : configuration.profiles?.[profileName], runLockfile = options.includeRunLockfile === !1 ? void 0 : readRunLockfile();
|
|
48
47
|
return {
|
|
49
48
|
options,
|
|
50
49
|
...profile === void 0 ? {} : { profile },
|
|
@@ -52,12 +51,26 @@ function resolveConnectionContext(options) {
|
|
|
52
51
|
};
|
|
53
52
|
}
|
|
54
53
|
function resolveServerString(context) {
|
|
55
|
-
return context.options.server ??
|
|
54
|
+
return context.options.server ?? readEnvironmentVariable("WEFT_ADDR") ?? context.profile?.server ?? context.runLockfile?.server ?? context.runLockfile?.url ?? DEFAULT_WEFT_ADDRESS;
|
|
55
|
+
}
|
|
56
|
+
function loadFsModule() {
|
|
57
|
+
return tryLoadNodeBuiltin("node:fs");
|
|
58
|
+
}
|
|
59
|
+
function loadFsPromisesModule() {
|
|
60
|
+
return tryLoadNodeBuiltin("node:fs/promises");
|
|
56
61
|
}
|
|
57
62
|
export async function writeRunLockfile(server) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
const fsPromises = loadFsPromisesModule();
|
|
64
|
+
if (fsPromises === void 0)
|
|
65
|
+
throw Error("writeRunLockfile requires Bun or Node 22.5+ (process.getBuiltinModule); not available in this runtime.");
|
|
66
|
+
await fsPromises.mkdir(weftHome(), { recursive: !0 });
|
|
67
|
+
const contents = `${JSON.stringify({ server }, null, 2)}
|
|
68
|
+
`;
|
|
69
|
+
if (isBunRuntime()) {
|
|
70
|
+
await Bun.write(runLockfilePath(), contents);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
await fsPromises.writeFile(runLockfilePath(), contents, "utf8");
|
|
61
74
|
}
|
|
62
75
|
export async function removeRunLockfile(server) {
|
|
63
76
|
const lockfile = readRunLockfile();
|
|
@@ -65,15 +78,23 @@ export async function removeRunLockfile(server) {
|
|
|
65
78
|
return;
|
|
66
79
|
if ((lockfile.server ?? lockfile.url) !== server)
|
|
67
80
|
return;
|
|
68
|
-
|
|
81
|
+
const fsPromises = loadFsPromisesModule();
|
|
82
|
+
if (fsPromises === void 0)
|
|
83
|
+
return;
|
|
84
|
+
await fsPromises.rm(runLockfilePath(), { force: !0 });
|
|
69
85
|
}
|
|
70
86
|
function readWeftConfiguration() {
|
|
87
|
+
if (!isBunRuntime())
|
|
88
|
+
return {};
|
|
89
|
+
const fs = loadFsModule();
|
|
90
|
+
if (fs === void 0)
|
|
91
|
+
return {};
|
|
71
92
|
const path = configurationPath();
|
|
72
|
-
if (!existsSync(path))
|
|
93
|
+
if (!fs.existsSync(path))
|
|
73
94
|
return {};
|
|
74
95
|
let parsed;
|
|
75
96
|
try {
|
|
76
|
-
parsed = Bun.TOML.parse(readFileSync(path, "utf8"));
|
|
97
|
+
parsed = Bun.TOML.parse(fs.readFileSync(path, "utf8"));
|
|
77
98
|
} catch (error) {
|
|
78
99
|
const message = error instanceof Error ? error.message : String(error);
|
|
79
100
|
throw new ConnectionConfigurationError(`Failed to read connection configuration at ${path}: ${message}`);
|
|
@@ -81,10 +102,13 @@ function readWeftConfiguration() {
|
|
|
81
102
|
return normalizeConfiguration(parsed);
|
|
82
103
|
}
|
|
83
104
|
function readRunLockfile() {
|
|
105
|
+
const fs = loadFsModule();
|
|
106
|
+
if (fs === void 0)
|
|
107
|
+
return;
|
|
84
108
|
const path = runLockfilePath();
|
|
85
|
-
if (!existsSync(path))
|
|
109
|
+
if (!fs.existsSync(path))
|
|
86
110
|
return;
|
|
87
|
-
const text = readFileSync(path, "utf8").trim();
|
|
111
|
+
const text = fs.readFileSync(path, "utf8").trim();
|
|
88
112
|
if (text === "")
|
|
89
113
|
return;
|
|
90
114
|
try {
|
|
@@ -137,11 +161,11 @@ function normalizeRunLockfile(value) {
|
|
|
137
161
|
function resolveToken(token, profile) {
|
|
138
162
|
const directToken = token ?? profile?.token;
|
|
139
163
|
if (directToken?.startsWith("env:"))
|
|
140
|
-
return
|
|
164
|
+
return readEnvironmentVariable(directToken.slice(4));
|
|
141
165
|
if (directToken !== void 0)
|
|
142
166
|
return directToken;
|
|
143
167
|
if (profile?.tokenEnv !== void 0)
|
|
144
|
-
return
|
|
168
|
+
return readEnvironmentVariable(profile.tokenEnv);
|
|
145
169
|
return;
|
|
146
170
|
}
|
|
147
171
|
function configurationPath() {
|
|
@@ -151,7 +175,7 @@ function runLockfilePath() {
|
|
|
151
175
|
return `${weftHome()}/run`;
|
|
152
176
|
}
|
|
153
177
|
function weftHome() {
|
|
154
|
-
return
|
|
178
|
+
return readEnvironmentVariable("WEFT_HOME") ?? `${readEnvironmentVariable("HOME") ?? "."}/.weft`;
|
|
155
179
|
}
|
|
156
180
|
function stringValue(value) {
|
|
157
181
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
@@ -77,7 +77,8 @@ export function createLifecycleCallbacks(engine) {
|
|
|
77
77
|
enforceHistoryCircuitBreaker: (workflowId) => terminateWorkflow(getInternals(engine), workflowId, "timed-out", createTerminationCallbacks(engine), HISTORY_CIRCUIT_BREAKER_REASON),
|
|
78
78
|
failWorkflowForUnavailableServices: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system"),
|
|
79
79
|
failWorkflowForRecoveryHook: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system"),
|
|
80
|
-
failWorkflowForCheckpointDecodeError: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system")
|
|
80
|
+
failWorkflowForCheckpointDecodeError: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system"),
|
|
81
|
+
failWorkflowForVersionMismatch: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system")
|
|
81
82
|
};
|
|
82
83
|
}
|
|
83
84
|
export function createTerminationCallbacksWith(engine, handleScheduledWorkflowTerminal) {
|
|
@@ -371,6 +371,12 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
371
371
|
* deploys or explicit operator storage repair.
|
|
372
372
|
* When set, unknown workflow types are skipped and reported through
|
|
373
373
|
* {@link WorkflowRecoverySkippedEvent}.
|
|
374
|
+
*
|
|
375
|
+
* A recovered workflow whose persisted version metadata no longer matches
|
|
376
|
+
* its registered `WorkflowDefinition.version` is isolated per
|
|
377
|
+
* {@link RecoverAllOptions.versionMismatchPolicy} (default `'fail-run'`):
|
|
378
|
+
* only that workflow fails, and `recoverAll()` continues recovering its
|
|
379
|
+
* siblings in the same call.
|
|
374
380
|
*/
|
|
375
381
|
recoverAll(options?: RecoverAllOptions): Promise<WorkflowHandle[]>;
|
|
376
382
|
/**
|
|
@@ -490,3 +496,40 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
490
496
|
*/
|
|
491
497
|
fireTimer(entry: TimerEntry): Promise<void>;
|
|
492
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* `Engine` with its two chained-builder registration methods removed —
|
|
501
|
+
* `register` and `registerWorkflows`, whose return type is itself
|
|
502
|
+
* `Engine<NarrowedRegistry>` (see `register()`'s JSDoc: registering returns
|
|
503
|
+
* "this same engine with the definition added to its phantom type
|
|
504
|
+
* registry"). That self-reference is what makes `Engine` invariant in its
|
|
505
|
+
* registry generics: a concretely narrowed `Engine<Concrete>` (e.g. from
|
|
506
|
+
* `Engine.create({ workflows })`) is not structurally assignable to the
|
|
507
|
+
* plain default `Engine<DefaultWorkflowRegistry>`, even though every other
|
|
508
|
+
* member — including `start` and `startOrSignal`, whose *parameter* types
|
|
509
|
+
* (not return types) reference `TWorkflows` but never produce another
|
|
510
|
+
* `Engine<T>` — is not part of that recursive comparison.
|
|
511
|
+
*
|
|
512
|
+
* `start` and `startOrSignal` are deliberately KEPT (not omitted): hosted
|
|
513
|
+
* transports genuinely call them at runtime (REST/JSON-RPC workflow starts,
|
|
514
|
+
* MCP tool invocations) via `runtimeWorkflowEngine()`'s registry-erased
|
|
515
|
+
* dynamic-name overload, so a value satisfying this type must still provide
|
|
516
|
+
* them — a duck-typed engine substitute lacking `start` correctly fails to
|
|
517
|
+
* satisfy `RegistryAgnosticEngine` (see this type's `.test-d.ts` coverage).
|
|
518
|
+
*
|
|
519
|
+
* Host-facing options that accept an already-constructed `Engine` without
|
|
520
|
+
* needing the two chained-builder registration methods — `serve({ engine })`,
|
|
521
|
+
* the Service Worker helpers, the MCP session/HTTP/stdio surfaces — use this
|
|
522
|
+
* type instead of the bare default `Engine`, so both `new Engine({ storage })`
|
|
523
|
+
* and `Engine.create({ workflows })` are accepted without a call-site cast.
|
|
524
|
+
* See #708.
|
|
525
|
+
*
|
|
526
|
+
* (`Engine<object, object>` looks like the obvious fix — the widest legal
|
|
527
|
+
* instantiation of the registry generics — but TypeScript's structural check
|
|
528
|
+
* on `register()`'s self-referential return type does not reliably resolve
|
|
529
|
+
* that relationship: it can pass or fail for the identical `Engine<A>` /
|
|
530
|
+
* `Engine<B>` pair depending on unrelated compilation context, such as other
|
|
531
|
+
* files in the same program. Removing the registry-typed members entirely,
|
|
532
|
+
* rather than widening their generic arguments, avoids the recursive
|
|
533
|
+
* comparison altogether.)
|
|
534
|
+
*/
|
|
535
|
+
export type RegistryAgnosticEngine = Omit<Engine, 'register' | 'registerWorkflows'>;
|
|
@@ -57,6 +57,22 @@ export type RecoverAllOptions = {
|
|
|
57
57
|
* recovery continues with its siblings.
|
|
58
58
|
*/
|
|
59
59
|
onRecoveredWorkflow?: (info: RecoveredWorkflowInfo) => void | Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Policy for a recovered workflow whose stored {@link WorkflowVersionTuple}
|
|
62
|
+
* (or legacy checkpoint `version`) no longer matches the registered
|
|
63
|
+
* {@link WorkflowDefinition.version}. The mismatch is detected before
|
|
64
|
+
* `resolveWorkflowServices` and `onRecoveredWorkflow` run for that workflow,
|
|
65
|
+
* so a mismatched run never re-provides services or invokes the hook.
|
|
66
|
+
*
|
|
67
|
+
* - `'fail-run'` (default): fail only the mismatched run to a terminal
|
|
68
|
+
* `failed` state with a `system` failure category carrying the
|
|
69
|
+
* {@link VersionMismatchError} message, then continue recovering its
|
|
70
|
+
* siblings. The run never advances user workflow code.
|
|
71
|
+
* - `'throw'`: preserve the pre-#702 behavior — rethrow the
|
|
72
|
+
* {@link VersionMismatchError} out of `recoverAll()` immediately, aborting
|
|
73
|
+
* recovery for every workflow not yet processed in this batch.
|
|
74
|
+
*/
|
|
75
|
+
versionMismatchPolicy?: 'fail-run' | 'throw';
|
|
60
76
|
};
|
|
61
77
|
export type LifecycleCallbacks = {
|
|
62
78
|
dispatchEvent: (event: Event) => void;
|
|
@@ -97,6 +113,15 @@ export type LifecycleCallbacks = {
|
|
|
97
113
|
* other workflows from the same storage backend.
|
|
98
114
|
*/
|
|
99
115
|
failWorkflowForCheckpointDecodeError: (workflowId: string, error: Error) => Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Force a recovered workflow to a terminal `failed` state because its
|
|
118
|
+
* persisted version metadata no longer matches the registered
|
|
119
|
+
* `WorkflowDefinition.version` (a {@link VersionMismatchError}). Fails just
|
|
120
|
+
* this run with a `system` failure category so `recoverAll()` can continue
|
|
121
|
+
* recovering other workflows under the default `'fail-run'`
|
|
122
|
+
* {@link RecoverAllOptions.versionMismatchPolicy}.
|
|
123
|
+
*/
|
|
124
|
+
failWorkflowForVersionMismatch: (workflowId: string, error: Error) => Promise<void>;
|
|
100
125
|
};
|
|
101
126
|
/**
|
|
102
127
|
* Pre-replay history circuit breaker. Called at every restore-from-checkpoint
|
|
@@ -4,6 +4,7 @@ import { RegExpExtensionDecodeError } from "../../codec/extension-codec.js";
|
|
|
4
4
|
import { Context, setContextWorkflowInterceptor } from "../../context.js";
|
|
5
5
|
import { EMPTY_EVENT_HEAD } from "../../event-log.js";
|
|
6
6
|
import { WorkflowRecoverySkippedEvent, WorkflowStartedEvent } from "../../events.js";
|
|
7
|
+
import { VersionMismatchError } from "../../versioning.js";
|
|
7
8
|
import { createCancelHandlerRegistration, resetCancelHandlers } from "../cancel-handlers.js";
|
|
8
9
|
import { forgetCommittedCheckpointBytes } from "../checkpoint-commit-snapshots.js";
|
|
9
10
|
import { hydrateCheckpointReplayState } from "../checkpoint-replay.js";
|
|
@@ -60,6 +61,21 @@ async function preflightRecoverAll(internals, callbacks) {
|
|
|
60
61
|
}
|
|
61
62
|
return result;
|
|
62
63
|
}
|
|
64
|
+
async function recoverEntryOrIsolateFailure(internals, workflowId, callbacks, options) {
|
|
65
|
+
try {
|
|
66
|
+
return await resume(internals, workflowId, callbacks, options?.onRecoveredWorkflow);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error instanceof RegExpExtensionDecodeError) {
|
|
69
|
+
await callbacks.failWorkflowForCheckpointDecodeError(workflowId, error);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (error instanceof VersionMismatchError && options?.versionMismatchPolicy !== "throw") {
|
|
73
|
+
await callbacks.failWorkflowForVersionMismatch(workflowId, error);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
63
79
|
export async function recoverAll(internals, callbacks, options) {
|
|
64
80
|
const preflight = await preflightRecoverAll(internals, callbacks), handles = [];
|
|
65
81
|
if (preflight.missingWorkflows.length > 0 && options?.acknowledgeUnknownWorkflowTypes !== !0)
|
|
@@ -76,15 +92,9 @@ export async function recoverAll(internals, callbacks, options) {
|
|
|
76
92
|
callbacks.dispatchEvent(new WorkflowRecoverySkippedEvent(entry.workflow.workflowId, entry.workflow.type, "type-not-registered"));
|
|
77
93
|
continue;
|
|
78
94
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (error instanceof RegExpExtensionDecodeError) {
|
|
83
|
-
await callbacks.failWorkflowForCheckpointDecodeError(entry.workflowId, error);
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
throw error;
|
|
87
|
-
}
|
|
95
|
+
const handle = await recoverEntryOrIsolateFailure(internals, entry.workflowId, callbacks, options);
|
|
96
|
+
if (handle !== null)
|
|
97
|
+
handles.push(handle);
|
|
88
98
|
}
|
|
89
99
|
return handles;
|
|
90
100
|
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { DefinitionSchema } from './definition-schema.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Reset the module-level cached Valibot `toJsonSchema` converter.
|
|
4
|
+
*
|
|
5
|
+
* `cachedValibotConverter` is a process-global singleton shared by every test
|
|
6
|
+
* file that imports this module in the same `bun test` run, so whether it is
|
|
7
|
+
* already warm when a given test executes depends on unrelated test order.
|
|
8
|
+
* Tests that need to exercise the cache-miss path deterministically (e.g. the
|
|
9
|
+
* "no `process.getBuiltinModule`" error) must reset it first.
|
|
10
|
+
* @internal Test-only.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resetValibotConverterCacheForTesting(): void;
|
|
2
13
|
/**
|
|
3
14
|
* Direction parameter for {@link definitionSchemaToJsonSchema}. `"input"`
|
|
4
15
|
* produces the JSON Schema describing the validator's accepted input;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
1
|
import { z } from "zod";
|
|
2
|
+
import { tryLoadNodeBuiltin } from "../../runtime/portable.js";
|
|
3
3
|
let cachedValibotConverter;
|
|
4
|
+
export function resetValibotConverterCacheForTesting() {
|
|
5
|
+
cachedValibotConverter = void 0;
|
|
6
|
+
}
|
|
4
7
|
export function definitionSchemaToJsonSchema(schema, direction = "input") {
|
|
5
8
|
const standard = schema["~standard"], vendor = standard.vendor;
|
|
6
9
|
if (vendor === "zod")
|
|
@@ -28,10 +31,16 @@ function convertValibot(schema) {
|
|
|
28
31
|
const result = loadValibotConverter()(schema);
|
|
29
32
|
return stripDialect(requirePlainObject(result, "valibot"));
|
|
30
33
|
}
|
|
34
|
+
function loadNodeRequire() {
|
|
35
|
+
return tryLoadNodeBuiltin("node:module")?.createRequire(import.meta.url);
|
|
36
|
+
}
|
|
31
37
|
export function loadValibotConverter(requireModule) {
|
|
32
|
-
const shouldUseCache = requireModule === void 0
|
|
38
|
+
const shouldUseCache = requireModule === void 0;
|
|
33
39
|
if (shouldUseCache && cachedValibotConverter !== void 0)
|
|
34
40
|
return cachedValibotConverter;
|
|
41
|
+
const resolver = requireModule ?? loadNodeRequire();
|
|
42
|
+
if (resolver === void 0)
|
|
43
|
+
throw Error("definitionSchemaToJsonSchema: converting a Valibot schema requires Bun or Node 22.5+ (process.getBuiltinModule) to resolve `@valibot/to-json-schema`. Not available in browser or edge runtimes; attach a `~standard.jsonSchema` converter to the schema instead.");
|
|
35
44
|
let valibotModule;
|
|
36
45
|
try {
|
|
37
46
|
valibotModule = resolver("@valibot/to-json-schema");
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function L(F){let G=[];for(let J=0;J<F.length;J+=512)G.push(String.fromCharCode(...F.subarray(J,J+512)));return btoa(G.join(""))}function A(F){let G=atob(F),J=new Uint8Array(G.length);for(let Q=0;Q<G.length;Q+=1)J[Q]=G.charCodeAt(Q);return J}function U(F){return typeof F==="object"&&F!==null&&!Array.isArray(F)}async function j(F,G){return await F.get(G)!==null}async function*X(F,G,J){for await(let[Q]of F.scan(G,J))yield Q}async function _(F,G){let J=0;for await(let Q of X(F,G))J++;return J}async function H(F,G){let J=[];for await(let Q of X(F,G))J.push({type:"delete",key:Q});if(J.length===0)return 0;return await F.batch(J),J.length}async function W(F,G,J){let Q=[];for await(let Z of X(F,G,J))Q.push({type:"delete",key:Z});if(Q.length===0)return 0;return await F.batch(Q),Q.length}function B(F,G,J){if(!F.capabilities()[G])throw Error(`Feature "${J}" requires storage capability "${G}", but this storage backend does not provide it.`)}var N=1e4;class R extends Error{code="StorageBatchOperationLimitExceededError";cap=N;count;target;constructor(F,G){super(`${F} count ${G} exceeds MAX_BATCH_OPERATIONS (${N}).`);this.name="StorageBatchOperationLimitExceededError",this.target=F,this.count=G}}function M(F,G){if(G>N)throw new R(F,G)}function C(F){return F.length>0?F.slice(0,-1)+String.fromCharCode(F.charCodeAt(F.length-1)+1):"ÿ"}function o(F,G={}){if(G.gt!==void 0&&F<=G.gt)return!1;if(G.gte!==void 0&&F<G.gte)return!1;if(G.lt!==void 0&&F>=G.lt)return!1;if(G.lte!==void 0&&F>G.lte)return!1;return!0}function e(F,G){if(F===null||G===null)return F===G;if(F.byteLength!==G.byteLength)return!1;for(let J=0;J<F.byteLength;J++)if(F[J]!==G[J])return!1;return!0}async function P(F,G){if(F.has)return F.has(G);return j(F,G)}function K(F,G,J){if(F.keys)return F.keys(G,J);return X(F,G,J)}async function S(F,G){if(F.count)return F.count(G);return _(F,G)}async function O(F,G){if(F.deletePrefix)return F.deletePrefix(G);return H(F,G)}async function b(F,G,J){if(M("conditionalBatch conditions",G.length),M("conditionalBatch operations",J.length),B(F,"conditionalBatch","storageConditionalBatch"),!F.conditionalBatch)throw Error("This storage backend reports conditionalBatch capability but does not implement the conditionalBatch() method.");return F.conditionalBatch(G,J)}function c(F){if(F===void 0)return;if(typeof F!=="number"||!Number.isInteger(F)||F<0)throw Error("deleteRange limit must be a finite non-negative integer");return F===0?0:F}function V(F){let G={},J=!1;for(let Z of["gt","gte","lt","lte"]){let $=F[Z];if($===void 0)continue;if(typeof $!=="string")throw Error("deleteRange bounds must be strings");G[Z]=$,J=!0}if(!J)throw Error("deleteRange requires at least one of gt/gte/lt/lte; use deletePrefix to delete a whole prefix");let Q=c(F.limit);if(Q!==void 0)G.limit=Q;return G}async function v(F,G,J){let Q=V(J);if(F.deleteRange)return F.deleteRange(G,Q);return W(F,G,Q)}function I(F,G){let J={key:F,open:!1};if(G.gte!==void 0&&G.gte>J.key)J.key=G.gte,J.open=!1;if(G.gt!==void 0&&G.gt>=J.key)J.key=G.gt,J.open=!0;return J}function g(F,G){let J={key:C(F),open:!0};if(G.lt!==void 0&&G.lt<=J.key)J.key=G.lt,J.open=!0;if(G.lte!==void 0&&G.lte<J.key)J.key=G.lte,J.open=!1;return J}function QF(F,G){let J=I(F,G),Q=g(F,G);if(J.key>Q.key||J.key===Q.key&&(J.open||Q.open))return null;return{lower:J,upper:Q}}function q(F){return F.replaceAll(/:+$/g,"")}function y(F,G){let J=q(F),Q=q(G);if(J.length===0)return Q;if(Q.length===0)return J;return`${J}:${Q}`}class D{#G;#J;constructor(F,G){this.#G=F,this.#J=q(G)}#F(F){if(this.#J.length===0)return F;return F.length===0?`${this.#J}:`:`${this.#J}:${F}`}#Q(F){if(this.#J.length===0)return F;return F.slice(this.#J.length+1)}#Z(F={}){let G={};if(F.limit!==void 0)G.limit=F.limit;if(F.reverse!==void 0)G.reverse=F.reverse;if(F.gt!==void 0)G.gt=this.#F(F.gt);if(F.gte!==void 0)G.gte=this.#F(F.gte);if(F.lt!==void 0)G.lt=this.#F(F.lt);if(F.lte!==void 0)G.lte=this.#F(F.lte);return G}#M(F){let G={};if(F.limit!==void 0)G.limit=F.limit;if(F.gt!==void 0)G.gt=this.#F(F.gt);if(F.gte!==void 0)G.gte=this.#F(F.gte);if(F.lt!==void 0)G.lt=this.#F(F.lt);if(F.lte!==void 0)G.lte=this.#F(F.lte);return G}capabilities(){return this.#G.capabilities()}scoped(F){return new D(this.#G,y(this.#J,F))}async get(F){return this.#G.get(this.#F(F))}async put(F,G){await this.#G.put(this.#F(F),G)}async delete(F){await this.#G.delete(this.#F(F))}async*scan(F,G){for await(let[J,Q]of this.#G.scan(this.#F(F),this.#Z(G)))yield[this.#Q(J),Q]}async batch(F){M("batch operations",F.length),await this.#G.batch(F.map((G)=>{if(G.type==="put")return{type:"put",key:this.#F(G.key),value:G.value};return{type:"delete",key:this.#F(G.key)}}))}async conditionalBatch(F,G){return b(this.#G,F.map((J)=>({key:this.#F(J.key),expectedValue:J.expectedValue})),G.map((J)=>{if(J.type==="put")return{type:"put",key:this.#F(J.key),value:J.value};return{type:"delete",key:this.#F(J.key)}}))}async has(F){return P(this.#G,this.#F(F))}async deletePrefix(F){return O(this.#G,this.#F(F))}async deleteRange(F,G){let J=this.#M(V(G));return v(this.#G,this.#F(F),J)}async*keys(F,G){for await(let J of K(this.#G,this.#F(F),this.#Z(G)))yield this.#Q(J)}async count(F){return S(this.#G,this.#F(F))}[Symbol.dispose](){this.#G[Symbol.dispose]()}}function h(F,G){return new D(F,G)}var u=67108864;function m(F){if(F.type==="put")return{type:"put",key:F.key,value:L(F.value)};return{type:"delete",key:F.key}}function k(F){return{key:F.key,expectedValue:F.expectedValue===null?null:L(F.expectedValue)}}function w(F){if(!U(F)||typeof F.key!=="string"||typeof F.value!=="string")throw Error("HTTPStorage scan response contained an invalid NDJSON entry.");return{key:F.key,value:F.value}}function f(F){if(!U(F)||typeof F.applied!=="boolean")throw Error('HTTPStorage conditional batch response must include a boolean "applied" field.');return F.applied}function Y(F,G,J){if(J!==void 0)F.searchParams.set(G,String(J))}function l(F){if(F.trim().length===0)return null;let G=w(JSON.parse(F));return[G.key,A(G.value)]}function d(F){if(F>u)throw Error("HTTPStorage scan response exceeded the maximum allowed size.")}async function*p(F){if(F.body===null)return;let G=F.body.getReader(),J=new TextDecoder,Q="",Z=0,$=!1;try{while(!0){let{done:E,value:T}=await G.read();if(E){$=!0;break}Z+=T.byteLength,d(Z),Q+=J.decode(T,{stream:!0});let z=Q.split(`
|
|
2
|
+
`);Q=z.pop()??"";for(let x of z)yield x}if(Q+=J.decode(),Q.length>0)yield Q}finally{try{if(!$)await G.cancel()}catch{}G.releaseLock()}}class a{#G;#J;#F;constructor(F){this.#G=F.baseUrl instanceof URL?F.baseUrl:new URL(F.baseUrl),this.#J={...F.headers},this.#F=F.remoteConditionalBatch??!1}capabilities(){return{persistence:"remote",readAfterWrite:"eventual",scanConsistency:"best-effort",atomicBatch:!0,conditionalBatch:this.#F,boundedRangeDelete:!1}}#Q(F){let G=this.#G.href.endsWith("/")?this.#G.href:`${this.#G.href}/`;return new URL(F.replace(/^\/+/,""),G)}#Z(F){return this.#Q(`/v1/storage/${encodeURIComponent(F)}`)}#M(F,G){let J=this.#Q("/v1/storage");return J.searchParams.set("prefix",F),Y(J,"limit",G.limit),Y(J,"reverse",G.reverse),Y(J,"gt",G.gt),Y(J,"gte",G.gte),Y(J,"lt",G.lt),Y(J,"lte",G.lte),J}async#$(F,G={},J=[]){let Q=new Headers(this.#J);for(let[$,E]of new Headers(G.headers).entries())Q.set($,E);let Z=await fetch(F,{...G,headers:Q});if(!Z.ok&&!J.includes(Z.status))throw Error(`HTTPStorage request failed: ${G.method??"GET"} ${F.pathname} returned ${String(Z.status)}.`);return Z}async get(F){let G=await this.#$(this.#Z(F),{method:"GET"},[404]);if(G.status===404)return null;return new Uint8Array(await G.arrayBuffer())}async put(F,G){await this.#$(this.#Z(F),{method:"PUT",headers:{"content-type":"application/octet-stream"},body:new Blob([G])})}async delete(F){await this.#$(this.#Z(F),{method:"DELETE"})}async*scan(F,G={}){let J=await this.#$(this.#M(F,G),{method:"GET",headers:{accept:"application/x-ndjson"}});for await(let Q of p(J)){let Z=l(Q);if(Z!==null)yield Z}}async batch(F){M("batch operations",F.length),await this.#$(this.#Q("/v1/storage/-/batch"),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({operations:F.map(m)})})}async conditionalBatch(F,G){M("conditionalBatch conditions",F.length),M("conditionalBatch operations",G.length);let J=await this.#$(this.#Q("/v1/storage/-/conditional-batch"),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({conditions:F.map(k),operations:G.map(m)})});return f(await J.json())}has(F){return j(this,F)}async*keys(F,G){yield*X(this,F,G)}count(F){return _(this,F)}deletePrefix(F){return H(this,F)}deleteRange(F,G){return W(this,F,V(G))}scoped(F){return h(this,F)}[Symbol.dispose](){}}export{a as HTTPStorage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async function q(G,J){return await G.get(J)!==null}async function*T(G,J,Q){for await(let[X]of G.scan(J,Q))yield X}async function O(G,J){let Q=0;for await(let X of T(G,J))Q++;return Q}async function h(G,J){let Q=[];for await(let X of T(G,J))Q.push({type:"delete",key:X});if(Q.length===0)return 0;return await G.batch(Q),Q.length}async function R(G,J,Q){let X=[];for await(let Y of T(G,J,Q))X.push({type:"delete",key:Y});if(X.length===0)return 0;return await G.batch(X),X.length}function E(G,J,Q){if(!G.capabilities()[J])throw Error(`Feature "${Q}" requires storage capability "${J}", but this storage backend does not provide it.`)}var A=1e4;class v extends Error{code="StorageBatchOperationLimitExceededError";cap=A;count;target;constructor(G,J){super(`${G} count ${J} exceeds MAX_BATCH_OPERATIONS (${A}).`);this.name="StorageBatchOperationLimitExceededError",this.target=G,this.count=J}}function M(G,J){if(J>A)throw new v(G,J)}function j(G){return G.length>0?G.slice(0,-1)+String.fromCharCode(G.charCodeAt(G.length-1)+1):"ÿ"}function S(G,J={}){if(J.gt!==void 0&&G<=J.gt)return!1;if(J.gte!==void 0&&G<J.gte)return!1;if(J.lt!==void 0&&G>=J.lt)return!1;if(J.lte!==void 0&&G>J.lte)return!1;return!0}function b(G,J){if(G===null||J===null)return G===J;if(G.byteLength!==J.byteLength)return!1;for(let Q=0;Q<G.byteLength;Q++)if(G[Q]!==J[Q])return!1;return!0}async function m(G,J){if(G.has)return G.has(J);return q(G,J)}function x(G,J,Q){if(G.keys)return G.keys(J,Q);return T(G,J,Q)}async function y(G,J){if(G.count)return G.count(J);return O(G,J)}async function I(G,J){if(G.deletePrefix)return G.deletePrefix(J);return h(G,J)}async function g(G,J,Q){if(M("conditionalBatch conditions",J.length),M("conditionalBatch operations",Q.length),E(G,"conditionalBatch","storageConditionalBatch"),!G.conditionalBatch)throw Error("This storage backend reports conditionalBatch capability but does not implement the conditionalBatch() method.");return G.conditionalBatch(J,Q)}function l(G){if(G===void 0)return;if(typeof G!=="number"||!Number.isInteger(G)||G<0)throw Error("deleteRange limit must be a finite non-negative integer");return G===0?0:G}function N(G){let J={},Q=!1;for(let Y of["gt","gte","lt","lte"]){let $=G[Y];if($===void 0)continue;if(typeof $!=="string")throw Error("deleteRange bounds must be strings");J[Y]=$,Q=!0}if(!Q)throw Error("deleteRange requires at least one of gt/gte/lt/lte; use deletePrefix to delete a whole prefix");let X=l(G.limit);if(X!==void 0)J.limit=X;return J}async function k(G,J,Q){let X=N(Q);if(G.deleteRange)return G.deleteRange(J,X);return R(G,J,X)}function d(G,J){let Q={key:G,open:!1};if(J.gte!==void 0&&J.gte>Q.key)Q.key=J.gte,Q.open=!1;if(J.gt!==void 0&&J.gt>=Q.key)Q.key=J.gt,Q.open=!0;return Q}function p(G,J){let Q={key:j(G),open:!0};if(J.lt!==void 0&&J.lt<=Q.key)Q.key=J.lt,Q.open=!0;if(J.lte!==void 0&&J.lte<Q.key)Q.key=J.lte,Q.open=!1;return Q}function c(G,J){let Q=d(G,J),X=p(G,J);if(Q.key>X.key||Q.key===X.key&&(Q.open||X.open))return null;return{lower:Q,upper:X}}function P(G){return G.replaceAll(/:+$/g,"")}function a(G,J){let Q=P(G),X=P(J);if(Q.length===0)return X;if(X.length===0)return Q;return`${Q}:${X}`}class C{#J;#Q;constructor(G,J){this.#J=G,this.#Q=P(J)}#G(G){if(this.#Q.length===0)return G;return G.length===0?`${this.#Q}:`:`${this.#Q}:${G}`}#X(G){if(this.#Q.length===0)return G;return G.slice(this.#Q.length+1)}#Y(G={}){let J={};if(G.limit!==void 0)J.limit=G.limit;if(G.reverse!==void 0)J.reverse=G.reverse;if(G.gt!==void 0)J.gt=this.#G(G.gt);if(G.gte!==void 0)J.gte=this.#G(G.gte);if(G.lt!==void 0)J.lt=this.#G(G.lt);if(G.lte!==void 0)J.lte=this.#G(G.lte);return J}#Z(G){let J={};if(G.limit!==void 0)J.limit=G.limit;if(G.gt!==void 0)J.gt=this.#G(G.gt);if(G.gte!==void 0)J.gte=this.#G(G.gte);if(G.lt!==void 0)J.lt=this.#G(G.lt);if(G.lte!==void 0)J.lte=this.#G(G.lte);return J}capabilities(){return this.#J.capabilities()}scoped(G){return new C(this.#J,a(this.#Q,G))}async get(G){return this.#J.get(this.#G(G))}async put(G,J){await this.#J.put(this.#G(G),J)}async delete(G){await this.#J.delete(this.#G(G))}async*scan(G,J){for await(let[Q,X]of this.#J.scan(this.#G(G),this.#Y(J)))yield[this.#X(Q),X]}async batch(G){M("batch operations",G.length),await this.#J.batch(G.map((J)=>{if(J.type==="put")return{type:"put",key:this.#G(J.key),value:J.value};return{type:"delete",key:this.#G(J.key)}}))}async conditionalBatch(G,J){return g(this.#J,G.map((Q)=>({key:this.#G(Q.key),expectedValue:Q.expectedValue})),J.map((Q)=>{if(Q.type==="put")return{type:"put",key:this.#G(Q.key),value:Q.value};return{type:"delete",key:this.#G(Q.key)}}))}async has(G){return m(this.#J,this.#G(G))}async deletePrefix(G){return I(this.#J,this.#G(G))}async deleteRange(G,J){let Q=this.#Z(N(J));return k(this.#J,this.#G(G),Q)}async*keys(G,J){for await(let Q of x(this.#J,this.#G(G),this.#Y(J)))yield this.#X(Q)}async count(G){return y(this.#J,this.#G(G))}[Symbol.dispose](){this.#J[Symbol.dispose]()}}function u(G,J){return new C(G,J)}var U="kv";function s(G=globalThis){let{indexedDB:J,IDBKeyRange:Q}=G;if(J===void 0||Q===void 0)throw Error("IndexedDBStorage requires both indexedDB and IDBKeyRange runtime globals.");return{indexedDB:J,IDBKeyRange:Q}}function K(G){return new Promise((J,Q)=>{G.onsuccess=()=>J(G.result),G.onerror=()=>Q(G.error)})}function w(G,J){let Q=null,X=null,Y=null,$=(Z,V)=>{let H=Z??Error(V);if(X){let L=X;Q=null,X=null,L(H);return}Y=H};return G.onsuccess=()=>{if(!Q)return;let Z=Q;Q=null,X=null,Z(G.result)},G.onerror=()=>{$(G.error,"IndexedDB cursor request failed.")},J.onerror=()=>{$(J.error,"IndexedDB transaction failed.")},J.onabort=()=>{$(J.error,"IndexedDB transaction aborted.")},()=>{return new Promise((Z,V)=>{if(Y){let H=Y;Y=null,V(H);return}if(Q=Z,X=V,G.readyState==="done"){let H=Q;Q=null,X=null,H?.(G.result)}})}}class n{#J;#Q=null;#G;#X;constructor(G="weft",J=s()){this.#J=G,this.#X=J,this.#G=this.#Y()}capabilities(){return{persistence:"local",readAfterWrite:"linearizable",scanConsistency:"best-effort",atomicBatch:!0,conditionalBatch:!0,boundedRangeDelete:!0}}#Y(){let G=this.#X.indexedDB.open(this.#J,1);return G.onupgradeneeded=()=>{let J=G.result;if(!J.objectStoreNames.contains(U))J.createObjectStore(U)},K(G).then((J)=>{return this.#Q=J,J})}async get(G){let X=(await this.#G).transaction(U,"readonly").objectStore(U),Y=await K(X.get(G));return Y===void 0?null:new Uint8Array(Y)}async put(G,J){let Y=(await this.#G).transaction(U,"readwrite").objectStore(U);await K(Y.put(J,G))}async delete(G){let X=(await this.#G).transaction(U,"readwrite").objectStore(U);await K(X.delete(G))}async has(G){let X=(await this.#G).transaction(U,"readonly").objectStore(U);return await K(X.count(G))>0}async deletePrefix(G){let J=await this.#G,Q=j(G),X=this.#X.IDBKeyRange.bound(G,Q,!1,!0);return new Promise((Y,$)=>{let Z=J.transaction(U,"readwrite"),V=Z.objectStore(U),H=0,L=V.count(X);L.onsuccess=()=>{H=L.result,V.delete(X)},Z.oncomplete=()=>Y(H),Z.onerror=()=>$(Z.error)})}async deleteRange(G,J){let Q=N(J),X=c(G,Q);if(X===null)return 0;let Y=this.#X.IDBKeyRange.bound(X.lower.key,X.upper.key,X.lower.open,X.upper.open),$=await this.#G,{limit:Z}=Q;return new Promise((V,H)=>{let L=$.transaction(U,"readwrite"),z=L.objectStore(U),B=0;if(Z===void 0){let F=z.count(Y);F.onsuccess=()=>{B=F.result,z.delete(Y)}}else{let F=z.openCursor(Y,"next");F.onsuccess=()=>{let D=F.result;if(D===null||B>=Z)return;if(D.delete(),B++,B<Z)D.continue()}}L.oncomplete=()=>V(B),L.onerror=()=>H(L.error)})}async*scan(G,J={}){let{limit:Q,reverse:X}=J,Y=await this.#G,$=j(G),Z=this.#X.IDBKeyRange.bound(G,$,!1,!0),V=X?"prev":"next",H=Y.transaction(U,"readonly"),z=H.objectStore(U).openCursor(Z,V),B=0,F=w(z,H),D=!1;try{let W=await F();while(W){if(Q!==void 0&&B>=Q)break;let _=W.key;if(S(_,J))yield[_,new Uint8Array(W.value)],B++;W.continue(),W=await F()}D=!0}finally{if(!D)try{H.abort()}catch{}}}async batch(G){if(M("batch operations",G.length),G.length===0)return;let J=await this.#G;return new Promise((Q,X)=>{let Y=J.transaction(U,"readwrite"),$=Y.objectStore(U);for(let Z of G)if(Z.type==="put")$.put(Z.value,Z.key);else $.delete(Z.key);Y.oncomplete=()=>Q(),Y.onerror=()=>X(Y.error)})}async conditionalBatch(G,J){M("conditionalBatch conditions",G.length),M("conditionalBatch operations",J.length);let Q=await this.#G;return new Promise((X,Y)=>{let $=Q.transaction(U,"readwrite"),Z=$.objectStore(U),V=!1,H=!1,L=(F,D)=>{if(V)return;V=!0,Y(F??Error(D))};$.oncomplete=()=>{if(V)return;V=!0,X(!0)},$.onerror=()=>{L($.error,"IndexedDB conditionalBatch transaction failed.")},$.onabort=()=>{if(V)return;if(V=!0,H){X(!1);return}Y($.error??Error("IndexedDB conditionalBatch transaction aborted."))};let z=()=>{for(let F of J)if(F.type==="put")Z.put(F.value,F.key);else Z.delete(F.key)},B=(F)=>{if(F>=G.length){z();return}let D=G[F],W=Z.get(D.key);W.onsuccess=()=>{let _=W.result,f=_===void 0?null:new Uint8Array(_);if(!b(f,D.expectedValue)){H=!0,$.abort();return}B(F+1)},W.onerror=()=>{L(W.error,"IndexedDB conditionalBatch condition check failed.")}};B(0)})}async*keys(G,J={}){let{limit:Q,reverse:X}=J,Y=await this.#G,$=j(G),Z=this.#X.IDBKeyRange.bound(G,$,!1,!0),V=X?"prev":"next",H=Y.transaction(U,"readonly"),z=H.objectStore(U).openKeyCursor(Z,V),B=0,F=w(z,H),D=!1;try{let W=await F();while(W){if(Q!==void 0&&B>=Q)break;let _=W.key;if(S(_,J))yield _,B++;W.continue(),W=await F()}D=!0}finally{if(!D)try{H.abort()}catch{}}}async count(G){let J=await this.#G,Q=j(G),Y=J.transaction(U,"readonly").objectStore(U);return K(Y.count(this.#X.IDBKeyRange.bound(G,Q,!1,!0)))}scoped(G){return u(this,G)}[Symbol.dispose](){if(this.#Q)this.#Q.close(),this.#Q=null}}export{n as IndexedDBStorage};
|
package/dist/json-schema.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
`)}function
|
|
4
|
-
${Y(z)}`}var
|
|
2
|
+
var O=import.meta.require,T=(j,q,z)=>{if(q!=null){if(typeof q!=="object"&&typeof q!=="function")throw TypeError('Object expected to be assigned to "using" declaration');let A;if(z)A=q[Symbol.asyncDispose];if(A===void 0)A=q[Symbol.dispose];if(typeof A!=="function")throw TypeError("Object not disposable");j.push([z,A,q])}else if(z)j.push([z]);return q},y=(j,q,z)=>{let A=(G)=>q=z?new SuppressedError(G,q,"An error was suppressed during disposal"):(z=!0,G),H=(G)=>{while(G=j.pop())try{var $=G[1]&&G[1].call(G[2]);if(G[0])return Promise.resolve($).then(H,(Q)=>(A(Q),H()))}catch(Q){A(Q)}if(z)throw q};return H()};class X extends Error{code;constructor(j,q,z){super(q,z);this.code=j,this.name=j}}var B={WorkflowAlreadyExistsError:!0,BulkDeleteRequiresTerminalWorkflowsError:!0,BulkOperationConfirmationError:!0,WorkflowTypeNotRegisteredForRecoveryError:!0,EngineCreateNameMismatchError:!0,EngineDisposedError:!0,WorkflowNotFoundError:!0,WorkflowNotRegisteredError:!0,WorkflowConcurrencyLimitExceededError:!0,WorkflowSuspendNotSupportedError:!0,ActivityResolutionError:!0,BranchTopologyChangedError:!0,PersistedDataIncompatibleError:!0,WorkflowTimeoutError:!0,HttpClientError:!0,WorkerProtocolIncompatibleError:!0,UpdateTimeoutError:!0,UpdateValidationError:!0,WorkflowTerminalError:!0,WorkflowBuilderError:!0,VersionMismatchError:!0,EffectReplayConflictError:!0,ReviewTimeoutError:!0,AtomicStateConflictError:!0,StandardSchemaValidationError:!0,ActivityReconciliationCapabilityError:!0,ActivityReconciliationConflictError:!0,ActivityReconciliationIndeterminateError:!0,DurableActivityScopeError:!0,DurableActivityUnsupportedError:!0,AsyncActivityTokenNotFoundError:!0,ActivityScheduleToCloseTimeoutError:!0,ActivityPerAttemptTimeoutError:!0,PayloadSizeExceededError:!0,StartOrSignalConflictError:!0,WorkflowTeardownPendingError:!0,IdempotencyKeyPurgedError:!0},R=new Set(Object.keys(B));class K extends X{fieldName;operation;issues;constructor(j){super("StandardSchemaValidationError",M(j.fieldName,j.operation,j.issues));this.fieldName=j.fieldName,this.operation=j.operation,this.issues=j.issues}}async function Z(j,q,z){let A=j["~standard"];if(!D(A))throw TypeError(`Schema for ${z.fieldName} does not provide runtime validation. Attach a Standard Schema validator (Zod, Valibot, or another vendor) or supply a runtime-validating schema at this boundary.`);let H=await A.validate(q);if(H.issues===void 0)return H.value;throw new K({fieldName:z.fieldName,operation:z.operation,issues:H.issues.map(U)})}function Y(j){return j.map((q)=>q.path===""?q.message:`${q.path}: ${q.message}`).join(`
|
|
3
|
+
`)}function D(j){return typeof j.validate==="function"}function U(j){return{message:j.message,path:b(j.path)}}function b(j){if(j===void 0||j.length===0)return"";let q="";for(let z of j)q+="/",q+=w(z);return q}function w(j){let q=F(j)?j.key:j;return J(String(q))}function F(j){return j!==null&&typeof j==="object"&&"key"in j}function J(j){return j.replace(/~/g,"~0").replace(/\//g,"~1")}function M(j,q,z){return`Validation failed for ${q===void 0?j:`${q} ${j}`}:
|
|
4
|
+
${Y(z)}`}var V=Y,k=K,P=Z;export{P as validateStandardSchema,V as formatStandardSchemaIssues,k as StandardSchemaValidationError};
|