@lostgradient/weft 0.13.0 → 0.15.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 +3 -8
- package/dist/cli/generated/operation-catalog.snapshot.json +977 -77
- package/dist/cli/generated/operation-client.generated.d.ts +14 -21
- package/dist/cli/help-text.d.ts +3 -3
- package/dist/cli/help-text.js +4 -4
- package/dist/cli/operation-catalog-snapshot.d.ts +1 -1
- package/dist/cli/schedule.js +1 -3
- package/dist/cli/serve-registrations.d.ts +3 -3
- package/dist/cli/serve-registrations.js +2 -2
- package/dist/cli/shutdown.d.ts +11 -0
- package/dist/cli/shutdown.js +25 -0
- package/dist/cli/validate.d.ts +1 -1
- package/dist/cli/version-check.d.ts +1 -1
- package/dist/cli/version-check.js +1 -1
- package/dist/cli-main.js +10 -29
- package/dist/client/http-client-storage.js +7 -35
- package/dist/client/http-request.d.ts +8 -9
- package/dist/client/http-request.js +3 -25
- package/dist/core/aggregate-validation.d.ts +2 -5
- package/dist/core/aggregate-validation.js +2 -10
- package/dist/core/atomic-state.js +21 -24
- package/dist/core/context/parallel-operations.d.ts +0 -2
- package/dist/core/context/parallel-operations.js +0 -7
- package/dist/core/engine/callback-checkpoint-persistence.d.ts +2 -0
- package/dist/core/engine/callback-checkpoint-persistence.js +6 -3
- package/dist/core/engine/callback-creators.js +4 -22
- package/dist/core/engine/checkpoint-io.d.ts +1 -1
- package/dist/core/engine/operations-coordination.js +1 -1
- package/dist/core/engine/parallel-dispatch.d.ts +1 -1
- package/dist/core/engine/parallel-dispatch.js +1 -1
- package/dist/core/engine/review-list-entries.d.ts +1 -1
- package/dist/core/engine/review-list-entries.js +6 -30
- package/dist/core/engine/schedules.js +4 -1
- package/dist/core/engine/timeline-coordinator-detail.d.ts +1 -1
- package/dist/core/inline-execution-strategy.js +8 -46
- package/dist/core/list-filter-validation.d.ts +2 -5
- package/dist/core/list-filter-validation.js +2 -10
- package/dist/core/review/index.d.ts +87 -0
- package/dist/core/review/index.js +29 -0
- package/dist/core/types/schedules.d.ts +13 -31
- package/dist/core/validation-issues.d.ts +13 -0
- package/dist/core/validation-issues.js +9 -0
- package/dist/diagnostics/validate.d.ts +9 -30
- package/dist/diagnostics/validate.js +83 -21
- package/dist/diagnostics/version-check.d.ts +2 -2
- package/dist/http.js +2 -2
- package/dist/indexeddb.js +1 -1
- package/dist/mcp/session.js +2 -10
- package/dist/mcp/tools.js +2 -10
- package/dist/mcp/tuple-list-equality.d.ts +1 -0
- package/dist/mcp/tuple-list-equality.js +12 -0
- package/dist/server/openapi-error-responses.js +0 -14
- package/dist/server/operation-catalog/index.d.ts +1 -1
- package/dist/server/operation-catalog/raise-fault.d.ts +2 -1
- package/dist/server/operation-catalog/types.d.ts +3 -2
- package/dist/server/operation-fault.d.ts +1 -4
- package/dist/server/operation-fault.js +1 -1
- package/dist/server/operation-registry.d.ts +2 -31
- package/dist/server/operations/bulk-filter-helpers.d.ts +17 -17
- package/dist/server/operations/bulk-filter-helpers.js +16 -37
- package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +27 -27
- package/dist/server/operations/bulk-signal-workflows.d.ts +26 -26
- package/dist/server/operations/create-schedule.js +7 -19
- package/dist/server/operations/event-stream-contracts.d.ts +20 -0
- package/dist/server/operations/event-stream-contracts.js +67 -0
- package/dist/server/operations/fleet-events-sse.js +21 -50
- package/dist/server/operations/fleet-events-subscription.js +8 -12
- package/dist/server/operations/list-reviews.js +2 -19
- package/dist/server/operations/list-workflows.d.ts +43 -43
- package/dist/server/operations/list-workflows.js +9 -30
- package/dist/server/operations/purge-workflows.d.ts +11 -11
- package/dist/server/operations/recover-all.js +1 -10
- package/dist/server/operations/schedule-rest-body.d.ts +11 -0
- package/dist/server/operations/schedule-rest-body.js +28 -0
- package/dist/server/operations/single-workflow-control-operation.d.ts +2 -1
- package/dist/server/operations/update-schedule.js +7 -19
- package/dist/server/operations/workflow-events-sse.js +29 -67
- package/dist/server/operations/workflow-events-subscription.js +9 -27
- package/dist/server/runtime/task-polling.js +3 -5
- package/dist/server/task-state.d.ts +2 -8
- package/dist/server/task-state.js +10 -7
- package/dist/storage/bounded-ndjson-response.d.ts +5 -0
- package/dist/storage/bounded-ndjson-response.js +33 -0
- package/dist/storage/bun-sql.js +52 -49
- package/dist/storage/conditional-batch-body.d.ts +7 -0
- package/dist/storage/conditional-batch-body.js +14 -0
- package/dist/storage/http.js +5 -37
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.d.ts +3 -16
- package/dist/storage/neon.js +2 -2
- package/dist/storage/node-sqlite-loader.d.ts +2 -2
- package/dist/storage/node-sqlite.js +32 -17
- package/dist/storage/postgres.js +1 -1
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/turso.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/dist/worker/execute-with-interceptors.d.ts +1 -1
- package/dist/worker/execute-with-interceptors.js +2 -2
- package/dist/worker/index.js +5 -5
- package/dist/worker/long-poll.js +3 -4
- package/dist/worker/protocol-messages.d.ts +11 -19
- package/dist/worker/protocol-schemas.d.ts +8 -8
- package/dist/worker/protocol-schemas.js +4 -4
- package/dist/worker/protocol-task-result.d.ts +1 -0
- package/dist/worker/protocol-task-result.js +1 -3
- package/dist/worker/protocol.js +1 -1
- package/dist/worker/registry/types.d.ts +2 -7
- package/dist/worker/registry.d.ts +3 -9
- package/dist/worker/registry.js +2 -5
- package/package.json +1 -1
|
@@ -19,8 +19,8 @@ export declare const CLIENT_REST_OPERATION_BINDINGS: {
|
|
|
19
19
|
};
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
|
-
type
|
|
23
|
-
readonly attributes?: ReadonlyArray<
|
|
22
|
+
type SharedAttributesBulkConcurrenc_ff397168 = {
|
|
23
|
+
readonly attributes?: ReadonlyArray<SharedGtGteKey_e658e64c>;
|
|
24
24
|
readonly bulkConcurrency?: number;
|
|
25
25
|
readonly confirmationToken?: string;
|
|
26
26
|
readonly createdAt?: SharedGtGteLt_d9a61361;
|
|
@@ -39,8 +39,8 @@ type SharedAttributesBulkConcurrenc_f62debcf = {
|
|
|
39
39
|
readonly type?: string;
|
|
40
40
|
readonly updatedAt?: SharedGtGteLt_d9a61361;
|
|
41
41
|
};
|
|
42
|
-
type
|
|
43
|
-
readonly attributes?: ReadonlyArray<
|
|
42
|
+
type SharedAttributesCreatedAtExecu_0caddefc = {
|
|
43
|
+
readonly attributes?: ReadonlyArray<SharedGtGteKey_e658e64c>;
|
|
44
44
|
readonly createdAt?: SharedGtGteLt_d9a61361;
|
|
45
45
|
readonly executionDeadline?: SharedGtGteLt_d9a61361;
|
|
46
46
|
readonly failureCategory?: unknown;
|
|
@@ -55,10 +55,10 @@ type SharedAttributesCreatedAtExecu_2af7f9ff = {
|
|
|
55
55
|
readonly type?: string;
|
|
56
56
|
readonly updatedAt?: SharedGtGteLt_d9a61361;
|
|
57
57
|
};
|
|
58
|
-
type
|
|
58
|
+
type SharedGtGteKey_e658e64c = {
|
|
59
59
|
readonly gt?: unknown;
|
|
60
60
|
readonly gte?: unknown;
|
|
61
|
-
readonly key:
|
|
61
|
+
readonly key: unknown;
|
|
62
62
|
readonly lt?: unknown;
|
|
63
63
|
readonly lte?: unknown;
|
|
64
64
|
readonly value?: unknown;
|
|
@@ -411,14 +411,7 @@ export type ClientOperationTypes = {
|
|
|
411
411
|
};
|
|
412
412
|
'weft.workflows.aggregate': {
|
|
413
413
|
readonly input: {
|
|
414
|
-
readonly attributes?: ReadonlyArray<
|
|
415
|
-
readonly gt?: unknown;
|
|
416
|
-
readonly gte?: unknown;
|
|
417
|
-
readonly key: unknown;
|
|
418
|
-
readonly lt?: unknown;
|
|
419
|
-
readonly lte?: unknown;
|
|
420
|
-
readonly value?: unknown;
|
|
421
|
-
}>;
|
|
414
|
+
readonly attributes?: ReadonlyArray<SharedGtGteKey_e658e64c>;
|
|
422
415
|
readonly createdAt?: SharedGtGteLt_d9a61361;
|
|
423
416
|
readonly executionDeadline?: SharedGtGteLt_d9a61361;
|
|
424
417
|
readonly failureCategory?: unknown;
|
|
@@ -461,23 +454,23 @@ export type ClientOperationTypes = {
|
|
|
461
454
|
readonly faults: never;
|
|
462
455
|
};
|
|
463
456
|
'weft.workflows.bulk.cancel': {
|
|
464
|
-
readonly input:
|
|
457
|
+
readonly input: SharedAttributesBulkConcurrenc_ff397168;
|
|
465
458
|
readonly output: unknown;
|
|
466
459
|
readonly faults: never;
|
|
467
460
|
};
|
|
468
461
|
'weft.workflows.bulk.delete': {
|
|
469
|
-
readonly input:
|
|
462
|
+
readonly input: SharedAttributesBulkConcurrenc_ff397168;
|
|
470
463
|
readonly output: unknown;
|
|
471
464
|
readonly faults: 'Unprocessable';
|
|
472
465
|
};
|
|
473
466
|
'weft.workflows.bulk.retryfailed': {
|
|
474
|
-
readonly input:
|
|
467
|
+
readonly input: SharedAttributesBulkConcurrenc_ff397168;
|
|
475
468
|
readonly output: unknown;
|
|
476
469
|
readonly faults: never;
|
|
477
470
|
};
|
|
478
471
|
'weft.workflows.bulk.signal': {
|
|
479
472
|
readonly input: {
|
|
480
|
-
readonly attributes?: ReadonlyArray<
|
|
473
|
+
readonly attributes?: ReadonlyArray<SharedGtGteKey_e658e64c>;
|
|
481
474
|
readonly bulkConcurrency?: number;
|
|
482
475
|
readonly confirmationToken?: string;
|
|
483
476
|
readonly createdAt?: SharedGtGteLt_d9a61361;
|
|
@@ -506,7 +499,7 @@ export type ClientOperationTypes = {
|
|
|
506
499
|
readonly bulkConcurrency?: number;
|
|
507
500
|
readonly confirmationToken?: string;
|
|
508
501
|
readonly dryRun?: boolean;
|
|
509
|
-
readonly filter?:
|
|
502
|
+
readonly filter?: SharedAttributesCreatedAtExecu_0caddefc;
|
|
510
503
|
readonly operation: 'add' | 'remove';
|
|
511
504
|
readonly requestId?: string;
|
|
512
505
|
readonly tags: ReadonlyArray<string>;
|
|
@@ -569,7 +562,7 @@ export type ClientOperationTypes = {
|
|
|
569
562
|
};
|
|
570
563
|
'weft.workflows.list': {
|
|
571
564
|
readonly input: {
|
|
572
|
-
readonly attributes?: ReadonlyArray<
|
|
565
|
+
readonly attributes?: ReadonlyArray<SharedGtGteKey_e658e64c>;
|
|
573
566
|
readonly createdAt?: SharedGtGteLt_d9a61361;
|
|
574
567
|
readonly executionDeadline?: SharedGtGteLt_d9a61361;
|
|
575
568
|
readonly failureCategory?: unknown;
|
|
@@ -589,7 +582,7 @@ export type ClientOperationTypes = {
|
|
|
589
582
|
readonly faults: 'Unprocessable';
|
|
590
583
|
};
|
|
591
584
|
'weft.workflows.purge': {
|
|
592
|
-
readonly input:
|
|
585
|
+
readonly input: SharedAttributesCreatedAtExecu_0caddefc;
|
|
593
586
|
readonly output: unknown;
|
|
594
587
|
readonly faults: never;
|
|
595
588
|
};
|
package/dist/cli/help-text.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export declare const HELP_TEXT = "\nweft - Bun-native durable execution engine\n\nUsage: weft [command] [options]\n\nCommands:\n serve Start the Weft server (default)\n doctor Run diagnostics on the Weft database\n conformance Run RemoteWorker protocol conformance checks\n schedule Manage recurring schedules\n timeline Inspect workflow timeline and replay history\n version:check Check workflow version compatibility\n validate Lint workflow
|
|
1
|
+
export declare const HELP_TEXT = "\nweft - Bun-native durable execution engine\n\nUsage: weft [command] [options]\n\nCommands:\n serve Start the Weft server (default)\n doctor Run diagnostics on the Weft database\n conformance Run RemoteWorker protocol conformance checks\n schedule Manage recurring schedules\n timeline Inspect workflow timeline and replay history\n version:check Check workflow version compatibility\n validate Lint workflow definitions for design-time anti-patterns\n codegen Generate TypeScript declarations from a registry snapshot\n api Inspect and invoke catalog operations on a running server\n server Inspect a running server's health and operation surface\n workflow List, inspect, start, signal, and cancel workflows on a server\n tail Stream a workflow's events as Server-Sent Events\n completions Generate or install shell completion scripts\n version Print the installed Weft version\n\nVersion (leading token only; a subcommand owns its own option line):\n weft version | weft --version | weft -v Print the installed Weft version\n\nServe Options:\n -p, --port <port> Server port (default: 7233)\n -d, --database <path> Database file path (default: ./weft.db)\n -s, --storage <backend> Storage backend: sqlite, lmdb, memory (default: sqlite)\n -w, --workflows <path> Path to workflow module to register on startup\n -h, --help Show this help message\n";
|
|
2
2
|
export declare const API_HELP_TEXT = "\nweft api - Inspect and invoke catalog operations on a running server\n\nUsage:\n weft api --list [options]\n weft api --describe <operation-name> [options]\n weft api <operation-name> [--input <json> | --input-file <path|->] [options]\n\nOptions:\n --server <url> Server URL (default: WEFT_ADDR, profile, run lockfile, or localhost)\n --token <token> Bearer token (default: WEFT_TOKEN)\n --profile <name> Profile from ~/.weft/config (default: WEFT_PROFILE or default_profile)\n --input <json> JSON object input for the operation\n --input-file <path> Read JSON object input from a file, or '-' for stdin\n --list List catalog operations\n --describe <name> Print one operation's schema and metadata\n --yes Confirm destructive operations without prompting\n -j, --json Emit machine-readable JSON output\n -h, --help Show this help message\n\nExit codes:\n 0 Success\n 1 Operation failed or destructive operation was not confirmed\n 2 Connection error\n 3 Usage or input validation error\n";
|
|
3
3
|
export declare const CONFORMANCE_HELP_TEXT = "\nweft conformance - Run RemoteWorker protocol conformance checks\n\nUsage: weft conformance [options] -- <worker-command> [args...]\n\nThe worker command receives:\n WEFT_WORKER_URL\n WEFT_WORKER_QUEUE\n WEFT_WORKER_ACTIVITIES\n WEFT_WORKER_PROTOCOL_VERSION\n\nOptions:\n --timeout <ms> Per-check timeout in milliseconds (default: 15000)\n -j, --json Output results as JSON\n -h, --help Show this help message\n";
|
|
4
4
|
export declare const DOCTOR_HELP_TEXT = "\nweft doctor - Run diagnostics on the Weft database\n\nUsage: weft doctor [options]\n\nOptions:\n -d, --database <path> Database file path (default: ./weft.db)\n -j, --json Output results as JSON\n -h, --help Show this help message\n";
|
|
5
5
|
export declare const VERSION_CHECK_HELP_TEXT = "\nweft version:check - Check workflow version compatibility\n\nUsage: weft version:check [options]\n\nOptions:\n -d, --database <path> Database file path (default: ./weft.db)\n -w, --workflows <path> Path to workflows module\n -j, --json Output results as JSON\n -h, --help Show this help message\n";
|
|
6
6
|
export declare const TIMELINE_HELP_TEXT = "\nweft timeline - Inspect workflow timeline and replay history\n\nUsage:\n weft timeline <workflowId> [options]\n weft timeline <workflowId> --diff <fromStep> <toStep> [options]\n\nOptions:\n -d, --database <path> Database file path (default: ./weft.db)\n --step <step> Show replay details for one checkpoint step\n --diff Diff two checkpoint steps (requires two positional step numbers)\n -h, --help Show this help message\n";
|
|
7
|
-
export declare const SCHEDULE_HELP_TEXT = "\nweft schedule - Manage recurring schedules\n\nUsage:\n weft schedule list [options]\n weft schedule create <workflowType> <cronExpression> [options]\n weft schedule create <workflowType> --every <duration> [options]\n weft schedule pause <scheduleId> [options]\n weft schedule resume <scheduleId> [options]\n weft schedule cancel <scheduleId> [options]\n\nProvide a cron expression positional OR an --every interval (e.g. \"30s\", \"1h\"),\nbut not both. Interval schedules fire one period after creation, then every\nperiod after that.\n\nOptions:\n -d, --database <path> Database file path (default: ./weft.db)\n -s, --storage <backend> Storage backend: sqlite, lmdb (default: sqlite)\n -w, --workflows <path> Path to workflow
|
|
8
|
-
export declare const VALIDATE_HELP_TEXT = "\nweft validate - Lint workflow
|
|
7
|
+
export declare const SCHEDULE_HELP_TEXT = "\nweft schedule - Manage recurring schedules\n\nUsage:\n weft schedule list [options]\n weft schedule create <workflowType> <cronExpression> [options]\n weft schedule create <workflowType> --every <duration> [options]\n weft schedule pause <scheduleId> [options]\n weft schedule resume <scheduleId> [options]\n weft schedule cancel <scheduleId> [options]\n\nProvide a cron expression positional OR an --every interval (e.g. \"30s\", \"1h\"),\nbut not both. Interval schedules fire one period after creation, then every\nperiod after that.\n\nOptions:\n -d, --database <path> Database file path (default: ./weft.db)\n -s, --storage <backend> Storage backend: sqlite, lmdb (default: sqlite)\n -w, --workflows <path> Path to workflow definitions module (required for create)\n --every <duration> Interval cadence for create (e.g. 30s, 5m, 1h); mutually exclusive with the cron positional\n --input <json> JSON input payload for create (default: null)\n --id <id> Custom schedule id for create\n --overlap <policy> Overlap policy: skip, queue, cancel-running, allow\n --backfill Run missed ticks on recovery\n --jitter <duration> Deterministic dispatch jitter for create (e.g. 30s, 5m)\n -j, --json Output results as JSON\n -h, --help Show this help message\n";
|
|
8
|
+
export declare const VALIDATE_HELP_TEXT = "\nweft validate - Lint workflow definitions for design-time anti-patterns\n\nUsage: weft validate <entry.ts>... [options]\n\nArguments:\n <entry.ts>... One or more TypeScript modules or glob patterns that\n resolve to workflow definitions and/or activity\n definitions.\n\nOptions:\n -j, --json Output results as JSON\n -h, --help Show this help message\n\nExit codes:\n 0 No errors (warnings may be present)\n 1 One or more errors detected\n 2 Entry file could not be loaded (takes precedence over validation errors)\n\nJSON output:\n { entries, valid, hasLoadErrors, hasValidationErrors }\n\nChecks performed:\n unbounded-retry Activity retry.maxAttempts is Infinity\n stateful-without-compensator Non-idempotent activity has no compensate fn\n";
|
|
9
9
|
export declare const SERVER_HELP_TEXT = "\nweft server - Inspect a running server's health and operation surface\n\nUsage:\n weft server health [options]\n weft server info [options]\n\nOptions:\n --server <url> Server URL (default: WEFT_ADDR, profile, run lockfile, or localhost)\n --token <token> Bearer token (default: WEFT_TOKEN)\n --profile <name> Profile from ~/.weft/config\n --wait (health) Poll until the server is reachable\n --wait-timeout <ms> (health) Maximum time to wait, in milliseconds (default: 30000)\n -j, --json Emit machine-readable JSON output\n -q, --quiet Suppress success/error text (use the exit code)\n -h, --help Show this help message\n\nExit codes:\n 0 Healthy\n 1 Unreachable / unhealthy\n 2 Connection error\n";
|
|
10
10
|
export declare const WORKFLOW_HELP_TEXT = "\nweft workflow - List, inspect, start, signal, and cancel workflows on a server\n\nUsage:\n weft workflow ls [--type <type>] [--status <status>] [--limit <n>] [options]\n weft workflow get <workflow-id> [options]\n weft workflow events <workflow-id> [options]\n weft workflow start <workflow-type> [--input <json> | --input-file <path|->] [--id <id>] [options]\n weft workflow cancel <workflow-id> [--yes] [--dry-run] [options]\n weft workflow signal <workflow-id> <signal-name> [--input <json> | --input-file <path|->] [options]\n\nOptions:\n --server <url> Server URL (default: WEFT_ADDR, profile, run lockfile, or localhost)\n --token <token> Bearer token (default: WEFT_TOKEN)\n --profile <name> Profile from ~/.weft/config\n --type <type> (ls) Filter by workflow type\n --status <status> (ls) Filter by workflow status\n --limit <n> (ls) Maximum number of rows\n --input <json> (start/signal) JSON input payload\n --input-file <path> (start/signal) Read JSON input from a file, or '-' for stdin\n --id <id> (start) Explicit workflow id\n -y, --yes (cancel) Confirm without prompting\n --dry-run (cancel) Print affected count without cancelling\n -j, --json Emit machine-readable output (NDJSON for lists)\n -q, --quiet Print ids only / suppress success text\n -h, --help Show this help message\n\nExit codes:\n 0 Success\n 1 Operation failed or destructive operation was not confirmed\n 2 Connection error\n 3 Usage or input error\n 4 Operation unavailable on this server (version skew)\n";
|
|
11
11
|
export declare const TAIL_HELP_TEXT = "\nweft tail - Stream a workflow's events as Server-Sent Events\n\nUsage:\n weft tail <workflow-id> [options]\n\nOptions:\n --server <url> Server URL (default: WEFT_ADDR, profile, run lockfile, or localhost)\n --token <token> Bearer token (default: WEFT_TOKEN)\n --profile <name> Profile from ~/.weft/config\n -j, --json Emit one JSON object per line (NDJSON)\n -q, --quiet Do not echo events to stdout\n -h, --help Show this help message\n\nPress Ctrl-C to stop tailing; the stream ends cleanly with exit code 0.\n";
|
package/dist/cli/help-text.js
CHANGED
|
@@ -10,7 +10,7 @@ Commands:
|
|
|
10
10
|
schedule Manage recurring schedules
|
|
11
11
|
timeline Inspect workflow timeline and replay history
|
|
12
12
|
version:check Check workflow version compatibility
|
|
13
|
-
validate Lint workflow
|
|
13
|
+
validate Lint workflow definitions for design-time anti-patterns
|
|
14
14
|
codegen Generate TypeScript declarations from a registry snapshot
|
|
15
15
|
api Inspect and invoke catalog operations on a running server
|
|
16
16
|
server Inspect a running server's health and operation surface
|
|
@@ -117,7 +117,7 @@ period after that.
|
|
|
117
117
|
Options:
|
|
118
118
|
-d, --database <path> Database file path (default: ./weft.db)
|
|
119
119
|
-s, --storage <backend> Storage backend: sqlite, lmdb (default: sqlite)
|
|
120
|
-
-w, --workflows <path> Path to workflow
|
|
120
|
+
-w, --workflows <path> Path to workflow definitions module (required for create)
|
|
121
121
|
--every <duration> Interval cadence for create (e.g. 30s, 5m, 1h); mutually exclusive with the cron positional
|
|
122
122
|
--input <json> JSON input payload for create (default: null)
|
|
123
123
|
--id <id> Custom schedule id for create
|
|
@@ -127,13 +127,13 @@ Options:
|
|
|
127
127
|
-j, --json Output results as JSON
|
|
128
128
|
-h, --help Show this help message
|
|
129
129
|
`, VALIDATE_HELP_TEXT = `
|
|
130
|
-
weft validate - Lint workflow
|
|
130
|
+
weft validate - Lint workflow definitions for design-time anti-patterns
|
|
131
131
|
|
|
132
132
|
Usage: weft validate <entry.ts>... [options]
|
|
133
133
|
|
|
134
134
|
Arguments:
|
|
135
135
|
<entry.ts>... One or more TypeScript modules or glob patterns that
|
|
136
|
-
resolve to workflow
|
|
136
|
+
resolve to workflow definitions and/or activity
|
|
137
137
|
definitions.
|
|
138
138
|
|
|
139
139
|
Options:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { FaultCode } from '../core/fault-code.ts';
|
|
1
2
|
import type { ErasedOperation, OperationKind, TransportAvailability } from '../server/operation-catalog.ts';
|
|
2
|
-
import type { FaultCode } from '../server/operation-fault.ts';
|
|
3
3
|
import type { ParamSource, ResponseShape } from '../server/rest-binding.ts';
|
|
4
4
|
export type CatalogRestBindingSnapshot = {
|
|
5
5
|
readonly method: string;
|
package/dist/cli/schedule.js
CHANGED
|
@@ -51,10 +51,8 @@ function parseScheduleInput(input) {
|
|
|
51
51
|
}
|
|
52
52
|
async function registerScheduleWorkflows(engine, workflowsPath, loadRegistrationsFromModule) {
|
|
53
53
|
const loaded = await loadRegistrationsFromModule(workflowsPath);
|
|
54
|
-
for (const
|
|
55
|
-
const definition = { ...registration, name: workflowType };
|
|
54
|
+
for (const definition of Object.values(loaded.registrations))
|
|
56
55
|
registerOnRuntimeEngine(runtimeWorkflowEngine(engine), definition);
|
|
57
|
-
}
|
|
58
56
|
}
|
|
59
57
|
async function executeScheduleCreate(options, engine, loadRegistrationsFromModule) {
|
|
60
58
|
const validationError = getScheduleCreateValidationError(options);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ActivityDefinition } from '../core/activity.ts';
|
|
2
2
|
import type { Engine } from '../core/engine.ts';
|
|
3
|
-
import type {
|
|
3
|
+
import type { WorkflowDefinition } from '../core/types.ts';
|
|
4
4
|
/**
|
|
5
5
|
* Convert a plain-object `ActivityDefinition` into a callable function that
|
|
6
6
|
* satisfies the engine's `isActivityDefinition` check (which requires a
|
|
@@ -8,8 +8,8 @@ import type { WorkflowRegistration } from '../diagnostics/validate.ts';
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function toActivityCallable(definition: ActivityDefinition): (...args: unknown[]) => unknown;
|
|
10
10
|
/**
|
|
11
|
-
* Register a map of workflow
|
|
11
|
+
* Register a map of workflow definitions and a list of activity definitions
|
|
12
12
|
* on an engine instance. Plain-object activities are normalized to callables
|
|
13
13
|
* before registration.
|
|
14
14
|
*/
|
|
15
|
-
export declare function registerModuleExports(engine: Engine, registrations: Record<string,
|
|
15
|
+
export declare function registerModuleExports(engine: Engine, registrations: Record<string, WorkflowDefinition>, activities: ActivityDefinition[]): void;
|
|
@@ -13,8 +13,8 @@ export function toActivityCallable(definition) {
|
|
|
13
13
|
}
|
|
14
14
|
export function registerModuleExports(engine, registrations, activities) {
|
|
15
15
|
const runtime = runtimeWorkflowEngine(engine);
|
|
16
|
-
for (const
|
|
17
|
-
registerOnRuntimeEngine(runtime,
|
|
16
|
+
for (const definition of Object.values(registrations))
|
|
17
|
+
registerOnRuntimeEngine(runtime, definition);
|
|
18
18
|
for (const activity of activities)
|
|
19
19
|
if (typeof activity === "function")
|
|
20
20
|
engine.register(activity);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const CLI_SHUTDOWN_SIGNALS: readonly ["SIGINT", "SIGTERM"];
|
|
2
|
+
export type CliShutdownSignal = (typeof CLI_SHUTDOWN_SIGNALS)[number];
|
|
3
|
+
export type CliShutdownDependencies = {
|
|
4
|
+
readonly stopServer: () => Promise<void>;
|
|
5
|
+
readonly removeRunLockfile: () => Promise<void>;
|
|
6
|
+
readonly disposeStorage: () => void;
|
|
7
|
+
readonly log: (message: string) => void;
|
|
8
|
+
readonly reportError: (message: string, error: unknown) => void;
|
|
9
|
+
readonly exit: (code: 0 | 1) => void;
|
|
10
|
+
};
|
|
11
|
+
export declare function createCliShutdownHandler(dependencies: CliShutdownDependencies): (signal: CliShutdownSignal) => Promise<void>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const CLI_SHUTDOWN_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
2
|
+
async function runCliShutdown(signal, dependencies) {
|
|
3
|
+
dependencies.log(`
|
|
4
|
+
Received ${signal}; shutting down...`);
|
|
5
|
+
try {
|
|
6
|
+
await dependencies.stopServer();
|
|
7
|
+
try {
|
|
8
|
+
await dependencies.removeRunLockfile();
|
|
9
|
+
} catch (error) {
|
|
10
|
+
dependencies.reportError("[weft] Failed to remove run lockfile:", error);
|
|
11
|
+
}
|
|
12
|
+
dependencies.disposeStorage();
|
|
13
|
+
dependencies.exit(0);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
dependencies.reportError("[weft] Shutdown error:", error);
|
|
16
|
+
dependencies.exit(1);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function createCliShutdownHandler(dependencies) {
|
|
20
|
+
let shutdownPromise;
|
|
21
|
+
return (signal) => {
|
|
22
|
+
shutdownPromise ??= runCliShutdown(signal, dependencies);
|
|
23
|
+
return shutdownPromise;
|
|
24
|
+
};
|
|
25
|
+
}
|
package/dist/cli/validate.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommandOutput } from './types.ts';
|
|
2
|
-
/** Validates workflow
|
|
2
|
+
/** Validates workflow definition modules and reports load or design-time errors. */
|
|
3
3
|
export declare function executeValidate(options: {
|
|
4
4
|
entryPaths: string[];
|
|
5
5
|
json: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommandOutput } from './types.ts';
|
|
2
|
-
/** Checks stored workflow history against the current workflow
|
|
2
|
+
/** Checks stored workflow history against the current workflow definitions. */
|
|
3
3
|
export declare function executeVersionCheck(options: {
|
|
4
4
|
database: string;
|
|
5
5
|
workflows: string;
|
|
@@ -8,7 +8,7 @@ export async function executeVersionCheck(options) {
|
|
|
8
8
|
};
|
|
9
9
|
const { runVersionCheck } = await import("../diagnostics/version-check.js"), { formatVersionCheckReport } = await import("../diagnostics/format.js"), { BunSQLiteStorage } = await import("../storage/bun-sql.js"), storage = new BunSQLiteStorage(options.database);
|
|
10
10
|
try {
|
|
11
|
-
const
|
|
11
|
+
const workflowsPath = resolve(process.cwd(), options.workflows), { loadRegistrationsFromModule } = await import("../diagnostics/validate.js"), { registrations } = await loadRegistrationsFromModule(workflowsPath), report = await runVersionCheck(storage, registrations);
|
|
12
12
|
return { stdout: options.json ? JSON.stringify(report, null, 2) : formatVersionCheckReport(report), exitCode: 0 };
|
|
13
13
|
} finally {
|
|
14
14
|
storage[Symbol.dispose]();
|
package/dist/cli-main.js
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
WORKFLOW_HELP_TEXT,
|
|
33
33
|
writeRunLockfile
|
|
34
34
|
} from "./cli/index.js";
|
|
35
|
+
import { CLI_SHUTDOWN_SIGNALS, createCliShutdownHandler } from "./cli/shutdown.js";
|
|
35
36
|
import { Engine } from "./core/engine.js";
|
|
36
37
|
import { serve } from "./server/index.js";
|
|
37
38
|
const parsedArguments = (() => {
|
|
@@ -67,36 +68,16 @@ if (parsedArguments.command === "version") {
|
|
|
67
68
|
console.log(`Health check: ${new URL("/v1/health", server.url).href}`);
|
|
68
69
|
console.log(`Storage: ${parsedArguments.storage}`);
|
|
69
70
|
console.log(`Database: ${parsedArguments.database}`);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
console.error("[weft] Failed to remove run lockfile:", error);
|
|
78
|
-
}
|
|
79
|
-
storage[Symbol.dispose]();
|
|
80
|
-
process.exit(0);
|
|
81
|
-
}).catch((error) => {
|
|
82
|
-
console.error("[weft] Shutdown error:", error);
|
|
83
|
-
process.exit(1);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
process.on("SIGTERM", () => {
|
|
87
|
-
server.stop().then(async () => {
|
|
88
|
-
try {
|
|
89
|
-
await removeRunLockfile(server.url);
|
|
90
|
-
} catch (error) {
|
|
91
|
-
console.error("[weft] Failed to remove run lockfile:", error);
|
|
92
|
-
}
|
|
93
|
-
storage[Symbol.dispose]();
|
|
94
|
-
process.exit(0);
|
|
95
|
-
}).catch((error) => {
|
|
96
|
-
console.error("[weft] Shutdown error:", error);
|
|
97
|
-
process.exit(1);
|
|
98
|
-
});
|
|
71
|
+
const shutdown = createCliShutdownHandler({
|
|
72
|
+
stopServer: () => server.stop(),
|
|
73
|
+
removeRunLockfile: () => removeRunLockfile(server.url),
|
|
74
|
+
disposeStorage: () => storage[Symbol.dispose](),
|
|
75
|
+
log: (message) => console.log(message),
|
|
76
|
+
reportError: (message, error) => console.error(message, error),
|
|
77
|
+
exit: (code) => process.exit(code)
|
|
99
78
|
});
|
|
79
|
+
for (const signal of CLI_SHUTDOWN_SIGNALS)
|
|
80
|
+
process.on(signal, () => void shutdown(signal));
|
|
100
81
|
} else if (parsedArguments.command === "doctor") {
|
|
101
82
|
if (parsedArguments.help) {
|
|
102
83
|
console.log(DOCTOR_HELP_TEXT);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readBoundedNdjsonResponse } from "../storage/bounded-ndjson-response.js";
|
|
1
2
|
import { decodeBase64ToBytes, encodeBytesToBase64, isRecord } from "../storage/byte-encoding.js";
|
|
2
3
|
import {
|
|
3
4
|
assertStorageBatchOperationCount
|
|
@@ -19,42 +20,13 @@ function scanEntry(value) {
|
|
|
19
20
|
throw Error("HttpClient storage scan response contained an invalid NDJSON entry.");
|
|
20
21
|
return [value.key, decodeBase64ToBytes(value.value)];
|
|
21
22
|
}
|
|
22
|
-
async function releaseScanReader(reader, reachedEndOfStream) {
|
|
23
|
-
if (!reachedEndOfStream)
|
|
24
|
-
try {
|
|
25
|
-
await reader.cancel();
|
|
26
|
-
} catch {}
|
|
27
|
-
reader.releaseLock();
|
|
28
|
-
}
|
|
29
23
|
async function* scanResponse(response) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const { done, value } = await reader.read();
|
|
37
|
-
if (done) {
|
|
38
|
-
reachedEndOfStream = !0;
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
41
|
-
bytesRead += value.byteLength;
|
|
42
|
-
if (bytesRead > MAX_SCAN_RESPONSE_BYTES)
|
|
43
|
-
throw Error("HttpClient storage scan response exceeded the maximum allowed size.");
|
|
44
|
-
bufferedText += decoder.decode(value, { stream: !0 });
|
|
45
|
-
const lines = bufferedText.split(`
|
|
46
|
-
`);
|
|
47
|
-
bufferedText = lines.pop() ?? "";
|
|
48
|
-
for (const line of lines)
|
|
49
|
-
if (line.trim().length > 0)
|
|
50
|
-
yield scanEntry(JSON.parse(line));
|
|
51
|
-
}
|
|
52
|
-
bufferedText += decoder.decode();
|
|
53
|
-
if (bufferedText.trim().length > 0)
|
|
54
|
-
yield scanEntry(JSON.parse(bufferedText));
|
|
55
|
-
} finally {
|
|
56
|
-
await releaseScanReader(reader, reachedEndOfStream);
|
|
57
|
-
}
|
|
24
|
+
for await (const line of readBoundedNdjsonResponse(response, {
|
|
25
|
+
maximumBytes: MAX_SCAN_RESPONSE_BYTES,
|
|
26
|
+
sizeLimitError: () => Error("HttpClient storage scan response exceeded the maximum allowed size.")
|
|
27
|
+
}))
|
|
28
|
+
if (line.trim().length > 0)
|
|
29
|
+
yield scanEntry(JSON.parse(line));
|
|
58
30
|
}
|
|
59
31
|
export function createHttpClientStorage(baseUrl, headers) {
|
|
60
32
|
return {
|
|
@@ -63,7 +63,7 @@ export declare function resolveHttpClientConnection(options: HttpClientOptions):
|
|
|
63
63
|
/**
|
|
64
64
|
* Error thrown when the server returns a non-2xx response.
|
|
65
65
|
*
|
|
66
|
-
* When
|
|
66
|
+
* When a transport response carries a recognized coarse fault code, the wire
|
|
67
67
|
* value is surfaced as {@link HttpClientError.faultCode} with a derived
|
|
68
68
|
* {@link HttpClientError.category}, so callers can branch without
|
|
69
69
|
* string-matching `message`. Both are `undefined` for the production flat REST
|
|
@@ -96,8 +96,8 @@ export declare class HttpClientError extends WeftError<'HttpClientError'> {
|
|
|
96
96
|
/** HTTP status code of the failed response. */
|
|
97
97
|
readonly status: number;
|
|
98
98
|
/**
|
|
99
|
-
* The server's stable wire fault code, when the response carried a
|
|
100
|
-
*
|
|
99
|
+
* The server's stable wire fault code, when the transport response carried a
|
|
100
|
+
* recognized code. `undefined` for flat REST error bodies or unrecognized codes.
|
|
101
101
|
*/
|
|
102
102
|
readonly faultCode?: FaultCode | undefined;
|
|
103
103
|
/**
|
|
@@ -107,18 +107,17 @@ export declare class HttpClientError extends WeftError<'HttpClientError'> {
|
|
|
107
107
|
readonly category?: FailureCategory | undefined;
|
|
108
108
|
/**
|
|
109
109
|
* The fine-grained originating public {@link WeftErrorCode} the server
|
|
110
|
-
* attached (e.g. `WorkflowNotFoundError`), when the
|
|
111
|
-
*
|
|
110
|
+
* attached (e.g. `WorkflowNotFoundError`), when the response carried one.
|
|
111
|
+
* This is what makes cross-transport branching work: a producer can call
|
|
112
112
|
* `isWeftFault(error, 'WorkflowNotFoundError')` and have it match over HTTP
|
|
113
113
|
* exactly as it matches the in-process typed error. `undefined` when the fault
|
|
114
|
-
* carried only the coarse {@link faultCode} (most faults) or no
|
|
114
|
+
* carried only the coarse {@link faultCode} (most faults) or no recognized code.
|
|
115
115
|
*/
|
|
116
116
|
readonly weftCode?: WeftErrorCode | undefined;
|
|
117
117
|
/**
|
|
118
118
|
* The fault's wire `data` payload, when the response carried a structured
|
|
119
|
-
* body (`{ error, data }` for production REST
|
|
120
|
-
*
|
|
121
|
-
* fault-code-dependent — see {@link FaultCode} and the server's
|
|
119
|
+
* body (`{ error, data }` for production REST or `error.data` for JSON-RPC).
|
|
120
|
+
* Shape is fault-code-dependent — see {@link FaultCode} and the server's
|
|
122
121
|
* `OperationFault` per-code `data` union for what each code carries (e.g.
|
|
123
122
|
* `InvalidParams.data.issues`, `NotFound.data.resource`). `undefined` for
|
|
124
123
|
* plain-string error bodies, bodies with no `data` field, or a `data` field
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveConnection } from "../connection.js";
|
|
2
|
-
import { failureCategoryForFaultCode
|
|
2
|
+
import { failureCategoryForFaultCode } from "../core/fault-code.js";
|
|
3
3
|
import { isWeftErrorCode, WeftError } from "../core/weft-error.js";
|
|
4
4
|
export function resolveHttpClientConnection(options) {
|
|
5
5
|
const connection = resolveConnection({
|
|
@@ -49,34 +49,12 @@ function parseFlatErrorBody(body) {
|
|
|
49
49
|
...data === void 0 ? {} : { data }
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
function isStructuredErrorBody(value) {
|
|
53
|
-
if (value === null || typeof value !== "object")
|
|
54
|
-
return !1;
|
|
55
|
-
const error = value.error;
|
|
56
|
-
if (error === null || typeof error !== "object")
|
|
57
|
-
return !1;
|
|
58
|
-
return typeof error.message === "string";
|
|
59
|
-
}
|
|
60
|
-
function weftCodeFromData(data) {
|
|
61
|
-
if (data === null || typeof data !== "object")
|
|
62
|
-
return;
|
|
63
|
-
const candidate = data.weftCode;
|
|
64
|
-
return isWeftErrorCode(candidate) ? candidate : void 0;
|
|
65
|
-
}
|
|
66
52
|
function isRecord(value) {
|
|
67
53
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
68
54
|
}
|
|
69
55
|
async function parseErrorBody(response) {
|
|
70
56
|
try {
|
|
71
57
|
const body = await response.json();
|
|
72
|
-
if (isStructuredErrorBody(body)) {
|
|
73
|
-
const { code, message, data } = body.error, weftCode = weftCodeFromData(data), base = { message };
|
|
74
|
-
if (weftCode !== void 0)
|
|
75
|
-
base.weftCode = weftCode;
|
|
76
|
-
if (isRecord(data))
|
|
77
|
-
base.data = data;
|
|
78
|
-
return isFaultCode(code) ? { ...base, faultCode: code } : base;
|
|
79
|
-
}
|
|
80
58
|
if (isFlatErrorBody(body) && body.error)
|
|
81
59
|
return parseFlatErrorBody(body);
|
|
82
60
|
return { message: response.statusText };
|
|
@@ -97,8 +75,8 @@ export async function requestResponse(baseUrl, path, baseHeaders, options) {
|
|
|
97
75
|
if (response.status === 404 && (!options?.method || options.method === "GET"))
|
|
98
76
|
return null;
|
|
99
77
|
if (!response.ok) {
|
|
100
|
-
const { message,
|
|
101
|
-
throw new HttpClientError(response.status, message, {
|
|
78
|
+
const { message, weftCode, data } = await parseErrorBody(response);
|
|
79
|
+
throw new HttpClientError(response.status, message, { weftCode, data });
|
|
102
80
|
}
|
|
103
81
|
return response;
|
|
104
82
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @module core/aggregate-validation
|
|
12
12
|
*/
|
|
13
13
|
import { z } from 'zod';
|
|
14
|
+
import { type ValidationIssue } from './validation-issues.ts';
|
|
14
15
|
import { WeftError } from './weft-error.ts';
|
|
15
16
|
/**
|
|
16
17
|
* Group-by dimension for `engine.aggregate()`. Either a fixed structural
|
|
@@ -54,11 +55,7 @@ export declare const aggregateOptionsObjectSchema: z.ZodObject<{
|
|
|
54
55
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
55
56
|
}, z.core.$strict>;
|
|
56
57
|
/** A flattened Zod issue suitable for cross-transport serialization. */
|
|
57
|
-
export type AggregateOptionsValidationIssue =
|
|
58
|
-
readonly path: ReadonlyArray<string | number>;
|
|
59
|
-
readonly message: string;
|
|
60
|
-
readonly code: string;
|
|
61
|
-
};
|
|
58
|
+
export type AggregateOptionsValidationIssue = ValidationIssue;
|
|
62
59
|
/**
|
|
63
60
|
* Thrown by {@link normalizeAggregateOptions} when input fails validation.
|
|
64
61
|
* Carries flattened Zod issues so transport adapters can map directly to
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { flattenZodIssue } from "./validation-issues.js";
|
|
2
3
|
import { WeftError } from "./weft-error.js";
|
|
3
4
|
const attributeDimensionSchema = z.object({ attribute: z.string().min(1) }).strict(), groupBySchema = z.union([
|
|
4
5
|
z.literal("status"),
|
|
@@ -10,15 +11,6 @@ export const AGGREGATE_DEFAULT_LIMIT = 1000, AGGREGATE_MAX_LIMIT = 1e4, MAX_AGGR
|
|
|
10
11
|
groupBy: groupBySchema,
|
|
11
12
|
limit: z.number().int().min(1).max(AGGREGATE_MAX_LIMIT).optional()
|
|
12
13
|
}).strict();
|
|
13
|
-
function flattenIssue(issue) {
|
|
14
|
-
const path = [];
|
|
15
|
-
for (const segment of issue.path)
|
|
16
|
-
if (typeof segment === "string" || typeof segment === "number")
|
|
17
|
-
path.push(segment);
|
|
18
|
-
else
|
|
19
|
-
path.push(String(segment));
|
|
20
|
-
return { path, message: issue.message, code: issue.code };
|
|
21
|
-
}
|
|
22
14
|
|
|
23
15
|
export class AggregateOptionsValidationError extends WeftError {
|
|
24
16
|
issues;
|
|
@@ -42,7 +34,7 @@ export class AggregateDistinctKeyCapExceededError extends WeftError {
|
|
|
42
34
|
export function normalizeAggregateOptions(input) {
|
|
43
35
|
const result = aggregateOptionsObjectSchema.safeParse(input ?? {});
|
|
44
36
|
if (!result.success)
|
|
45
|
-
throw new AggregateOptionsValidationError(result.error.issues.map(
|
|
37
|
+
throw new AggregateOptionsValidationError(result.error.issues.map(flattenZodIssue));
|
|
46
38
|
const { groupBy, limit } = result.data;
|
|
47
39
|
return { groupBy, ...limit !== void 0 && { limit } };
|
|
48
40
|
}
|
|
@@ -121,35 +121,18 @@ export class AtomicState extends EventTarget {
|
|
|
121
121
|
return (await this.#read()).value;
|
|
122
122
|
}
|
|
123
123
|
async update(updater) {
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return nextValue;
|
|
129
|
-
}
|
|
130
|
-
dispatchAtomicStateEvent(this, new AtomicStateConflictEvent(this.#stateKey, attempt + 1));
|
|
131
|
-
if (attempt < this.#maxRetries - 1)
|
|
132
|
-
await this.#sleep(retryDelay(attempt));
|
|
133
|
-
}
|
|
134
|
-
dispatchAtomicStateEvent(this, new AtomicStateExhaustedEvent(this.#stateKey, this.#maxRetries));
|
|
135
|
-
throw new AtomicStateConflictError(this.#stateKey, this.#maxRetries);
|
|
124
|
+
return this.#runOptimisticMutation(async (snapshot) => {
|
|
125
|
+
const nextValue = updater(snapshot.value);
|
|
126
|
+
return { commit: await commitAtomicStateValue(this.#storage, this.#dataKey, snapshot.version, nextValue), result: nextValue, eventValue: nextValue };
|
|
127
|
+
});
|
|
136
128
|
}
|
|
137
129
|
async set(value) {
|
|
138
130
|
return this.update(() => value);
|
|
139
131
|
}
|
|
140
132
|
async delete() {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
dispatchAtomicStateEvent(this, new AtomicStateChangeEvent(void 0, snapshot.value, commit.version));
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
dispatchAtomicStateEvent(this, new AtomicStateConflictEvent(this.#stateKey, attempt + 1));
|
|
148
|
-
if (attempt < this.#maxRetries - 1)
|
|
149
|
-
await this.#sleep(retryDelay(attempt));
|
|
150
|
-
}
|
|
151
|
-
dispatchAtomicStateEvent(this, new AtomicStateExhaustedEvent(this.#stateKey, this.#maxRetries));
|
|
152
|
-
throw new AtomicStateConflictError(this.#stateKey, this.#maxRetries);
|
|
133
|
+
await this.#runOptimisticMutation(async (snapshot) => {
|
|
134
|
+
return { commit: await commitAtomicStateDelete(this.#storage, this.#dataKey, snapshot.version), result: void 0, eventValue: void 0 };
|
|
135
|
+
});
|
|
153
136
|
}
|
|
154
137
|
increment(amount = 1) {
|
|
155
138
|
return this.update((current) => (current ?? 0) + amount);
|
|
@@ -225,6 +208,20 @@ export class AtomicState extends EventTarget {
|
|
|
225
208
|
this.removeEventListener("exhausted", listener);
|
|
226
209
|
}
|
|
227
210
|
}
|
|
211
|
+
async#runOptimisticMutation(attemptMutation) {
|
|
212
|
+
for (let attempt = 0;attempt < this.#maxRetries; attempt++) {
|
|
213
|
+
const snapshot = await this.#read(), mutation = await attemptMutation(snapshot);
|
|
214
|
+
if (mutation.commit.applied) {
|
|
215
|
+
dispatchAtomicStateEvent(this, new AtomicStateChangeEvent(mutation.eventValue, snapshot.value, mutation.commit.version));
|
|
216
|
+
return mutation.result;
|
|
217
|
+
}
|
|
218
|
+
dispatchAtomicStateEvent(this, new AtomicStateConflictEvent(this.#stateKey, attempt + 1));
|
|
219
|
+
if (attempt < this.#maxRetries - 1)
|
|
220
|
+
await this.#sleep(retryDelay(attempt));
|
|
221
|
+
}
|
|
222
|
+
dispatchAtomicStateEvent(this, new AtomicStateExhaustedEvent(this.#stateKey, this.#maxRetries));
|
|
223
|
+
throw new AtomicStateConflictError(this.#stateKey, this.#maxRetries);
|
|
224
|
+
}
|
|
228
225
|
async#read() {
|
|
229
226
|
return readAtomicStateSnapshot(this.#storage, this.#dataKey, this.#options);
|
|
230
227
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { Context } from './index.ts';
|
|
2
2
|
import type { ContextInternals } from './internals.ts';
|
|
3
3
|
import type { ContextOperationRequest } from './operation-request.ts';
|
|
4
|
-
import { assertValidParallelOperationCacheEntry, BranchTopologyChangedError, createParallelOperationCacheEntry, isParallelOperationCacheEntry, type ParallelBranchSlot, type ParallelOperationCacheEntry } from './parallel-cache-entry.ts';
|
|
5
|
-
export { assertValidParallelOperationCacheEntry, BranchTopologyChangedError, createParallelOperationCacheEntry, isParallelOperationCacheEntry, type ParallelBranchSlot, type ParallelOperationCacheEntry, };
|
|
6
4
|
export declare function all(context: Context, internals: ContextInternals, operations: Generator<ContextOperationRequest, unknown, unknown>[]): Generator<ContextOperationRequest, unknown[], unknown>;
|
|
7
5
|
export declare function race(context: Context, internals: ContextInternals, operations: Generator<ContextOperationRequest, unknown, unknown>[], branchNames?: string[]): Generator<ContextOperationRequest, unknown, unknown>;
|
|
8
6
|
export declare function memo<T>(context: Context, internals: ContextInternals, key: string, fn: () => T | Promise<T>): Generator<ContextOperationRequest, T, unknown>;
|