@lostgradient/weft 0.14.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.
Files changed (70) hide show
  1. package/README.md +3 -8
  2. package/dist/cli/generated/operation-catalog.snapshot.json +977 -77
  3. package/dist/cli/generated/operation-client.generated.d.ts +14 -21
  4. package/dist/core/aggregate-validation.d.ts +2 -5
  5. package/dist/core/aggregate-validation.js +2 -10
  6. package/dist/core/atomic-state.js +21 -24
  7. package/dist/core/engine/schedules.js +4 -1
  8. package/dist/core/inline-execution-strategy.js +8 -46
  9. package/dist/core/list-filter-validation.d.ts +2 -5
  10. package/dist/core/list-filter-validation.js +2 -10
  11. package/dist/core/types/schedules.d.ts +13 -31
  12. package/dist/core/validation-issues.d.ts +13 -0
  13. package/dist/core/validation-issues.js +9 -0
  14. package/dist/http.js +1 -1
  15. package/dist/indexeddb.js +1 -1
  16. package/dist/mcp/session.js +2 -10
  17. package/dist/mcp/tools.js +2 -10
  18. package/dist/mcp/tuple-list-equality.d.ts +1 -0
  19. package/dist/mcp/tuple-list-equality.js +12 -0
  20. package/dist/server/operation-catalog/types.d.ts +1 -1
  21. package/dist/server/operation-registry.d.ts +2 -31
  22. package/dist/server/operations/bulk-filter-helpers.d.ts +17 -17
  23. package/dist/server/operations/bulk-filter-helpers.js +16 -37
  24. package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +27 -27
  25. package/dist/server/operations/bulk-signal-workflows.d.ts +26 -26
  26. package/dist/server/operations/create-schedule.js +7 -19
  27. package/dist/server/operations/event-stream-contracts.d.ts +20 -0
  28. package/dist/server/operations/event-stream-contracts.js +67 -0
  29. package/dist/server/operations/fleet-events-sse.js +21 -50
  30. package/dist/server/operations/fleet-events-subscription.js +8 -12
  31. package/dist/server/operations/list-workflows.d.ts +43 -43
  32. package/dist/server/operations/list-workflows.js +9 -30
  33. package/dist/server/operations/purge-workflows.d.ts +11 -11
  34. package/dist/server/operations/schedule-rest-body.d.ts +11 -0
  35. package/dist/server/operations/schedule-rest-body.js +28 -0
  36. package/dist/server/operations/update-schedule.js +7 -19
  37. package/dist/server/operations/workflow-events-sse.js +29 -67
  38. package/dist/server/operations/workflow-events-subscription.js +9 -27
  39. package/dist/server/runtime/task-polling.js +3 -5
  40. package/dist/server/task-state.d.ts +2 -8
  41. package/dist/server/task-state.js +10 -7
  42. package/dist/storage/bun-sql.js +52 -49
  43. package/dist/storage/conditional-batch-body.d.ts +7 -0
  44. package/dist/storage/conditional-batch-body.js +14 -0
  45. package/dist/storage/lmdb.js +1 -1
  46. package/dist/storage/memory.js +1 -1
  47. package/dist/storage/neon.js +2 -2
  48. package/dist/storage/node-sqlite-loader.d.ts +2 -2
  49. package/dist/storage/node-sqlite.js +32 -17
  50. package/dist/storage/postgres.js +1 -1
  51. package/dist/storage/resolve.js +1 -1
  52. package/dist/storage/scoped-storage.js +1 -1
  53. package/dist/storage/turso.js +1 -1
  54. package/dist/version.d.ts +1 -1
  55. package/dist/version.js +1 -1
  56. package/dist/web-extension.js +1 -1
  57. package/dist/worker/execute-with-interceptors.d.ts +1 -1
  58. package/dist/worker/execute-with-interceptors.js +2 -2
  59. package/dist/worker/index.js +5 -5
  60. package/dist/worker/long-poll.js +3 -4
  61. package/dist/worker/protocol-messages.d.ts +11 -19
  62. package/dist/worker/protocol-schemas.d.ts +8 -8
  63. package/dist/worker/protocol-schemas.js +4 -4
  64. package/dist/worker/protocol-task-result.d.ts +1 -0
  65. package/dist/worker/protocol-task-result.js +1 -3
  66. package/dist/worker/protocol.js +1 -1
  67. package/dist/worker/registry/types.d.ts +2 -7
  68. package/dist/worker/registry.d.ts +3 -9
  69. package/dist/worker/registry.js +2 -5
  70. package/package.json +1 -1
@@ -19,8 +19,8 @@ export declare const CLIENT_REST_OPERATION_BINDINGS: {
19
19
  };
20
20
  };
21
21
  };
