@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.
Files changed (114) 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/cli/help-text.d.ts +3 -3
  5. package/dist/cli/help-text.js +4 -4
  6. package/dist/cli/operation-catalog-snapshot.d.ts +1 -1
  7. package/dist/cli/schedule.js +1 -3
  8. package/dist/cli/serve-registrations.d.ts +3 -3
  9. package/dist/cli/serve-registrations.js +2 -2
  10. package/dist/cli/shutdown.d.ts +11 -0
  11. package/dist/cli/shutdown.js +25 -0
  12. package/dist/cli/validate.d.ts +1 -1
  13. package/dist/cli/version-check.d.ts +1 -1
  14. package/dist/cli/version-check.js +1 -1
  15. package/dist/cli-main.js +10 -29
  16. package/dist/client/http-client-storage.js +7 -35
  17. package/dist/client/http-request.d.ts +8 -9
  18. package/dist/client/http-request.js +3 -25
  19. package/dist/core/aggregate-validation.d.ts +2 -5
  20. package/dist/core/aggregate-validation.js +2 -10
  21. package/dist/core/atomic-state.js +21 -24
  22. package/dist/core/context/parallel-operations.d.ts +0 -2
  23. package/dist/core/context/parallel-operations.js +0 -7
  24. package/dist/core/engine/callback-checkpoint-persistence.d.ts +2 -0
  25. package/dist/core/engine/callback-checkpoint-persistence.js +6 -3
  26. package/dist/core/engine/callback-creators.js +4 -22
  27. package/dist/core/engine/checkpoint-io.d.ts +1 -1
  28. package/dist/core/engine/operations-coordination.js +1 -1
  29. package/dist/core/engine/parallel-dispatch.d.ts +1 -1
  30. package/dist/core/engine/parallel-dispatch.js +1 -1
  31. package/dist/core/engine/review-list-entries.d.ts +1 -1
  32. package/dist/core/engine/review-list-entries.js +6 -30
  33. package/dist/core/engine/schedules.js +4 -1
  34. package/dist/core/engine/timeline-coordinator-detail.d.ts +1 -1
  35. package/dist/core/inline-execution-strategy.js +8 -46
  36. package/dist/core/list-filter-validation.d.ts +2 -5
  37. package/dist/core/list-filter-validation.js +2 -10
  38. package/dist/core/review/index.d.ts +87 -0
  39. package/dist/core/review/index.js +29 -0
  40. package/dist/core/types/schedules.d.ts +13 -31
  41. package/dist/core/validation-issues.d.ts +13 -0
  42. package/dist/core/validation-issues.js +9 -0
  43. package/dist/diagnostics/validate.d.ts +9 -30
  44. package/dist/diagnostics/validate.js +83 -21
  45. package/dist/diagnostics/version-check.d.ts +2 -2
  46. package/dist/http.js +2 -2
  47. package/dist/indexeddb.js +1 -1
  48. package/dist/mcp/session.js +2 -10
  49. package/dist/mcp/tools.js +2 -10
  50. package/dist/mcp/tuple-list-equality.d.ts +1 -0
  51. package/dist/mcp/tuple-list-equality.js +12 -0
  52. package/dist/server/openapi-error-responses.js +0 -14
  53. package/dist/server/operation-catalog/index.d.ts +1 -1
  54. package/dist/server/operation-catalog/raise-fault.d.ts +2 -1
  55. package/dist/server/operation-catalog/types.d.ts +3 -2
  56. package/dist/server/operation-fault.d.ts +1 -4
  57. package/dist/server/operation-fault.js +1 -1
  58. package/dist/server/operation-registry.d.ts +2 -31
  59. package/dist/server/operations/bulk-filter-helpers.d.ts +17 -17
  60. package/dist/server/operations/bulk-filter-helpers.js +16 -37
  61. package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +27 -27
  62. package/dist/server/operations/bulk-signal-workflows.d.ts +26 -26
  63. package/dist/server/operations/create-schedule.js +7 -19
  64. package/dist/server/operations/event-stream-contracts.d.ts +20 -0
  65. package/dist/server/operations/event-stream-contracts.js +67 -0
  66. package/dist/server/operations/fleet-events-sse.js +21 -50
  67. package/dist/server/operations/fleet-events-subscription.js +8 -12
  68. package/dist/server/operations/list-reviews.js +2 -19
  69. package/dist/server/operations/list-workflows.d.ts +43 -43
  70. package/dist/server/operations/list-workflows.js +9 -30
  71. package/dist/server/operations/purge-workflows.d.ts +11 -11
  72. package/dist/server/operations/recover-all.js +1 -10
  73. package/dist/server/operations/schedule-rest-body.d.ts +11 -0
  74. package/dist/server/operations/schedule-rest-body.js +28 -0
  75. package/dist/server/operations/single-workflow-control-operation.d.ts +2 -1
  76. package/dist/server/operations/update-schedule.js +7 -19
  77. package/dist/server/operations/workflow-events-sse.js +29 -67
  78. package/dist/server/operations/workflow-events-subscription.js +9 -27
  79. package/dist/server/runtime/task-polling.js +3 -5
  80. package/dist/server/task-state.d.ts +2 -8
  81. package/dist/server/task-state.js +10 -7
  82. package/dist/storage/bounded-ndjson-response.d.ts +5 -0
  83. package/dist/storage/bounded-ndjson-response.js +33 -0
  84. package/dist/storage/bun-sql.js +52 -49
  85. package/dist/storage/conditional-batch-body.d.ts +7 -0
  86. package/dist/storage/conditional-batch-body.js +14 -0
  87. package/dist/storage/http.js +5 -37
  88. package/dist/storage/lmdb.js +1 -1
  89. package/dist/storage/memory.js +1 -1
  90. package/dist/storage/neon.d.ts +3 -16
  91. package/dist/storage/neon.js +2 -2
  92. package/dist/storage/node-sqlite-loader.d.ts +2 -2
  93. package/dist/storage/node-sqlite.js +32 -17
  94. package/dist/storage/postgres.js +1 -1
  95. package/dist/storage/resolve.js +1 -1
  96. package/dist/storage/scoped-storage.js +1 -1
  97. package/dist/storage/turso.js +1 -1
  98. package/dist/version.d.ts +1 -1
  99. package/dist/version.js +1 -1
  100. package/dist/web-extension.js +1 -1
  101. package/dist/worker/execute-with-interceptors.d.ts +1 -1
  102. package/dist/worker/execute-with-interceptors.js +2 -2
  103. package/dist/worker/index.js +5 -5
  104. package/dist/worker/long-poll.js +3 -4
  105. package/dist/worker/protocol-messages.d.ts +11 -19
  106. package/dist/worker/protocol-schemas.d.ts +8 -8
  107. package/dist/worker/protocol-schemas.js +4 -4
  108. package/dist/worker/protocol-task-result.d.ts +1 -0
  109. package/dist/worker/protocol-task-result.js +1 -3
  110. package/dist/worker/protocol.js +1 -1
  111. package/dist/worker/registry/types.d.ts +2 -7
  112. package/dist/worker/registry.d.ts +3 -9
  113. package/dist/worker/registry.js +2 -5
  114. package/package.json +1 -1
