@lostgradient/weft 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli/api.d.ts +2 -0
- package/dist/cli/api.js +3 -4
- package/dist/cli/generated/operation-catalog.snapshot.json +5167 -0
- package/dist/cli/generated/operation-client.generated.d.ts +119 -10
- package/dist/cli/generated/operation-client.generated.js +74 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/operation-catalog-snapshot.d.ts +11 -2
- package/dist/cli/operation-catalog-snapshot.js +14 -5
- package/dist/cli/operation-client-runtime.d.ts +29 -0
- package/dist/cli-main.js +227 -401
- package/dist/client/client-storage.d.ts +24 -0
- package/dist/client/client-storage.js +14 -0
- package/dist/client/handle-delegation.d.ts +3 -3
- package/dist/client/handle-delegation.js +2 -2
- package/dist/client/http-client-requests.d.ts +5 -3
- package/dist/client/http-client-requests.js +20 -2
- package/dist/client/http-client-storage.d.ts +3 -0
- package/dist/client/http-client-storage.js +110 -0
- package/dist/client/http-client.d.ts +9 -6
- package/dist/client/http-client.js +13 -18
- package/dist/client/http-operations.d.ts +3 -1
- package/dist/client/http-operations.js +84 -2
- package/dist/client/http-request.d.ts +35 -6
- package/dist/client/http-request.js +31 -10
- package/dist/client/in-process-operations.d.ts +2 -2
- package/dist/client/in-process-operations.js +2 -2
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +18 -0
- package/dist/client/interface.d.ts +26 -26
- package/dist/client/local.d.ts +9 -6
- package/dist/client/local.js +9 -4
- package/dist/client/search-params.js +10 -6
- package/dist/client/start-body.d.ts +3 -1
- package/dist/client/start-body.js +9 -0
- package/dist/connection.d.ts +8 -0
- package/dist/connection.js +41 -17
- package/dist/core/bulk-workflow-filter.d.ts +2 -1
- package/dist/core/bulk-workflow-filter.js +5 -1
- package/dist/core/engine/async-activity-records.d.ts +12 -1
- package/dist/core/engine/async-activity-records.js +81 -2
- package/dist/core/engine/bulk-operations-purge.js +16 -1
- package/dist/core/engine/bulk-operations-shared.js +2 -0
- package/dist/core/engine/callback-creators-core.js +2 -1
- package/dist/core/engine/callback-creators-schedule.d.ts +2 -1
- package/dist/core/engine/callback-creators-schedule.js +3 -3
- package/dist/core/engine/checkpoint-reads.js +11 -1
- package/dist/core/engine/child-workflow.js +15 -6
- package/dist/core/engine/construction.js +3 -0
- package/dist/core/engine/disposal.js +2 -0
- package/dist/core/engine/engine-internal-types.d.ts +4 -1
- package/dist/core/engine/fenced-write.d.ts +5 -3
- package/dist/core/engine/finalizer-status.d.ts +10 -0
- package/dist/core/engine/finalizer-status.js +82 -0
- package/dist/core/engine/index.d.ts +69 -2
- package/dist/core/engine/index.js +71 -8
- package/dist/core/engine/internals.d.ts +3 -0
- package/dist/core/engine/lease-health.d.ts +64 -0
- package/dist/core/engine/lease-health.js +0 -0
- package/dist/core/engine/lease-manager.d.ts +4 -2
- package/dist/core/engine/lease-manager.js +32 -4
- package/dist/core/engine/lifecycle/recovered-services.js +0 -2
- package/dist/core/engine/lifecycle/shared.d.ts +28 -0
- package/dist/core/engine/lifecycle/start-batch.js +12 -0
- package/dist/core/engine/lifecycle/start.d.ts +1 -1
- package/dist/core/engine/lifecycle/start.js +34 -5
- package/dist/core/engine/lifecycle/transition.js +19 -9
- package/dist/core/engine/operations-coordination.d.ts +1 -12
- package/dist/core/engine/operations-coordination.js +57 -10
- package/dist/core/engine/operations-speculate.d.ts +1 -1
- package/dist/core/engine/operations-speculate.js +19 -5
- package/dist/core/engine/registration.js +14 -0
- package/dist/core/engine/schedule-handle.d.ts +4 -4
- package/dist/core/engine/schedule-handle.js +2 -2
- package/dist/core/engine/schedule-overlap.d.ts +11 -0
- package/dist/core/engine/schedule-overlap.js +50 -0
- package/dist/core/engine/schedule-run.d.ts +11 -3
- package/dist/core/engine/schedule-run.js +27 -4
- package/dist/core/engine/schedule-timer.js +10 -1
- package/dist/core/engine/schedules.d.ts +5 -4
- package/dist/core/engine/schedules.js +62 -56
- package/dist/core/engine/state-utilities.js +1 -1
- package/dist/core/engine/storage-io.d.ts +12 -0
- package/dist/core/engine/storage-io.js +49 -10
- package/dist/core/engine/termination/finalizer-claim.d.ts +8 -6
- package/dist/core/engine/termination/finalizer-claim.js +2 -1
- package/dist/core/engine/termination/finalizer.js +10 -14
- package/dist/core/engine/timeline-coordinator-constants.d.ts +3 -0
- package/dist/core/engine/timeline-coordinator-constants.js +1 -0
- package/dist/core/engine/timeline-coordinator-detail.d.ts +13 -0
- package/dist/core/engine/timeline-coordinator-detail.js +76 -0
- package/dist/core/engine/validation/schedule-options.d.ts +8 -1
- package/dist/core/engine/validation/schedule-options.js +18 -0
- package/dist/core/engine/validation/schedule.d.ts +1 -1
- package/dist/core/engine/validation/schedule.js +27 -3
- package/dist/core/engine/validation.js +66 -2
- package/dist/core/engine/workflow-state-stream.d.ts +5 -1
- package/dist/core/engine/workflow-state-stream.js +37 -14
- package/dist/core/events/schedule-events.d.ts +3 -4
- package/dist/core/events/workflow-events.d.ts +2 -1
- package/dist/core/list-filter-validation.d.ts +3 -0
- package/dist/core/list-filter-validation.js +11 -0
- package/dist/core/registry-snapshot.d.ts +32 -0
- package/dist/core/registry-snapshot.js +28 -0
- package/dist/core/review/index.d.ts +4 -4
- package/dist/core/types/activity.d.ts +52 -5
- package/dist/core/types/bulk.d.ts +1 -0
- package/dist/core/types/definition-schema-to-json.d.ts +11 -0
- package/dist/core/types/definition-schema-to-json.js +11 -2
- package/dist/core/types/list-options.d.ts +6 -0
- package/dist/core/types/options.d.ts +6 -5
- package/dist/core/types/reviews.d.ts +2 -2
- package/dist/core/types/schedules.d.ts +45 -2
- package/dist/core/types/services-resolution.d.ts +5 -5
- package/dist/core/types/state.d.ts +64 -0
- package/dist/core/types/workflow-log.d.ts +3 -2
- package/dist/core/types/workflow-observability.d.ts +50 -0
- package/dist/core/types/workflow-observability.js +0 -0
- package/dist/core/types/workflow-registry.d.ts +7 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.js +1 -0
- package/dist/http.js +2 -0
- package/dist/index.d.ts +4 -3
- package/dist/indexeddb.js +1 -0
- package/dist/json-schema.js +3 -3
- package/dist/mcp/cli.js +63 -61
- package/dist/mcp/http.d.ts +7 -2
- package/dist/mcp/session.d.ts +3 -3
- package/dist/mcp/session.js +3 -2
- package/dist/mcp/stdio.d.ts +7 -2
- package/dist/observability/index.js +2 -2
- package/dist/runtime/portable.d.ts +33 -0
- package/dist/runtime/portable.js +17 -6
- package/dist/server/access-policy-metadata.d.ts +92 -0
- package/dist/server/access-policy-metadata.js +78 -0
- package/dist/server/engine-event-feed-backend.d.ts +22 -3
- package/dist/server/fault-to-http.d.ts +3 -7
- package/dist/server/fault-to-http.js +2 -34
- package/dist/server/fleet-event-feed.d.ts +65 -0
- package/dist/server/handler/index.d.ts +11 -2
- package/dist/server/handler/index.js +8 -1
- package/dist/server/handler/route-dispatch.d.ts +10 -3
- package/dist/server/handler/route-dispatch.js +19 -4
- package/dist/server/handler.js +1 -56
- package/dist/server/index.d.ts +13 -2
- package/dist/server/index.js +88 -64
- package/dist/server/interactive-operations.js +2 -0
- package/dist/server/openapi-error-responses.js +55 -4
- package/dist/server/openapi.d.ts +3 -1
- package/dist/server/openapi.js +4 -0
- package/dist/server/openrpc-document-schema.d.ts +64 -0
- package/dist/server/openrpc-document-schema.js +6 -26
- package/dist/server/openrpc.d.ts +4 -0
- package/dist/server/openrpc.js +9 -33
- package/dist/server/operation-fault.d.ts +24 -7
- package/dist/server/operation-fault.js +65 -13
- package/dist/server/operations/aggregate-workflows.d.ts +6 -0
- package/dist/server/operations/aggregate-workflows.js +3 -2
- package/dist/server/operations/async-activity.d.ts +14 -0
- package/dist/server/operations/async-activity.js +88 -4
- package/dist/server/operations/bulk-filter-helpers.d.ts +3 -0
- package/dist/server/operations/bulk-filter-helpers.js +27 -3
- package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +6 -0
- package/dist/server/operations/bulk-signal-workflows.d.ts +6 -0
- package/dist/server/operations/get-stream-chunks.js +2 -7
- package/dist/server/operations/get-system-lease.d.ts +19 -0
- package/dist/server/operations/get-system-lease.js +48 -0
- package/dist/server/operations/get-workflow-observability.d.ts +24 -0
- package/dist/server/operations/get-workflow-observability.js +80 -0
- package/dist/server/operations/get-workflow-result.js +2 -2
- package/dist/server/operations/get-workflow.d.ts +2 -2
- package/dist/server/operations/list-filter-query-extractor.js +15 -0
- package/dist/server/operations/list-workflows.d.ts +6 -0
- package/dist/server/operations/list-workflows.js +12 -3
- package/dist/server/operations/operation-helpers.d.ts +9 -18
- package/dist/server/operations/operation-helpers.js +5 -23
- package/dist/server/operations/purge-workflows.d.ts +3 -0
- package/dist/server/operations/recover-all.js +2 -1
- package/dist/server/operations/single-workflow-tag-mutation.js +2 -2
- package/dist/server/operations/sse-stream.js +2 -7
- package/dist/server/operations/storage-capabilities.d.ts +34 -0
- package/dist/server/operations/storage-capabilities.js +38 -0
- package/dist/server/operations/storage.js +8 -17
- package/dist/server/operations/stream-workflow-sse.js +3 -9
- package/dist/server/operations/submit-review-decision.d.ts +2 -0
- package/dist/server/operations/submit-review-decision.js +19 -2
- package/dist/server/operations/update-schedule.d.ts +8 -0
- package/dist/server/operations/update-schedule.js +70 -7
- package/dist/server/operations/workflow-events-sse.js +2 -2
- package/dist/server/replay-live-feed-internals.d.ts +19 -0
- package/dist/server/replay-live-feed-internals.js +76 -0
- package/dist/server/rest-binding.d.ts +7 -6
- package/dist/server/rest-bindings.d.ts +2 -13
- package/dist/server/rest-bindings.js +19 -10
- package/dist/server/runtime/authentication-bridge.d.ts +2 -2
- package/dist/server/serve-internals.js +3 -3
- package/dist/server/task-queue.d.ts +7 -5
- package/dist/server/workflow-event-feed.d.ts +100 -11
- package/dist/server/workflow-event-feed.js +1 -140
- package/dist/service-worker/index.d.ts +8 -2
- package/dist/service-worker/index.js +37 -56
- package/dist/service-worker/setup.d.ts +6 -2
- package/dist/storage/auto.js +1 -1
- package/dist/storage/bun-sql.js +3 -3
- package/dist/storage/capabilities.d.ts +1 -1
- package/dist/storage/cloudflare-durable-object-sql.d.ts +75 -0
- package/dist/storage/cloudflare-durable-object-sql.js +0 -0
- package/dist/storage/cloudflare-value-codec.d.ts +67 -0
- package/dist/storage/cloudflare-value-codec.js +46 -0
- package/dist/storage/cloudflare.d.ts +140 -0
- package/dist/storage/cloudflare.js +127 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/http.js +200 -2
- package/dist/storage/index.d.ts +8 -1
- package/dist/storage/indexeddb.js +311 -1
- package/dist/storage/interface.d.ts +16 -4
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +4 -0
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +4 -4
- package/dist/storage/node-sqlite.js +3 -3
- package/dist/storage/postgres-key-value-queries.d.ts +6 -0
- package/dist/storage/postgres-key-value-queries.js +2 -3
- package/dist/storage/postgres.js +4 -4
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/sql-identifier.d.ts +35 -0
- package/dist/storage/sql-identifier.js +5 -0
- package/dist/storage/sqlite-key-value-queries.d.ts +11 -6
- package/dist/storage/sqlite-key-value-queries.js +3 -3
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/storage/typed-storage.js +138 -2
- package/dist/storage/web-extension.js +298 -1
- package/dist/testing/index.js +21 -60
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -0
- package/dist/worker/protocol.js +1 -1
- package/package.json +8 -3
package/dist/storage/http.js
CHANGED
|
@@ -1,2 +1,200 @@
|
|
|
1
|
-
var u=Object.defineProperty;var k=(F)=>F;function w(F,G){this[F]=k.bind(null,G)}var JF=(F,G)=>{for(var J in G)u(F,J,{get:G[J],enumerable:!0,configurable:!0,set:w.bind(G,J)})};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 R(F){let G=atob(F),J=new Uint8Array(G.length);for(let Y=0;Y<G.length;Y+=1)J[Y]=G.charCodeAt(Y);return J}function D(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[Y]of F.scan(G,J))yield Y}async function W(F,G){let J=0;for await(let Y of X(F,G))J++;return J}async function H(F,G){let J=[];for await(let Y of X(F,G))J.push({type:"delete",key:Y});if(J.length===0)return 0;return await F.batch(J),J.length}async function L(F,G,J){let Y=[];for await(let Z of X(F,G,J))Y.push({type:"delete",key:Z});if(Y.length===0)return 0;return await F.batch(Y),Y.length}function q(F,G,J){if(!F.capabilities()[G])throw Error(`Feature "${J}" requires storage capability "${G}", but this storage backend does not provide it.`)}var S="default";var T=1e4,jF=1e4;class K extends Error{code="StorageBatchOperationLimitExceededError";cap=T;count;target;constructor(F,G){super(`${F} count ${G} exceeds MAX_BATCH_OPERATIONS (${T}).`);this.name="StorageBatchOperationLimitExceededError",this.target=F,this.count=G}}function $(F,G){if(G>T)throw new K(F,G)}function O(F){return F.length>0?F.slice(0,-1)+String.fromCharCode(F.charCodeAt(F.length-1)+1):"ÿ"}function WF(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 HF(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 h(F,G){if(F.has)return F.has(G);return j(F,G)}function b(F,G,J){if(F.keys)return F.keys(G,J);return X(F,G,J)}async function v(F,G){if(F.count)return F.count(G);return W(F,G)}async function m(F,G){if(F.deletePrefix)return F.deletePrefix(G);return H(F,G)}async function LF(F,G){$("batch operations",G.length),await F.batch(G)}async function x(F,G,J){if($("conditionalBatch conditions",G.length),$("conditionalBatch operations",J.length),q(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 Q(F){return encodeURIComponent(F)}function UF(F){return decodeURIComponent(F)}function NF(F){try{return decodeURIComponent(F)}catch{return null}}var _=(F)=>String(F).padStart(16,"0"),f="0",l="1",P=(F,G,J,Y)=>`sig:${Q(F)}:${Q(G)}:${Y}:${Q(J)}`,DF={workflow:(F)=>`wf:${Q(F)}`,checkpoint:(F)=>`wf:${Q(F)}:ckpt`,checkpointHistory:(F,G)=>`wf:${Q(F)}:ckpt:${String(G).padStart(10,"0")}`,timelinePrefix:(F)=>`wf:${Q(F)}:timeline:`,timeline:(F,G)=>`wf:${Q(F)}:timeline:${String(G).padStart(10,"0")}`,schedule:(F)=>`schedule:${Q(F)}`,scheduleTick:(F,G)=>`schedule-due:${String(F).padStart(16,"0")}:${Q(G)}`,scheduleRun:(F)=>`schedule-run:${Q(F)}`,operation:(F,G,J)=>`op:${F}:${_(G)}:${J}`,operationInflight:(F)=>`op:inflight:${F}`,operationQueued:(F)=>`op:queued:${F}`,operationResolved:(F)=>`op:resolved:${F}`,operationDeadLetterPrefix:()=>"op:dead-letter:",operationDeadLetter:(F)=>`op:dead-letter:${F}`,bulkOperationAuditPrefix:()=>"audit:bulk:",bulkOperationAudit:(F,G,J)=>`audit:bulk:${_(F)}:${Q(G)}:${Q(J)}`,operationResolvedByTimePrefix:()=>"op:resolved-by-time:",operationResolvedByTime:(F,G)=>`op:resolved-by-time:${_(F)}:${Q(G)}`,asyncActivity:(F,G)=>`async-act:v1:${Q(F)}:${Q(G)}`,asyncActivityResolution:(F,G)=>`async-act:v1:${Q(F)}:${Q(G)}:resolution`,activityReconciliationPrefix:(F)=>`actrec:v1:${Q(F)}:`,activityReconciliation:(F,G,J)=>`actrec:v1:${Q(F)}:${Q(G)}:${J}`,eventPrefix:(F)=>`ev:${Q(F)}:`,event:(F,G)=>`ev:${Q(F)}:${String(G).padStart(10,"0")}`,eventHead:(F)=>`ev:${Q(F)}:head`,eventWatermark:(F)=>`ev:${Q(F)}:watermark`,fleetEventPrefix:()=>"fleet-event:",fleetEvent:(F)=>`fleet-event:${String(F).padStart(10,"0")}`,fleetEventTail:()=>"fleet-event-tail",fleetEventByWorkflowPrefix:(F)=>`fleet-event-by-workflow:${Q(F)}:`,fleetEventByWorkflow:(F,G)=>`fleet-event-by-workflow:${Q(F)}:${String(G).padStart(10,"0")}`,signal:(F,G,J)=>P(F,G,J,l),startSignal:(F,G,J)=>P(F,G,J,f),signalSequence:(F)=>`sigseq:v1:${Q(F)}`,signalAcceptedResponsePrefix:(F)=>`sigres:v1:${Q(F)}:`,signalAcceptedResponse:(F,G,J)=>`sigres:v1:${Q(F)}:${Q(G)}:${Q(J)}`,deadline:(F,G)=>`wf-deadline:${_(F)}:${Q(G)}`,terminalCleanup:(F,G)=>`wf-cleanup:${_(F)}:${Q(G)}`,teardownTimer:(F,G)=>`wf-teardown:${_(F)}:${Q(G)}`,delayedStart:(F,G)=>`wf-delayed:${_(F)}:${Q(G)}`,terminalWorkflowPrefix:()=>"wf-terminal:",terminalWorkflow:(F,G)=>`wf-terminal:${_(F)}:${Q(G)}`,attribute:(F)=>`attr:${Q(F)}`,attributeIndex:(F,G,J)=>`idx:${F}:${G}:${Q(J)}`,tagIndex:(F,G)=>`tag:${Q(F)}:${Q(G)}`,updatePrefix:(F)=>`upd:${Q(F)}:`,update:(F,G)=>`upd:${Q(F)}:${G}`,updateResponse:(F)=>`upr:${F}`,updateIdempotency:(F,G)=>`upk:${Q(F)}:${G}`,startIdempotency:(F)=>`start-idem:${Q(F)}`,startIdempotencySignalId:(F)=>`start-idem:${F}`,livenessPrefix:()=>"liveness:",liveness:(F)=>`liveness:${Q(F)}`,leasePrefix:()=>"lease:",leaseEpoch:()=>"lease:epoch",leaseHolder:()=>"lease:holder",budget:(F,G,J)=>`budget:${F}:${G}:${J}`,review:(F,G)=>`review:${Q(F)}:${G}`,workflowHeaders:(F)=>`wf-headers:${Q(F)}`,childCancellationPrefix:(F)=>`child-cancel:${Q(F)}:`,childCancellation:(F,G)=>`child-cancel:${Q(F)}:${Q(G)}`,terminalCleanupNeeded:(F)=>`wf-cleanup-needed:${Q(F)}`,workflowConcurrency:(F,G)=>`wf-concurrency:${Q(F)}:${Q(G)}`,workflowConcurrencyHolder:(F)=>`wf-concurrency-holder:${Q(F)}`,workflowHasServices:(F)=>`wf-has-services:${Q(F)}`,finalizerState:(F)=>`wf-finalizer-state:${Q(F)}`,teardownOwed:(F)=>`wf-teardown-needed:${Q(F)}`,teardownDeadLetter:(F)=>`wf-teardown-deadletter:${Q(F)}`,offload:(F,G)=>`offload:${Q(F)}:${G}`,archive:(F,G)=>`archive:${Q(F)}:${G}`,stateExecution:(F,G)=>`state:execution:${Q(F)}:${Q(G)}`,stateWorkflow:(F,G)=>`state:workflow-scope:${S}:${Q(F)}:${Q(G)}`,streamChunkPrefix:(F,G)=>`blob:${Q(F)}:${G}:chunk:`,streamChunk:(F,G,J)=>`blob:${Q(F)}:${G}:chunk:${String(J).padStart(10,"0")}`,streamTail:(F,G)=>`blob:${Q(F)}:${G}:tail`,streamMetadata:(F,G)=>`blob:${Q(F)}:${G}:meta`,budgetCharged:(F)=>`budget-charged:${F}`,toolEffect:(F,G,J)=>`tool-effect:${Q(F)}:${G}:${J}`,workflowVisibilityStatus:(F,G)=>`wf-idx-status:${Q(F)}:${Q(G)}`,workflowVisibilityType:(F,G)=>`wf-idx-type:${Q(F)}:${Q(G)}`,workflowVisibilityCreated:(F,G)=>`wf-idx-created:${_(F)}:${Q(G)}`,workflowVisibilityUpdated:(F,G)=>`wf-idx-updated:${_(F)}:${Q(G)}`,workflowVisibilityDeadline:(F,G)=>`wf-idx-deadline:${_(F)}:${Q(G)}`,workflowVisibilityManifest:(F)=>`wf-idx-manifest:${Q(F)}`,workflowVisibilityMetaVersion:()=>"wf-idx-meta:version",workflowVisibilityMetaBuiltAt:()=>"wf-idx-meta:built-at",workflowVisibilityMetaCursor:()=>"wf-idx-meta:cursor"};function d(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 M=F[Z];if(M===void 0)continue;if(typeof M!=="string")throw Error("deleteRange bounds must be strings");G[Z]=M,J=!0}if(!J)throw Error("deleteRange requires at least one of gt/gte/lt/lte; use deletePrefix to delete a whole prefix");let Y=d(F.limit);if(Y!==void 0)G.limit=Y;return G}async function c(F,G,J){let Y=V(J);if(F.deleteRange)return F.deleteRange(G,Y);return L(F,G,Y)}function p(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 a(F,G){let J={key:O(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 BF(F,G){let J=p(F,G),Y=a(F,G);if(J.key>Y.key||J.key===Y.key&&(J.open||Y.open))return null;return{lower:J,upper:Y}}function A(F){return F.replaceAll(/:+$/g,"")}function s(F,G){let J=A(F),Y=A(G);if(J.length===0)return Y;if(Y.length===0)return J;return`${J}:${Y}`}class z{#G;#J;constructor(F,G){this.#G=F,this.#J=A(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)}#Y(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}#_(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 z(this.#G,s(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,Y]of this.#G.scan(this.#F(F),this.#Y(G)))yield[this.#Q(J),Y]}async batch(F){$("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 x(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 h(this.#G,this.#F(F))}async deletePrefix(F){return m(this.#G,this.#F(F))}async deleteRange(F,G){let J=this.#_(V(G));return c(this.#G,this.#F(F),J)}async*keys(F,G){for await(let J of b(this.#G,this.#F(F),this.#Y(G)))yield this.#Q(J)}async count(F){return v(this.#G,this.#F(F))}[Symbol.dispose](){this.#G[Symbol.dispose]()}}function g(F,G){return new z(F,G)}var n=67108864;function y(F){if(F.type==="put")return{type:"put",key:F.key,value:N(F.value)};return{type:"delete",key:F.key}}function r(F){return{key:F.key,expectedValue:F.expectedValue===null?null:N(F.expectedValue)}}function i(F){if(!D(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 t(F){if(!D(F)||typeof F.applied!=="boolean")throw Error('HTTPStorage conditional batch response must include a boolean "applied" field.');return F.applied}function E(F,G,J){if(J!==void 0)F.searchParams.set(G,String(J))}function o(F){if(F.trim().length===0)return null;let G=i(JSON.parse(F));return[G.key,R(G.value)]}function e(F){if(F>n)throw Error("HTTPStorage scan response exceeded the maximum allowed size.")}async function*FF(F){if(F.body===null)return;let G=F.body.getReader(),J=new TextDecoder,Y="",Z=0,M=!1;try{while(!0){let{done:U,value:B}=await G.read();if(U){M=!0;break}Z+=B.byteLength,e(Z),Y+=J.decode(B,{stream:!0});let C=Y.split(`
|
|
2
|
-
|
|
1
|
+
import { decodeBase64ToBytes, encodeBytesToBase64, isRecord } from "./byte-encoding.js";
|
|
2
|
+
import { normalizeDeleteRangeOptions } from "./delete-range.js";
|
|
3
|
+
import {
|
|
4
|
+
storageCountCore,
|
|
5
|
+
storageDeletePrefixCore,
|
|
6
|
+
storageDeleteRangeCore,
|
|
7
|
+
storageHasCore,
|
|
8
|
+
storageKeysCore
|
|
9
|
+
} from "./derived-operations.js";
|
|
10
|
+
import {
|
|
11
|
+
assertStorageBatchOperationCount
|
|
12
|
+
} from "./interface.js";
|
|
13
|
+
import { scopedStorage } from "./scoped-storage.js";
|
|
14
|
+
const MAX_SCAN_RESPONSE_BYTES = 67108864;
|
|
15
|
+
function encodeOperation(operation) {
|
|
16
|
+
if (operation.type === "put")
|
|
17
|
+
return {
|
|
18
|
+
type: "put",
|
|
19
|
+
key: operation.key,
|
|
20
|
+
value: encodeBytesToBase64(operation.value)
|
|
21
|
+
};
|
|
22
|
+
return { type: "delete", key: operation.key };
|
|
23
|
+
}
|
|
24
|
+
function encodeCondition(condition) {
|
|
25
|
+
return {
|
|
26
|
+
key: condition.key,
|
|
27
|
+
expectedValue: condition.expectedValue === null ? null : encodeBytesToBase64(condition.expectedValue)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function parseScanEntry(value) {
|
|
31
|
+
if (!isRecord(value) || typeof value.key !== "string" || typeof value.value !== "string")
|
|
32
|
+
throw Error("HTTPStorage scan response contained an invalid NDJSON entry.");
|
|
33
|
+
return { key: value.key, value: value.value };
|
|
34
|
+
}
|
|
35
|
+
function parseConditionalBatchResponse(value) {
|
|
36
|
+
if (!isRecord(value) || typeof value.applied !== "boolean")
|
|
37
|
+
throw Error('HTTPStorage conditional batch response must include a boolean "applied" field.');
|
|
38
|
+
return value.applied;
|
|
39
|
+
}
|
|
40
|
+
function appendOptionalSearchParameter(url, name, value) {
|
|
41
|
+
if (value !== void 0)
|
|
42
|
+
url.searchParams.set(name, String(value));
|
|
43
|
+
}
|
|
44
|
+
function parseScanLine(line) {
|
|
45
|
+
if (line.trim().length === 0)
|
|
46
|
+
return null;
|
|
47
|
+
const entry = parseScanEntry(JSON.parse(line));
|
|
48
|
+
return [entry.key, decodeBase64ToBytes(entry.value)];
|
|
49
|
+
}
|
|
50
|
+
function assertScanResponseSize(bytesRead) {
|
|
51
|
+
if (bytesRead > MAX_SCAN_RESPONSE_BYTES)
|
|
52
|
+
throw Error("HTTPStorage scan response exceeded the maximum allowed size.");
|
|
53
|
+
}
|
|
54
|
+
async function* readNdjsonLines(response) {
|
|
55
|
+
if (response.body === null)
|
|
56
|
+
return;
|
|
57
|
+
const reader = response.body.getReader(), decoder = new TextDecoder;
|
|
58
|
+
let bufferedText = "", bytesRead = 0, reachedEndOfStream = !1;
|
|
59
|
+
try {
|
|
60
|
+
while (!0) {
|
|
61
|
+
const { done, value } = await reader.read();
|
|
62
|
+
if (done) {
|
|
63
|
+
reachedEndOfStream = !0;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
bytesRead += value.byteLength;
|
|
67
|
+
assertScanResponseSize(bytesRead);
|
|
68
|
+
bufferedText += decoder.decode(value, { stream: !0 });
|
|
69
|
+
const lines = bufferedText.split(`
|
|
70
|
+
`);
|
|
71
|
+
bufferedText = lines.pop() ?? "";
|
|
72
|
+
for (const line of lines)
|
|
73
|
+
yield line;
|
|
74
|
+
}
|
|
75
|
+
bufferedText += decoder.decode();
|
|
76
|
+
if (bufferedText.length > 0)
|
|
77
|
+
yield bufferedText;
|
|
78
|
+
} finally {
|
|
79
|
+
try {
|
|
80
|
+
if (!reachedEndOfStream)
|
|
81
|
+
await reader.cancel();
|
|
82
|
+
} catch {}
|
|
83
|
+
reader.releaseLock();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export class HTTPStorage {
|
|
88
|
+
#baseUrl;
|
|
89
|
+
#headers;
|
|
90
|
+
#remoteConditionalBatch;
|
|
91
|
+
constructor(options) {
|
|
92
|
+
this.#baseUrl = options.baseUrl instanceof URL ? options.baseUrl : new URL(options.baseUrl);
|
|
93
|
+
this.#headers = { ...options.headers };
|
|
94
|
+
this.#remoteConditionalBatch = options.remoteConditionalBatch ?? !1;
|
|
95
|
+
}
|
|
96
|
+
capabilities() {
|
|
97
|
+
return {
|
|
98
|
+
persistence: "remote",
|
|
99
|
+
readAfterWrite: "eventual",
|
|
100
|
+
scanConsistency: "best-effort",
|
|
101
|
+
atomicBatch: !0,
|
|
102
|
+
conditionalBatch: this.#remoteConditionalBatch,
|
|
103
|
+
boundedRangeDelete: !1
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
#url(path) {
|
|
107
|
+
const base = this.#baseUrl.href.endsWith("/") ? this.#baseUrl.href : `${this.#baseUrl.href}/`;
|
|
108
|
+
return new URL(path.replace(/^\/+/, ""), base);
|
|
109
|
+
}
|
|
110
|
+
#storageKeyUrl(key) {
|
|
111
|
+
return this.#url(`/v1/storage/${encodeURIComponent(key)}`);
|
|
112
|
+
}
|
|
113
|
+
#scanUrl(prefix, options) {
|
|
114
|
+
const url = this.#url("/v1/storage");
|
|
115
|
+
url.searchParams.set("prefix", prefix);
|
|
116
|
+
appendOptionalSearchParameter(url, "limit", options.limit);
|
|
117
|
+
appendOptionalSearchParameter(url, "reverse", options.reverse);
|
|
118
|
+
appendOptionalSearchParameter(url, "gt", options.gt);
|
|
119
|
+
appendOptionalSearchParameter(url, "gte", options.gte);
|
|
120
|
+
appendOptionalSearchParameter(url, "lt", options.lt);
|
|
121
|
+
appendOptionalSearchParameter(url, "lte", options.lte);
|
|
122
|
+
return url;
|
|
123
|
+
}
|
|
124
|
+
async#request(url, init = {}, allowedStatuses = []) {
|
|
125
|
+
const headers = new Headers(this.#headers);
|
|
126
|
+
for (const [key, value] of new Headers(init.headers).entries())
|
|
127
|
+
headers.set(key, value);
|
|
128
|
+
const response = await fetch(url, { ...init, headers });
|
|
129
|
+
if (!response.ok && !allowedStatuses.includes(response.status))
|
|
130
|
+
throw Error(`HTTPStorage request failed: ${init.method ?? "GET"} ${url.pathname} returned ${String(response.status)}.`);
|
|
131
|
+
return response;
|
|
132
|
+
}
|
|
133
|
+
async get(key) {
|
|
134
|
+
const response = await this.#request(this.#storageKeyUrl(key), { method: "GET" }, [404]);
|
|
135
|
+
if (response.status === 404)
|
|
136
|
+
return null;
|
|
137
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
138
|
+
}
|
|
139
|
+
async put(key, value) {
|
|
140
|
+
await this.#request(this.#storageKeyUrl(key), {
|
|
141
|
+
method: "PUT",
|
|
142
|
+
headers: { "content-type": "application/octet-stream" },
|
|
143
|
+
body: new Blob([value])
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async delete(key) {
|
|
147
|
+
await this.#request(this.#storageKeyUrl(key), { method: "DELETE" });
|
|
148
|
+
}
|
|
149
|
+
async* scan(prefix, options = {}) {
|
|
150
|
+
const response = await this.#request(this.#scanUrl(prefix, options), {
|
|
151
|
+
method: "GET",
|
|
152
|
+
headers: { accept: "application/x-ndjson" }
|
|
153
|
+
});
|
|
154
|
+
for await (const line of readNdjsonLines(response)) {
|
|
155
|
+
const entry = parseScanLine(line);
|
|
156
|
+
if (entry !== null)
|
|
157
|
+
yield entry;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async batch(operations) {
|
|
161
|
+
assertStorageBatchOperationCount("batch operations", operations.length);
|
|
162
|
+
await this.#request(this.#url("/v1/storage/-/batch"), {
|
|
163
|
+
method: "POST",
|
|
164
|
+
headers: { "content-type": "application/json" },
|
|
165
|
+
body: JSON.stringify({ operations: operations.map(encodeOperation) })
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async conditionalBatch(conditions, operations) {
|
|
169
|
+
assertStorageBatchOperationCount("conditionalBatch conditions", conditions.length);
|
|
170
|
+
assertStorageBatchOperationCount("conditionalBatch operations", operations.length);
|
|
171
|
+
const response = await this.#request(this.#url("/v1/storage/-/conditional-batch"), {
|
|
172
|
+
method: "POST",
|
|
173
|
+
headers: { "content-type": "application/json" },
|
|
174
|
+
body: JSON.stringify({
|
|
175
|
+
conditions: conditions.map(encodeCondition),
|
|
176
|
+
operations: operations.map(encodeOperation)
|
|
177
|
+
})
|
|
178
|
+
});
|
|
179
|
+
return parseConditionalBatchResponse(await response.json());
|
|
180
|
+
}
|
|
181
|
+
has(key) {
|
|
182
|
+
return storageHasCore(this, key);
|
|
183
|
+
}
|
|
184
|
+
async* keys(prefix, options) {
|
|
185
|
+
yield* storageKeysCore(this, prefix, options);
|
|
186
|
+
}
|
|
187
|
+
count(prefix) {
|
|
188
|
+
return storageCountCore(this, prefix);
|
|
189
|
+
}
|
|
190
|
+
deletePrefix(prefix) {
|
|
191
|
+
return storageDeletePrefixCore(this, prefix);
|
|
192
|
+
}
|
|
193
|
+
deleteRange(prefix, options) {
|
|
194
|
+
return storageDeleteRangeCore(this, prefix, normalizeDeleteRangeOptions(options));
|
|
195
|
+
}
|
|
196
|
+
scoped(prefix) {
|
|
197
|
+
return scopedStorage(this, prefix);
|
|
198
|
+
}
|
|
199
|
+
[Symbol.dispose]() {}
|
|
200
|
+
}
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* import { LMDBStorage } from '@lostgradient/weft/storage/lmdb'; // peer: lmdb
|
|
15
15
|
* import { TursoStorage } from '@lostgradient/weft/storage/turso'; // peer: @libsql/client
|
|
16
16
|
* import { NeonStorage } from '@lostgradient/weft/storage/neon'; // peer: @neondatabase/serverless
|
|
17
|
+
* import { CloudflareDurableObjectSQLiteStorage } from '@lostgradient/weft/storage/cloudflare'; // caller-injected `sql` binding, zero runtime deps
|
|
17
18
|
* import { IndexedDBStorage } from '@lostgradient/weft/storage/indexeddb'; // browser-only
|
|
18
19
|
* import { WebExtensionStorage } from '@lostgradient/weft/storage/web-extension'; // extension-only
|
|
19
20
|
* import { HTTPStorage } from '@lostgradient/weft/storage/http'; // remote storage
|
|
@@ -89,6 +90,9 @@ declare const exportedKeys: {
|
|
|
89
90
|
readonly schedule: (id: string) => string;
|
|
90
91
|
readonly scheduleTick: (fireAt: number, id: string) => string;
|
|
91
92
|
readonly scheduleRun: (workflowId: string) => string;
|
|
93
|
+
readonly scheduleRunLink: (workflowId: string) => string;
|
|
94
|
+
readonly scheduleRunBySchedulePrefix: (scheduleId: string) => string;
|
|
95
|
+
readonly scheduleRunBySchedule: (scheduleId: string, workflowId: string) => string;
|
|
92
96
|
readonly operation: (queue: string, scheduledAt: number, id: string) => string;
|
|
93
97
|
readonly operationInflight: (id: string) => string;
|
|
94
98
|
readonly operationQueued: (id: string) => string;
|
|
@@ -142,12 +146,15 @@ declare const exportedKeys: {
|
|
|
142
146
|
readonly workflowHeaders: (workflowId: string) => string;
|
|
143
147
|
readonly childCancellationPrefix: (workflowId: string) => string;
|
|
144
148
|
readonly childCancellation: (workflowId: string, childWorkflowId: string) => string;
|
|
149
|
+
readonly childWorkflowByParentPrefix: (parentWorkflowId: string, parentWorkflowExecutionToken?: string) => string;
|
|
150
|
+
readonly childWorkflowByParent: (parentWorkflowId: string, parentWorkflowExecutionToken: string | undefined, childWorkflowId: string) => string;
|
|
145
151
|
readonly terminalCleanupNeeded: (workflowId: string) => string;
|
|
146
152
|
readonly workflowConcurrency: (workflowType: string, partitionKey: string) => string;
|
|
147
153
|
readonly workflowConcurrencyHolder: (workflowId: string) => string;
|
|
148
154
|
readonly workflowHasServices: (workflowId: string) => string;
|
|
149
155
|
readonly finalizerState: (workflowId: string) => string;
|
|
150
156
|
readonly teardownOwed: (workflowId: string) => string;
|
|
157
|
+
readonly teardownSucceeded: (workflowId: string) => string;
|
|
151
158
|
readonly teardownDeadLetter: (workflowId: string) => string;
|
|
152
159
|
readonly offload: (workflowId: string, key: string) => string;
|
|
153
160
|
readonly archive: (workflowId: string, key: string) => string;
|
|
@@ -348,7 +355,7 @@ declare const exportedTextValueStore: typeof textValueStore;
|
|
|
348
355
|
* void isWeftKey;
|
|
349
356
|
* ```
|
|
350
357
|
*/
|
|
351
|
-
declare const exportedWeftReservedKeyPrefixes: readonly ["actrec:", "archive:", "async-act:", "attr:", "audit:bulk:", "blob:", "budget:", "budget-charged:", "ev:", "fleet-event-by-workflow:", "fleet-event:", "fleet-event-tail", "idx:", "lease:", "liveness:", "offload:", "op:", "review:", "schedule:", "schedule-due:", "schedule-run:", "sig:", "sigres:", "sigseq:", "start-idem:", "state:", "tag:", "tool-effect:", "upd:", "upk:", "upr:", "wf:", "wf-cleanup:", "wf-cleanup-needed:", "wf-concurrency:", "wf-concurrency-holder:", "wf-deadline:", "wf-delayed:", "wf-finalizer-state:", "wf-has-services:", "wf-headers:", "wf-idx-", "wf-teardown:", "wf-teardown-deadletter:", "wf-teardown-needed:", "wf-terminal:"];
|
|
358
|
+
declare const exportedWeftReservedKeyPrefixes: readonly ["actrec:", "archive:", "async-act:", "attr:", "audit:bulk:", "blob:", "budget:", "budget-charged:", "child-by-parent:", "ev:", "fleet-event-by-workflow:", "fleet-event:", "fleet-event-tail", "idx:", "lease:", "liveness:", "offload:", "op:", "review:", "schedule:", "schedule-due:", "schedule-run-by-schedule:", "schedule-run-link:", "schedule-run:", "sig:", "sigres:", "sigseq:", "start-idem:", "state:", "tag:", "tool-effect:", "upd:", "upk:", "upr:", "wf:", "wf-cleanup:", "wf-cleanup-needed:", "wf-concurrency:", "wf-concurrency-holder:", "wf-deadline:", "wf-delayed:", "wf-finalizer-state:", "wf-has-services:", "wf-headers:", "wf-idx-", "wf-teardown:", "wf-teardown-deadletter:", "wf-teardown-needed:", "wf-teardown-succeeded:", "wf-terminal:"];
|
|
352
359
|
/**
|
|
353
360
|
* Re-exported {@link withCodec}. See the original declaration for full docs.
|
|
354
361
|
*
|
|
@@ -1 +1,311 @@
|
|
|
1
|
-
var s=Object.defineProperty;var n=(U)=>U;function i(U,Y){this[U]=n.bind(null,Y)}var QU=(U,Y)=>{for(var G in Y)s(U,G,{get:Y[G],enumerable:!0,configurable:!0,set:i.bind(Y,G)})};async function E(U,Y){return await U.get(Y)!==null}async function*S(U,Y,G){for await(let[Q]of U.scan(Y,G))yield Q}async function R(U,Y){let G=0;for await(let Q of S(U,Y))G++;return G}async function v(U,Y){let G=[];for await(let Q of S(U,Y))G.push({type:"delete",key:Q});if(G.length===0)return 0;return await U.batch(G),G.length}async function b(U,Y,G){let Q=[];for await(let X of S(U,Y,G))Q.push({type:"delete",key:X});if(Q.length===0)return 0;return await U.batch(Q),Q.length}function A(U,Y,G){if(!U.capabilities()[Y])throw Error(`Feature "${G}" requires storage capability "${Y}", but this storage backend does not provide it.`)}var m="default";var P=1e4,BU=1e4;class y extends Error{code="StorageBatchOperationLimitExceededError";cap=P;count;target;constructor(U,Y){super(`${U} count ${Y} exceeds MAX_BATCH_OPERATIONS (${P}).`);this.name="StorageBatchOperationLimitExceededError",this.target=U,this.count=Y}}function T(U,Y){if(Y>P)throw new y(U,Y)}function K(U){return U.length>0?U.slice(0,-1)+String.fromCharCode(U.charCodeAt(U.length-1)+1):"ÿ"}function C(U,Y={}){if(Y.gt!==void 0&&U<=Y.gt)return!1;if(Y.gte!==void 0&&U<Y.gte)return!1;if(Y.lt!==void 0&&U>=Y.lt)return!1;if(Y.lte!==void 0&&U>Y.lte)return!1;return!0}function I(U,Y){if(U===null||Y===null)return U===Y;if(U.byteLength!==Y.byteLength)return!1;for(let G=0;G<U.byteLength;G++)if(U[G]!==Y[G])return!1;return!0}async function g(U,Y){if(U.has)return U.has(Y);return E(U,Y)}function k(U,Y,G){if(U.keys)return U.keys(Y,G);return S(U,Y,G)}async function c(U,Y){if(U.count)return U.count(Y);return R(U,Y)}async function w(U,Y){if(U.deletePrefix)return U.deletePrefix(Y);return v(U,Y)}async function DU(U,Y){T("batch operations",Y.length),await U.batch(Y)}async function u(U,Y,G){if(T("conditionalBatch conditions",Y.length),T("conditionalBatch operations",G.length),A(U,"conditionalBatch","storageConditionalBatch"),!U.conditionalBatch)throw Error("This storage backend reports conditionalBatch capability but does not implement the conditionalBatch() method.");return U.conditionalBatch(Y,G)}function J(U){return encodeURIComponent(U)}function _U(U){return decodeURIComponent(U)}function zU(U){try{return decodeURIComponent(U)}catch{return null}}var z=(U)=>String(U).padStart(16,"0"),r="0",t="1",x=(U,Y,G,Q)=>`sig:${J(U)}:${J(Y)}:${Q}:${J(G)}`,MU={workflow:(U)=>`wf:${J(U)}`,checkpoint:(U)=>`wf:${J(U)}:ckpt`,checkpointHistory:(U,Y)=>`wf:${J(U)}:ckpt:${String(Y).padStart(10,"0")}`,timelinePrefix:(U)=>`wf:${J(U)}:timeline:`,timeline:(U,Y)=>`wf:${J(U)}:timeline:${String(Y).padStart(10,"0")}`,schedule:(U)=>`schedule:${J(U)}`,scheduleTick:(U,Y)=>`schedule-due:${String(U).padStart(16,"0")}:${J(Y)}`,scheduleRun:(U)=>`schedule-run:${J(U)}`,operation:(U,Y,G)=>`op:${U}:${z(Y)}:${G}`,operationInflight:(U)=>`op:inflight:${U}`,operationQueued:(U)=>`op:queued:${U}`,operationResolved:(U)=>`op:resolved:${U}`,operationDeadLetterPrefix:()=>"op:dead-letter:",operationDeadLetter:(U)=>`op:dead-letter:${U}`,bulkOperationAuditPrefix:()=>"audit:bulk:",bulkOperationAudit:(U,Y,G)=>`audit:bulk:${z(U)}:${J(Y)}:${J(G)}`,operationResolvedByTimePrefix:()=>"op:resolved-by-time:",operationResolvedByTime:(U,Y)=>`op:resolved-by-time:${z(U)}:${J(Y)}`,asyncActivity:(U,Y)=>`async-act:v1:${J(U)}:${J(Y)}`,asyncActivityResolution:(U,Y)=>`async-act:v1:${J(U)}:${J(Y)}:resolution`,activityReconciliationPrefix:(U)=>`actrec:v1:${J(U)}:`,activityReconciliation:(U,Y,G)=>`actrec:v1:${J(U)}:${J(Y)}:${G}`,eventPrefix:(U)=>`ev:${J(U)}:`,event:(U,Y)=>`ev:${J(U)}:${String(Y).padStart(10,"0")}`,eventHead:(U)=>`ev:${J(U)}:head`,eventWatermark:(U)=>`ev:${J(U)}:watermark`,fleetEventPrefix:()=>"fleet-event:",fleetEvent:(U)=>`fleet-event:${String(U).padStart(10,"0")}`,fleetEventTail:()=>"fleet-event-tail",fleetEventByWorkflowPrefix:(U)=>`fleet-event-by-workflow:${J(U)}:`,fleetEventByWorkflow:(U,Y)=>`fleet-event-by-workflow:${J(U)}:${String(Y).padStart(10,"0")}`,signal:(U,Y,G)=>x(U,Y,G,t),startSignal:(U,Y,G)=>x(U,Y,G,r),signalSequence:(U)=>`sigseq:v1:${J(U)}`,signalAcceptedResponsePrefix:(U)=>`sigres:v1:${J(U)}:`,signalAcceptedResponse:(U,Y,G)=>`sigres:v1:${J(U)}:${J(Y)}:${J(G)}`,deadline:(U,Y)=>`wf-deadline:${z(U)}:${J(Y)}`,terminalCleanup:(U,Y)=>`wf-cleanup:${z(U)}:${J(Y)}`,teardownTimer:(U,Y)=>`wf-teardown:${z(U)}:${J(Y)}`,delayedStart:(U,Y)=>`wf-delayed:${z(U)}:${J(Y)}`,terminalWorkflowPrefix:()=>"wf-terminal:",terminalWorkflow:(U,Y)=>`wf-terminal:${z(U)}:${J(Y)}`,attribute:(U)=>`attr:${J(U)}`,attributeIndex:(U,Y,G)=>`idx:${U}:${Y}:${J(G)}`,tagIndex:(U,Y)=>`tag:${J(U)}:${J(Y)}`,updatePrefix:(U)=>`upd:${J(U)}:`,update:(U,Y)=>`upd:${J(U)}:${Y}`,updateResponse:(U)=>`upr:${U}`,updateIdempotency:(U,Y)=>`upk:${J(U)}:${Y}`,startIdempotency:(U)=>`start-idem:${J(U)}`,startIdempotencySignalId:(U)=>`start-idem:${U}`,livenessPrefix:()=>"liveness:",liveness:(U)=>`liveness:${J(U)}`,leasePrefix:()=>"lease:",leaseEpoch:()=>"lease:epoch",leaseHolder:()=>"lease:holder",budget:(U,Y,G)=>`budget:${U}:${Y}:${G}`,review:(U,Y)=>`review:${J(U)}:${Y}`,workflowHeaders:(U)=>`wf-headers:${J(U)}`,childCancellationPrefix:(U)=>`child-cancel:${J(U)}:`,childCancellation:(U,Y)=>`child-cancel:${J(U)}:${J(Y)}`,terminalCleanupNeeded:(U)=>`wf-cleanup-needed:${J(U)}`,workflowConcurrency:(U,Y)=>`wf-concurrency:${J(U)}:${J(Y)}`,workflowConcurrencyHolder:(U)=>`wf-concurrency-holder:${J(U)}`,workflowHasServices:(U)=>`wf-has-services:${J(U)}`,finalizerState:(U)=>`wf-finalizer-state:${J(U)}`,teardownOwed:(U)=>`wf-teardown-needed:${J(U)}`,teardownDeadLetter:(U)=>`wf-teardown-deadletter:${J(U)}`,offload:(U,Y)=>`offload:${J(U)}:${Y}`,archive:(U,Y)=>`archive:${J(U)}:${Y}`,stateExecution:(U,Y)=>`state:execution:${J(U)}:${J(Y)}`,stateWorkflow:(U,Y)=>`state:workflow-scope:${m}:${J(U)}:${J(Y)}`,streamChunkPrefix:(U,Y)=>`blob:${J(U)}:${Y}:chunk:`,streamChunk:(U,Y,G)=>`blob:${J(U)}:${Y}:chunk:${String(G).padStart(10,"0")}`,streamTail:(U,Y)=>`blob:${J(U)}:${Y}:tail`,streamMetadata:(U,Y)=>`blob:${J(U)}:${Y}:meta`,budgetCharged:(U)=>`budget-charged:${U}`,toolEffect:(U,Y,G)=>`tool-effect:${J(U)}:${Y}:${G}`,workflowVisibilityStatus:(U,Y)=>`wf-idx-status:${J(U)}:${J(Y)}`,workflowVisibilityType:(U,Y)=>`wf-idx-type:${J(U)}:${J(Y)}`,workflowVisibilityCreated:(U,Y)=>`wf-idx-created:${z(U)}:${J(Y)}`,workflowVisibilityUpdated:(U,Y)=>`wf-idx-updated:${z(U)}:${J(Y)}`,workflowVisibilityDeadline:(U,Y)=>`wf-idx-deadline:${z(U)}:${J(Y)}`,workflowVisibilityManifest:(U)=>`wf-idx-manifest:${J(U)}`,workflowVisibilityMetaVersion:()=>"wf-idx-meta:version",workflowVisibilityMetaBuiltAt:()=>"wf-idx-meta:built-at",workflowVisibilityMetaCursor:()=>"wf-idx-meta:cursor"};function o(U){if(U===void 0)return;if(typeof U!=="number"||!Number.isInteger(U)||U<0)throw Error("deleteRange limit must be a finite non-negative integer");return U===0?0:U}function h(U){let Y={},G=!1;for(let X of["gt","gte","lt","lte"]){let $=U[X];if($===void 0)continue;if(typeof $!=="string")throw Error("deleteRange bounds must be strings");Y[X]=$,G=!0}if(!G)throw Error("deleteRange requires at least one of gt/gte/lt/lte; use deletePrefix to delete a whole prefix");let Q=o(U.limit);if(Q!==void 0)Y.limit=Q;return Y}async function f(U,Y,G){let Q=h(G);if(U.deleteRange)return U.deleteRange(Y,Q);return b(U,Y,Q)}function e(U,Y){let G={key:U,open:!1};if(Y.gte!==void 0&&Y.gte>G.key)G.key=Y.gte,G.open=!1;if(Y.gt!==void 0&&Y.gt>=G.key)G.key=Y.gt,G.open=!0;return G}function UU(U,Y){let G={key:K(U),open:!0};if(Y.lt!==void 0&&Y.lt<=G.key)G.key=Y.lt,G.open=!0;if(Y.lte!==void 0&&Y.lte<G.key)G.key=Y.lte,G.open=!1;return G}function l(U,Y){let G=e(U,Y),Q=UU(U,Y);if(G.key>Q.key||G.key===Q.key&&(G.open||Q.open))return null;return{lower:G,upper:Q}}function q(U){return U.replaceAll(/:+$/g,"")}function YU(U,Y){let G=q(U),Q=q(Y);if(G.length===0)return Q;if(Q.length===0)return G;return`${G}:${Q}`}class O{#Y;#G;constructor(U,Y){this.#Y=U,this.#G=q(Y)}#U(U){if(this.#G.length===0)return U;return U.length===0?`${this.#G}:`:`${this.#G}:${U}`}#J(U){if(this.#G.length===0)return U;return U.slice(this.#G.length+1)}#Q(U={}){let Y={};if(U.limit!==void 0)Y.limit=U.limit;if(U.reverse!==void 0)Y.reverse=U.reverse;if(U.gt!==void 0)Y.gt=this.#U(U.gt);if(U.gte!==void 0)Y.gte=this.#U(U.gte);if(U.lt!==void 0)Y.lt=this.#U(U.lt);if(U.lte!==void 0)Y.lte=this.#U(U.lte);return Y}#X(U){let Y={};if(U.limit!==void 0)Y.limit=U.limit;if(U.gt!==void 0)Y.gt=this.#U(U.gt);if(U.gte!==void 0)Y.gte=this.#U(U.gte);if(U.lt!==void 0)Y.lt=this.#U(U.lt);if(U.lte!==void 0)Y.lte=this.#U(U.lte);return Y}capabilities(){return this.#Y.capabilities()}scoped(U){return new O(this.#Y,YU(this.#G,U))}async get(U){return this.#Y.get(this.#U(U))}async put(U,Y){await this.#Y.put(this.#U(U),Y)}async delete(U){await this.#Y.delete(this.#U(U))}async*scan(U,Y){for await(let[G,Q]of this.#Y.scan(this.#U(U),this.#Q(Y)))yield[this.#J(G),Q]}async batch(U){T("batch operations",U.length),await this.#Y.batch(U.map((Y)=>{if(Y.type==="put")return{type:"put",key:this.#U(Y.key),value:Y.value};return{type:"delete",key:this.#U(Y.key)}}))}async conditionalBatch(U,Y){return u(this.#Y,U.map((G)=>({key:this.#U(G.key),expectedValue:G.expectedValue})),Y.map((G)=>{if(G.type==="put")return{type:"put",key:this.#U(G.key),value:G.value};return{type:"delete",key:this.#U(G.key)}}))}async has(U){return g(this.#Y,this.#U(U))}async deletePrefix(U){return w(this.#Y,this.#U(U))}async deleteRange(U,Y){let G=this.#X(h(Y));return f(this.#Y,this.#U(U),G)}async*keys(U,Y){for await(let G of k(this.#Y,this.#U(U),this.#Q(Y)))yield this.#J(G)}async count(U){return c(this.#Y,this.#U(U))}[Symbol.dispose](){this.#Y[Symbol.dispose]()}}function d(U,Y){return new O(U,Y)}var F="kv";function GU(U=globalThis){let{indexedDB:Y,IDBKeyRange:G}=U;if(Y===void 0||G===void 0)throw Error("IndexedDBStorage requires both indexedDB and IDBKeyRange runtime globals.");return{indexedDB:Y,IDBKeyRange:G}}function N(U){return new Promise((Y,G)=>{U.onsuccess=()=>Y(U.result),U.onerror=()=>G(U.error)})}function p(U,Y){let G=null,Q=null,X=null,$=(Z,L)=>{let H=Z??Error(L);if(Q){let B=Q;G=null,Q=null,B(H);return}X=H};return U.onsuccess=()=>{if(!G)return;let Z=G;G=null,Q=null,Z(U.result)},U.onerror=()=>{$(U.error,"IndexedDB cursor request failed.")},Y.onerror=()=>{$(Y.error,"IndexedDB transaction failed.")},Y.onabort=()=>{$(Y.error,"IndexedDB transaction aborted.")},()=>{return new Promise((Z,L)=>{if(X){let H=X;X=null,L(H);return}if(G=Z,Q=L,U.readyState==="done"){let H=G;G=null,Q=null,H?.(U.result)}})}}class JU{#Y;#G=null;#U;#J;constructor(U="weft",Y=GU()){this.#Y=U,this.#J=Y,this.#U=this.#Q()}capabilities(){return{persistence:"local",readAfterWrite:"linearizable",scanConsistency:"best-effort",atomicBatch:!0,conditionalBatch:!0,boundedRangeDelete:!0}}#Q(){let U=this.#J.indexedDB.open(this.#Y,1);return U.onupgradeneeded=()=>{let Y=U.result;if(!Y.objectStoreNames.contains(F))Y.createObjectStore(F)},N(U).then((Y)=>{return this.#G=Y,Y})}async get(U){let Q=(await this.#U).transaction(F,"readonly").objectStore(F),X=await N(Q.get(U));return X===void 0?null:new Uint8Array(X)}async put(U,Y){let X=(await this.#U).transaction(F,"readwrite").objectStore(F);await N(X.put(Y,U))}async delete(U){let Q=(await this.#U).transaction(F,"readwrite").objectStore(F);await N(Q.delete(U))}async has(U){let Q=(await this.#U).transaction(F,"readonly").objectStore(F);return await N(Q.count(U))>0}async deletePrefix(U){let Y=await this.#U,G=K(U),Q=this.#J.IDBKeyRange.bound(U,G,!1,!0);return new Promise((X,$)=>{let Z=Y.transaction(F,"readwrite"),L=Z.objectStore(F),H=0,B=L.count(Q);B.onsuccess=()=>{H=B.result,L.delete(Q)},Z.oncomplete=()=>X(H),Z.onerror=()=>$(Z.error)})}async deleteRange(U,Y){let G=h(Y),Q=l(U,G);if(Q===null)return 0;let X=this.#J.IDBKeyRange.bound(Q.lower.key,Q.upper.key,Q.lower.open,Q.upper.open),$=await this.#U,{limit:Z}=G;return new Promise((L,H)=>{let B=$.transaction(F,"readwrite"),M=B.objectStore(F),D=0;if(Z===void 0){let W=M.count(X);W.onsuccess=()=>{D=W.result,M.delete(X)}}else{let W=M.openCursor(X,"next");W.onsuccess=()=>{let _=W.result;if(_===null||D>=Z)return;if(_.delete(),D++,D<Z)_.continue()}}B.oncomplete=()=>L(D),B.onerror=()=>H(B.error)})}async*scan(U,Y={}){let{limit:G,reverse:Q}=Y,X=await this.#U,$=K(U),Z=this.#J.IDBKeyRange.bound(U,$,!1,!0),L=Q?"prev":"next",H=X.transaction(F,"readonly"),M=H.objectStore(F).openCursor(Z,L),D=0,W=p(M,H),_=!1;try{let V=await W();while(V){if(G!==void 0&&D>=G)break;let j=V.key;if(C(j,Y))yield[j,new Uint8Array(V.value)],D++;V.continue(),V=await W()}_=!0}finally{if(!_)try{H.abort()}catch{}}}async batch(U){if(T("batch operations",U.length),U.length===0)return;let Y=await this.#U;return new Promise((G,Q)=>{let X=Y.transaction(F,"readwrite"),$=X.objectStore(F);for(let Z of U)if(Z.type==="put")$.put(Z.value,Z.key);else $.delete(Z.key);X.oncomplete=()=>G(),X.onerror=()=>Q(X.error)})}async conditionalBatch(U,Y){T("conditionalBatch conditions",U.length),T("conditionalBatch operations",Y.length);let G=await this.#U;return new Promise((Q,X)=>{let $=G.transaction(F,"readwrite"),Z=$.objectStore(F),L=!1,H=!1,B=(W,_)=>{if(L)return;L=!0,X(W??Error(_))};$.oncomplete=()=>{if(L)return;L=!0,Q(!0)},$.onerror=()=>{B($.error,"IndexedDB conditionalBatch transaction failed.")},$.onabort=()=>{if(L)return;if(L=!0,H){Q(!1);return}X($.error??Error("IndexedDB conditionalBatch transaction aborted."))};let M=()=>{for(let W of Y)if(W.type==="put")Z.put(W.value,W.key);else Z.delete(W.key)},D=(W)=>{if(W>=U.length){M();return}let _=U[W],V=Z.get(_.key);V.onsuccess=()=>{let j=V.result,a=j===void 0?null:new Uint8Array(j);if(!I(a,_.expectedValue)){H=!0,$.abort();return}D(W+1)},V.onerror=()=>{B(V.error,"IndexedDB conditionalBatch condition check failed.")}};D(0)})}async*keys(U,Y={}){let{limit:G,reverse:Q}=Y,X=await this.#U,$=K(U),Z=this.#J.IDBKeyRange.bound(U,$,!1,!0),L=Q?"prev":"next",H=X.transaction(F,"readonly"),M=H.objectStore(F).openKeyCursor(Z,L),D=0,W=p(M,H),_=!1;try{let V=await W();while(V){if(G!==void 0&&D>=G)break;let j=V.key;if(C(j,Y))yield j,D++;V.continue(),V=await W()}_=!0}finally{if(!_)try{H.abort()}catch{}}}async count(U){let Y=await this.#U,G=K(U),X=Y.transaction(F,"readonly").objectStore(F);return N(X.count(this.#J.IDBKeyRange.bound(U,G,!1,!0)))}scoped(U){return d(this,U)}[Symbol.dispose](){if(this.#G)this.#G.close(),this.#G=null}}export{JU as IndexedDBStorage};
|
|
1
|
+
import {
|
|
2
|
+
normalizeDeleteRangeOptions,
|
|
3
|
+
resolveDeleteRangeBounds
|
|
4
|
+
} from "./delete-range.js";
|
|
5
|
+
import {
|
|
6
|
+
assertStorageBatchOperationCount,
|
|
7
|
+
matchesScanOptions,
|
|
8
|
+
resolvePrefixRangeEnd,
|
|
9
|
+
storageValuesEqual
|
|
10
|
+
} from "./interface.js";
|
|
11
|
+
import { scopedStorage } from "./scoped-storage.js";
|
|
12
|
+
const STORE_NAME = "kv";
|
|
13
|
+
function resolveIndexedDbRuntime(runtime = globalThis) {
|
|
14
|
+
const { indexedDB: indexedDbFactory, IDBKeyRange: keyRangeFactory } = runtime;
|
|
15
|
+
if (indexedDbFactory === void 0 || keyRangeFactory === void 0)
|
|
16
|
+
throw Error("IndexedDBStorage requires both indexedDB and IDBKeyRange runtime globals.");
|
|
17
|
+
return {
|
|
18
|
+
indexedDB: indexedDbFactory,
|
|
19
|
+
IDBKeyRange: keyRangeFactory
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function promisify(request) {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
request.onsuccess = () => resolve(request.result);
|
|
25
|
+
request.onerror = () => reject(request.error);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function createCursorRequestAwaiter(request, transaction) {
|
|
29
|
+
let resolveCurrent = null, rejectCurrent = null, pendingError = null;
|
|
30
|
+
const rejectPendingCursor = (error, fallbackMessage) => {
|
|
31
|
+
const reason = error ?? Error(fallbackMessage);
|
|
32
|
+
if (rejectCurrent) {
|
|
33
|
+
const reject = rejectCurrent;
|
|
34
|
+
resolveCurrent = null;
|
|
35
|
+
rejectCurrent = null;
|
|
36
|
+
reject(reason);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
pendingError = reason;
|
|
40
|
+
};
|
|
41
|
+
request.onsuccess = () => {
|
|
42
|
+
if (!resolveCurrent)
|
|
43
|
+
return;
|
|
44
|
+
const resolve = resolveCurrent;
|
|
45
|
+
resolveCurrent = null;
|
|
46
|
+
rejectCurrent = null;
|
|
47
|
+
resolve(request.result);
|
|
48
|
+
};
|
|
49
|
+
request.onerror = () => {
|
|
50
|
+
rejectPendingCursor(request.error, "IndexedDB cursor request failed.");
|
|
51
|
+
};
|
|
52
|
+
transaction.onerror = () => {
|
|
53
|
+
rejectPendingCursor(transaction.error, "IndexedDB transaction failed.");
|
|
54
|
+
};
|
|
55
|
+
transaction.onabort = () => {
|
|
56
|
+
rejectPendingCursor(transaction.error, "IndexedDB transaction aborted.");
|
|
57
|
+
};
|
|
58
|
+
return () => {
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
if (pendingError) {
|
|
61
|
+
const error = pendingError;
|
|
62
|
+
pendingError = null;
|
|
63
|
+
reject(error);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
resolveCurrent = resolve;
|
|
67
|
+
rejectCurrent = reject;
|
|
68
|
+
if (request.readyState === "done") {
|
|
69
|
+
const resolveReady = resolveCurrent;
|
|
70
|
+
resolveCurrent = null;
|
|
71
|
+
rejectCurrent = null;
|
|
72
|
+
resolveReady?.(request.result);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export class IndexedDBStorage {
|
|
79
|
+
#databaseName;
|
|
80
|
+
#database = null;
|
|
81
|
+
#databasePromise;
|
|
82
|
+
#runtime;
|
|
83
|
+
constructor(databaseName = "weft", runtime = resolveIndexedDbRuntime()) {
|
|
84
|
+
this.#databaseName = databaseName;
|
|
85
|
+
this.#runtime = runtime;
|
|
86
|
+
this.#databasePromise = this.#open();
|
|
87
|
+
}
|
|
88
|
+
capabilities() {
|
|
89
|
+
return {
|
|
90
|
+
persistence: "local",
|
|
91
|
+
readAfterWrite: "linearizable",
|
|
92
|
+
scanConsistency: "best-effort",
|
|
93
|
+
atomicBatch: !0,
|
|
94
|
+
conditionalBatch: !0,
|
|
95
|
+
boundedRangeDelete: !0
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
#open() {
|
|
99
|
+
const request = this.#runtime.indexedDB.open(this.#databaseName, 1);
|
|
100
|
+
request.onupgradeneeded = () => {
|
|
101
|
+
const database = request.result;
|
|
102
|
+
if (!database.objectStoreNames.contains(STORE_NAME))
|
|
103
|
+
database.createObjectStore(STORE_NAME);
|
|
104
|
+
};
|
|
105
|
+
return promisify(request).then((database) => {
|
|
106
|
+
this.#database = database;
|
|
107
|
+
return database;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async get(key) {
|
|
111
|
+
const store = (await this.#databasePromise).transaction(STORE_NAME, "readonly").objectStore(STORE_NAME), result = await promisify(store.get(key));
|
|
112
|
+
return result === void 0 ? null : new Uint8Array(result);
|
|
113
|
+
}
|
|
114
|
+
async put(key, value) {
|
|
115
|
+
const store = (await this.#databasePromise).transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME);
|
|
116
|
+
await promisify(store.put(value, key));
|
|
117
|
+
}
|
|
118
|
+
async delete(key) {
|
|
119
|
+
const store = (await this.#databasePromise).transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME);
|
|
120
|
+
await promisify(store.delete(key));
|
|
121
|
+
}
|
|
122
|
+
async has(key) {
|
|
123
|
+
const store = (await this.#databasePromise).transaction(STORE_NAME, "readonly").objectStore(STORE_NAME);
|
|
124
|
+
return await promisify(store.count(key)) > 0;
|
|
125
|
+
}
|
|
126
|
+
async deletePrefix(prefix) {
|
|
127
|
+
const database = await this.#databasePromise, prefixEnd = resolvePrefixRangeEnd(prefix), range = this.#runtime.IDBKeyRange.bound(prefix, prefixEnd, !1, !0);
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
const transaction = database.transaction(STORE_NAME, "readwrite"), store = transaction.objectStore(STORE_NAME);
|
|
130
|
+
let deletedCount = 0;
|
|
131
|
+
const countRequest = store.count(range);
|
|
132
|
+
countRequest.onsuccess = () => {
|
|
133
|
+
deletedCount = countRequest.result;
|
|
134
|
+
store.delete(range);
|
|
135
|
+
};
|
|
136
|
+
transaction.oncomplete = () => resolve(deletedCount);
|
|
137
|
+
transaction.onerror = () => reject(transaction.error);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async deleteRange(prefix, options) {
|
|
141
|
+
const normalized = normalizeDeleteRangeOptions(options), bounds = resolveDeleteRangeBounds(prefix, normalized);
|
|
142
|
+
if (bounds === null)
|
|
143
|
+
return 0;
|
|
144
|
+
const range = this.#runtime.IDBKeyRange.bound(bounds.lower.key, bounds.upper.key, bounds.lower.open, bounds.upper.open), database = await this.#databasePromise, { limit } = normalized;
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
const transaction = database.transaction(STORE_NAME, "readwrite"), store = transaction.objectStore(STORE_NAME);
|
|
147
|
+
let deletedCount = 0;
|
|
148
|
+
if (limit === void 0) {
|
|
149
|
+
const countRequest = store.count(range);
|
|
150
|
+
countRequest.onsuccess = () => {
|
|
151
|
+
deletedCount = countRequest.result;
|
|
152
|
+
store.delete(range);
|
|
153
|
+
};
|
|
154
|
+
} else {
|
|
155
|
+
const cursorRequest = store.openCursor(range, "next");
|
|
156
|
+
cursorRequest.onsuccess = () => {
|
|
157
|
+
const cursor = cursorRequest.result;
|
|
158
|
+
if (cursor === null || deletedCount >= limit)
|
|
159
|
+
return;
|
|
160
|
+
cursor.delete();
|
|
161
|
+
deletedCount++;
|
|
162
|
+
if (deletedCount < limit)
|
|
163
|
+
cursor.continue();
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
transaction.oncomplete = () => resolve(deletedCount);
|
|
167
|
+
transaction.onerror = () => reject(transaction.error);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
async* scan(prefix, options = {}) {
|
|
171
|
+
const { limit, reverse } = options, database = await this.#databasePromise, prefixEnd = resolvePrefixRangeEnd(prefix), range = this.#runtime.IDBKeyRange.bound(prefix, prefixEnd, !1, !0), direction = reverse ? "prev" : "next", transaction = database.transaction(STORE_NAME, "readonly"), request = transaction.objectStore(STORE_NAME).openCursor(range, direction);
|
|
172
|
+
let count = 0;
|
|
173
|
+
const nextCursor = createCursorRequestAwaiter(request, transaction);
|
|
174
|
+
let completed = !1;
|
|
175
|
+
try {
|
|
176
|
+
let cursor = await nextCursor();
|
|
177
|
+
while (cursor) {
|
|
178
|
+
if (limit !== void 0 && count >= limit)
|
|
179
|
+
break;
|
|
180
|
+
const key = cursor.key;
|
|
181
|
+
if (matchesScanOptions(key, options)) {
|
|
182
|
+
yield [key, new Uint8Array(cursor.value)];
|
|
183
|
+
count++;
|
|
184
|
+
}
|
|
185
|
+
cursor.continue();
|
|
186
|
+
cursor = await nextCursor();
|
|
187
|
+
}
|
|
188
|
+
completed = !0;
|
|
189
|
+
} finally {
|
|
190
|
+
if (!completed)
|
|
191
|
+
try {
|
|
192
|
+
transaction.abort();
|
|
193
|
+
} catch {}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async batch(operations) {
|
|
197
|
+
assertStorageBatchOperationCount("batch operations", operations.length);
|
|
198
|
+
if (operations.length === 0)
|
|
199
|
+
return;
|
|
200
|
+
const database = await this.#databasePromise;
|
|
201
|
+
return new Promise((resolve, reject) => {
|
|
202
|
+
const transaction = database.transaction(STORE_NAME, "readwrite"), store = transaction.objectStore(STORE_NAME);
|
|
203
|
+
for (const operation of operations)
|
|
204
|
+
if (operation.type === "put")
|
|
205
|
+
store.put(operation.value, operation.key);
|
|
206
|
+
else
|
|
207
|
+
store.delete(operation.key);
|
|
208
|
+
transaction.oncomplete = () => resolve();
|
|
209
|
+
transaction.onerror = () => reject(transaction.error);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async conditionalBatch(conditions, operations) {
|
|
213
|
+
assertStorageBatchOperationCount("conditionalBatch conditions", conditions.length);
|
|
214
|
+
assertStorageBatchOperationCount("conditionalBatch operations", operations.length);
|
|
215
|
+
const database = await this.#databasePromise;
|
|
216
|
+
return new Promise((resolve, reject) => {
|
|
217
|
+
const transaction = database.transaction(STORE_NAME, "readwrite"), store = transaction.objectStore(STORE_NAME);
|
|
218
|
+
let settled = !1, abortedByCondition = !1;
|
|
219
|
+
const settleReject = (error, message) => {
|
|
220
|
+
if (settled)
|
|
221
|
+
return;
|
|
222
|
+
settled = !0;
|
|
223
|
+
reject(error ?? Error(message));
|
|
224
|
+
};
|
|
225
|
+
transaction.oncomplete = () => {
|
|
226
|
+
if (settled)
|
|
227
|
+
return;
|
|
228
|
+
settled = !0;
|
|
229
|
+
resolve(!0);
|
|
230
|
+
};
|
|
231
|
+
transaction.onerror = () => {
|
|
232
|
+
settleReject(transaction.error, "IndexedDB conditionalBatch transaction failed.");
|
|
233
|
+
};
|
|
234
|
+
transaction.onabort = () => {
|
|
235
|
+
if (settled)
|
|
236
|
+
return;
|
|
237
|
+
settled = !0;
|
|
238
|
+
if (abortedByCondition) {
|
|
239
|
+
resolve(!1);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
reject(transaction.error ?? Error("IndexedDB conditionalBatch transaction aborted."));
|
|
243
|
+
};
|
|
244
|
+
const applyOperations = () => {
|
|
245
|
+
for (const operation of operations)
|
|
246
|
+
if (operation.type === "put")
|
|
247
|
+
store.put(operation.value, operation.key);
|
|
248
|
+
else
|
|
249
|
+
store.delete(operation.key);
|
|
250
|
+
}, verifyCondition = (index) => {
|
|
251
|
+
if (index >= conditions.length) {
|
|
252
|
+
applyOperations();
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const condition = conditions[index], request = store.get(condition.key);
|
|
256
|
+
request.onsuccess = () => {
|
|
257
|
+
const raw = request.result, currentValue = raw === void 0 ? null : new Uint8Array(raw);
|
|
258
|
+
if (!storageValuesEqual(currentValue, condition.expectedValue)) {
|
|
259
|
+
abortedByCondition = !0;
|
|
260
|
+
transaction.abort();
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
verifyCondition(index + 1);
|
|
264
|
+
};
|
|
265
|
+
request.onerror = () => {
|
|
266
|
+
settleReject(request.error, "IndexedDB conditionalBatch condition check failed.");
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
verifyCondition(0);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
async* keys(prefix, options = {}) {
|
|
273
|
+
const { limit, reverse } = options, database = await this.#databasePromise, prefixEnd = resolvePrefixRangeEnd(prefix), range = this.#runtime.IDBKeyRange.bound(prefix, prefixEnd, !1, !0), direction = reverse ? "prev" : "next", transaction = database.transaction(STORE_NAME, "readonly"), request = transaction.objectStore(STORE_NAME).openKeyCursor(range, direction);
|
|
274
|
+
let count = 0;
|
|
275
|
+
const nextCursor = createCursorRequestAwaiter(request, transaction);
|
|
276
|
+
let completed = !1;
|
|
277
|
+
try {
|
|
278
|
+
let cursor = await nextCursor();
|
|
279
|
+
while (cursor) {
|
|
280
|
+
if (limit !== void 0 && count >= limit)
|
|
281
|
+
break;
|
|
282
|
+
const key = cursor.key;
|
|
283
|
+
if (matchesScanOptions(key, options)) {
|
|
284
|
+
yield key;
|
|
285
|
+
count++;
|
|
286
|
+
}
|
|
287
|
+
cursor.continue();
|
|
288
|
+
cursor = await nextCursor();
|
|
289
|
+
}
|
|
290
|
+
completed = !0;
|
|
291
|
+
} finally {
|
|
292
|
+
if (!completed)
|
|
293
|
+
try {
|
|
294
|
+
transaction.abort();
|
|
295
|
+
} catch {}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
async count(prefix) {
|
|
299
|
+
const database = await this.#databasePromise, prefixEnd = resolvePrefixRangeEnd(prefix), store = database.transaction(STORE_NAME, "readonly").objectStore(STORE_NAME);
|
|
300
|
+
return promisify(store.count(this.#runtime.IDBKeyRange.bound(prefix, prefixEnd, !1, !0)));
|
|
301
|
+
}
|
|
302
|
+
scoped(prefix) {
|
|
303
|
+
return scopedStorage(this, prefix);
|
|
304
|
+
}
|
|
305
|
+
[Symbol.dispose]() {
|
|
306
|
+
if (this.#database) {
|
|
307
|
+
this.#database.close();
|
|
308
|
+
this.#database = null;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
@@ -365,6 +365,14 @@ export declare const KEYS: {
|
|
|
365
365
|
readonly schedule: (id: string) => string;
|
|
366
366
|
readonly scheduleTick: (fireAt: number, id: string) => string;
|
|
367
367
|
readonly scheduleRun: (workflowId: string) => string;
|
|
368
|
+
/**
|
|
369
|
+
* Durable per-workflow manifest for the schedule that launched a run. Unlike
|
|
370
|
+
* `scheduleRun`, this link survives terminal cleanup so schedule history can
|
|
371
|
+
* be queried until the workflow itself is purged.
|
|
372
|
+
*/
|
|
373
|
+
readonly scheduleRunLink: (workflowId: string) => string;
|
|
374
|
+
readonly scheduleRunBySchedulePrefix: (scheduleId: string) => string;
|
|
375
|
+
readonly scheduleRunBySchedule: (scheduleId: string, workflowId: string) => string;
|
|
368
376
|
readonly operation: (queue: string, scheduledAt: number, id: string) => string;
|
|
369
377
|
readonly operationInflight: (id: string) => string;
|
|
370
378
|
readonly operationQueued: (id: string) => string;
|
|
@@ -471,6 +479,8 @@ export declare const KEYS: {
|
|
|
471
479
|
readonly workflowHeaders: (workflowId: string) => string;
|
|
472
480
|
readonly childCancellationPrefix: (workflowId: string) => string;
|
|
473
481
|
readonly childCancellation: (workflowId: string, childWorkflowId: string) => string;
|
|
482
|
+
readonly childWorkflowByParentPrefix: (parentWorkflowId: string, parentWorkflowExecutionToken?: string) => string;
|
|
483
|
+
readonly childWorkflowByParent: (parentWorkflowId: string, parentWorkflowExecutionToken: string | undefined, childWorkflowId: string) => string;
|
|
474
484
|
readonly terminalCleanupNeeded: (workflowId: string) => string;
|
|
475
485
|
readonly workflowConcurrency: (workflowType: string, partitionKey: string) => string;
|
|
476
486
|
readonly workflowConcurrencyHolder: (workflowId: string) => string;
|
|
@@ -512,14 +522,16 @@ export declare const KEYS: {
|
|
|
512
522
|
* success or when it dead-letters, which is what unblocks purge.
|
|
513
523
|
*/
|
|
514
524
|
readonly teardownOwed: (workflowId: string) => string;
|
|
525
|
+
/** Durable successful finalizer outcome, retained until workflow purge or retention. */
|
|
526
|
+
readonly teardownSucceeded: (workflowId: string) => string;
|
|
515
527
|
/**
|
|
516
528
|
* Durable audit record written when a workflow's finalizer permanently fails — the
|
|
517
529
|
* retry horizon is reached, or the recorded resource state vanished so the finalizer
|
|
518
530
|
* can never run (issue #446 Phase 2). Holds the `TeardownDeadLetterRecord` shape
|
|
519
|
-
* `{ type, lastError, attempts, deadLetteredAt, finalizerInput? }`.
|
|
520
|
-
* the workflow purge delete-set** so it survives as the operator's
|
|
521
|
-
* leaked external resource
|
|
522
|
-
*
|
|
531
|
+
* `{ type, lastError, attempts, deadLetteredAt, workflowExecutionToken?, finalizerInput? }`.
|
|
532
|
+
* **Excluded from the workflow purge delete-set** so it survives as the operator's
|
|
533
|
+
* evidence of a leaked external resource and remains queryable through the durable
|
|
534
|
+
* finalizer-status API after purge.
|
|
523
535
|
*/
|
|
524
536
|
readonly teardownDeadLetter: (workflowId: string) => string;
|
|
525
537
|
readonly offload: (workflowId: string, key: string) => string;
|