22
- type SharedAttributesBulkConcurrenc_f62debcf = {
23
- readonly attributes?: ReadonlyArray<SharedGtGteKey_896a0c41>;
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 SharedAttributesCreatedAtExecu_2af7f9ff = {
43
- readonly attributes?: ReadonlyArray<SharedGtGteKey_896a0c41>;
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 SharedGtGteKey_896a0c41 = {
58
+ type SharedGtGteKey_e658e64c = {
59
59
  readonly gt?: unknown;
60
60
  readonly gte?: unknown;
61
- readonly key: string;
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: SharedAttributesBulkConcurrenc_f62debcf;
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: SharedAttributesBulkConcurrenc_f62debcf;
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: SharedAttributesBulkConcurrenc_f62debcf;
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<SharedGtGteKey_896a0c41>;
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?: SharedAttributesCreatedAtExecu_2af7f9ff;
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<SharedGtGteKey_896a0c41>;
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: SharedAttributesCreatedAtExecu_2af7f9ff;
585
+ readonly input: SharedAttributesCreatedAtExecu_0caddefc;
593
586
  readonly output: unknown;
594
587
  readonly faults: never;
595
588
  };
@@ -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(flattenIssue));
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
- for (let attempt = 0;attempt < this.#maxRetries; attempt++) {
125
- const snapshot = await this.#read(), nextValue = updater(snapshot.value), commit = await commitAtomicStateValue(this.#storage, this.#dataKey, snapshot.version, nextValue);
126
- if (commit.applied) {
127
- dispatchAtomicStateEvent(this, new AtomicStateChangeEvent(nextValue, snapshot.value, commit.version));
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
- for (let attempt = 0;attempt < this.#maxRetries; attempt++) {
142
- const snapshot = await this.#read(), commit = await commitAtomicStateDelete(this.#storage, this.#dataKey, snapshot.version);
143
- if (commit.applied) {
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
  }
@@ -100,7 +100,10 @@ async function hasCurrentScheduleTimer(internals, state) {
100
100
  }
101
101
  export function toScheduleSummary(state) {
102
102
  const { input: _input, ...summary } = state;
103
- return { ...summary, queuedRuns: summary.queuedRuns.map((queuedRun) => ({ ...queuedRun })) };
103
+ return {
104
+ ...summary,
105
+ queuedRuns: summary.queuedRuns.map((queuedRun) => ({ ...queuedRun }))
106
+ };
104
107
  }
105
108
  export async function pauseSchedule(internals, scheduleId) {
106
109
  const normalizedScheduleId = coerceScheduleId(scheduleId, "scheduleId"), state = await requireScheduleState(internals, normalizedScheduleId);
@@ -128,11 +128,17 @@ export class InlineExecutionStrategy {
128
128
  this[Symbol.dispose]();
129
129
  }
130
130
  #driveGenerator(workflowId, generator, lastResult) {
131
+ return this.#advanceGenerator(workflowId, () => generator.next(lastResult), void 0);
132
+ }
133
+ #throwIntoGenerator(workflowId, generator, error, operationFailureCategory) {
134
+ return this.#advanceGenerator(workflowId, () => generator.throw(error), operationFailureCategory);
135
+ }
136
+ #advanceGenerator(workflowId, advance, fallbackFailureCategory) {
131
137
  return this.#trackWorkflowAdvance(workflowId, (async () => {
132
138
  try {
133
139
  if (this.#abortControllers.get(workflowId)?.signal.aborted)
134
140
  return;
135
- const iterationResult = await generator.next(lastResult);
141
+ const iterationResult = await advance();
136
142
  if (iterationResult.done) {
137
143
  this.#cleanup(workflowId, {
138
144
  preserveTrackedAdvance: !0,
@@ -161,7 +167,7 @@ export class InlineExecutionStrategy {
161
167
  type: "failed",
162
168
  workflowId,
163
169
  error: error instanceof Error ? error.message : String(error),
164
- failureCategory: classifyErrorAsFailureCategory(error, {
170
+ failureCategory: fallbackFailureCategory ?? classifyErrorAsFailureCategory(error, {
165
171
  defaultErrorCategory: "application"
166
172
  })
167
173
  };
@@ -171,50 +177,6 @@ export class InlineExecutionStrategy {
171
177
  }
172
178
  })());
173
179
  }
174
- #throwIntoGenerator(workflowId, generator, error, operationFailureCategory) {
175
- return this.#trackWorkflowAdvance(workflowId, (async () => {
176
- try {
177
- if (this.#abortControllers.get(workflowId)?.signal.aborted)
178
- return;
179
- const iterationResult = await generator.throw(error);
180
- if (iterationResult.done) {
181
- this.#cleanup(workflowId, {
182
- preserveTrackedAdvance: !0,
183
- preserveTrackedTurn: !0
184
- });
185
- this.#emit({
186
- type: "completed",
187
- workflowId,
188
- result: iterationResult.value
189
- });
190
- return;
191
- }
192
- const operation = iterationResult.value;
193
- this.#emit({
194
- type: "checkpoint",
195
- workflowId,
196
- checkpoint: new ArrayBuffer(0),
197
- operationRequest: operation
198
- });
199
- } catch (innerError) {
200
- this.#cleanup(workflowId, {
201
- preserveTrackedAdvance: !0,
202
- preserveTrackedTurn: !0
203
- });
204
- const failedMessage = {
205
- type: "failed",
206
- workflowId,
207
- error: innerError instanceof Error ? innerError.message : String(innerError),
208
- failureCategory: operationFailureCategory ?? classifyErrorAsFailureCategory(innerError, {
209
- defaultErrorCategory: "application"
210
- })
211
- };
212
- if (innerError instanceof Error && innerError.stack !== void 0)
213
- failedMessage.errorStack = innerError.stack;
214
- this.#emit(failedMessage);
215
- }
216
- })());
217
- }
218
180
  #trackWorkflowAdvance(workflowId, pendingAdvance) {