@@ -24,14 +24,11 @@ function checkStatefulWithoutCompensator(workflowType, activity) {
24
24
  }
25
25
  export function validateRegistrations(registrations, activities = []) {
26
26
  const issues = [], workflowTypes = Object.keys(registrations);
27
- for (const activity of activities) {
28
- const retryIssue = checkUnboundedRetry("(standalone)", activity);
29
- if (retryIssue)
30
- issues.push(retryIssue);
31
- const compensatorIssue = checkStatefulWithoutCompensator("(standalone)", activity);
32
- if (compensatorIssue)
33
- issues.push(compensatorIssue);
34
- }
27
+ for (const definition of Object.values(registrations))
28
+ for (const activity of workflowActivities(definition))
29
+ appendActivityIssues(issues, definition.name, activity);
30
+ for (const activity of activities)
31
+ appendActivityIssues(issues, "(standalone)", activity);
35
32
  const hasErrors = issues.some((i) => i.severity === "error");
36
33
  return {
37
34
  workflowCount: workflowTypes.length,
@@ -39,26 +36,91 @@ export function validateRegistrations(registrations, activities = []) {
39
36
  valid: !hasErrors
40
37
  };
41
38
  }
39
+ function appendActivityIssues(issues, workflowType, activity) {
40
+ const retryIssue = checkUnboundedRetry(workflowType, activity);
41
+ if (retryIssue)
42
+ issues.push(retryIssue);
43
+ const compensatorIssue = checkStatefulWithoutCompensator(workflowType, activity);
44
+ if (compensatorIssue)
45
+ issues.push(compensatorIssue);
46
+ }
47
+ function workflowActivities(definition) {
48
+ if (!("activities" in definition) || !isObject(definition.activities))
49
+ return [];
50
+ return Object.values(definition.activities).filter(isActivityDefinition);
51
+ }
42
52
  function collectFromExports(entries, registrations, activities, options) {
43
53
  for (const [key, value] of entries)
44
- if (isWorkflowRegistration(value)) {
45
- if (options.allowOverwrite || !(key in registrations))
46
- registrations[key] = value;
47
- } else if (isActivityDefinition(value)) {
48
- if (options.allowOverwrite || !activities.includes(value))
49
- activities.push(value);
50
- }
54
+ collectExport(key, value, registrations, activities, options);
55
+ }
56
+ function collectExport(key, value, registrations, activities, options) {
57
+ if (isWorkflowDefinition(value)) {
58
+ if (options.allowOverwrite || !Object.hasOwn(registrations, value.name))
59
+ registrations[value.name] = value;
60
+ return;
61
+ }
62
+ if (isActivityDefinition(value)) {
63
+ if (options.allowOverwrite || !activities.includes(value))
64
+ activities.push(value);
65
+ return;
66
+ }
67
+ if (!isObject(value))
68
+ return;
69
+ if (options.depth === 0 && isDefinitionMap(value)) {
70
+ collectFromExports(Object.entries(value), registrations, activities, {
71
+ ...options,
72
+ depth: options.depth + 1
73
+ });
74
+ return;
75
+ }
76
+ assertNotRemovedWorkflowShape(key, value);
51
77
  }
52
78
  export async function loadRegistrationsFromModule(modulePath) {
53
- const mod = await import(resolve(process.cwd(), modulePath)), registrations = {}, activities = [], defaultExport = mod.default;
54
- if (defaultExport !== null && typeof defaultExport === "object")
55
- collectFromExports(Object.entries(defaultExport), registrations, activities, { allowOverwrite: !0 });
79
+ const mod = await import(resolve(process.cwd(), modulePath)), registrations = Object.create(null), activities = [], defaultExport = mod.default;
80
+ if (defaultExport !== void 0)
81
+ collectFromExports([["default", defaultExport]], registrations, activities, {
82
+ allowOverwrite: !0,
83
+ depth: 0
84
+ });
56
85
  const namedEntries = Object.entries(mod).filter(([key]) => key !== "default");
57
- collectFromExports(namedEntries, registrations, activities, { allowOverwrite: !1 });
86
+ collectFromExports(namedEntries, registrations, activities, {
87
+ allowOverwrite: !1,
88
+ depth: 0
89
+ });
58
90
  return { registrations, activities };
59
91
  }
60
- function isWorkflowRegistration(value) {
61
- return typeof value === "object" && value !== null && "handler" in value && typeof value.handler === "function";
92
+ function isObject(value) {
93
+ return typeof value === "object" && value !== null;
94
+ }
95
+ function isRemovedWorkflowShape(value) {
96
+ if (!isObject(value) || !Object.hasOwn(value, "handler"))
97
+ return !1;
98
+ const handler = value.handler;
99
+ if (typeof handler !== "function")
100
+ return !1;
101
+ const functionKind = Object.prototype.toString.call(handler);
102
+ if (functionKind === "[object AsyncGeneratorFunction]")
103
+ return !0;
104
+ if ([
105
+ "version",
106
+ "description",
107
+ "tags",
108
+ "inputSchema",
109
+ "outputSchema",
110
+ "searchAttributes"
111
+ ].some((key) => Object.hasOwn(value, key)))
112
+ return !0;
113
+ return functionKind === "[object Function]" && Object.keys(value).length === 1;
114
+ }
115
+ function assertNotRemovedWorkflowShape(exportName, value) {
116
+ if (isRemovedWorkflowShape(value))
117
+ throw TypeError(`Workflow export "${exportName}" must be a builder-produced workflow definition with its own name. Create it with \`workflow({ name }).execute(handler)\`.`);
118
+ }
119
+ function isDefinitionMap(value) {
120
+ return Object.values(value).some((entry) => isWorkflowDefinition(entry) || isActivityDefinition(entry) || isRemovedWorkflowShape(entry));
121
+ }
122
+ function isWorkflowDefinition(value) {
123
+ return isObject(value) && typeof value.name === "string" && "handler" in value && typeof value.handler === "function";
62
124
  }
63
125
  function isActivityDefinition(value) {
64
126
  if (value === null || typeof value !== "object" && typeof value !== "function")
@@ -7,9 +7,9 @@
7
7
  *
8
8
  * @module diagnostics/version-check
9
9
  */
10
+ import type { WorkflowDefinition } from '../core/types.ts';
10
11
  import type { Storage } from '../storage/interface.ts';
11
12
  import type { VersionCheckReport } from './types.ts';
12
- import type { WorkflowRegistration } from './validate.ts';
13
13
  /**
14
14
  * Scans active (running and pending) workflows in `storage`, groups them by
15
15
  * type, and compares stored workflow versions against currently registered
@@ -31,4 +31,4 @@ import type { WorkflowRegistration } from './validate.ts';
31
31
  * console.log(report.overallVerdict); // 'safe'
32
32
  * ```
33
33
  */
34
- export declare function runVersionCheck(storage: Storage, registrations: Record<string, WorkflowRegistration>): Promise<VersionCheckReport>;
34
+ export declare function runVersionCheck(storage: Storage, registrations: Record<string, WorkflowDefinition>): Promise<VersionCheckReport>;
package/dist/http.js CHANGED
@@ -1,2 +1,2 @@
1
- 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 j(F,G){return await F.get(G)!==null}async function*X(F,G,J){for await(let[Q]of F.scan(G,J))yield Q}async function _(F,G){let J=0;for await(let Q of X(F,G))J++;return J}async function H(F,G){let J=[];for await(let Q of X(F,G))J.push({type:"delete",key:Q});if(J.length===0)return 0;return await F.batch(J),J.length}async function L(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 R(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 C 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 C(F,G)}function T(F){return F.length>0?F.slice(0,-1)+String.fromCharCode(F.charCodeAt(F.length-1)+1):"ÿ"}function o(F,G={}){if(G.gt!==void 0&&F<=G.gt)return!1;if(G.gte!==void 0&&F<G.gte)return!1;if(G.lt!==void 0&&F>=G.lt)return!1;if(G.lte!==void 0&&F>G.lte)return!1;return!0}function e(F,G){if(F===null||G===null)return F===G;if(F.byteLength!==G.byteLength)return!1;for(let J=0;J<F.byteLength;J++)if(F[J]!==G[J])return!1;return!0}async function P(F,G){if(F.has)return F.has(G);return j(F,G)}function K(F,G,J){if(F.keys)return F.keys(G,J);return X(F,G,J)}async function S(F,G){if(F.count)return F.count(G);return _(F,G)}async function O(F,G){if(F.deletePrefix)return F.deletePrefix(G);return H(F,G)}async function b(F,G,J){if(M("conditionalBatch conditions",G.length),M("conditionalBatch operations",J.length),R(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 g(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=g(F.limit);if(Q!==void 0)G.limit=Q;return G}async function v(F,G,J){let Q=V(J);if(F.deleteRange)return F.deleteRange(G,Q);return L(F,G,Q)}function y(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 c(F,G){let J={key:T(F),open:!0};if(G.lt!==void 0&&G.lt<=J.key)J.key=G.lt,J.open=!0;if(G.lte!==void 0&&G.lte<J.key)J.key=G.lte,J.open=!1;return J}function QF(F,G){let J=y(F,G),Q=c(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 I(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,I(this.#J,F))}async get(F){return this.#G.get(this.#F(F))}async put(F,G){await this.#G.put(this.#F(F),G)}async delete(F){await this.#G.delete(this.#F(F))}async*scan(F,G){for await(let[J,Q]of this.#G.scan(this.#F(F),this.#Z(G)))yield[this.#Q(J),Q]}async batch(F){M("batch operations",F.length),await this.#G.batch(F.map((G)=>{if(G.type==="put")return{type:"put",key:this.#F(G.key),value:G.value};return{type:"delete",key:this.#F(G.key)}}))}async conditionalBatch(F,G){return b(this.#G,F.map((J)=>({key:this.#F(J.key),expectedValue:J.expectedValue})),G.map((J)=>{if(J.type==="put")return{type:"put",key:this.#F(J.key),value:J.value};return{type:"delete",key:this.#F(J.key)}}))}async has(F){return P(this.#G,this.#F(F))}async deletePrefix(F){return O(this.#G,this.#F(F))}async deleteRange(F,G){let J=this.#M(V(G));return v(this.#G,this.#F(F),J)}async*keys(F,G){for await(let J of K(this.#G,this.#F(F),this.#Z(G)))yield this.#Q(J)}async count(F){return S(this.#G,this.#F(F))}[Symbol.dispose](){this.#G[Symbol.dispose]()}}function h(F,G){return new W(F,G)}var u=67108864;function m(F){if(F.type==="put")return{type:"put",key:F.key,value:N(F.value)};return{type:"delete",key:F.key}}function k(F){return{key:F.key,expectedValue:F.expectedValue===null?null:N(F.expectedValue)}}function w(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 f(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 l(F){if(F.trim().length===0)return null;let G=w(JSON.parse(F));return[G.key,B(G.value)]}function d(F){if(F>u)throw Error("HTTPStorage scan response exceeded the maximum allowed size.")}async function*p(F){if(F.body===null)return;let G=F.body.getReader(),J=new TextDecoder,Q="",Z=0,$=!1;try{while(!0){let{done:U,value:z}=await G.read();if(U){$=!0;break}Z+=z.byteLength,d(Z),Q+=J.decode(z,{stream:!0});let A=Q.split(`
2
- `);Q=A.pop()??"";for(let x of A)yield x}if(Q+=J.decode(),Q.length>0)yield Q}finally{try{if(!$)await G.cancel()}catch{}G.releaseLock()}}class a{#G;#J;#F;constructor(F){this.#G=F.baseUrl instanceof URL?F.baseUrl:new URL(F.baseUrl),this.#J={...F.headers},this.#F=F.remoteConditionalBatch??!1}capabilities(){return{persistence:"remote",readAfterWrite:"eventual",scanConsistency:"best-effort",atomicBatch:!0,conditionalBatch:this.#F,boundedRangeDelete:!1}}#Q(F){let G=this.#G.href.endsWith("/")?this.#G.href:`${this.#G.href}/`;return new URL(F.replace(/^\/+/,""),G)}#Z(F){return this.#Q(`/v1/storage/${encodeURIComponent(F)}`)}#M(F,G){let J=this.#Q("/v1/storage");return J.searchParams.set("prefix",F),Y(J,"limit",G.limit),Y(J,"reverse",G.reverse),Y(J,"gt",G.gt),Y(J,"gte",G.gte),Y(J,"lt",G.lt),Y(J,"lte",G.lte),J}async#$(F,G={},J=[]){let Q=new Headers(this.#J);for(let[$,U]of new Headers(G.headers).entries())Q.set($,U);let Z=await fetch(F,{...G,headers:Q});if(!Z.ok&&!J.includes(Z.status))throw Error(`HTTPStorage request failed: ${G.method??"GET"} ${F.pathname} returned ${String(Z.status)}.`);return Z}async get(F){let G=await this.#$(this.#Z(F),{method:"GET"},[404]);if(G.status===404)return null;return new Uint8Array(await G.arrayBuffer())}async put(F,G){await this.#$(this.#Z(F),{method:"PUT",headers:{"content-type":"application/octet-stream"},body:new Blob([G])})}async delete(F){await this.#$(this.#Z(F),{method:"DELETE"})}async*scan(F,G={}){let J=await this.#$(this.#M(F,G),{method:"GET",headers:{accept:"application/x-ndjson"}});for await(let Q of p(J)){let Z=l(Q);if(Z!==null)yield Z}}async batch(F){M("batch operations",F.length),await this.#$(this.#Q("/v1/storage/-/batch"),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({operations:F.map(m)})})}async conditionalBatch(F,G){M("conditionalBatch conditions",F.length),M("conditionalBatch operations",G.length);let J=await this.#$(this.#Q("/v1/storage/-/conditional-batch"),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({conditions:F.map(k),operations:G.map(m)})});return f(await J.json())}has(F){return j(this,F)}async*keys(F,G){yield*X(this,F,G)}count(F){return _(this,F)}deletePrefix(F){return H(this,F)}deleteRange(F,G){return L(this,F,V(G))}scoped(F){return h(this,F)}[Symbol.dispose](){}}export{a as HTTPStorage};
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 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
+ }
@@ -10,20 +10,6 @@ export const ERROR_SCHEMA = {
10
10
  type: "string",
11
11
  description: "Fine-grained public Weft error code when one is available"
12
12
  },
13
- missingTypes: {
14
- type: "array",
15
- items: { type: "string" },
16
- description: "Established recovery-conflict field; also present under data"
17
- },
18
- missingWorkflowCount: {
19
- type: "integer",
20
- minimum: 0,
21
- description: "Established recovery-conflict field; also present under data"
22
- },
23
- samplesTruncated: {
24
- type: "boolean",
25
- description: "Established recovery-conflict field; also present under data"
26
- },
27
13
  data: {
28
14
  type: "object",
29
15
  description: "Audited fault-specific context; omitted when no fields are safe to expose",
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @module server/operation-catalog
10
10
  */
11
- export type { FaultCode } from '../operation-fault.ts';
11
+ export type { FaultCode } from '../../core/fault-code.ts';
12
12
  export { catalogActivities, catalogActivity } from './activity-adapter.ts';
13
13
  export type { CatalogActivityDefinition } from './activity-adapter.ts';
14
14
  export { DISPATCH_ALLOWLIST } from './dispatch-allowlist.ts';
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * @module server/operation-catalog/raise-fault
5
5
  */
6
- import type { FaultCode, OperationFault } from '../operation-fault.ts';
6
+ import type { FaultCode } from '../../core/fault-code.ts';
7
+ import type { OperationFault } from '../operation-fault.ts';
7
8
  import type { ErasedOperation } from './types.ts';
8
9
  /**
9
10
  * Fault codes that every operation can raise through the shared pipeline
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
+ import type { FaultCode } from '../../core/fault-code.ts';
2
3
  import type { AccessPolicy } from '../authorization.ts';
3
- import type { FaultCode, OperationFault, TransportKind } from '../operation-fault.ts';
4
+ import type { OperationFault, TransportKind } from '../operation-fault.ts';
4
5
  import type { Principal } from '../principal.ts';
5
6
  /**
6
7
  * Regex for the canonical `weft.<segment>(.<segment>)+` operation-name form.
@@ -98,7 +99,7 @@ export type OperationContext<Input> = {
98
99
  * Common operation fields shared by unary, stream, and subscription kinds.
99
100
  * The discriminated union below adds `kind` and `eventSchema` per kind.
100
101
  */
101
- type OperationDefinitionBase<Input, Output, Element = unknown> = {
102
+ export type OperationDefinitionBase<Input, Output, Element = unknown> = {
102
103
  readonly name: string;
103
104
  readonly mcpExposable: boolean;
104
105
  readonly mcpTool?: McpToolMetadata;
@@ -36,7 +36,6 @@
36
36
  */
37
37
  import type { FaultCode } from '../core/fault-code.ts';
38
38
  import { type WeftErrorCode } from '../core/weft-error.ts';
39
- export type { FaultCode };
40
39
  /** Transport identifiers as seen by `executeOperation`. */
41
40
  export type TransportKind = 'http-rest' | 'jsonRpcHttp' | 'jsonRpcWebSocket' | 'jsonRpcStdio';
42
41
  /** A flattened zod issue, kept loose so we don't pin a zod version here. */
@@ -170,10 +169,8 @@ export type RestFaultBody = {
170
169
  * `{ "error": "Internal server error" }`, regardless of response overrides.
171
170
  */
172
171
  export declare function shapeOperationFaultAsJson(fault: OperationFault, options?: RestFaultResponseOptions): Response;
173
- /** Canonical flat REST response used by bindings and route-dispatch fallback. */
172
+ /** Canonical REST response used by bindings and route-dispatch fallback. */
174
173
  export declare function shapeRestFaultAsJson(fault: OperationFault, options?: RestFaultResponseOptions): Response;
175
- /** Build the audited body for bespoke REST shapers that retain extra legacy fields. */
176
- export declare function shapeRestFaultBody(fault: OperationFault, message?: string): RestFaultBody;
177
174
  /**
178
175
  * JSON-RPC error code for each fault. Reserved codes (-32700..-32603) keep
179
176
  * the spec meanings (`InvalidParams`, `MethodNotFound`); Weft domain codes
@@ -61,7 +61,7 @@ export function shapeRestFaultAsJson(fault, options = {}) {
61
61
  headers: { "Content-Type": "application/json" }
62
62
  });
63
63
  }
64
- export function shapeRestFaultBody(fault, message) {
64
+ function shapeRestFaultBody(fault, message) {
65
65
  if (fault.code === "EngineFailure")
66
66
  return { error: "Internal server error" };
67
67
  const error = message ?? fault.message, weftCode = weftCodeFromFaultData(fault.data), data = restDataFromFault(fault), body = { error };
@@ -17,9 +17,7 @@
17
17
  * cast required at the registry boundary.
18
18
  */
19
19
  import type { z } from 'zod';
20
- import type { AccessPolicy } from './authorization.ts';
21
- import type { AuthorizationDecision, McpToolMetadata, OperationContext, OperationDefinition, OperationInvocationResult, ParameterizedAccessHint, TransportAvailability, UnknownKeyPolicy } from './operation-catalog/types.ts';
22
- import type { FaultCode } from './operation-fault.ts';
20
+ import type { OperationDefinition, OperationDefinitionBase } from './operation-catalog/types.ts';
23
21
  export { isValidOperationName, validateOperationName } from './operation-catalog.ts';
24
22
  /**
25
23
  * Input shape for `defineOperation`. Mirrors `OperationDefinition` but
@@ -31,35 +29,8 @@ export { isValidOperationName, validateOperationName } from './operation-catalog
31
29
  * passes. When present, BOTH `access` AND `authorize` must permit the
32
30
  * call: the policy runs first, then the parameter-aware hook.
33
31
  */
34
- type OperationDefinitionInputBase<Input, Output, Element = unknown> = {
35
- readonly name: string;
36
- readonly mcpExposable: boolean;
37
- readonly mcpTool?: McpToolMetadata;
38
- readonly summary: string;
39
- /**
40
- * Optional longer-form prose. See {@link OperationDefinition} for the
41
- * contract and the surfaces (OpenAPI, OpenRPC, CLI `--describe`, MCP
42
- * discovery) that read it. `summary` stays mandatory and short.
43
- */
44
- readonly description?: string;
32
+ type OperationDefinitionInputBase<Input, Output, Element = unknown> = Omit<OperationDefinitionBase<Input, Output, Element>, 'tags'> & {
45
33
  readonly tags?: ReadonlyArray<string>;
46
- /**
47
- * Whether invoking this operation irreversibly mutates state. Required —
48
- * there is deliberately no default, so every operation author must make
49
- * the call explicitly. See {@link OperationDefinition} for the contract
50
- * and the consumers that read it.
51
- */
52
- readonly destructive: boolean;
53
- readonly inputSchema: z.ZodType<Input>;
54
- readonly outputSchema: z.ZodType<Output>;
55
- readonly access: AccessPolicy;
56
- readonly parameterizedAccess?: ParameterizedAccessHint;
57
- readonly producibleFaults?: ReadonlyArray<FaultCode>;
58
- readonly discoverable?: boolean;
59
- readonly transports: TransportAvailability;
60
- readonly unknownKeyPolicy: UnknownKeyPolicy;
61
- readonly authorize?: (context: OperationContext<Input>) => Promise<AuthorizationDecision>;
62
- readonly invoke: (context: OperationContext<Input>) => Promise<OperationInvocationResult<Output, Element>>;
63
34
  };
64
35
  /**
65
36
  * Discriminated input for `defineOperation`, mirroring the discriminated
@@ -1,46 +1,46 @@
1
1
  import { z } from 'zod';
2
- import type { AttributeFilterScalarValue, BulkOperationCommitOptions, BulkOperationDryRunOptions, FailureCategory, ListFilter, SearchAttributeValue, WorkflowStatus } from '../../core/types.ts';
2
+ import type { BulkOperationCommitOptions, BulkOperationDryRunOptions, ListFilter, WorkflowStatus } from '../../core/types.ts';
3
3
  import type { OperationFault } from '../operation-fault.ts';
4
4
  import type { Principal } from '../principal.ts';
5
5
  import type { RestInputContext } from '../rest-binding.ts';
6
6
  export declare const bulkListFilterInputSchema: z.ZodObject<{
7
- status: z.ZodOptional<z.ZodUnion<readonly [z.ZodCustom<WorkflowStatus, WorkflowStatus>, z.ZodArray<z.ZodCustom<WorkflowStatus, WorkflowStatus>>]>>;
7
+ status: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<WorkflowStatus, unknown, z.core.$ZodTypeInternals<WorkflowStatus, unknown>>, z.ZodArray<z.ZodType<WorkflowStatus, unknown, z.core.$ZodTypeInternals<WorkflowStatus, unknown>>>]>>;
8
8
  type: z.ZodOptional<z.ZodString>;
9
9
  scheduleId: z.ZodOptional<z.ZodString>;
10
10
  parentWorkflowId: z.ZodOptional<z.ZodString>;
11
11
  parentWorkflowExecutionToken: z.ZodOptional<z.ZodString>;
12
12
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
13
13
  attributes: z.ZodOptional<z.ZodArray<z.ZodObject<{
14
- key: z.ZodString;
15
- value: z.ZodOptional<z.ZodCustom<SearchAttributeValue, SearchAttributeValue>>;
16
- gt: z.ZodOptional<z.ZodCustom<AttributeFilterScalarValue, AttributeFilterScalarValue>>;
17
- lt: z.ZodOptional<z.ZodCustom<AttributeFilterScalarValue, AttributeFilterScalarValue>>;
18
- gte: z.ZodOptional<z.ZodCustom<AttributeFilterScalarValue, AttributeFilterScalarValue>>;
19
- lte: z.ZodOptional<z.ZodCustom<AttributeFilterScalarValue, AttributeFilterScalarValue>>;
14
+ key: z.ZodUnion<readonly [z.ZodString, z.ZodAny]>;
15
+ value: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
16
+ gt: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
17
+ lt: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
18
+ gte: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
19
+ lte: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
20
20
  }, z.core.$strip>>>;
21
- limit: z.ZodOptional<z.ZodNumber>;
22
21
  offset: z.ZodOptional<z.ZodNumber>;
23
22
  idPrefix: z.ZodOptional<z.ZodString>;
24
- failureCategory: z.ZodOptional<z.ZodUnion<readonly [z.ZodCustom<FailureCategory, FailureCategory>, z.ZodArray<z.ZodCustom<FailureCategory, FailureCategory>>]>>;
25
23
  createdAt: z.ZodOptional<z.ZodObject<{
26
24
  gte: z.ZodOptional<z.ZodNumber>;
27
- gt: z.ZodOptional<z.ZodNumber>;
28
25
  lte: z.ZodOptional<z.ZodNumber>;
26
+ gt: z.ZodOptional<z.ZodNumber>;
29
27
  lt: z.ZodOptional<z.ZodNumber>;
30
- }, z.core.$strip>>;
28
+ }, z.core.$strict>>;
31
29
  updatedAt: z.ZodOptional<z.ZodObject<{
32
30
  gte: z.ZodOptional<z.ZodNumber>;
33
- gt: z.ZodOptional<z.ZodNumber>;
34
31
  lte: z.ZodOptional<z.ZodNumber>;
32
+ gt: z.ZodOptional<z.ZodNumber>;
35
33
  lt: z.ZodOptional<z.ZodNumber>;
36
- }, z.core.$strip>>;
34
+ }, z.core.$strict>>;
37
35
  executionDeadline: z.ZodOptional<z.ZodObject<{
38
36
  gte: z.ZodOptional<z.ZodNumber>;
39
- gt: z.ZodOptional<z.ZodNumber>;
40
37
  lte: z.ZodOptional<z.ZodNumber>;
38
+ gt: z.ZodOptional<z.ZodNumber>;
41
39
  lt: z.ZodOptional<z.ZodNumber>;
42
- }, z.core.$strip>>;
43
- }, z.core.$strip>;
40
+ }, z.core.$strict>>;
41
+ failureCategory: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<import("../../index.ts").FailureCategory, unknown, z.core.$ZodTypeInternals<import("../../index.ts").FailureCategory, unknown>>, z.ZodArray<z.ZodType<import("../../index.ts").FailureCategory, unknown, z.core.$ZodTypeInternals<import("../../index.ts").FailureCategory, unknown>>>]>>;
42
+ limit: z.ZodOptional<z.ZodNumber>;
43
+ }, z.core.$strict>;
44
44
  export type BulkListFilterInput = z.infer<typeof bulkListFilterInputSchema>;
45
45
  export declare const bulkOperationControlInputSchema: z.ZodObject<{
46
46
  dryRun: z.ZodOptional<z.ZodBoolean>;
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { assertScopedBulkWorkflowFilter } from "../../core/bulk-workflow-filter.js";
3
- import { isFailureCategory } from "../../core/failure-categories.js";
3
+ import { listFilterObjectSchema, normalizeListFilter } from "../../core/list-filter-validation.js";
4
4
  import { coerceStartWorkflowTags } from "../../core/start-workflow-validation.js";
5
5
  import {
6
6
  MAX_BULK_CONFIRMATION_TOKEN_LENGTH,
@@ -9,38 +9,8 @@ import {
9
9
  import { readRestTextBody } from "../rest-body.js";
10
10
  import { parseOptionalFailureCategoryFilter } from "./failure-category-filter.js";
11
11
  import { invalidParamsFault, isOperationFault } from "./operation-helpers.js";
12
- const workflowStatusSchema = z.custom((value) => typeof value === "string"), searchAttributeValueSchema = z.custom((value) => {
13
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
14
- return !0;
15
- return Array.isArray(value) && value.every((entry) => typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean");
16
- }), attributeFilterScalarValueSchema = z.custom((value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean"), attributeFilterSchema = z.object({
17
- key: z.string().min(1),
18
- value: searchAttributeValueSchema.optional(),
19
- gt: attributeFilterScalarValueSchema.optional(),
20
- lt: attributeFilterScalarValueSchema.optional(),
21
- gte: attributeFilterScalarValueSchema.optional(),
22
- lte: attributeFilterScalarValueSchema.optional()
23
- }), failureCategorySchema = z.custom(isFailureCategory), timeRangeSchema = z.object({
24
- gte: z.number().optional(),
25
- gt: z.number().optional(),
26
- lte: z.number().optional(),
27
- lt: z.number().optional()
28
- });
29
- export const bulkListFilterInputSchema = z.object({
30
- status: z.union([workflowStatusSchema, z.array(workflowStatusSchema)]).optional(),
31
- type: z.string().optional(),
32
- scheduleId: z.string().min(1).optional(),
33
- parentWorkflowId: z.string().min(1).optional(),
34
- parentWorkflowExecutionToken: z.string().min(1).optional(),
35
- tags: z.array(z.string()).optional(),
36
- attributes: z.array(attributeFilterSchema).optional(),
37
- limit: z.number().int().min(0).optional(),
38
- offset: z.number().int().min(0).optional(),
39
- idPrefix: z.string().optional(),
40
- failureCategory: z.union([failureCategorySchema, z.array(failureCategorySchema)]).optional(),
41
- createdAt: timeRangeSchema.optional(),
42
- updatedAt: timeRangeSchema.optional(),
43
- executionDeadline: timeRangeSchema.optional()
12
+ export const bulkListFilterInputSchema = listFilterObjectSchema.extend({
13
+ limit: z.number().int().min(0).optional()
44
14
  }), bulkOperationControlInputSchema = z.object({
45
15
  dryRun: z.boolean().optional(),
46
16
  confirmationToken: z.string().min(1).max(MAX_BULK_CONFIRMATION_TOKEN_LENGTH).optional(),
@@ -223,7 +193,7 @@ export function parseBulkListFilterFromBody(body) {
223
193
  const filterRecord = rawFilter, filter = {};
224
194
  for (const applyDimension of BULK_FILTER_DIMENSION_PARSERS)
225
195
  applyDimension(filter, filterRecord);
226
- return filter;
196
+ return normalizeBulkListFilter(filter);
227
197
  }
228
198
  const TIME_RANGE_BOUNDS = ["gte", "gt", "lte", "lt"];
229
199
  function parseOptionalTimeRange(value) {
@@ -254,7 +224,13 @@ export function listFilterFromBulkInput(input) {
254
224
  applyBasicBulkFilterFields(filter, input);
255
225
  applyExtendedBulkFilterFields(filter, input);
256
226
  applyBulkTimeRangeFields(filter, input);
257
- return filter;
227
+ return normalizeBulkListFilter(filter);
228
+ }
229
+ function normalizeBulkListFilter(filter) {
230
+ const limit = filter.limit;
231
+ delete filter.limit;
232
+ const normalized = normalizeListFilter(filter);
233
+ return limit === void 0 ? normalized : { ...normalized, limit };
258
234
  }
259
235
  function applyBasicBulkFilterFields(filter, input) {
260
236
  if (input.status !== void 0)
@@ -272,8 +248,11 @@ function applyBasicBulkFilterFields(filter, input) {
272
248
  }
273
249
  function copyAttributeFilter(attribute) {
274
250
  const filter = { key: attribute.key };
275
- if (attribute.value !== void 0)
251
+ if (attribute.value !== void 0) {
252
+ if (!isJsonSearchAttributeValue(attribute.value))
253
+ throw Error('Field "filter.attributes[].value" must be a string, number, boolean, or scalar array');
276
254
  filter.value = attribute.value;
255
+ }
277
256
  if (attribute.gt !== void 0)
278
257
  filter.gt = copyAttributeRangeBound(attribute.gt, "gt");
279
258
  if (attribute.lt !== void 0)
@@ -285,7 +264,7 @@ function copyAttributeFilter(attribute) {
285
264
  return filter;
286
265
  }
287
266
  function copyAttributeRangeBound(value, property) {
288
- if (Array.isArray(value))
267
+ if (!isJsonSearchAttributeValue(value) || Array.isArray(value))
289
268
  throw Error(`Field "filter.attributes[].${property}" must be a string, number, or boolean`);
290
269
  return value;
291
270
  }