@lostgradient/weft 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/generated/operation-catalog.snapshot.json +4671 -0
  3. package/dist/cli/generated/operation-client.generated.d.ts +1 -0
  4. package/dist/cli/index.js +1 -0
  5. package/dist/cli-main.js +227 -401
  6. package/dist/client/http-operations.js +7 -1
  7. package/dist/client/http-request.d.ts +23 -1
  8. package/dist/client/http-request.js +12 -3
  9. package/dist/client/index.d.ts +2 -0
  10. package/dist/client/index.js +7 -0
  11. package/dist/connection.d.ts +8 -0
  12. package/dist/connection.js +41 -17
  13. package/dist/core/engine/callback-creators-core.js +2 -1
  14. package/dist/core/engine/index.d.ts +43 -0
  15. package/dist/core/engine/lifecycle/shared.d.ts +25 -0
  16. package/dist/core/engine/lifecycle/transition.js +19 -9
  17. package/dist/core/types/definition-schema-to-json.d.ts +11 -0
  18. package/dist/core/types/definition-schema-to-json.js +11 -2
  19. package/dist/http.js +2 -0
  20. package/dist/indexeddb.js +1 -0
  21. package/dist/json-schema.js +3 -3
  22. package/dist/mcp/cli.js +63 -61
  23. package/dist/mcp/http.d.ts +7 -2
  24. package/dist/mcp/session.d.ts +3 -3
  25. package/dist/mcp/session.js +3 -2
  26. package/dist/mcp/stdio.d.ts +7 -2
  27. package/dist/observability/index.js +2 -2
  28. package/dist/runtime/portable.d.ts +33 -0
  29. package/dist/runtime/portable.js +17 -6
  30. package/dist/server/engine-event-feed-backend.d.ts +22 -3
  31. package/dist/server/fleet-event-feed.d.ts +65 -0
  32. package/dist/server/handler/index.d.ts +11 -2
  33. package/dist/server/handler/index.js +7 -0
  34. package/dist/server/handler.js +1 -56
  35. package/dist/server/index.d.ts +12 -1
  36. package/dist/server/index.js +87 -64
  37. package/dist/server/operations/submit-review-decision.d.ts +2 -0
  38. package/dist/server/operations/submit-review-decision.js +19 -2
  39. package/dist/server/replay-live-feed-internals.d.ts +19 -0
  40. package/dist/server/replay-live-feed-internals.js +76 -0
  41. package/dist/server/runtime/authentication-bridge.d.ts +2 -2
  42. package/dist/server/serve-internals.js +3 -3
  43. package/dist/server/workflow-event-feed.d.ts +100 -11
  44. package/dist/server/workflow-event-feed.js +1 -140
  45. package/dist/service-worker/index.d.ts +8 -2
  46. package/dist/service-worker/index.js +37 -56
  47. package/dist/service-worker/setup.d.ts +6 -2
  48. package/dist/storage/auto.js +1 -1
  49. package/dist/storage/bun-sql.js +3 -3
  50. package/dist/storage/cloudflare-durable-object-sql.d.ts +75 -0
  51. package/dist/storage/cloudflare-durable-object-sql.js +0 -0
  52. package/dist/storage/cloudflare-value-codec.d.ts +65 -0
  53. package/dist/storage/cloudflare-value-codec.js +46 -0
  54. package/dist/storage/cloudflare.d.ts +140 -0
  55. package/dist/storage/cloudflare.js +127 -0
  56. package/dist/storage/compressed-storage.js +1 -1
  57. package/dist/storage/http.js +200 -2
  58. package/dist/storage/index.d.ts +1 -0
  59. package/dist/storage/indexeddb.js +311 -1
  60. package/dist/storage/interface.js +1 -1
  61. package/dist/storage/lmdb.js +1 -1
  62. package/dist/storage/memory.js +1 -1
  63. package/dist/storage/neon.js +4 -4
  64. package/dist/storage/node-sqlite.js +3 -3
  65. package/dist/storage/postgres-key-value-queries.d.ts +6 -0
  66. package/dist/storage/postgres-key-value-queries.js +2 -3
  67. package/dist/storage/postgres.js +4 -4
  68. package/dist/storage/resolve.js +1 -1
  69. package/dist/storage/scoped-storage.js +1 -1
  70. package/dist/storage/sql-identifier.d.ts +35 -0
  71. package/dist/storage/sql-identifier.js +5 -0
  72. package/dist/storage/sqlite-key-value-queries.d.ts +11 -6
  73. package/dist/storage/sqlite-key-value-queries.js +3 -3
  74. package/dist/storage/testing.js +1 -1
  75. package/dist/storage/turso.js +2 -2
  76. package/dist/storage/typed-storage.js +138 -2
  77. package/dist/storage/web-extension.js +298 -1
  78. package/dist/testing/index.js +21 -60
  79. package/dist/version.d.ts +1 -1
  80. package/dist/version.js +1 -1
  81. package/dist/web-extension.js +1 -0
  82. package/dist/worker/protocol.js +1 -1
  83. package/package.json +8 -3
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * @module service-worker/setup
12
12
  */
13
- import { Engine } from '../core/engine';
13
+ import { Engine, type RegistryAgnosticEngine } from '../core/engine';
14
14
  import type { Storage as WeftStorage } from '../storage/interface';
15
15
  import { ServiceWorkerScheduler } from './scheduler';
16
16
  /**
@@ -47,8 +47,12 @@ export interface SetupServiceWorkerOptions {
47
47
  /**
48
48
  * Pre-built engine. If provided, must use the same storage instance as
49
49
  * `options.storage` (or its own storage if `storage` is omitted).
50
+ *
51
+ * Typed as {@link RegistryAgnosticEngine} (see its JSDoc) rather than the
52
+ * plain default `Engine`, so both `new Engine({ storage })` and
53
+ * `Engine.create({ workflows })` type-check here directly.
50
54
  */