219
181
  const trackedAdvance = pendingAdvance.finally(() => {
220
182
  if (this.#workflowAdvances.get(workflowId) === trackedAdvance)
@@ -12,6 +12,7 @@ import { z } from 'zod';
12
12
  import { isFailureCategory } from './failure-categories.ts';
13
13
  import type { FailureCategory, WorkflowStatus } from './types/identity.ts';
14
14
  import type { ListFilter } from './types/list-options.ts';
15
+ import { type ValidationIssue } from './validation-issues.ts';
15
16
  import { WeftError } from './weft-error.ts';
16
17
  /**
17
18
  * Concrete object schema for {@link ListFilter}. Supports `.omit()` and
@@ -56,11 +57,7 @@ export declare const listFilterObjectSchema: z.ZodObject<{
56
57
  failureCategory: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<FailureCategory, unknown, z.core.$ZodTypeInternals<FailureCategory, unknown>>, z.ZodArray<z.ZodType<FailureCategory, unknown, z.core.$ZodTypeInternals<FailureCategory, unknown>>>]>>;
57
58
  }, z.core.$strict>;
58
59
  /** A flattened Zod issue suitable for cross-transport serialization. */
59
- export type FilterValidationIssue = {
60
- readonly path: ReadonlyArray<string | number>;
61
- readonly message: string;
62
- readonly code: string;
63
- };
60
+ export type FilterValidationIssue = ValidationIssue;
64
61
  /**
65
62
  * Thrown by {@link normalizeListFilter} when the input fails validation.
66
63
  * Carries flattened Zod issues so transport adapters can map directly to the
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { FAILURE_CATEGORIES, isFailureCategory } from "./failure-categories.js";
3
+ import { flattenZodIssue } from "./validation-issues.js";
3
4
  import { WeftError } from "./weft-error.js";
4
5
  const WORKFLOW_STATUSES = [
5
6
  "pending",
@@ -48,15 +49,6 @@ export const listFilterObjectSchema = z.object({
48
49
  executionDeadline: timeRangeSchema.optional(),
49
50
  failureCategory: z.union([failureCategorySchema, z.array(failureCategorySchema).min(1)]).optional()
50
51
  }).strict();
51
- function flattenIssue(issue) {
52
- const path = [];
53
- for (const segment of issue.path)
54
- if (typeof segment === "string" || typeof segment === "number")
55
- path.push(segment);
56
- else
57
- path.push(String(segment));
58
- return { path, message: issue.message, code: issue.code };
59
- }
60
52
 
61
53
  export class ListFilterValidationError extends WeftError {
62
54
  issues;
@@ -72,7 +64,7 @@ export class ListFilterValidationError extends WeftError {
72
64
  export function normalizeListFilter(input) {
73
65
  const result = listFilterObjectSchema.safeParse(input ?? {});
74
66
  if (!result.success)
75
- throw new ListFilterValidationError(result.error.issues.map(flattenIssue));
67
+ throw new ListFilterValidationError(result.error.issues.map(flattenZodIssue));
76
68
  if (result.data.parentWorkflowExecutionToken !== void 0 && result.data.parentWorkflowId === void 0)
77
69
  throw new ListFilterValidationError([
78
70
  {
@@ -181,14 +181,13 @@ export type ScheduleDefinition<TInput = unknown> = ScheduleSpec & {
181
181
  */
182
182
  export declare function schedule<TInput>(definition: ScheduleDefinition<TInput>): ScheduleDefinition<TInput>;
183
183
  /**
184
- * Full persisted state of a recurring schedule. Returned by `engine.getSchedule(id)`.
185
- * Use {@link ScheduleSummary} (returned by list operations and `engine.getSchedule()`)
186
- * for the lightweight variant it omits `input` to keep payloads small.
184
+ * Metadata shared by persisted schedule state and lightweight schedule summaries.
185
+ * Persisted state and summaries extend this contract so metadata cannot drift
186
+ * between durable records and public lightweight responses.
187
187
  */
188
- export interface ScheduleState {
188
+ export interface ScheduleMetadata {
189
189
  id: string;
190
190
  workflowType: string;
191
- input: unknown;
192
191
  /** Human-readable operator description stored with this schedule. */
193
192
  description?: string;
194
193
  /**
@@ -220,38 +219,21 @@ export interface ScheduleState {
220
219
  /** Ordered durable occurrences waiting behind `currentWorkflowId`. */
221
220
  queuedRuns: ScheduleQueuedRun[];
222
221
  }
222
+ /**
223
+ * Full persisted state of a recurring schedule. Returned by `engine.getSchedule(id)`.
224
+ * Use {@link ScheduleSummary} (returned by list operations and `engine.getSchedule()`)
225
+ * for the lightweight variant — it omits `input` to keep payloads small.
226
+ */
227
+ export interface ScheduleState extends ScheduleMetadata {
228
+ input: unknown;
229
+ }
223
230
  /**
224
231
  * Lightweight summary of a recurring schedule returned by list operations.
225
232
  * Contains cron expression, status, timing metadata, and the ID of the
226
233
  * currently running workflow (if any). For the full record including the
227
234
  * `input`, use {@link ScheduleState}.
228
235
  */
229
- export interface ScheduleSummary {
230
- id: string;
231
- workflowType: string;
232
- /** Human-readable operator description stored with this schedule. */
233
- description?: string;
234
- /** Cron expression for cron-based schedules; absent for interval schedules. */
235
- cronExpression?: string;
236
- /** Interval period in milliseconds for interval-based schedules; absent for cron schedules. */
237
- intervalMs?: number;
238
- status: ScheduleStatus;
239
- overlap: ScheduleOverlapPolicy;
240
- backfill: boolean;
241
- /** Normalized deterministic jitter window in milliseconds. */
242
- jitterMs?: number;
243
- createdAt: number;
244
- updatedAt: number;
245
- /** Most recent occurrence that started a scheduled workflow. */
246
- lastFireAt?: number;
247
- /** Most recent occurrence skipped because a non-backfill timer was late. */
248
- lastMissedFireAt?: number;
249
- /** Lifetime count of occurrences skipped because a non-backfill timer was late. */
250
- missedFireCount: number;
251
- nextFireAt: number | null;
252
- currentWorkflowId?: string;
253
- /** Ordered durable occurrences waiting behind `currentWorkflowId`. */
254
- queuedRuns: ScheduleQueuedRun[];
236
+ export interface ScheduleSummary extends ScheduleMetadata {
255
237
  }
256
238
  /**
257
239
  * Filter criteria for `engine.listSchedules`. All fields are optional.
@@ -0,0 +1,13 @@
1
+ import type { ZodIssue } from 'zod';
2
+ /** A flattened Zod issue suitable for cross-transport serialization. */
3
+ export type ValidationIssue = {
4
+ readonly path: ReadonlyArray<string | number>;
5
+ readonly message: string;
6
+ readonly code: string;
7
+ };
8
+ /**
9
+ * Convert a Zod issue into the stable diagnostic shape used by core validators.
10
+ * Path segments outside the JSON-friendly string and number forms are rendered
11
+ * with their string representation, preserving the original issue order.
12
+ */
13
+ export declare function flattenZodIssue(issue: ZodIssue): ValidationIssue;
@@ -0,0 +1,9 @@
1
+ export function flattenZodIssue(issue) {
2
+ const path = [];
3
+ for (const segment of issue.path)
4
+ if (typeof segment === "string" || typeof segment === "number")
5
+ path.push(segment);
6
+ else
7
+ path.push(String(segment));
8
+ return { path, message: issue.message, code: issue.code };
9
+ }
package/dist/http.js CHANGED
@@ -1,2 +1,2 @@
1
1
  async function*R(F,G){if(F.body===null)return;let J=F.body.getReader(),Q=new TextDecoder,Z="",$=0,j=!1;try{while(!0){let{done:y,value:z}=await J.read();if(y){j=!0;break}if($+=z.byteLength,$>G.maximumBytes)throw G.sizeLimitError();Z+=Q.decode(z,{stream:!0});let A=Z.split(`
2
- `);Z=A.pop()??"";for(let g of A)yield g}if(Z+=Q.decode(),Z.length>0)yield Z}finally{if(!j)try{await J.cancel()}catch{}J.releaseLock()}}function N(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 B(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 q(F){return typeof F==="object"&&F!==null&&!Array.isArray(F)}async function _(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 H(F,G){let J=0;for await(let Q of X(F,G))J++;return J}async function L(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 U(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 C(F,G,J){if(!F.capabilities()[G])throw Error(`Feature "${J}" requires storage capability "${G}", but this storage backend does not provide it.`)}var D=1e4;class T extends Error{code="StorageBatchOperationLimitExceededError";cap=D;count;target;constructor(F,G){super(`${F} count ${G} exceeds MAX_BATCH_OPERATIONS (${D}).`);this.name="StorageBatchOperationLimitExceededError",this.target=F,this.count=G}}function M(F,G){if(G>D)throw new T(F,G)}function S(F){return F.length>0?F.slice(0,-1)+String.fromCharCode(F.charCodeAt(F.length-1)+1):"ÿ"}function e(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 FF(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 K(F,G){if(F.has)return F.has(G);return _(F,G)}function P(F,G,J){if(F.keys)return F.keys(G,J);return X(F,G,J)}async function O(F,G){if(F.count)return F.count(G);return H(F,G)}async function b(F,G){if(F.deletePrefix)return F.deletePrefix(G);return L(F,G)}async function v(F,G,J){if(M("conditionalBatch conditions",G.length),M("conditionalBatch operations",J.length),C(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 h(F,G,J){let Q=V(J);if(F.deleteRange)return F.deleteRange(G,Q);return U(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 u(F,G){let J={key:S(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 ZF(F,G){let J=I(F,G),Q=u(F,G);if(J.key>Q.key||J.key===Q.key&&(J.open||Q.open))return null;return{lower:J,upper:Q}}function E(F){return F.replaceAll(/:+$/g,"")}function k(F,G){let J=E(F),Q=E(G);if(J.length===0)return Q;if(Q.length===0)return J;return`${J}:${Q}`}class W{#G;#J;constructor(F,G){this.#G=F,this.#J=E(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 W(this.#G,k(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 v(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 K(this.#G,this.#F(F))}async deletePrefix(F){return b(this.#G,this.#F(F))}async deleteRange(F,G){let J=this.#M(V(G));return h(this.#G,this.#F(F),J)}async*keys(F,G){for await(let J of P(this.#G,this.#F(F),this.#Z(G)))yield this.#Q(J)}async count(F){return O(this.#G,this.#F(F))}[Symbol.dispose](){this.#G[Symbol.dispose]()}}function m(F,G){return new W(F,G)}var w=67108864;function x(F){if(F.type==="put")return{type:"put",key:F.key,value:N(F.value)};return{type:"delete",key:F.key}}function f(F){return{key:F.key,expectedValue:F.expectedValue===null?null:N(F.expectedValue)}}function d(F){if(!q(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 l(F){if(!q(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 p(F){if(F.trim().length===0)return null;let G=d(JSON.parse(F));return[G.key,B(G.value)]}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[$,j]of new Headers(G.headers).entries())Q.set($,j);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 R(J,{maximumBytes:w,sizeLimitError:()=>Error("HTTPStorage scan response exceeded the maximum allowed size.")})){let Z=p(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(x)})})}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(f),operations:G.map(x)})});return l(await J.json())}has(F){return _(this,F)}async*keys(F,G){yield*X(this,F,G)}count(F){return H(this,F)}deletePrefix(F){return L(this,F)}deleteRange(F,G){return U(this,F,V(G))}scoped(F){return m(this,F)}[Symbol.dispose](){}}export{a as HTTPStorage};
2
+ `);Z=A.pop()??"";for(let g of A)yield g}if(Z+=Q.decode(),Z.length>0)yield Z}finally{if(!j)try{await J.cancel()}catch{}J.releaseLock()}}function N(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 B(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 q(F){return typeof F==="object"&&F!==null&&!Array.isArray(F)}async function _(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 H(F,G){let J=0;for await(let Q of X(F,G))J++;return J}async function L(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 U(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 C(F,G,J){if(!F.capabilities()[G])throw Error(`Feature "${J}" requires storage capability "${G}", but this storage backend does not provide it.`)}var D=1e4;class T extends Error{code="StorageBatchOperationLimitExceededError";cap=D;count;target;constructor(F,G){super(`${F} count ${G} exceeds MAX_BATCH_OPERATIONS (${D}).`);this.name="StorageBatchOperationLimitExceededError",this.target=F,this.count=G}}function M(F,G){if(G>D)throw new T(F,G)}function K(F){return F.length>0?F.slice(0,-1)+String.fromCharCode(F.charCodeAt(F.length-1)+1):"ÿ"}function e(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 FF(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 S(F,G){if(F.has)return F.has(G);return _(F,G)}function P(F,G,J){if(F.keys)return F.keys(G,J);return X(F,G,J)}async function O(F,G){if(F.count)return F.count(G);return H(F,G)}async function b(F,G){if(F.deletePrefix)return F.deletePrefix(G);return L(F,G)}async function v(F,G,J){if(M("conditionalBatch conditions",G.length),M("conditionalBatch operations",J.length),C(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 h(F,G,J){let Q=V(J);if(F.deleteRange)return F.deleteRange(G,Q);return U(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 u(F,G){let J={key:K(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 ZF(F,G){let J=I(F,G),Q=u(F,G);if(J.key>Q.key||J.key===Q.key&&(J.open||Q.open))return null;return{lower:J,upper:Q}}function E(F){return F.replaceAll(/:+$/g,"")}function k(F,G){let J=E(F),Q=E(G);if(J.length===0)return Q;if(Q.length===0)return J;return`${J}:${Q}`}class W{#G;#J;constructor(F,G){this.#G=F,this.#J=E(G)}#F(F){if(this.#J.length===0)return F;return F.length===0?`${this.#J}:`:`${this.#J}:${F}`}#Z(F){return 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)}})}#$(F){if(this.#J.length===0)return F;return F.slice(this.#J.length+1)}#M(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}#Q(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 W(this.#G,k(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.#M(G)))yield[this.#$(J),Q]}async batch(F){M("batch operations",F.length),await this.#G.batch(this.#Z(F))}async conditionalBatch(F,G){return v(this.#G,F.map((J)=>({key:this.#F(J.key),expectedValue:J.expectedValue})),this.#Z(G))}async has(F){return S(this.#G,this.#F(F))}async deletePrefix(F){return b(this.#G,this.#F(F))}async deleteRange(F,G){let J=this.#Q(V(G));return h(this.#G,this.#F(F),J)}async*keys(F,G){for await(let J of P(this.#G,this.#F(F),this.#M(G)))yield this.#$(J)}async count(F){return O(this.#G,this.#F(F))}[Symbol.dispose](){this.#G[Symbol.dispose]()}}function m(F,G){return new W(F,G)}var w=67108864;function x(F){if(F.type==="put")return{type:"put",key:F.key,value:N(F.value)};return{type:"delete",key:F.key}}function f(F){return{key:F.key,expectedValue:F.expectedValue===null?null:N(F.expectedValue)}}function d(F){if(!q(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 l(F){if(!q(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 p(F){if(F.trim().length===0)return null;let G=d(JSON.parse(F));return[G.key,B(G.value)]}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}}#Z(F){let G=this.#G.href.endsWith("/")?this.#G.href:`${this.#G.href}/`;return new URL(F.replace(/^\/+/,""),G)}#$(F){return this.#Z(`/v1/storage/${encodeURIComponent(F)}`)}#M(F,G){let J=this.#Z("/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#Q(F,G={},J=[]){let Q=new Headers(this.#J);for(let[$,j]of new Headers(G.headers).entries())Q.set($,j);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.#Q(this.#$(F),{method:"GET"},[404]);if(G.status===404)return null;return new Uint8Array(await G.arrayBuffer())}async put(F,G){await this.#Q(this.#$(F),{method:"PUT",headers:{"content-type":"application/octet-stream"},body:new Blob([G])})}async delete(F){await this.#Q(this.#$(F),{method:"DELETE"})}async*scan(F,G={}){let J=await this.#Q(this.#M(F,G),{method:"GET",headers:{accept:"application/x-ndjson"}});for await(let Q of R(J,{maximumBytes:w,sizeLimitError:()=>Error("HTTPStorage scan response exceeded the maximum allowed size.")})){let Z=p(Q);if(Z!==null)yield Z}}async batch(F){M("batch operations",F.length),await this.#Q(this.#Z("/v1/storage/-/batch"),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({operations:F.map(x)})})}async conditionalBatch(F,G){M("conditionalBatch conditions",F.length),M("conditionalBatch operations",G.length);let J=await this.#Q(this.#Z("/v1/storage/-/conditional-batch"),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({conditions:F.map(f),operations:G.map(x)})});return l(await J.json())}has(F){return _(this,F)}async*keys(F,G){yield*X(this,F,G)}count(F){return H(this,F)}deletePrefix(F){return L(this,F)}deleteRange(F,G){return U(this,F,V(G))}scoped(F){return m(this,F)}[Symbol.dispose](){}}export{a as HTTPStorage};
package/dist/indexeddb.js CHANGED
@@ -1 +1 @@
1
- async function q(G,J){return await G.get(J)!==null}async function*N(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 N(G,J))Q++;return Q}async function R(G,J){let Q=[];for await(let X of N(G,J))Q.push({type:"delete",key:X});if(Q.length===0)return 0;return await G.batch(Q),Q.length}async function h(G,J,Q){let X=[];for await(let Y of N(G,J,Q))X.push({type:"delete",key:Y});if(X.length===0)return 0;return await G.batch(X),X.length}function v(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 E 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 E(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 N(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 R(G,J)}async function g(G,J,Q){if(M("conditionalBatch conditions",J.length),M("conditionalBatch operations",Q.length),v(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 T(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=T(Q);if(G.deleteRange)return G.deleteRange(J,X);return h(G,J,X)}function p(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 d(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=p(G,J),X=d(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(T(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 B=X;Q=null,X=null,B(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,B=V.count(X);B.onsuccess=()=>{H=B.result,V.delete(X)},Z.oncomplete=()=>Y(H),Z.onerror=()=>$(Z.error)})}async deleteRange(G,J){let Q=T(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 B=$.transaction(U,"readwrite"),z=B.objectStore(U),D=0;if(Z===void 0){let F=z.count(Y);F.onsuccess=()=>{D=F.result,z.delete(Y)}}else{let F=z.openCursor(Y,"next");F.onsuccess=()=>{let W=F.result;if(W===null||D>=Z)return;if(W.delete(),D++,D<Z)W.continue()}}B.oncomplete=()=>V(D),B.onerror=()=>H(B.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),D=0,F=w(z,H),W=!1;try{let L=await F();while(L){if(Q!==void 0&&D>=Q)break;let _=L.key;if(S(_,J))yield[_,new Uint8Array(L.value)],D++;L.continue(),L=await F()}W=!0}finally{if(!W)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,B=(F,W)=>{if(V)return;V=!0,Y(F??Error(W))};$.oncomplete=()=>{if(V)return;V=!0,X(!0)},$.onerror=()=>{B($.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)},D=(F)=>{if(F>=G.length){z();return}let W=G[F],L=Z.get(W.key);L.onsuccess=()=>{let _=L.result,f=_===void 0?null:new Uint8Array(_);if(!b(f,W.expectedValue)){H=!0,$.abort();return}D(F+1)},L.onerror=()=>{B(L.error,"IndexedDB conditionalBatch condition check failed.")}};D(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),D=0,F=w(z,H),W=!1;try{let L=await F();while(L){if(Q!==void 0&&D>=Q)break;let _=L.key;if(S(_,J))yield _,D++;L.continue(),L=await F()}W=!0}finally{if(!W)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};
1
+ async function q(G,J){return await G.get(J)!==null}async function*N(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 N(G,J))Q++;return Q}async function R(G,J){let Q=[];for await(let X of N(G,J))Q.push({type:"delete",key:X});if(Q.length===0)return 0;return await G.batch(Q),Q.length}async function h(G,J,Q){let X=[];for await(let Y of N(G,J,Q))X.push({type:"delete",key:Y});if(X.length===0)return 0;return await G.batch(X),X.length}function v(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 E 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 E(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 N(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 R(G,J)}async function g(G,J,Q){if(M("conditionalBatch conditions",J.length),M("conditionalBatch operations",Q.length),v(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 T(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=T(Q);if(G.deleteRange)return G.deleteRange(J,X);return h(G,J,X)}function p(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 d(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=p(G,J),X=d(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){return 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)}})}#Y(G){if(this.#Q.length===0)return G;return G.slice(this.#Q.length+1)}#Z(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}#$(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.#Z(J)))yield[this.#Y(Q),X]}async batch(G){M("batch operations",G.length),await this.#J.batch(this.#X(G))}async conditionalBatch(G,J){return g(this.#J,G.map((Q)=>({key:this.#G(Q.key),expectedValue:Q.expectedValue})),this.#X(J))}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.#$(T(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.#Z(J)))yield this.#Y(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 B=X;Q=null,X=null,B(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,B=V.count(X);B.onsuccess=()=>{H=B.result,V.delete(X)},Z.oncomplete=()=>Y(H),Z.onerror=()=>$(Z.error)})}async deleteRange(G,J){let Q=T(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 B=$.transaction(U,"readwrite"),z=B.objectStore(U),D=0;if(Z===void 0){let F=z.count(Y);F.onsuccess=()=>{D=F.result,z.delete(Y)}}else{let F=z.openCursor(Y,"next");F.onsuccess=()=>{let W=F.result;if(W===null||D>=Z)return;if(W.delete(),D++,D<Z)W.continue()}}B.oncomplete=()=>V(D),B.onerror=()=>H(B.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),D=0,F=w(z,H),W=!1;try{let L=await F();while(L){if(Q!==void 0&&D>=Q)break;let _=L.key;if(S(_,J))yield[_,new Uint8Array(L.value)],D++;L.continue(),L=await F()}W=!0}finally{if(!W)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,B=(F,W)=>{if(V)return;V=!0,Y(F??Error(W))};$.oncomplete=()=>{if(V)return;V=!0,X(!0)},$.onerror=()=>{B($.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)},D=(F)=>{if(F>=G.length){z();return}let W=G[F],L=Z.get(W.key);L.onsuccess=()=>{let _=L.result,f=_===void 0?null:new Uint8Array(_);if(!b(f,W.expectedValue)){H=!0,$.abort();return}D(F+1)},L.onerror=()=>{B(L.error,"IndexedDB conditionalBatch condition check failed.")}};D(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),D=0,F=w(z,H),W=!1;try{let L=await F();while(L){if(Q!==void 0&&D>=Q)break;let _=L.key;if(S(_,J))yield _,D++;L.continue(),L=await F()}W=!0}finally{if(!W)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};
@@ -3,6 +3,7 @@ import { WeftError } from "../core/weft-error.js";
3
3
  import { MCP_TOOLS_LIST_CHANGED_NOTIFICATION, requestIdKey } from "./protocol.js";
4
4
  import { isWorkflowSearchResourceUri, workflowResourceUri } from "./resources.js";
5
5
  import { listMcpTools } from "./tools.js";
6
+ import { tupleListsEqual } from "./tuple-list-equality.js";
6
7
 
7
8
  export class McpSessionLimitExceededError extends WeftError {
8
9
  constructor() {
@@ -243,16 +244,7 @@ function toolListSignature(engine) {
243
244
  ]);
244
245
  }
245
246
  function toolListSignaturesEqual(left, right) {
246
- if (left.length !== right.length)
247
- return !1;
248
- for (let index = 0;index < left.length; index++) {
249
- const leftEntry = left[index], rightEntry = right[index];
250
- if (leftEntry === void 0 || rightEntry === void 0)
251
- return !1;
252
- if (leftEntry[0] !== rightEntry[0] || leftEntry[1] !== rightEntry[1] || leftEntry[2] !== rightEntry[2] || leftEntry[3] !== rightEntry[3])
253
- return !1;
254
- }
255
- return !0;
247
+ return tupleListsEqual(left, right, (leftEntry, rightEntry) => leftEntry[0] === rightEntry[0] && leftEntry[1] === rightEntry[1] && leftEntry[2] === rightEntry[2] && leftEntry[3] === rightEntry[3]);
256
248
  }
257
249
  export function createMcpSessionManager(engine, options) {
258
250
  return new McpSessionManager(engine, options);
package/dist/mcp/tools.js CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  listVisibleWorkflows
9
9
  } from "./access.js";
10
10
  import { parseMcpListFilter } from "./list-filter.js";
11
+ import { tupleListsEqual } from "./tuple-list-equality.js";
11
12
  const toolRegistryCache = new WeakMap, DEFAULT_WORKFLOW_TOOL_TIMEOUT_MS = 30000, MAX_WORKFLOW_TOOL_TIMEOUT_MS = 2147483647;
12
13
  export function listMcpTools(engine) {
13
14
  return getToolRegistry(engine).tools.map((tool) => tool.definition);
@@ -44,16 +45,7 @@ function toolRegistrySignature(engine) {
44
45
  return engine.listWorkflowDefinitions().toSorted((left, right) => left.type < right.type ? -1 : left.type > right.type ? 1 : 0).map((definition) => [definition.type, definition.description, definition.inputSchema]);
45
46
  }
46
47
  function toolRegistrySignaturesEqual(left, right) {
47
- if (left.length !== right.length)
48
- return !1;
49
- for (let index = 0;index < left.length; index++) {
50
- const leftEntry = left[index], rightEntry = right[index];
51
- if (leftEntry === void 0 || rightEntry === void 0)
52
- return !1;
53
- if (leftEntry[0] !== rightEntry[0] || leftEntry[1] !== rightEntry[1] || leftEntry[2] !== rightEntry[2])
54
- return !1;
55
- }
56
- return !0;
48
+ return tupleListsEqual(left, right, (leftEntry, rightEntry) => leftEntry[0] === rightEntry[0] && leftEntry[1] === rightEntry[1] && leftEntry[2] === rightEntry[2]);
57
49
  }
58
50
  function buildToolImplementations(engine) {
59
51
  const tools = [...builtInTools()], usedNames = new Set(tools.map((tool) => tool.definition.name));
@@ -0,0 +1 @@
1
+ export declare function tupleListsEqual<Tuple extends readonly unknown[]>(left: ReadonlyArray<Tuple>, right: ReadonlyArray<Tuple>, entryEqual: (leftEntry: Tuple, rightEntry: Tuple) => boolean): boolean;
@@ -0,0 +1,12 @@
1
+ export function tupleListsEqual(left, right, entryEqual) {
2
+ if (left.length !== right.length)
3
+ return !1;
4
+ for (let index = 0;index < left.length; index++) {
5
+ const leftEntry = left[index], rightEntry = right[index];
6
+ if (leftEntry === void 0 || rightEntry === void 0)
7
+ return !1;
8
+ if (!entryEqual(leftEntry, rightEntry))
9
+ return !1;
10
+ }
11
+ return !0;
12
+ }
@@ -99,7 +99,7 @@ export type OperationContext<Input> = {
99
99
  * Common operation fields shared by unary, stream, and subscription kinds.
100
100
  * The discriminated union below adds `kind` and `eventSchema` per kind.
101
101
  */
102
- type OperationDefinitionBase<Input, Output, Element = unknown> = {
102
+ export type OperationDefinitionBase<Input, Output, Element = unknown> = {
103
103
  readonly name: string;
104
104
  readonly mcpExposable: boolean;
105
105
  readonly mcpTool?: McpToolMetadata;