51
- engine?: Engine;
55
+ engine?: RegistryAgnosticEngine;
52
56
  /**
53
57
  * Pre-built storage instance. Must be the same `===` reference as the
54
58
  * engine's storage when both are provided.
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- var F=Object.defineProperty;var P=(z)=>z;function k(z,C){this[z]=P.bind(null,C)}var T=(z,C)=>{for(var J in C)F(z,J,{get:C[J],enumerable:!0,configurable:!0,set:k.bind(C,J)})};var h=(z,C)=>()=>(z&&(C=z(z=0)),C);var Z=import.meta.require,O=(z,C,J)=>{if(C!=null){if(typeof C!=="object"&&typeof C!=="function")throw TypeError('Object expected to be assigned to "using" declaration');let K;if(J)K=C[Symbol.asyncDispose];if(K===void 0)K=C[Symbol.dispose];if(typeof K!=="function")throw TypeError("Object not disposable");z.push([J,K,C])}else if(J)z.push([J]);return C},y=(z,C,J)=>{let K=(V)=>C=J?new SuppressedError(V,C,"An error was suppressed during disposal"):(J=!0,V),Y=(V)=>{while(V=z.pop())try{var A=V[1]&&V[1].call(V[2]);if(V[0])return Promise.resolve(A).then(Y,(q)=>(K(q),Y()))}catch(q){K(q)}if(J)throw C};return Y()};function Q(z){return{hasBun:typeof z.Bun<"u",hasIndexedDB:typeof z.indexedDB<"u",hasNode:z.process!==void 0&&typeof z.process.versions?.node==="string",hasWebExtensionStorage:z.browser?.storage!==void 0||z.chrome?.storage!==void 0}}async function U(z){let{createHash:C}=await import("crypto"),J=z.process?.cwd?.()??"weft-default";return C("sha256").update(J).digest("hex").slice(0,16)}async function X(z){let[{mkdirSync:C},{tmpdir:J},K]=await Promise.all([import("fs"),import("os"),import("path")]),Y=z.process?.env?.WEFT_DEFAULT_STORAGE_PATH,V=Y!==void 0&&Y.length>0?Y:K.join(J(),"weft-default",`${await U(z)}.db`);return C(K.dirname(V),{recursive:!0}),V}function H(z,C){if(C==="Bun")return typeof z.Bun;if(C==="browser.storage")return typeof(z.browser?.storage??z.chrome?.storage);return typeof z.process}function j(z,C){return import.meta.url.endsWith(".ts")?z:C}async function $(z){return await import(z)}function W(z){if(z.browser?.storage!==void 0)return z.browser;if(z.chrome?.storage!==void 0)return z.chrome;return{}}function B(z){let{indexedDB:C,IDBKeyRange:J}=z;if(C===void 0||J===void 0)throw Error("resolveDefaultStorage: IndexedDB resolution requires both indexedDB and IDBKeyRange.");return{indexedDB:C,IDBKeyRange:J}}function N(z){let C=typeof z.indexedDB,J=typeof z.IDBKeyRange;return`typeof indexedDB=${C}, typeof IDBKeyRange=${J}`}var w=j("./bun-sql.ts","./bun-sql.js"),I=j("./node-sqlite.ts","./node-sqlite.js"),L=j("./indexeddb.ts","./indexeddb.js"),R=j("./web-extension.ts","./web-extension.js");async function v(z=globalThis){let C=Q(z);if(C.hasBun){let{BunSQLiteStorage:J}=await $(w);return new J(await X(z))}if(C.hasNode){let{NodeSQLiteStorage:J}=await $(I);return new J(await X(z))}if(C.hasWebExtensionStorage){let{WebExtensionStorage:J}=await $(R);return new J({},W(z))}if(C.hasIndexedDB){let{IndexedDBStorage:J}=await $(L);return new J("weft",B(z))}throw Error(`resolveDefaultStorage: requires Bun, Node, WebExtension storage, or IndexedDB. Detected: typeof Bun=${H(z,"Bun")}, typeof process=${H(z,"process")}, typeof browser.storage=${H(z,"browser.storage")}, ${N(z)}.`)}export{v as resolveDefaultStorage};
2
+ var Z=import.meta.require,I=(z,C,J)=>{if(C!=null){if(typeof C!=="object"&&typeof C!=="function")throw TypeError('Object expected to be assigned to "using" declaration');let K;if(J)K=C[Symbol.asyncDispose];if(K===void 0)K=C[Symbol.dispose];if(typeof K!=="function")throw TypeError("Object not disposable");z.push([J,K,C])}else if(J)z.push([J]);return C},L=(z,C,J)=>{let K=(V)=>C=J?new SuppressedError(V,C,"An error was suppressed during disposal"):(J=!0,V),Y=(V)=>{while(V=z.pop())try{var A=V[1]&&V[1].call(V[2]);if(V[0])return Promise.resolve(A).then(Y,(q)=>(K(q),Y()))}catch(q){K(q)}if(J)throw C};return Y()};function F(z){return{hasBun:typeof z.Bun<"u",hasIndexedDB:typeof z.indexedDB<"u",hasNode:z.process!==void 0&&typeof z.process.versions?.node==="string",hasWebExtensionStorage:z.browser?.storage!==void 0||z.chrome?.storage!==void 0}}async function P(z){let{createHash:C}=await import("crypto"),J=z.process?.cwd?.()??"weft-default";return C("sha256").update(J).digest("hex").slice(0,16)}async function X(z){let[{mkdirSync:C},{tmpdir:J},K]=await Promise.all([import("fs"),import("os"),import("path")]),Y=z.process?.env?.WEFT_DEFAULT_STORAGE_PATH,V=Y!==void 0&&Y.length>0?Y:K.join(J(),"weft-default",`${await P(z)}.db`);return C(K.dirname(V),{recursive:!0}),V}function H(z,C){if(C==="Bun")return typeof z.Bun;if(C==="browser.storage")return typeof(z.browser?.storage??z.chrome?.storage);return typeof z.process}function j(z,C){return import.meta.url.endsWith(".ts")?z:C}async function $(z){return await import(z)}function k(z){if(z.browser?.storage!==void 0)return z.browser;if(z.chrome?.storage!==void 0)return z.chrome;return{}}function Q(z){let{indexedDB:C,IDBKeyRange:J}=z;if(C===void 0||J===void 0)throw Error("resolveDefaultStorage: IndexedDB resolution requires both indexedDB and IDBKeyRange.");return{indexedDB:C,IDBKeyRange:J}}function U(z){let C=typeof z.indexedDB,J=typeof z.IDBKeyRange;return`typeof indexedDB=${C}, typeof IDBKeyRange=${J}`}var W=j("./bun-sql.ts","./bun-sql.js"),B=j("./node-sqlite.ts","./node-sqlite.js"),N=j("./indexeddb.ts","./indexeddb.js"),w=j("./web-extension.ts","./web-extension.js");async function T(z=globalThis){let C=F(z);if(C.hasBun){let{BunSQLiteStorage:J}=await $(W);return new J(await X(z))}if(C.hasNode){let{NodeSQLiteStorage:J}=await $(B);return new J(await X(z))}if(C.hasWebExtensionStorage){let{WebExtensionStorage:J}=await $(w);return new J({},k(z))}if(C.hasIndexedDB){let{IndexedDBStorage:J}=await $(N);return new J("weft",Q(z))}throw Error(`resolveDefaultStorage: requires Bun, Node, WebExtension storage, or IndexedDB. Detected: typeof Bun=${H(z,"Bun")}, typeof process=${H(z,"process")}, typeof browser.storage=${H(z,"browser.storage")}, ${U(z)}.`)}export{T as resolveDefaultStorage};
@@ -391,19 +391,19 @@ function buildSqliteKeyRangeQuery(prefix, options = {}) {
391
391
  sqlSuffix: `WHERE ${conditions.join(" AND ")} ORDER BY key ${direction}${limitClause}`
392
392
  };
393
393
  }
394
- function buildSqliteKeyRangeDelete(prefix, options) {
394
+ function buildSqliteKeyRangeDelete(prefix, options, table = "kv") {
395
395
  const { conditions, parameters } = buildSqliteKeyRangeConditions(prefix, options);
396
396
  const whereClause = conditions.join(" AND ");
397
397
  if (options.limit === undefined) {
398
398
  return {
399
399
  parameters,
400
- sql: `DELETE FROM kv WHERE ${whereClause}`
400
+ sql: `DELETE FROM ${table} WHERE ${whereClause}`
401
401
  };
402
402
  }
403
403
  parameters.push(options.limit);
404
404
  return {
405
405
  parameters,
406
- sql: `DELETE FROM kv WHERE key IN (SELECT key FROM kv WHERE ${whereClause} ORDER BY key ASC LIMIT ?)`
406
+ sql: `DELETE FROM ${table} WHERE key IN (SELECT key FROM ${table} WHERE ${whereClause} ORDER BY key ASC LIMIT ?)`
407
407
  };
408
408
  }
409
409
  function buildSqliteKeyValueRangeSelect(prefix, options = {}) {
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Minimal structural view of a Cloudflare Durable Object's `ctx.storage.sql`
3
+ * binding.
4
+ *
5
+ * Deliberately hand-written instead of importing `@cloudflare/workers-types`:
6
+ * the real binding's `.exec()` method is synchronous (it runs against
7
+ * transactional local storage with no I/O wait), and this structural
8
+ * interface only needs the slice of that surface the adapter actually calls.
9
+ * Any object satisfying this shape — the real Durable Object binding, or a
10
+ * test double backed by `bun:sqlite` — works as `sql`.
11
+ *
12
+ * @module storage/cloudflare-durable-object-sql
13
+ */
14
+ /**
15
+ * The value types a Durable Object SQL column can hold.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import type { SqlStorageValue } from '@lostgradient/weft/storage/cloudflare';
20
+ *
21
+ * const bound: SqlStorageValue = 'a bound query parameter';
22
+ * void bound;
23
+ * ```
24
+ */
25
+ export type SqlStorageValue = ArrayBuffer | string | number | null;
26
+ /**
27
+ * The lazily-iterated result of one `Sql.exec()` call. Matches the subset of
28
+ * Cloudflare's `SqlStorageCursor` this adapter reads: row iteration.
29
+ *
30
+ * Deliberately omits `rowsWritten`: on the real Durable Object binding that
31
+ * field is a billing counter that also counts index writes, not a logical
32
+ * rows-affected count — this `kv` table's implicit primary-key index means a
33
+ * single-row `DELETE` can report more than one. `deletePrefix()` and
34
+ * `deleteRange()` instead read the logical count with a same-connection
35
+ * `SELECT changes()` query run immediately after the write, with no `await`
36
+ * in between (see `cloudflare.ts`).
37
+ *
38
+ * On the real binding, `exec()` runs the statement immediately — iterating
39
+ * only consumes the already-computed result, it does not defer execution.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * import type { Sql, SqlStorageCursor } from '@lostgradient/weft/storage/cloudflare';
44
+ *
45
+ * declare const sql: Sql;
46
+ * const cursor: SqlStorageCursor<{ key: string }> = sql.exec('SELECT key FROM kv');
47
+ * const rows = [...cursor];
48
+ * void rows;
49
+ * ```
50
+ */
51
+ export type SqlStorageCursor<T = Record<string, SqlStorageValue>> = Iterable<T>;
52
+ /**
53
+ * The structural shape of a Cloudflare Durable Object's `ctx.storage.sql`
54
+ * binding that this adapter depends on.
55
+ *
56
+ * `exec()` is synchronous by contract: Durable Object storage operations are
57
+ * transactional only up to the next `await` in the calling code, so every
58
+ * code path in {@link CloudflareDurableObjectSQLiteStorage} that needs that
59
+ * guarantee (`conditionalBatch`'s read-compare-write, `batch`'s multi-write,
60
+ * `scan`'s snapshot read) calls `exec()` with no `await` in between.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * import { CloudflareDurableObjectSQLiteStorage, type Sql } from '@lostgradient/weft/storage/cloudflare';
65
+ *
66
+ * // Injected by the Durable Object runtime: `ctx.storage.sql` inside a
67
+ * // `DurableObject` subclass.
68
+ * declare const sql: Sql;
69
+ * const storage = new CloudflareDurableObjectSQLiteStorage({ sql });
70
+ * void storage;
71
+ * ```
72
+ */
73
+ export interface Sql {
74
+ exec<T = Record<string, SqlStorageValue>>(query: string, ...bindings: SqlStorageValue[]): SqlStorageCursor<T>;
75
+ }
File without changes
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Value encoding for {@link CloudflareDurableObjectSQLiteStorage}'s `value`
3
+ * column: the default base64-`TEXT` encoding, and the opt-in raw
4
+ * `ArrayBuffer`/`BLOB` encoding.
5
+ *
6
+ * @module storage/cloudflare-value-codec
7
+ */
8
+ import type { SqlStorageValue } from './cloudflare-durable-object-sql.ts';
9
+ /**
10
+ * How {@link CloudflareDurableObjectSQLiteStorage} stores values in its
11
+ * `value` column.
12
+ *
13
+ * - `'base64'` (the default): values are base64-encoded and stored as
14
+ * `TEXT`. Keeps the adapter's SQL binding contract to the TEXT/number/null
15
+ * value types the Durable Object SQL binding guarantees, at the cost of
16
+ * ~4/3 size expansion per value.
17
+ * - `'blob'`: values are bound and stored as raw `ArrayBuffer`/`BLOB`,
18
+ * avoiding the base64 expansion. Requires the wider binding contract the
19
+ * real Durable Object SQL binding also supports (`ArrayBuffer` bind
20
+ * parameters and `BLOB` columns).
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import type { CloudflareValueEncoding } from '@lostgradient/weft/storage/cloudflare';
25
+ *
26
+ * const encoding: CloudflareValueEncoding = 'blob';
27
+ * void encoding;
28
+ * ```
29
+ */
30
+ export type CloudflareValueEncoding = 'base64' | 'blob';
31
+ /**
32
+ * A `value`-column codec: how to bind a `Uint8Array` as a SQL parameter, and
33
+ * how to decode a column value read back out. `sqlColumnType` is the
34
+ * declared type used only when `CREATE TABLE IF NOT EXISTS` creates a fresh
35
+ * table — SQLite's manifest typing means an already-existing table keeps
36
+ * whichever storage class (`TEXT` or `BLOB`) each row was actually written
37
+ * with, regardless of the column's declared type. That is exactly what lets
38
+ * {@link decode} on both codecs detect and reject a value written under the
39
+ * *other* encoding: reading a `TEXT` value with the `'blob'` codec (or a
40
+ * `BLOB` value with the `'base64'` codec) fails the type guard below and
41
+ * throws immediately, instead of silently misinterpreting the bytes.
42
+ *
43
+ * This is the cross-mode contract for
44
+ * {@link CloudflareDurableObjectSQLiteStorageOptions.valueEncoding}: a table
45
+ * must use a single `valueEncoding` for its lifetime. There is no dual-read
46
+ * fallback and no migration path between encodings — pick one per table.
47
+ */
48
+ type CloudflareValueCodec = {
49
+ readonly sqlColumnType: 'TEXT' | 'BLOB';
50
+ encode(value: Uint8Array): SqlStorageValue;
51
+ decode(value: SqlStorageValue, key: string): Uint8Array;
52
+ };
53
+ /**
54
+ * Resolve a {@link CloudflareValueEncoding} to its {@link CloudflareValueCodec}.
55
+ *
56
+ * `valueEncoding` is a durable, per-table format choice (see
57
+ * {@link CloudflareValueCodec}'s docs on the cross-mode contract), so an
58
+ * unrecognized value is rejected outright rather than silently falling back
59
+ * to `'base64'` — the TypeScript type only guards callers who type-check;
60
+ * a caller passing an unvalidated string (a config value, a typo'd literal
61
+ * from plain JavaScript) must not have that typo silently pick the wrong
62
+ * on-disk format for a table.
63
+ */
64
+ export declare function resolveCloudflareValueCodec(encoding: CloudflareValueEncoding): CloudflareValueCodec;
65
+ export {};
@@ -0,0 +1,46 @@
1
+ const BASE64_CHUNK_SIZE = 32768;
2
+ function bytesToBase64(bytes) {
3
+ let binary = "";
4
+ for (let offset = 0;offset < bytes.length; offset += BASE64_CHUNK_SIZE) {
5
+ const chunk = bytes.subarray(offset, offset + BASE64_CHUNK_SIZE);
6
+ binary += String.fromCharCode(...chunk);
7
+ }
8
+ return btoa(binary);
9
+ }
10
+ function base64ToBytes(base64) {
11
+ const binary = atob(base64), bytes = new Uint8Array(binary.length);
12
+ for (let index = 0;index < binary.length; index += 1)
13
+ bytes[index] = binary.charCodeAt(index);
14
+ return bytes;
15
+ }
16
+ function unexpectedValueTypeError(key, expectedEncoding, actualType) {
17
+ return Error(`Cloudflare Durable Object SQLite storage: key "${key}" holds a value of type ${actualType}, but this instance is configured for valueEncoding: '${expectedEncoding}'. A table must use a single, ` + "consistent valueEncoding for its lifetime \u2014 this row was written by an instance configured " + "with a different valueEncoding. Pick one encoding per table (or per-instance configured table name) and do not change it; there is no automatic migration between encodings.");
18
+ }
19
+ const base64Codec = {
20
+ sqlColumnType: "TEXT",
21
+ encode(value) {
22
+ return bytesToBase64(value);
23
+ },
24
+ decode(value, key) {
25
+ if (typeof value !== "string")
26
+ throw unexpectedValueTypeError(key, "base64", value === null ? "null" : typeof value);
27
+ return base64ToBytes(value);
28
+ }
29
+ }, blobCodec = {
30
+ sqlColumnType: "BLOB",
31
+ encode(value) {
32
+ return new Uint8Array(value).buffer;
33
+ },
34
+ decode(value, key) {
35
+ if (!(value instanceof ArrayBuffer))
36
+ throw unexpectedValueTypeError(key, "blob", value === null ? "null" : typeof value);
37
+ return new Uint8Array(value);
38
+ }
39
+ };
40
+ export function resolveCloudflareValueCodec(encoding) {
41
+ if (encoding === "base64")
42
+ return base64Codec;
43
+ if (encoding === "blob")
44
+ return blobCodec;
45
+ throw Error(`Cloudflare Durable Object SQLite storage: valueEncoding must be 'base64' or 'blob', received ${JSON.stringify(encoding)}.`);
46
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Cloudflare Durable Object SQLite storage adapter.
3
+ *
4
+ * Wraps a Durable Object's `ctx.storage.sql` binding (structurally typed as
5
+ * {@link Sql} — see `cloudflare-durable-object-sql.ts`) in the same `Storage`
6
+ * interface every other adapter implements, over a single key/value table.
7
+ * `@cloudflare/workers-types` is never imported: the structural `Sql`/
8
+ * `SqlStorageCursor` shape is enough to both type this adapter and drive it
9
+ * in tests with a `bun:sqlite`-backed double.
10
+ *
11
+ * This module has zero runtime-specific imports of its own — the `sql`
12
+ * binding is injected by the caller — so it is bundleable for Bun, Node, and
13
+ * the Cloudflare Workers (`workerd`) runtime alike. Import from
14
+ * `@lostgradient/weft/storage/cloudflare`.
15
+ *
16
+ * @module storage/cloudflare
17
+ */
18
+ import type { Sql } from './cloudflare-durable-object-sql.ts';
19
+ import { type CloudflareValueEncoding } from './cloudflare-value-codec.ts';
20
+ import { type DeleteRangeOptions } from './delete-range.ts';
21
+ import { type BatchOperation, type ConditionalBatchCondition, type ScanOptions, type Storage, type StorageCapabilities } from './interface.ts';
22
+ export type { Sql, SqlStorageCursor, SqlStorageValue } from './cloudflare-durable-object-sql.ts';
23
+ export type { CloudflareValueEncoding } from './cloudflare-value-codec.ts';
24
+ /**
25
+ * Configuration for {@link CloudflareDurableObjectSQLiteStorage}.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import type { CloudflareDurableObjectSQLiteStorageOptions } from '@lostgradient/weft/storage/cloudflare';
30
+ * import type { Sql } from '@lostgradient/weft/storage/cloudflare';
31
+ *
32
+ * declare const sql: Sql;
33
+ * const options: CloudflareDurableObjectSQLiteStorageOptions = { sql, table: 'weft_kv' };
34
+ * void options;
35
+ * ```
36
+ */
37
+ export type CloudflareDurableObjectSQLiteStorageOptions = {
38
+ /** The Durable Object's `ctx.storage.sql` binding, or a structurally compatible double. */
39
+ sql: Sql;
40
+ /**
41
+ * Table name for the single key/value table this adapter reads and writes.
42
+ * Validated as a strict SQL identifier at construction; defaults to `kv`.
43
+ */
44
+ table?: string;
45
+ /**
46
+ * How values are stored in the `value` column. Defaults to `'base64'`
47
+ * (base64-encoded `TEXT`), which keeps this adapter's SQL binding contract
48
+ * to the TEXT/number/null value types the Durable Object SQL binding
49
+ * guarantees. Opt into `'blob'` to bind and store raw `ArrayBuffer`/`BLOB`
50
+ * values instead, avoiding base64's ~4/3 size expansion for large values —
51
+ * this requires the wider binding contract the real Durable Object SQL
52
+ * binding also supports.
53
+ *
54
+ * A table's `value` column holds whichever encoding wrote each row: pick
55
+ * one `valueEncoding` for a table's lifetime and do not change it. Reading
56
+ * a row written under the other encoding fails fast with a descriptive
57
+ * error rather than silently misinterpreting the bytes — see the
58
+ * `documentation/guides/storage.md` Cloudflare section for the full
59
+ * cross-mode contract.
60
+ */
61
+ valueEncoding?: CloudflareValueEncoding;
62
+ };
63
+ /**
64
+ * Storage adapter over a Cloudflare Durable Object's `ctx.storage.sql`
65
+ * binding.
66
+ *
67
+ * A **non-owning** view: the `sql` binding is injected, the Durable Object
68
+ * owns its storage connection, and `[Symbol.dispose]` is a no-op — there is
69
+ * nothing here to close.
70
+ *
71
+ * Schema is one `kv(key TEXT PRIMARY KEY, value ...)` table (name
72
+ * configurable via `table`). By default (`valueEncoding: 'base64'`) values
73
+ * are stored as base64-encoded text, keeping this adapter's SQL binding
74
+ * contract to the TEXT/number/null value types the Durable Object SQL
75
+ * binding guarantees. Set `valueEncoding: 'blob'` to bind and store raw
76
+ * `ArrayBuffer`/`BLOB` values instead — see
77
+ * {@link CloudflareDurableObjectSQLiteStorageOptions.valueEncoding}.
78
+ *
79
+ * `ctx.storage.sql.exec()` is synchronous — Durable Object storage is
80
+ * transactional only up to the next `await`/yield point in the calling code.
81
+ * Every method here that needs that guarantee (`batch`, `conditionalBatch`,
82
+ * `scan`) runs its `exec()` calls with no `await` in between, so a single
83
+ * `Storage` call from this adapter is one atomic unit of Durable Object
84
+ * storage work.
85
+ *
86
+ * `deletePrefix()` and `deleteRange()` are native single-statement `DELETE`s
87
+ * (not a scan-then-batch fallback), so `capabilities().boundedRangeDelete`
88
+ * is honestly `true`.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * import { CloudflareDurableObjectSQLiteStorage, type Sql } from '@lostgradient/weft/storage/cloudflare';
93
+ * import { Engine, workflow, type WorkflowContext } from '@lostgradient/weft';
94
+ *
95
+ * // Injected by the Durable Object runtime: `ctx.storage.sql` inside a
96
+ * // `DurableObject` subclass.
97
+ * declare const sql: Sql;
98
+ *
99
+ * const storage = new CloudflareDurableObjectSQLiteStorage({ sql });
100
+ *
101
+ * // Durable Objects drive their own event loop; there is no host process to
102
+ * // own background intervals, so the engine runs in manual maintenance mode
103
+ * // and the Durable Object alarm (or a Worker Cron Trigger) drives
104
+ * // `engine.runMaintenance()` explicitly.
105
+ * const engine = await Engine.create({
106
+ * storage,
107
+ * backgroundTasks: 'manual',
108
+ * startScheduler: false,
109
+ * });
110
+ *
111
+ * engine.register(
112
+ * workflow({ name: 'echo' }).execute(async function* (ctx: WorkflowContext, input: unknown) {
113
+ * return input;
114
+ * }),
115
+ * );
116
+ * ```
117
+ */
118
+ export declare class CloudflareDurableObjectSQLiteStorage implements Storage {
119
+ #private;
120
+ constructor(options: CloudflareDurableObjectSQLiteStorageOptions);
121
+ capabilities(): StorageCapabilities;
122
+ get(key: string): Promise<Uint8Array | null>;
123
+ put(key: string, value: Uint8Array): Promise<void>;
124
+ delete(key: string): Promise<void>;
125
+ has(key: string): Promise<boolean>;
126
+ count(prefix: string): Promise<number>;
127
+ deletePrefix(prefix: string): Promise<number>;
128
+ deleteRange(prefix: string, options: DeleteRangeOptions): Promise<number>;
129
+ scan(prefix: string, options?: ScanOptions): AsyncIterable<[string, Uint8Array]>;
130
+ keys(prefix: string, options?: ScanOptions): AsyncIterable<string>;
131
+ batch(operations: BatchOperation[]): Promise<void>;
132
+ conditionalBatch(conditions: ConditionalBatchCondition[], operations: BatchOperation[]): Promise<boolean>;
133
+ /**
134
+ * No-op. This adapter is a non-owning view over an injected `sql` binding
135
+ * — the Durable Object owns its storage connection, so there is nothing
136
+ * here to close. Disposing this adapter never touches `sql` beyond the
137
+ * ordinary reads/writes issued by the methods above.
138
+ */
139
+ [Symbol.dispose](): void;
140
+ }
@@ -0,0 +1,127 @@
1
+ import {
2
+ resolveCloudflareValueCodec
3
+ } from "./cloudflare-value-codec.js";
4
+ import { normalizeDeleteRangeOptions } from "./delete-range.js";
5
+ import {
6
+ assertStorageBatchOperationCount,
7
+ storageValuesEqual
8
+ } from "./interface.js";
9
+ import { assertSqlIdentifier } from "./sql-identifier.js";
10
+ import {
11
+ buildSqliteKeyRangeDelete,
12
+ buildSqliteKeyRangeQuery,
13
+ buildSqlitePrefixRangeParameters
14
+ } from "./sqlite-key-value-queries.js";
15
+ const DEFAULT_TABLE = "kv", DEFAULT_VALUE_ENCODING = "base64";
16
+
17
+ export class CloudflareDurableObjectSQLiteStorage {
18
+ #sql;
19
+ #table;
20
+ #codec;
21
+ constructor(options) {
22
+ const { sql, table = DEFAULT_TABLE, valueEncoding = DEFAULT_VALUE_ENCODING } = options;
23
+ assertSqlIdentifier(table, "table", "Cloudflare Durable Object SQLite");
24
+ this.#sql = sql;
25
+ this.#table = table;
26
+ this.#codec = resolveCloudflareValueCodec(valueEncoding);
27
+ this.#sql.exec(`CREATE TABLE IF NOT EXISTS ${this.#table} (
28
+ key TEXT PRIMARY KEY,
29
+ value ${this.#codec.sqlColumnType} NOT NULL
30
+ )`);
31
+ }
32
+ capabilities() {
33
+ return {
34
+ persistence: "local",
35
+ readAfterWrite: "linearizable",
36
+ scanConsistency: "snapshot",
37
+ atomicBatch: !0,
38
+ conditionalBatch: !0,
39
+ boundedRangeDelete: !0
40
+ };
41
+ }
42
+ async get(key) {
43
+ return this.#getSync(key);
44
+ }
45
+ async put(key, value) {
46
+ this.#putSync(key, value);
47
+ }
48
+ async delete(key) {
49
+ this.#deleteSync(key);
50
+ }
51
+ async has(key) {
52
+ return [
53
+ ...this.#sql.exec(`SELECT 1 AS present FROM ${this.#table} WHERE key = ? LIMIT 1`, key)
54
+ ].length > 0;
55
+ }
56
+ async count(prefix) {
57
+ const [rangeStart, rangeEnd] = buildSqlitePrefixRangeParameters(prefix);
58
+ return [
59
+ ...this.#sql.exec(`SELECT COUNT(*) AS count FROM ${this.#table} WHERE key >= ? AND key < ?`, rangeStart, rangeEnd)
60
+ ][0]?.count ?? 0;
61
+ }
62
+ async deletePrefix(prefix) {
63
+ const [rangeStart, rangeEnd] = buildSqlitePrefixRangeParameters(prefix);
64
+ this.#sql.exec(`DELETE FROM ${this.#table} WHERE key >= ? AND key < ?`, rangeStart, rangeEnd);
65
+ return this.#logicalChangeCount();
66
+ }
67
+ async deleteRange(prefix, options) {
68
+ const normalized = normalizeDeleteRangeOptions(options), { parameters, sql } = buildSqliteKeyRangeDelete(prefix, normalized, this.#table);
69
+ this.#sql.exec(sql, ...parameters);
70
+ return this.#logicalChangeCount();
71
+ }
72
+ #logicalChangeCount() {
73
+ return [...this.#sql.exec("SELECT changes() AS value")][0]?.value ?? 0;
74
+ }
75
+ async* scan(prefix, options = {}) {
76
+ const { parameters, sqlSuffix } = buildSqliteKeyRangeQuery(prefix, options), rows = [
77
+ ...this.#sql.exec(`SELECT key, value FROM ${this.#table} ${sqlSuffix}`, ...parameters)
78
+ ];
79
+ for (const row of rows)
80
+ yield [row.key, this.#codec.decode(row.value, row.key)];
81
+ }
82
+ async* keys(prefix, options = {}) {
83
+ const { parameters, sqlSuffix } = buildSqliteKeyRangeQuery(prefix, options), rows = [
84
+ ...this.#sql.exec(`SELECT key FROM ${this.#table} ${sqlSuffix}`, ...parameters)
85
+ ];
86
+ for (const row of rows)
87
+ yield row.key;
88
+ }
89
+ async batch(operations) {
90
+ assertStorageBatchOperationCount("batch operations", operations.length);
91
+ if (operations.length === 0)
92
+ return;
93
+ for (const operation of operations)
94
+ this.#applyOperation(operation);
95
+ }
96
+ async conditionalBatch(conditions, operations) {
97
+ assertStorageBatchOperationCount("conditionalBatch conditions", conditions.length);
98
+ assertStorageBatchOperationCount("conditionalBatch operations", operations.length);
99
+ for (const condition of conditions) {
100
+ const currentValue = this.#getSync(condition.key);
101
+ if (!storageValuesEqual(currentValue, condition.expectedValue))
102
+ return !1;
103
+ }
104
+ for (const operation of operations)
105
+ this.#applyOperation(operation);
106
+ return !0;
107
+ }
108
+ #getSync(key) {
109
+ const row = [
110
+ ...this.#sql.exec(`SELECT value FROM ${this.#table} WHERE key = ?`, key)
111
+ ][0];
112
+ return row ? this.#codec.decode(row.value, key) : null;
113
+ }
114
+ #putSync(key, value) {
115
+ this.#sql.exec(`INSERT INTO ${this.#table} (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`, key, this.#codec.encode(value));
116
+ }
117
+ #deleteSync(key) {
118
+ this.#sql.exec(`DELETE FROM ${this.#table} WHERE key = ?`, key);
119
+ }
120
+ #applyOperation(operation) {
121
+ if (operation.type === "put")
122
+ this.#putSync(operation.key, operation.value);
123
+ else
124
+ this.#deleteSync(operation.key);
125
+ }
126
+ [Symbol.dispose]() {}
127
+ }
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- var n=Object.defineProperty;var l=(W)=>W;function s(W,F){this[W]=l.bind(null,F)}var UW=(W,F)=>{for(var X in F)n(W,X,{get:F[X],enumerable:!0,configurable:!0,set:s.bind(F,X)})};var P=(W,F)=>()=>(W&&(F=W(W=0)),F);var VW=import.meta.require,PW=(W,F,X)=>{if(F!=null){if(typeof F!=="object"&&typeof F!=="function")throw TypeError('Object expected to be assigned to "using" declaration');let Y;if(X)Y=F[Symbol.asyncDispose];if(Y===void 0)Y=F[Symbol.dispose];if(typeof Y!=="function")throw TypeError("Object not disposable");W.push([X,Y,F])}else if(X)W.push([X]);return F},qW=(W,F,X)=>{let Y=($)=>F=X?new SuppressedError($,F,"An error was suppressed during disposal"):(X=!0,$),U=($)=>{while($=W.pop())try{var j=$[1]&&$[1].call($[2]);if($[0])return Promise.resolve(j).then(U,(D)=>(Y(D),U()))}catch(D){Y(D)}if(X)throw F};return U()};function S(W,F,X){if(!W.capabilities()[F])throw Error(`Feature "${X}" requires storage capability "${F}", but this storage backend does not provide it.`)}function d(W){let F=W.capabilities(),X=[];if(F.persistence!=="local"&&F.persistence!=="remote")X.push(`persistence must be "local" or "remote" (got "${F.persistence}")`);if(F.readAfterWrite!=="linearizable")X.push(`readAfterWrite must be "linearizable" (got "${F.readAfterWrite}")`);if(F.scanConsistency!=="snapshot")X.push(`scanConsistency must be "snapshot" (got "${F.scanConsistency}")`);if(!F.atomicBatch)X.push("atomicBatch must be true");if(!F.conditionalBatch)X.push("conditionalBatch must be true");if(X.length>0)throw Error(`Storage is not durable enough for recovery: ${X.join("; ")}.`)}var Z="default";async function B(W,F){return await W.get(F)!==null}async function*z(W,F,X){for await(let[Y]of W.scan(F,X))yield Y}async function x(W,F){let X=0;for await(let Y of z(W,F))X++;return X}async function v(W,F){let X=[];for await(let Y of z(W,F))X.push({type:"delete",key:Y});if(X.length===0)return 0;return await W.batch(X),X.length}async function CW(W,F,X){let Y=[];for await(let U of z(W,F,X))Y.push({type:"delete",key:U});if(Y.length===0)return 0;return await W.batch(Y),Y.length}var a;var O=P(()=>{a=["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:"]});function G(W,F){if(F>_)throw new h(W,F)}function HW(W){return W.length>0?W.slice(0,-1)+String.fromCharCode(W.charCodeAt(W.length-1)+1):"\xFF"}function EW(W,F={}){if(F.gt!==void 0&&W<=F.gt)return!1;if(F.gte!==void 0&&W<F.gte)return!1;if(F.lt!==void 0&&W>=F.lt)return!1;if(F.lte!==void 0&&W>F.lte)return!1;return!0}function BW(W,F){if(W===null||F===null)return W===F;if(W.byteLength!==F.byteLength)return!1;for(let X=0;X<W.byteLength;X++)if(W[X]!==F[X])return!1;return!0}async function xW(W,F){if(W.has)return W.has(F);return B(W,F)}function vW(W,F,X){if(W.keys)return W.keys(F,X);return z(W,F,X)}async function OW(W,F){if(W.count)return W.count(F);return x(W,F)}async function TW(W,F){if(W.deletePrefix)return W.deletePrefix(F);return v(W,F)}async function hW(W,F){G("batch operations",F.length),await W.batch(F)}async function AW(W,F,X){if(G("conditionalBatch conditions",F.length),G("conditionalBatch operations",X.length),S(W,"conditionalBatch","storageConditionalBatch"),!W.conditionalBatch)throw Error("This storage backend reports conditionalBatch capability but does not implement the conditionalBatch() method.");return W.conditionalBatch(F,X)}function J(W){return encodeURIComponent(W)}function RW(W){return decodeURIComponent(W)}function bW(W){try{return decodeURIComponent(W)}catch{return null}}var _=1e4,NW=1e4,h,K=(W)=>String(W).padStart(16,"0"),i="0",t="1",T=(W,F,X,Y)=>`sig:${J(W)}:${J(F)}:${Y}:${J(X)}`,cW;var A=P(()=>{O();h=class h extends Error{code="StorageBatchOperationLimitExceededError";cap=_;count;target;constructor(W,F){super(`${W} count ${F} exceeds MAX_BATCH_OPERATIONS (${_}).`);this.name="StorageBatchOperationLimitExceededError",this.target=W,this.count=F}};cW={workflow:(W)=>`wf:${J(W)}`,checkpoint:(W)=>`wf:${J(W)}:ckpt`,checkpointHistory:(W,F)=>`wf:${J(W)}:ckpt:${String(F).padStart(10,"0")}`,timelinePrefix:(W)=>`wf:${J(W)}:timeline:`,timeline:(W,F)=>`wf:${J(W)}:timeline:${String(F).padStart(10,"0")}`,schedule:(W)=>`schedule:${J(W)}`,scheduleTick:(W,F)=>`schedule-due:${String(W).padStart(16,"0")}:${J(F)}`,scheduleRun:(W)=>`schedule-run:${J(W)}`,operation:(W,F,X)=>`op:${W}:${K(F)}:${X}`,operationInflight:(W)=>`op:inflight:${W}`,operationQueued:(W)=>`op:queued:${W}`,operationResolved:(W)=>`op:resolved:${W}`,operationDeadLetterPrefix:()=>"op:dead-letter:",operationDeadLetter:(W)=>`op:dead-letter:${W}`,bulkOperationAuditPrefix:()=>"audit:bulk:",bulkOperationAudit:(W,F,X)=>`audit:bulk:${K(W)}:${J(F)}:${J(X)}`,operationResolvedByTimePrefix:()=>"op:resolved-by-time:",operationResolvedByTime:(W,F)=>`op:resolved-by-time:${K(W)}:${J(F)}`,asyncActivity:(W,F)=>`async-act:v1:${J(W)}:${J(F)}`,asyncActivityResolution:(W,F)=>`async-act:v1:${J(W)}:${J(F)}:resolution`,activityReconciliationPrefix:(W)=>`actrec:v1:${J(W)}:`,activityReconciliation:(W,F,X)=>`actrec:v1:${J(W)}:${J(F)}:${X}`,eventPrefix:(W)=>`ev:${J(W)}:`,event:(W,F)=>`ev:${J(W)}:${String(F).padStart(10,"0")}`,eventHead:(W)=>`ev:${J(W)}:head`,eventWatermark:(W)=>`ev:${J(W)}:watermark`,fleetEventPrefix:()=>"fleet-event:",fleetEvent:(W)=>`fleet-event:${String(W).padStart(10,"0")}`,fleetEventTail:()=>"fleet-event-tail",fleetEventByWorkflowPrefix:(W)=>`fleet-event-by-workflow:${J(W)}:`,fleetEventByWorkflow:(W,F)=>`fleet-event-by-workflow:${J(W)}:${String(F).padStart(10,"0")}`,signal:(W,F,X)=>T(W,F,X,t),startSignal:(W,F,X)=>T(W,F,X,i),signalSequence:(W)=>`sigseq:v1:${J(W)}`,signalAcceptedResponsePrefix:(W)=>`sigres:v1:${J(W)}:`,signalAcceptedResponse:(W,F,X)=>`sigres:v1:${J(W)}:${J(F)}:${J(X)}`,deadline:(W,F)=>`wf-deadline:${K(W)}:${J(F)}`,terminalCleanup:(W,F)=>`wf-cleanup:${K(W)}:${J(F)}`,teardownTimer:(W,F)=>`wf-teardown:${K(W)}:${J(F)}`,delayedStart:(W,F)=>`wf-delayed:${K(W)}:${J(F)}`,terminalWorkflowPrefix:()=>"wf-terminal:",terminalWorkflow:(W,F)=>`wf-terminal:${K(W)}:${J(F)}`,attribute:(W)=>`attr:${J(W)}`,attributeIndex:(W,F,X)=>`idx:${W}:${F}:${J(X)}`,tagIndex:(W,F)=>`tag:${J(W)}:${J(F)}`,updatePrefix:(W)=>`upd:${J(W)}:`,update:(W,F)=>`upd:${J(W)}:${F}`,updateResponse:(W)=>`upr:${W}`,updateIdempotency:(W,F)=>`upk:${J(W)}:${F}`,startIdempotency:(W)=>`start-idem:${J(W)}`,startIdempotencySignalId:(W)=>`start-idem:${W}`,livenessPrefix:()=>"liveness:",liveness:(W)=>`liveness:${J(W)}`,leasePrefix:()=>"lease:",leaseEpoch:()=>"lease:epoch",leaseHolder:()=>"lease:holder",budget:(W,F,X)=>`budget:${W}:${F}:${X}`,review:(W,F)=>`review:${J(W)}:${F}`,workflowHeaders:(W)=>`wf-headers:${J(W)}`,childCancellationPrefix:(W)=>`child-cancel:${J(W)}:`,childCancellation:(W,F)=>`child-cancel:${J(W)}:${J(F)}`,terminalCleanupNeeded:(W)=>`wf-cleanup-needed:${J(W)}`,workflowConcurrency:(W,F)=>`wf-concurrency:${J(W)}:${J(F)}`,workflowConcurrencyHolder:(W)=>`wf-concurrency-holder:${J(W)}`,workflowHasServices:(W)=>`wf-has-services:${J(W)}`,finalizerState:(W)=>`wf-finalizer-state:${J(W)}`,teardownOwed:(W)=>`wf-teardown-needed:${J(W)}`,teardownDeadLetter:(W)=>`wf-teardown-deadletter:${J(W)}`,offload:(W,F)=>`offload:${J(W)}:${F}`,archive:(W,F)=>`archive:${J(W)}:${F}`,stateExecution:(W,F)=>`state:execution:${J(W)}:${J(F)}`,stateWorkflow:(W,F)=>`state:workflow-scope:${Z}:${J(W)}:${J(F)}`,streamChunkPrefix:(W,F)=>`blob:${J(W)}:${F}:chunk:`,streamChunk:(W,F,X)=>`blob:${J(W)}:${F}:chunk:${String(X).padStart(10,"0")}`,streamTail:(W,F)=>`blob:${J(W)}:${F}:tail`,streamMetadata:(W,F)=>`blob:${J(W)}:${F}:meta`,budgetCharged:(W)=>`budget-charged:${W}`,toolEffect:(W,F,X)=>`tool-effect:${J(W)}:${F}:${X}`,workflowVisibilityStatus:(W,F)=>`wf-idx-status:${J(W)}:${J(F)}`,workflowVisibilityType:(W,F)=>`wf-idx-type:${J(W)}:${J(F)}`,workflowVisibilityCreated:(W,F)=>`wf-idx-created:${K(W)}:${J(F)}`,workflowVisibilityUpdated:(W,F)=>`wf-idx-updated:${K(W)}:${J(F)}`,workflowVisibilityDeadline:(W,F)=>`wf-idx-deadline:${K(W)}:${J(F)}`,workflowVisibilityManifest:(W)=>`wf-idx-manifest:${J(W)}`,workflowVisibilityMetaVersion:()=>"wf-idx-meta:version",workflowVisibilityMetaBuiltAt:()=>"wf-idx-meta:built-at",workflowVisibilityMetaCursor:()=>"wf-idx-meta:cursor"}});function L(){return typeof(V&&"bun"in V?V.bun:globalThis.Bun)<"u"}function r(){if(V&&"process"in V)return V.process;return globalThis.process}function fW(W){if(L())return Bun.sleep(W);return new Promise((F)=>setTimeout(F,W))}function R(W){let F=e;for(let X=0;X<W.length;X++)F^=BigInt(W[X]),F=F*o&WW;return F.toString(16).padStart(16,"0")}function IW(W){return R(W)}function pW(W){return R(FW.encode(W))}function M(W){let X=r()?.getBuiltinModule;if(typeof X!=="function")return;return X(W)}function kW(W){if(L())return Bun.file(W).size;let F=M("node:fs");if(!F)throw Error("fileSize() requires Bun or Node 22.5+ (process.getBuiltinModule). Not available in browser or edge runtimes.");try{return F.statSync(W).size}catch(X){if(typeof X==="object"&&X!==null&&"code"in X&&X.code==="ENOENT")return 0;throw X}}function b(){let W=M("node:zlib");if(!W)throw Error("gzip/gunzip require Bun or Node 22.5+ (process.getBuiltinModule). "+"Not available in browser or edge runtimes \u2014 use CompressionStream directly.");return W}function c(W){if(L())return new Uint8Array(Bun.gzipSync(new Uint8Array(W)));return new Uint8Array(b().gzipSync(W))}function y(W){if(L())return new Uint8Array(Bun.gunzipSync(new Uint8Array(W)));return new Uint8Array(b().gunzipSync(W))}function m(){return M("node:zlib")}var V,e=0xcbf29ce484222325n,o=0x00000100000001b3n,WW=0xffffffffffffffffn,FW;var g=P(()=>{FW=new TextEncoder});function u(){let W=m();if(!W)throw Error("Brotli compression requires Bun or Node 22.5+ with process.getBuiltinModule support. Use gzip compression for browser/edge runtimes.");return W}function XW(W){return new Uint8Array(u().brotliCompressSync(W))}function JW(W){return new Uint8Array(u().brotliDecompressSync(W))}function p(W){return YW(W)}function YW(W){switch(W){case"gzip":return{algorithm:"gzip",compress(F){return c(F)}};case"brotli":return{algorithm:"brotli",compress(F){return XW(F)}};case"none":return{algorithm:"none",compress(F){return F}}}}async function H(W,F,X){if(W.length<X||F.algorithm==="none"){let j=new Uint8Array(W.length+Q);return j[0]=C,j[1]=N,j.set(W,Q),j}let Y=await F.compress(W);if(Y.length+Q>=W.length+Q){let j=new Uint8Array(W.length+Q);return j[0]=C,j[1]=N,j.set(W,Q),j}let U=F.algorithm==="gzip"?f:I,$=new Uint8Array(Y.length+Q);return $[0]=C,$[1]=U,$.set(Y,Q),$}async function E(W){if(W.length<Q)throw Error("Compression payload missing 2-byte header.");if(W[0]!==C)throw Error("Compression payload missing magic byte 0xC1.");let F=W[1],X=W.slice(Q);switch(F){case N:return X;case f:return y(X);case I:return JW(X);default:throw Error(`Compression payload uses unsupported algorithm byte 0x${F.toString(16).padStart(2,"0")}.`)}}function k(W){return{threshold:W?.threshold??$W,algorithm:W?.algorithm??jW}}var C=193,N=0,f=1,I=2,Q=2,$W=4096,jW="gzip";var w=P(()=>{g()});var KW;var QW=P(()=>{w();A();KW=class KW{#W;#F;#X;constructor(W,F){this.#W=W;let X=k(F);if(this.#F=p(X.algorithm),this.#X=X.threshold,W.query){let Y=W.query.bind(W);Object.defineProperty(this,"query",{value:Y,enumerable:!0,configurable:!0})}}capabilities(){let W=this.#W.capabilities();return{...W.persistence===void 0?{}:{persistence:W.persistence},readAfterWrite:W.readAfterWrite,scanConsistency:W.scanConsistency,atomicBatch:W.atomicBatch,conditionalBatch:!1,boundedRangeDelete:!1}}async get(W){let F=await this.#W.get(W);if(!F)return null;return E(F)}async put(W,F){let X=await H(F,this.#F,this.#X);return this.#W.put(W,X)}async delete(W){return this.#W.delete(W)}async*scan(W,F){for await(let[X,Y]of this.#W.scan(W,F))yield[X,await E(Y)]}async batch(W){G("batch operations",W.length);let F=await Promise.all(W.map(async(X)=>{if(X.type==="put")return{type:"put",key:X.key,value:await H(X.value,this.#F,this.#X)};return X}));return this.#W.batch(F)}[Symbol.dispose](){this.#W[Symbol.dispose]()}}});QW();export{KW as CompressedStorage};
2
+ var i=import.meta.require,t=(W,F,X)=>{if(F!=null){if(typeof F!=="object"&&typeof F!=="function")throw TypeError('Object expected to be assigned to "using" declaration');let Y;if(X)Y=F[Symbol.asyncDispose];if(Y===void 0)Y=F[Symbol.dispose];if(typeof Y!=="function")throw TypeError("Object not disposable");W.push([X,Y,F])}else if(X)W.push([X]);return F},r=(W,F,X)=>{let Y=($)=>F=X?new SuppressedError($,F,"An error was suppressed during disposal"):(X=!0,$),U=($)=>{while($=W.pop())try{var j=$[1]&&$[1].call($[2]);if($[0])return Promise.resolve(j).then(U,(C)=>(Y(C),U()))}catch(C){Y(C)}if(X)throw F};return U()};function G(W,F,X){if(!W.capabilities()[F])throw Error(`Feature "${X}" requires storage capability "${F}", but this storage backend does not provide it.`)}function g(W){let F=W.capabilities(),X=[];if(F.persistence!=="local"&&F.persistence!=="remote")X.push(`persistence must be "local" or "remote" (got "${F.persistence}")`);if(F.readAfterWrite!=="linearizable")X.push(`readAfterWrite must be "linearizable" (got "${F.readAfterWrite}")`);if(F.scanConsistency!=="snapshot")X.push(`scanConsistency must be "snapshot" (got "${F.scanConsistency}")`);if(!F.atomicBatch)X.push("atomicBatch must be true");if(!F.conditionalBatch)X.push("conditionalBatch must be true");if(X.length>0)throw Error(`Storage is not durable enough for recovery: ${X.join("; ")}.`)}var D="default";async function M(W,F){return await W.get(F)!==null}async function*P(W,F,X){for await(let[Y]of W.scan(F,X))yield Y}async function N(W,F){let X=0;for await(let Y of P(W,F))X++;return X}async function H(W,F){let X=[];for await(let Y of P(W,F))X.push({type:"delete",key:Y});if(X.length===0)return 0;return await W.batch(X),X.length}async function FW(W,F,X){let Y=[];for await(let U of P(W,F,X))Y.push({type:"delete",key:U});if(Y.length===0)return 0;return await W.batch(Y),Y.length}var u=["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:"];var L=1e4,KW=1e4;class B extends Error{code="StorageBatchOperationLimitExceededError";cap=L;count;target;constructor(W,F){super(`${W} count ${F} exceeds MAX_BATCH_OPERATIONS (${L}).`);this.name="StorageBatchOperationLimitExceededError",this.target=W,this.count=F}}function q(W,F){if(F>L)throw new B(W,F)}function QW(W){return W.length>0?W.slice(0,-1)+String.fromCharCode(W.charCodeAt(W.length-1)+1):"\xFF"}function UW(W,F={}){if(F.gt!==void 0&&W<=F.gt)return!1;if(F.gte!==void 0&&W<F.gte)return!1;if(F.lt!==void 0&&W>=F.lt)return!1;if(F.lte!==void 0&&W>F.lte)return!1;return!0}function VW(W,F){if(W===null||F===null)return W===F;if(W.byteLength!==F.byteLength)return!1;for(let X=0;X<W.byteLength;X++)if(W[X]!==F[X])return!1;return!0}async function PW(W,F){if(W.has)return W.has(F);return M(W,F)}function qW(W,F,X){if(W.keys)return W.keys(F,X);return P(W,F,X)}async function zW(W,F){if(W.count)return W.count(F);return N(W,F)}async function CW(W,F){if(W.deletePrefix)return W.deletePrefix(F);return H(W,F)}async function GW(W,F){q("batch operations",F.length),await W.batch(F)}async function DW(W,F,X){if(q("conditionalBatch conditions",F.length),q("conditionalBatch operations",X.length),G(W,"conditionalBatch","storageConditionalBatch"),!W.conditionalBatch)throw Error("This storage backend reports conditionalBatch capability but does not implement the conditionalBatch() method.");return W.conditionalBatch(F,X)}function J(W){return encodeURIComponent(W)}function LW(W){return decodeURIComponent(W)}function SW(W){try{return decodeURIComponent(W)}catch{return null}}var K=(W)=>String(W).padStart(16,"0"),f="0",I="1",E=(W,F,X,Y)=>`sig:${J(W)}:${J(F)}:${Y}:${J(X)}`,ZW={workflow:(W)=>`wf:${J(W)}`,checkpoint:(W)=>`wf:${J(W)}:ckpt`,checkpointHistory:(W,F)=>`wf:${J(W)}:ckpt:${String(F).padStart(10,"0")}`,timelinePrefix:(W)=>`wf:${J(W)}:timeline:`,timeline:(W,F)=>`wf:${J(W)}:timeline:${String(F).padStart(10,"0")}`,schedule:(W)=>`schedule:${J(W)}`,scheduleTick:(W,F)=>`schedule-due:${String(W).padStart(16,"0")}:${J(F)}`,scheduleRun:(W)=>`schedule-run:${J(W)}`,operation:(W,F,X)=>`op:${W}:${K(F)}:${X}`,operationInflight:(W)=>`op:inflight:${W}`,operationQueued:(W)=>`op:queued:${W}`,operationResolved:(W)=>`op:resolved:${W}`,operationDeadLetterPrefix:()=>"op:dead-letter:",operationDeadLetter:(W)=>`op:dead-letter:${W}`,bulkOperationAuditPrefix:()=>"audit:bulk:",bulkOperationAudit:(W,F,X)=>`audit:bulk:${K(W)}:${J(F)}:${J(X)}`,operationResolvedByTimePrefix:()=>"op:resolved-by-time:",operationResolvedByTime:(W,F)=>`op:resolved-by-time:${K(W)}:${J(F)}`,asyncActivity:(W,F)=>`async-act:v1:${J(W)}:${J(F)}`,asyncActivityResolution:(W,F)=>`async-act:v1:${J(W)}:${J(F)}:resolution`,activityReconciliationPrefix:(W)=>`actrec:v1:${J(W)}:`,activityReconciliation:(W,F,X)=>`actrec:v1:${J(W)}:${J(F)}:${X}`,eventPrefix:(W)=>`ev:${J(W)}:`,event:(W,F)=>`ev:${J(W)}:${String(F).padStart(10,"0")}`,eventHead:(W)=>`ev:${J(W)}:head`,eventWatermark:(W)=>`ev:${J(W)}:watermark`,fleetEventPrefix:()=>"fleet-event:",fleetEvent:(W)=>`fleet-event:${String(W).padStart(10,"0")}`,fleetEventTail:()=>"fleet-event-tail",fleetEventByWorkflowPrefix:(W)=>`fleet-event-by-workflow:${J(W)}:`,fleetEventByWorkflow:(W,F)=>`fleet-event-by-workflow:${J(W)}:${String(F).padStart(10,"0")}`,signal:(W,F,X)=>E(W,F,X,I),startSignal:(W,F,X)=>E(W,F,X,f),signalSequence:(W)=>`sigseq:v1:${J(W)}`,signalAcceptedResponsePrefix:(W)=>`sigres:v1:${J(W)}:`,signalAcceptedResponse:(W,F,X)=>`sigres:v1:${J(W)}:${J(F)}:${J(X)}`,deadline:(W,F)=>`wf-deadline:${K(W)}:${J(F)}`,terminalCleanup:(W,F)=>`wf-cleanup:${K(W)}:${J(F)}`,teardownTimer:(W,F)=>`wf-teardown:${K(W)}:${J(F)}`,delayedStart:(W,F)=>`wf-delayed:${K(W)}:${J(F)}`,terminalWorkflowPrefix:()=>"wf-terminal:",terminalWorkflow:(W,F)=>`wf-terminal:${K(W)}:${J(F)}`,attribute:(W)=>`attr:${J(W)}`,attributeIndex:(W,F,X)=>`idx:${W}:${F}:${J(X)}`,tagIndex:(W,F)=>`tag:${J(W)}:${J(F)}`,updatePrefix:(W)=>`upd:${J(W)}:`,update:(W,F)=>`upd:${J(W)}:${F}`,updateResponse:(W)=>`upr:${W}`,updateIdempotency:(W,F)=>`upk:${J(W)}:${F}`,startIdempotency:(W)=>`start-idem:${J(W)}`,startIdempotencySignalId:(W)=>`start-idem:${W}`,livenessPrefix:()=>"liveness:",liveness:(W)=>`liveness:${J(W)}`,leasePrefix:()=>"lease:",leaseEpoch:()=>"lease:epoch",leaseHolder:()=>"lease:holder",budget:(W,F,X)=>`budget:${W}:${F}:${X}`,review:(W,F)=>`review:${J(W)}:${F}`,workflowHeaders:(W)=>`wf-headers:${J(W)}`,childCancellationPrefix:(W)=>`child-cancel:${J(W)}:`,childCancellation:(W,F)=>`child-cancel:${J(W)}:${J(F)}`,terminalCleanupNeeded:(W)=>`wf-cleanup-needed:${J(W)}`,workflowConcurrency:(W,F)=>`wf-concurrency:${J(W)}:${J(F)}`,workflowConcurrencyHolder:(W)=>`wf-concurrency-holder:${J(W)}`,workflowHasServices:(W)=>`wf-has-services:${J(W)}`,finalizerState:(W)=>`wf-finalizer-state:${J(W)}`,teardownOwed:(W)=>`wf-teardown-needed:${J(W)}`,teardownDeadLetter:(W)=>`wf-teardown-deadletter:${J(W)}`,offload:(W,F)=>`offload:${J(W)}:${F}`,archive:(W,F)=>`archive:${J(W)}:${F}`,stateExecution:(W,F)=>`state:execution:${J(W)}:${J(F)}`,stateWorkflow:(W,F)=>`state:workflow-scope:${D}:${J(W)}:${J(F)}`,streamChunkPrefix:(W,F)=>`blob:${J(W)}:${F}:chunk:`,streamChunk:(W,F,X)=>`blob:${J(W)}:${F}:chunk:${String(X).padStart(10,"0")}`,streamTail:(W,F)=>`blob:${J(W)}:${F}:tail`,streamMetadata:(W,F)=>`blob:${J(W)}:${F}:meta`,budgetCharged:(W)=>`budget-charged:${W}`,toolEffect:(W,F,X)=>`tool-effect:${J(W)}:${F}:${X}`,workflowVisibilityStatus:(W,F)=>`wf-idx-status:${J(W)}:${J(F)}`,workflowVisibilityType:(W,F)=>`wf-idx-type:${J(W)}:${J(F)}`,workflowVisibilityCreated:(W,F)=>`wf-idx-created:${K(W)}:${J(F)}`,workflowVisibilityUpdated:(W,F)=>`wf-idx-updated:${K(W)}:${J(F)}`,workflowVisibilityDeadline:(W,F)=>`wf-idx-deadline:${K(W)}:${J(F)}`,workflowVisibilityManifest:(W)=>`wf-idx-manifest:${J(W)}`,workflowVisibilityMetaVersion:()=>"wf-idx-meta:version",workflowVisibilityMetaBuiltAt:()=>"wf-idx-meta:built-at",workflowVisibilityMetaCursor:()=>"wf-idx-meta:cursor"};var V;function p(){if(V&&"bun"in V)return V.bun;return globalThis.Bun}function x(){return typeof p()<"u"}function k(){if(V&&"process"in V)return V.process;return globalThis.process}function v(W){let X=k()?.getBuiltinModule;if(typeof X!=="function")return;return X(W)}function O(){let W=v("node:zlib");if(!W)throw Error("gzip/gunzip require Bun or Node 22.5+ (process.getBuiltinModule). "+"Not available in browser or edge runtimes \u2014 use CompressionStream directly.");return W}function T(W){if(x())return new Uint8Array(Bun.gzipSync(new Uint8Array(W)));return new Uint8Array(O().gzipSync(W))}function h(W){if(x())return new Uint8Array(Bun.gunzipSync(new Uint8Array(W)));return new Uint8Array(O().gunzipSync(W))}function A(){return v("node:zlib")}function R(){let W=A();if(!W)throw Error("Brotli compression requires Bun or Node 22.5+ with process.getBuiltinModule support. Use gzip compression for browser/edge runtimes.");return W}function w(W){return new Uint8Array(R().brotliCompressSync(W))}function n(W){return new Uint8Array(R().brotliDecompressSync(W))}var z=193,S=0,b=1,c=2,Q=2;function y(W){return l(W)}function l(W){switch(W){case"gzip":return{algorithm:"gzip",compress(F){return T(F)}};case"brotli":return{algorithm:"brotli",compress(F){return w(F)}};case"none":return{algorithm:"none",compress(F){return F}}}}async function Z(W,F,X){if(W.length<X||F.algorithm==="none"){let j=new Uint8Array(W.length+Q);return j[0]=z,j[1]=S,j.set(W,Q),j}let Y=await F.compress(W);if(Y.length+Q>=W.length+Q){let j=new Uint8Array(W.length+Q);return j[0]=z,j[1]=S,j.set(W,Q),j}let U=F.algorithm==="gzip"?b:c,$=new Uint8Array(Y.length+Q);return $[0]=z,$[1]=U,$.set(Y,Q),$}async function _(W){if(W.length<Q)throw Error("Compression payload missing 2-byte header.");if(W[0]!==z)throw Error("Compression payload missing magic byte 0xC1.");let F=W[1],X=W.slice(Q);switch(F){case S:return X;case b:return h(X);case c:return n(X);default:throw Error(`Compression payload uses unsupported algorithm byte 0x${F.toString(16).padStart(2,"0")}.`)}}var s=4096,d="gzip";function m(W){return{threshold:W?.threshold??s,algorithm:W?.algorithm??d}}class a{#W;#F;#X;constructor(W,F){this.#W=W;let X=m(F);if(this.#F=y(X.algorithm),this.#X=X.threshold,W.query){let Y=W.query.bind(W);Object.defineProperty(this,"query",{value:Y,enumerable:!0,configurable:!0})}}capabilities(){let W=this.#W.capabilities();return{...W.persistence===void 0?{}:{persistence:W.persistence},readAfterWrite:W.readAfterWrite,scanConsistency:W.scanConsistency,atomicBatch:W.atomicBatch,conditionalBatch:!1,boundedRangeDelete:!1}}async get(W){let F=await this.#W.get(W);if(!F)return null;return _(F)}async put(W,F){let X=await Z(F,this.#F,this.#X);return this.#W.put(W,X)}async delete(W){return this.#W.delete(W)}async*scan(W,F){for await(let[X,Y]of this.#W.scan(W,F))yield[X,await _(Y)]}async batch(W){q("batch operations",W.length);let F=await Promise.all(W.map(async(X)=>{if(X.type==="put")return{type:"put",key:X.key,value:await Z(X.value,this.#F,this.#X)};return X}));return this.#W.batch(F)}[Symbol.dispose](){this.#W[Symbol.dispose]()}}export{a as CompressedStorage};