@effect-agent/storage-cloudflare 0.1.0-beta.45 → 0.1.0-beta.47

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 (68) hide show
  1. package/dist/DoMemoryStore.d.mts +24 -0
  2. package/dist/DoMemoryStore.mjs +50 -0
  3. package/dist/DoMemoryStore.mjs.map +1 -0
  4. package/dist/DoScheduleStore.d.mts +36 -0
  5. package/dist/DoScheduleStore.mjs +369 -0
  6. package/dist/DoScheduleStore.mjs.map +1 -0
  7. package/dist/DoStorageConfig.d.mts +45 -0
  8. package/dist/DoStorageConfig.mjs +52 -0
  9. package/dist/DoStorageConfig.mjs.map +1 -0
  10. package/dist/{do-storage-failpoint-9XB9tuif.d.mts → DoStorageError-Qwybzk0O.d.mts} +6 -15
  11. package/dist/DoStorageError.d.mts +2 -0
  12. package/dist/DoStorageError.mjs +158 -0
  13. package/dist/DoStorageError.mjs.map +1 -0
  14. package/dist/DoStorageFailpoint.d.mts +17 -0
  15. package/dist/{do-storage-failpoint-C-Qtchs7.mjs → DoStorageFailpoint.mjs} +5 -3
  16. package/dist/DoStorageFailpoint.mjs.map +1 -0
  17. package/dist/{testing.d.mts → DoStorageFailpointTesting.d.mts} +4 -3
  18. package/dist/{testing.mjs → DoStorageFailpointTesting.mjs} +3 -3
  19. package/dist/DoStorageFailpointTesting.mjs.map +1 -0
  20. package/dist/DoStorageVersion-KrYUXqeJ.d.mts +10 -0
  21. package/dist/DoStorageVersion.d.mts +2 -0
  22. package/dist/DoStorageVersion.mjs +8 -0
  23. package/dist/DoStorageVersion.mjs.map +1 -0
  24. package/dist/DoSubmissionLedger.d.mts +23 -0
  25. package/dist/DoSubmissionLedger.mjs +1716 -0
  26. package/dist/DoSubmissionLedger.mjs.map +1 -0
  27. package/dist/DoSubscriptionStore.d.mts +25 -0
  28. package/dist/DoSubscriptionStore.mjs +720 -0
  29. package/dist/DoSubscriptionStore.mjs.map +1 -0
  30. package/dist/DoThreadStore-D9ebIYPv.mjs +1083 -0
  31. package/dist/DoThreadStore-D9ebIYPv.mjs.map +1 -0
  32. package/dist/DoThreadStore.d.mts +59 -0
  33. package/dist/DoThreadStore.mjs +5 -0
  34. package/dist/MemoryProtocol.d.mts +19796 -0
  35. package/dist/MemoryProtocol.mjs +182 -0
  36. package/dist/MemoryProtocol.mjs.map +1 -0
  37. package/dist/PortProtocol.d.mts +1587 -0
  38. package/dist/PortProtocol.mjs +175 -0
  39. package/dist/PortProtocol.mjs.map +1 -0
  40. package/dist/PortRouting.d.mts +82 -0
  41. package/dist/PortRouting.mjs +404 -0
  42. package/dist/PortRouting.mjs.map +1 -0
  43. package/dist/index.d.mts +13 -21619
  44. package/dist/index.mjs +13 -4954
  45. package/dist/migrations-Bo4GU-pp.mjs +236 -0
  46. package/dist/migrations-Bo4GU-pp.mjs.map +1 -0
  47. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  48. package/package.json +1 -1
  49. package/src/{do-memory-store.ts → DoMemoryStore.ts} +5 -2
  50. package/src/{do-schedule-store.ts → DoScheduleStore.ts} +6 -4
  51. package/src/{errors.ts → DoStorageError.ts} +1 -1
  52. package/src/{do-storage-failpoint.ts → DoStorageFailpoint.ts} +1 -1
  53. package/src/{do-storage-failpoint-testing.ts → DoStorageFailpointTesting.ts} +2 -2
  54. package/src/DoStorageVersion.ts +2 -0
  55. package/src/{do-ledger.ts → DoSubmissionLedger.ts} +22 -20
  56. package/src/{do-subscription-store.ts → DoSubscriptionStore.ts} +10 -8
  57. package/src/{do-thread-store.ts → DoThreadStore.ts} +19 -21
  58. package/src/{memory-protocol.ts → MemoryProtocol.ts} +15 -10
  59. package/src/{port-protocol.ts → PortProtocol.ts} +13 -11
  60. package/src/{routing.ts → PortRouting.ts} +10 -8
  61. package/src/index.ts +12 -36
  62. package/src/{do-journal.ts → internal/do-journal.ts} +2 -2
  63. package/dist/do-storage-failpoint-C-Qtchs7.mjs.map +0 -1
  64. package/dist/index.mjs.map +0 -1
  65. package/dist/testing.mjs.map +0 -1
  66. package/src/testing.ts +0 -2
  67. /package/src/{do-storage-config.ts → DoStorageConfig.ts} +0 -0
  68. /package/src/{migrations.ts → internal/migrations.ts} +0 -0
@@ -0,0 +1,24 @@
1
+ import { MemoryMutationFailpoint } from "@effect-agent/core/MemoryStore";
2
+ import { SqliteClient } from "@effect/sql-sqlite-do";
3
+ import { Layer, Schema } from "effect";
4
+ declare namespace DoMemoryStore_d_exports {
5
+ export { DoMemoryStorageLimits, defaultDoMemoryStorageLimits, doMemoryStoreLayer, doMemoryStoreLayerWithFailpoints };
6
+ }
7
+ declare const DoMemoryStorageLimits_base: Schema.Class<DoMemoryStorageLimits, Schema.Struct<{
8
+ readonly maxRowBytes: Schema.Int;
9
+ readonly maxStorageBytes: Schema.Int;
10
+ readonly maxDocuments: Schema.Int;
11
+ readonly maxReceipts: Schema.Int;
12
+ }>, {}>;
13
+ declare class DoMemoryStorageLimits extends DoMemoryStorageLimits_base {}
14
+ declare const defaultDoMemoryStorageLimits: DoMemoryStorageLimits;
15
+ /**
16
+ * Local memory only, without Thread tables. Keep one SQL client per owner and pass the
17
+ * full storage handle: sql-only handles cannot provide atomic receipts and revisions.
18
+ * Byte limits conservatively count encoded rows, not SQLite page/index overhead.
19
+ */
20
+ declare const doMemoryStoreLayerWithFailpoints: (storage: NonNullable<SqliteClient.SqliteClientConfig["storage"]>, limits?: DoMemoryStorageLimits) => Layer.Layer<import("@effect-agent/core/MemoryStore").MemoryReader | import("@effect-agent/core/MemoryStore").MemoryWriter, import("@effect-agent/thread/SqlMemoryStore").SqliteMemoryInitializationError, MemoryMutationFailpoint>;
21
+ declare const doMemoryStoreLayer: (storage: NonNullable<SqliteClient.SqliteClientConfig["storage"]>, limits?: DoMemoryStorageLimits) => Layer.Layer<import("@effect-agent/core/MemoryStore").MemoryReader | import("@effect-agent/core/MemoryStore").MemoryWriter, import("@effect-agent/thread/SqlMemoryStore").SqliteMemoryInitializationError, never>;
22
+ //#endregion
23
+ export { DoMemoryStorageLimits, defaultDoMemoryStorageLimits, doMemoryStoreLayer, doMemoryStoreLayerWithFailpoints, DoMemoryStore_d_exports as t };
24
+ //# sourceMappingURL=DoMemoryStore.d.mts.map
@@ -0,0 +1,50 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { MemoryMutationFailpoint, MemoryStorageError } from "@effect-agent/core/MemoryStore";
3
+ import { SqlMemoryLimits, memoryStoreLayerWithFailpoints } from "@effect-agent/thread/SqlMemoryStore";
4
+ import { SqliteClient } from "@effect/sql-sqlite-do";
5
+ import { Effect, Layer, Schema } from "effect";
6
+ //#region src/DoMemoryStore.ts
7
+ var DoMemoryStore_exports = /* @__PURE__ */ __exportAll({
8
+ DoMemoryStorageLimits: () => DoMemoryStorageLimits,
9
+ defaultDoMemoryStorageLimits: () => defaultDoMemoryStorageLimits,
10
+ doMemoryStoreLayer: () => doMemoryStoreLayer,
11
+ doMemoryStoreLayerWithFailpoints: () => doMemoryStoreLayerWithFailpoints
12
+ });
13
+ var DoMemoryStorageLimits = class extends Schema.Class("@effect-agent/storage-cloudflare/DoMemoryStorageLimits")({
14
+ maxRowBytes: Schema.Int.check(Schema.isBetween({
15
+ minimum: 1,
16
+ maximum: 19e5
17
+ })),
18
+ maxStorageBytes: Schema.Int.check(Schema.isBetween({
19
+ minimum: 1,
20
+ maximum: 536870912
21
+ })),
22
+ maxDocuments: Schema.Int.check(Schema.isBetween({
23
+ minimum: 1,
24
+ maximum: 1e5
25
+ })),
26
+ maxReceipts: Schema.Int.check(Schema.isBetween({
27
+ minimum: 1,
28
+ maximum: 1e6
29
+ }))
30
+ }) {};
31
+ const defaultDoMemoryStorageLimits = DoMemoryStorageLimits.make({
32
+ maxRowBytes: 19e5,
33
+ maxStorageBytes: 536870912,
34
+ maxDocuments: 1e4,
35
+ maxReceipts: 1e5
36
+ });
37
+ /**
38
+ * Local memory only, without Thread tables. Keep one SQL client per owner and pass the
39
+ * full storage handle: sql-only handles cannot provide atomic receipts and revisions.
40
+ * Byte limits conservatively count encoded rows, not SQLite page/index overhead.
41
+ */
42
+ const doMemoryStoreLayerWithFailpoints = (storage, limits = defaultDoMemoryStorageLimits) => Layer.unwrap(Schema.decodeUnknownEffect(DoMemoryStorageLimits)(limits).pipe(Effect.mapError(() => MemoryStorageError.make({
43
+ operation: "memory storage limits",
44
+ reason: "invalid-input"
45
+ })), Effect.map((validated) => memoryStoreLayerWithFailpoints.pipe(Layer.provide(Layer.succeed(SqlMemoryLimits, validated)), Layer.provide(SqliteClient.layer({ storage }))))));
46
+ const doMemoryStoreLayer = (storage, limits = defaultDoMemoryStorageLimits) => doMemoryStoreLayerWithFailpoints(storage, limits).pipe(Layer.provide(MemoryMutationFailpoint.layer));
47
+ //#endregion
48
+ export { DoMemoryStorageLimits, defaultDoMemoryStorageLimits, doMemoryStoreLayer, doMemoryStoreLayerWithFailpoints, DoMemoryStore_exports as t };
49
+
50
+ //# sourceMappingURL=DoMemoryStore.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DoMemoryStore.mjs","names":[],"sources":["../src/DoMemoryStore.ts"],"sourcesContent":["import { MemoryStorageError, MemoryMutationFailpoint } from \"@effect-agent/core/MemoryStore\";\nimport {\n memoryStoreLayerWithFailpoints,\n SqlMemoryLimits,\n} from \"@effect-agent/thread/SqlMemoryStore\";\nimport { SqliteClient } from \"@effect/sql-sqlite-do\";\nimport { Effect, Layer, Schema } from \"effect\";\n\nexport class DoMemoryStorageLimits extends Schema.Class<DoMemoryStorageLimits>(\n \"@effect-agent/storage-cloudflare/DoMemoryStorageLimits\",\n)({\n maxRowBytes: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 1_900_000 })),\n maxStorageBytes: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 536_870_912 })),\n maxDocuments: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100_000 })),\n maxReceipts: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 1_000_000 })),\n}) {}\n\nexport const defaultDoMemoryStorageLimits = DoMemoryStorageLimits.make({\n maxRowBytes: 1_900_000,\n maxStorageBytes: 536_870_912,\n maxDocuments: 10_000,\n maxReceipts: 100_000,\n});\n\n/**\n * Local memory only, without Thread tables. Keep one SQL client per owner and pass the\n * full storage handle: sql-only handles cannot provide atomic receipts and revisions.\n * Byte limits conservatively count encoded rows, not SQLite page/index overhead.\n */\nexport const doMemoryStoreLayerWithFailpoints = (\n storage: NonNullable<SqliteClient.SqliteClientConfig[\"storage\"]>,\n limits: DoMemoryStorageLimits = defaultDoMemoryStorageLimits,\n) =>\n Layer.unwrap(\n Schema.decodeUnknownEffect(DoMemoryStorageLimits)(limits).pipe(\n Effect.mapError(() =>\n MemoryStorageError.make({ operation: \"memory storage limits\", reason: \"invalid-input\" }),\n ),\n Effect.map((validated) =>\n memoryStoreLayerWithFailpoints.pipe(\n Layer.provide(Layer.succeed(SqlMemoryLimits, validated)),\n Layer.provide(SqliteClient.layer({ storage })),\n ),\n ),\n ),\n );\n\nexport const doMemoryStoreLayer = (\n storage: NonNullable<SqliteClient.SqliteClientConfig[\"storage\"]>,\n limits: DoMemoryStorageLimits = defaultDoMemoryStorageLimits,\n) =>\n doMemoryStoreLayerWithFailpoints(storage, limits).pipe(\n Layer.provide(MemoryMutationFailpoint.layer),\n );\n"],"mappings":";;;;;;;;;;;;AAQA,IAAa,wBAAb,cAA2C,OAAO,MAChD,wDACF,CAAC,CAAC;CACA,aAAa,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAU,CAAC,CAAC;CAClF,iBAAiB,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAY,CAAC,CAAC;CACxF,cAAc,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAQ,CAAC,CAAC;CACjF,aAAa,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAU,CAAC,CAAC;AACpF,CAAC,CAAC,CAAC,CAAC;AAEJ,MAAa,+BAA+B,sBAAsB,KAAK;CACrE,aAAa;CACb,iBAAiB;CACjB,cAAc;CACd,aAAa;AACf,CAAC;;;;;;AAOD,MAAa,oCACX,SACA,SAAgC,iCAEhC,MAAM,OACJ,OAAO,oBAAoB,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,KACxD,OAAO,eACL,mBAAmB,KAAK;CAAE,WAAW;CAAyB,QAAQ;AAAgB,CAAC,CACzF,GACA,OAAO,KAAK,cACV,+BAA+B,KAC7B,MAAM,QAAQ,MAAM,QAAQ,iBAAiB,SAAS,CAAC,GACvD,MAAM,QAAQ,aAAa,MAAM,EAAE,QAAQ,CAAC,CAAC,CAC/C,CACF,CACF,CACF;AAEF,MAAa,sBACX,SACA,SAAgC,iCAEhC,iCAAiC,SAAS,MAAM,CAAC,CAAC,KAChD,MAAM,QAAQ,wBAAwB,KAAK,CAC7C"}
@@ -0,0 +1,36 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { ScheduleFailpointError, ScheduleStorageError, ScheduleStore } from "@effect-agent/thread/Schedule";
3
+ import * as SqlClientService from "effect/unstable/sql/SqlClient";
4
+ declare namespace DoScheduleStore_d_exports {
5
+ export { DoScheduleAlarmControl, DoScheduleAlarmReplacement, DoScheduleReplaceAlarm, DoScheduleTransaction, scheduleStoreLayer };
6
+ }
7
+ interface DoScheduleAlarmReplacement {
8
+ readonly deadlineAtMillis: number | null;
9
+ /** Included in every logical alarm payload so equal-time replacement stays distinguishable. */
10
+ readonly generation: number;
11
+ }
12
+ type DoScheduleReplaceAlarm = (replacement: DoScheduleAlarmReplacement) => Effect.Effect<void, ScheduleStorageError>;
13
+ declare const DoScheduleTransaction_base: Context.ServiceClass<DoScheduleTransaction, "@effect-agent/storage-cloudflare/DoScheduleTransaction", {
14
+ readonly run: <A, E, R>(body: (replaceAlarm: DoScheduleReplaceAlarm) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | ScheduleStorageError, R>;
15
+ }>;
16
+ /**
17
+ * Platform-owned transaction boundary for schedule SQL and logical alarm mutation. The callback
18
+ * and its `replaceAlarm` capability belong to one fiber and must not escape or fork.
19
+ */
20
+ declare class DoScheduleTransaction extends DoScheduleTransaction_base {}
21
+ declare const DoScheduleAlarmControl_base: Context.ServiceClass<DoScheduleAlarmControl, "@effect-agent/storage-cloudflare/DoScheduleAlarmControl", {
22
+ /** Establish a future recovery wake before cross-Object admission starts. */
23
+ readonly prearm: (deadlineAtMillis: number) => Effect.Effect<void, ScheduleStorageError | ScheduleFailpointError>;
24
+ /** Replace or cancel the wake from the object's authoritative indexed deadline. */
25
+ readonly reconcile: Effect.Effect<void, ScheduleStorageError | ScheduleFailpointError>;
26
+ }>;
27
+ /** Platform driver operations that use the same schedule-state and alarm transaction. */
28
+ declare class DoScheduleAlarmControl extends DoScheduleAlarmControl_base {}
29
+ /**
30
+ * Durable Object SQLite ScheduleStore. Platform code supplies the one transaction owner that
31
+ * combines these SQL mutations with its logical and native alarm lifecycle.
32
+ */
33
+ declare const scheduleStoreLayer: Layer.Layer<ScheduleStore | DoScheduleAlarmControl, ScheduleStorageError, SqlClientService.SqlClient | DoScheduleTransaction>;
34
+ //#endregion
35
+ export { DoScheduleAlarmControl, DoScheduleAlarmReplacement, DoScheduleReplaceAlarm, DoScheduleTransaction, scheduleStoreLayer, DoScheduleStore_d_exports as t };
36
+ //# sourceMappingURL=DoScheduleStore.d.mts.map
@@ -0,0 +1,369 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { Context, Effect, Layer, Result, Schema } from "effect";
3
+ import { ScheduleCapacityError, ScheduleChange, ScheduleConflict, ScheduleDueCursor, ScheduleFailpoint, ScheduleId, ScheduleInstant, ScheduleKey, ScheduleNotFound, ScheduleOwner, SchedulePageRequest, ScheduleRecord, ScheduleStorageError, ScheduleStore, defaultSchedulingLimits } from "@effect-agent/thread/Schedule";
4
+ import { applyScheduleChange, scheduleDeadline, scheduleUsesCapacity } from "@effect-agent/thread/ScheduleTransition";
5
+ import * as SqlClientService from "effect/unstable/sql/SqlClient";
6
+ //#region src/DoScheduleStore.ts
7
+ var DoScheduleStore_exports = /* @__PURE__ */ __exportAll({
8
+ DoScheduleAlarmControl: () => DoScheduleAlarmControl,
9
+ DoScheduleTransaction: () => DoScheduleTransaction,
10
+ scheduleStoreLayer: () => scheduleStoreLayer
11
+ });
12
+ const CURRENT_SCHEDULE_STORE_VERSION = 2;
13
+ const StoredScheduleJson = Schema.String.check(Schema.isMaxLength(19e5));
14
+ const StoredDeadline = Schema.NullOr(ScheduleInstant);
15
+ var ScheduleRow = class extends Schema.Class("@effect-agent/storage-cloudflare/ScheduleRow")({
16
+ tenant_id: ScheduleOwner.fields.tenantId,
17
+ owner_id: ScheduleOwner.fields.ownerId,
18
+ schedule_id: ScheduleId,
19
+ deadline_at_millis: StoredDeadline,
20
+ record_json: StoredScheduleJson
21
+ }) {};
22
+ const ScheduleDueRow = Schema.Struct({
23
+ tenant_id: ScheduleOwner.fields.tenantId,
24
+ owner_id: ScheduleOwner.fields.ownerId,
25
+ schedule_id: ScheduleId,
26
+ deadline_at_millis: ScheduleInstant
27
+ });
28
+ var ScheduleCountRow = class extends Schema.Class("@effect-agent/storage-cloudflare/ScheduleCountRow")({ schedule_count: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)) }) {};
29
+ var ScheduleDeadlineRow = class extends Schema.Class("@effect-agent/storage-cloudflare/ScheduleDeadlineRow")({ deadline_at_millis: StoredDeadline }) {};
30
+ var ScheduleStoreStateRow = class extends Schema.Class("@effect-agent/storage-cloudflare/ScheduleStoreStateRow")({
31
+ storage_version: Schema.Int.check(Schema.isGreaterThan(0)),
32
+ alarm_generation: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
33
+ }) {};
34
+ var ScheduleTableNameRow = class extends Schema.Class("@effect-agent/storage-cloudflare/ScheduleTableNameRow")({ name: Schema.String }) {};
35
+ /**
36
+ * Platform-owned transaction boundary for schedule SQL and logical alarm mutation. The callback
37
+ * and its `replaceAlarm` capability belong to one fiber and must not escape or fork.
38
+ */
39
+ var DoScheduleTransaction = class extends Context.Service()("@effect-agent/storage-cloudflare/DoScheduleTransaction") {};
40
+ /** Platform driver operations that use the same schedule-state and alarm transaction. */
41
+ var DoScheduleAlarmControl = class extends Context.Service()("@effect-agent/storage-cloudflare/DoScheduleAlarmControl") {};
42
+ const unavailable = (operation) => ScheduleStorageError.make({
43
+ operation,
44
+ reason: "unavailable"
45
+ });
46
+ const corrupt = (operation) => ScheduleStorageError.make({
47
+ operation,
48
+ reason: "corrupt"
49
+ });
50
+ const decodeRows = Effect.fn("DoScheduleStore.decodeRows")(function* (schema, rows, operation) {
51
+ return yield* Schema.decodeUnknownEffect(schema)(rows).pipe(Effect.mapError(() => corrupt(operation)));
52
+ });
53
+ const decodeBoundary = (schema, value, operation) => Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(() => corrupt(operation)));
54
+ const decodeRecord = Effect.fn("DoScheduleStore.decodeRecord")(function* (row) {
55
+ const record = yield* Schema.decodeEffect(Schema.fromJsonString(ScheduleRecord))(row.record_json).pipe(Effect.mapError(() => corrupt("decode schedule")));
56
+ if (record.owner.tenantId !== row.tenant_id || record.owner.ownerId !== row.owner_id || record.scheduleId !== row.schedule_id || scheduleDeadline(record) !== row.deadline_at_millis) return yield* corrupt("decode schedule index");
57
+ return record;
58
+ });
59
+ const encodeRecord = Effect.fn("DoScheduleStore.encodeRecord")(function* (record) {
60
+ const encoded = yield* Schema.encodeEffect(Schema.fromJsonString(ScheduleRecord))(record).pipe(Effect.mapError(() => corrupt("encode schedule")));
61
+ return yield* Schema.decodeUnknownEffect(StoredScheduleJson)(encoded).pipe(Effect.mapError(() => corrupt("encode schedule bounds")));
62
+ });
63
+ const initializeScheduleStore = Effect.fn("DoScheduleStore.initialize")(function* () {
64
+ const sql = yield* SqlClientService.SqlClient;
65
+ const operation = "initialize schedule store";
66
+ const rawTables = yield* sql`
67
+ SELECT name
68
+ FROM sqlite_master
69
+ WHERE type = 'table'
70
+ AND name IN (
71
+ 'effect_agent_schedule_store_state',
72
+ 'effect_agent_schedules'
73
+ )
74
+ ORDER BY name
75
+ `.pipe(Effect.mapError(() => unavailable(operation)));
76
+ const tables = yield* decodeRows(Schema.Array(ScheduleTableNameRow), rawTables, operation);
77
+ const hasState = tables.some((row) => row.name === "effect_agent_schedule_store_state");
78
+ const hasSchedules = tables.some((row) => row.name === "effect_agent_schedules");
79
+ if (!hasState) {
80
+ if (hasSchedules) return yield* corrupt(operation);
81
+ yield* sql.withTransaction(Effect.gen(function* () {
82
+ yield* sql`
83
+ CREATE TABLE effect_agent_schedule_store_state (
84
+ singleton INTEGER PRIMARY KEY NOT NULL CHECK (singleton = 1),
85
+ storage_version INTEGER NOT NULL,
86
+ alarm_generation INTEGER NOT NULL
87
+ )
88
+ `.withoutTransform;
89
+ yield* sql`
90
+ CREATE TABLE effect_agent_schedules (
91
+ tenant_id TEXT NOT NULL,
92
+ owner_id TEXT NOT NULL,
93
+ schedule_id TEXT NOT NULL,
94
+ deadline_at_millis INTEGER,
95
+ record_json TEXT NOT NULL,
96
+ PRIMARY KEY (tenant_id, owner_id, schedule_id)
97
+ )
98
+ `.withoutTransform;
99
+ yield* sql`
100
+ CREATE INDEX effect_agent_schedules_deadline
101
+ ON effect_agent_schedules (deadline_at_millis, tenant_id, owner_id, schedule_id)
102
+ WHERE deadline_at_millis IS NOT NULL
103
+ `.withoutTransform;
104
+ yield* sql`
105
+ CREATE INDEX effect_agent_schedules_owner_deadline
106
+ ON effect_agent_schedules (tenant_id, owner_id, deadline_at_millis, schedule_id)
107
+ WHERE deadline_at_millis IS NOT NULL
108
+ `.withoutTransform;
109
+ yield* sql`
110
+ INSERT INTO effect_agent_schedule_store_state (
111
+ singleton, storage_version, alarm_generation
112
+ ) VALUES (1, ${CURRENT_SCHEDULE_STORE_VERSION}, 0)
113
+ `.withoutTransform;
114
+ })).pipe(Effect.mapError(() => unavailable(operation)));
115
+ return;
116
+ }
117
+ if (!hasSchedules) return yield* corrupt(operation);
118
+ const rawState = yield* sql`
119
+ SELECT storage_version, alarm_generation
120
+ FROM effect_agent_schedule_store_state
121
+ WHERE singleton = 1
122
+ `.pipe(Effect.mapError(() => unavailable(operation)));
123
+ const state = yield* decodeRows(Schema.Array(ScheduleStoreStateRow), rawState, operation);
124
+ if (state.length !== 1 || state[0].storage_version !== CURRENT_SCHEDULE_STORE_VERSION) return yield* corrupt(state.length === 1 ? `${operation}: incompatible storage version ${state[0].storage_version}; expected ${CURRENT_SCHEDULE_STORE_VERSION}` : `${operation}: invalid storage version row`);
125
+ });
126
+ const makeServices = Effect.gen(function* () {
127
+ const sql = yield* SqlClientService.SqlClient;
128
+ const transactions = yield* DoScheduleTransaction;
129
+ const scheduleFailpoint = yield* ScheduleFailpoint;
130
+ yield* initializeScheduleStore();
131
+ const readRows = Effect.fn("DoScheduleStore.readRows")(function* (key, operation) {
132
+ const rows = yield* sql`
133
+ SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json
134
+ FROM effect_agent_schedules
135
+ WHERE tenant_id = ${key.owner.tenantId}
136
+ AND owner_id = ${key.owner.ownerId}
137
+ AND schedule_id = ${key.scheduleId}
138
+ `.pipe(Effect.mapError(() => unavailable(operation)));
139
+ return yield* decodeRows(Schema.Array(ScheduleRow), rows, operation);
140
+ });
141
+ const readOne = Effect.fn("DoScheduleStore.readOne")(function* (key, operation) {
142
+ const rows = yield* readRows(key, operation);
143
+ if (rows.length === 0) return null;
144
+ if (rows.length !== 1) return yield* corrupt(operation);
145
+ return yield* decodeRecord(rows[0]);
146
+ });
147
+ const readNextDeadline = Effect.fn("DoScheduleStore.readNextDeadline")(function* (owner, operation) {
148
+ const rows = owner === void 0 ? yield* sql`
149
+ SELECT MIN(deadline_at_millis) AS deadline_at_millis
150
+ FROM effect_agent_schedules
151
+ WHERE deadline_at_millis IS NOT NULL
152
+ `.pipe(Effect.mapError(() => unavailable(operation))) : yield* sql`
153
+ SELECT MIN(deadline_at_millis) AS deadline_at_millis
154
+ FROM effect_agent_schedules
155
+ WHERE tenant_id = ${owner.tenantId}
156
+ AND owner_id = ${owner.ownerId}
157
+ AND deadline_at_millis IS NOT NULL
158
+ `.pipe(Effect.mapError(() => unavailable(operation)));
159
+ const decoded = yield* decodeRows(Schema.Array(ScheduleDeadlineRow), rows, operation);
160
+ if (decoded.length !== 1) return yield* corrupt(operation);
161
+ return decoded[0].deadline_at_millis;
162
+ });
163
+ const replaceAlarm = Effect.fn("DoScheduleStore.replaceAlarm")(function* (replace, deadlineAtMillis, operation) {
164
+ const rawState = yield* sql`
165
+ UPDATE effect_agent_schedule_store_state
166
+ SET alarm_generation = alarm_generation + 1
167
+ WHERE singleton = 1
168
+ RETURNING storage_version, alarm_generation
169
+ `.pipe(Effect.mapError(() => unavailable(operation)));
170
+ const state = yield* decodeRows(Schema.Array(ScheduleStoreStateRow), rawState, operation);
171
+ if (state.length !== 1 || state[0].storage_version !== CURRENT_SCHEDULE_STORE_VERSION) return yield* corrupt(operation);
172
+ yield* scheduleFailpoint.hit("schedule:alarm:before");
173
+ yield* replace({
174
+ deadlineAtMillis,
175
+ generation: state[0].alarm_generation
176
+ });
177
+ yield* scheduleFailpoint.hit("schedule:alarm:after");
178
+ });
179
+ const insert = Effect.fn("DoScheduleStore.insert")(function* (record, ownerLimit) {
180
+ const operation = "insert schedule";
181
+ const canonical = yield* decodeBoundary(ScheduleRecord, record, operation);
182
+ const recordJson = yield* encodeRecord(canonical);
183
+ const result = yield* transactions.run((replace) => Effect.gen(function* () {
184
+ const existing = yield* readOne(canonical, operation);
185
+ if (existing !== null) {
186
+ if (existing.creationFingerprint === canonical.creationFingerprint) return {
187
+ record: existing,
188
+ inserted: false
189
+ };
190
+ return yield* ScheduleConflict.make({
191
+ reason: "creation",
192
+ key: canonical
193
+ });
194
+ }
195
+ const rawCounts = yield* sql`
196
+ SELECT COUNT(*) AS schedule_count
197
+ FROM effect_agent_schedules
198
+ WHERE tenant_id = ${canonical.owner.tenantId}
199
+ AND owner_id = ${canonical.owner.ownerId}
200
+ AND (json_extract(record_json, '$.pending') IS NOT NULL OR
201
+ (json_extract(record_json, '$.state') != 'cancelled' AND json_extract(record_json, '$.nextAtMillis') IS NOT NULL))
202
+ `.pipe(Effect.mapError(() => unavailable(operation)));
203
+ const counts = yield* decodeRows(Schema.Array(ScheduleCountRow), rawCounts, operation);
204
+ if (counts.length !== 1) return yield* corrupt(operation);
205
+ if (counts[0].schedule_count >= ownerLimit) return yield* ScheduleCapacityError.make({ limit: ownerLimit });
206
+ yield* scheduleFailpoint.hit("schedule:insert:before");
207
+ yield* sql`
208
+ INSERT INTO effect_agent_schedules (
209
+ tenant_id, owner_id, schedule_id, deadline_at_millis, record_json
210
+ ) VALUES (
211
+ ${canonical.owner.tenantId},
212
+ ${canonical.owner.ownerId},
213
+ ${canonical.scheduleId},
214
+ ${scheduleDeadline(canonical)},
215
+ ${recordJson}
216
+ )
217
+ `.pipe(Effect.mapError(() => unavailable(operation)));
218
+ const deadline = yield* readNextDeadline(void 0, operation);
219
+ yield* replaceAlarm(replace, deadline, operation);
220
+ return {
221
+ record: canonical,
222
+ inserted: true
223
+ };
224
+ }));
225
+ if (result.inserted) yield* scheduleFailpoint.hit("schedule:insert:after");
226
+ return result.record;
227
+ });
228
+ const get = Effect.fn("DoScheduleStore.get")(function* (key) {
229
+ const canonical = yield* decodeBoundary(ScheduleKey, key, "get schedule");
230
+ return yield* readOne(canonical, "get schedule");
231
+ });
232
+ const list = Effect.fn("DoScheduleStore.list")(function* (requestValue) {
233
+ const operation = "list schedules";
234
+ const request = yield* decodeBoundary(SchedulePageRequest, requestValue, operation);
235
+ const rows = request.after === void 0 ? yield* sql`
236
+ SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json
237
+ FROM effect_agent_schedules
238
+ WHERE tenant_id = ${request.owner.tenantId}
239
+ AND owner_id = ${request.owner.ownerId}
240
+ ORDER BY schedule_id
241
+ LIMIT ${request.limit + 1}
242
+ `.pipe(Effect.mapError(() => unavailable(operation))) : yield* sql`
243
+ SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json
244
+ FROM effect_agent_schedules
245
+ WHERE tenant_id = ${request.owner.tenantId}
246
+ AND owner_id = ${request.owner.ownerId}
247
+ AND schedule_id > ${request.after}
248
+ ORDER BY schedule_id
249
+ LIMIT ${request.limit + 1}
250
+ `.pipe(Effect.mapError(() => unavailable(operation)));
251
+ const decoded = yield* decodeRows(Schema.Array(ScheduleRow), rows, operation);
252
+ const records = yield* Effect.forEach(decoded, decodeRecord);
253
+ const hasNext = records.length > request.limit;
254
+ const items = hasNext ? records.slice(0, request.limit) : records;
255
+ return {
256
+ items,
257
+ next: hasNext ? items.at(-1)?.scheduleId ?? null : null
258
+ };
259
+ });
260
+ const change = Effect.fn("DoScheduleStore.change")(function* (key, change, ownerLimit = defaultSchedulingLimits.maxSchedulesPerOwner) {
261
+ const operation = "change schedule";
262
+ const canonicalKey = yield* decodeBoundary(ScheduleKey, key, operation);
263
+ const canonicalChange = yield* decodeBoundary(ScheduleChange, change, operation);
264
+ const result = yield* transactions.run((replace) => Effect.gen(function* () {
265
+ const current = yield* readOne(canonicalKey, operation);
266
+ if (current === null) return yield* ScheduleNotFound.make({ key: canonicalKey });
267
+ const transition = applyScheduleChange(current, canonicalChange);
268
+ if (Result.isFailure(transition)) return yield* transition.failure;
269
+ const next = transition.success;
270
+ if (!scheduleUsesCapacity(current) && scheduleUsesCapacity(next)) {
271
+ const rawCounts = yield* sql`
272
+ SELECT COUNT(*) AS schedule_count FROM effect_agent_schedules
273
+ WHERE tenant_id = ${key.owner.tenantId} AND owner_id = ${key.owner.ownerId}
274
+ AND (json_extract(record_json, '$.pending') IS NOT NULL OR
275
+ (json_extract(record_json, '$.state') != 'cancelled' AND json_extract(record_json, '$.nextAtMillis') IS NOT NULL))
276
+ `.pipe(Effect.mapError(() => unavailable(operation)));
277
+ const counts = yield* decodeRows(Schema.Array(ScheduleCountRow), rawCounts, operation);
278
+ if (counts.length !== 1) return yield* corrupt(operation);
279
+ if (counts[0].schedule_count >= ownerLimit) return yield* ScheduleCapacityError.make({ limit: ownerLimit });
280
+ }
281
+ if (next === current) return {
282
+ record: current,
283
+ changed: false
284
+ };
285
+ const recordJson = yield* encodeRecord(next);
286
+ yield* scheduleFailpoint.hit(`schedule:${canonicalChange._tag.toLowerCase()}:before`);
287
+ yield* sql`
288
+ UPDATE effect_agent_schedules
289
+ SET deadline_at_millis = ${scheduleDeadline(next)}, record_json = ${recordJson}
290
+ WHERE tenant_id = ${canonicalKey.owner.tenantId}
291
+ AND owner_id = ${canonicalKey.owner.ownerId}
292
+ AND schedule_id = ${canonicalKey.scheduleId}
293
+ `.pipe(Effect.mapError(() => unavailable(operation)));
294
+ const deadline = yield* readNextDeadline(void 0, operation);
295
+ yield* replaceAlarm(replace, deadline, operation);
296
+ return {
297
+ record: next,
298
+ changed: true
299
+ };
300
+ }));
301
+ if (result.changed) yield* scheduleFailpoint.hit(`schedule:${canonicalChange._tag.toLowerCase()}:after`);
302
+ return result.record;
303
+ });
304
+ const due = Effect.fn("DoScheduleStore.due")(function* (nowMillis, limit, owner, after) {
305
+ const operation = "query due schedules";
306
+ const cursor = after === void 0 ? void 0 : yield* Schema.decodeUnknownEffect(ScheduleDueCursor)(after).pipe(Effect.mapError(() => corrupt(operation)));
307
+ const continuation = cursor === void 0 ? sql`1 = 1` : sql`
308
+ (deadline_at_millis, tenant_id, owner_id, schedule_id) >
309
+ (${cursor.deadlineAtMillis}, ${cursor.owner.tenantId}, ${cursor.owner.ownerId}, ${cursor.scheduleId})`;
310
+ const rows = owner === void 0 ? yield* sql`
311
+ SELECT tenant_id, owner_id, schedule_id, deadline_at_millis
312
+ FROM effect_agent_schedules
313
+ WHERE deadline_at_millis <= ${nowMillis} AND ${continuation}
314
+ ORDER BY deadline_at_millis, tenant_id, owner_id, schedule_id
315
+ LIMIT ${limit}
316
+ `.pipe(Effect.mapError(() => unavailable(operation))) : yield* sql`
317
+ SELECT tenant_id, owner_id, schedule_id, deadline_at_millis
318
+ FROM effect_agent_schedules
319
+ WHERE tenant_id = ${owner.tenantId}
320
+ AND owner_id = ${owner.ownerId}
321
+ AND deadline_at_millis <= ${nowMillis} AND ${continuation}
322
+ ORDER BY deadline_at_millis, schedule_id
323
+ LIMIT ${limit}
324
+ `.pipe(Effect.mapError(() => unavailable(operation)));
325
+ return (yield* decodeRows(Schema.Array(ScheduleDueRow), rows, operation)).map((row) => ({
326
+ owner: {
327
+ tenantId: row.tenant_id,
328
+ ownerId: row.owner_id
329
+ },
330
+ scheduleId: row.schedule_id,
331
+ deadlineAtMillis: row.deadline_at_millis
332
+ }));
333
+ });
334
+ const nextDeadline = Effect.fn("DoScheduleStore.nextDeadline")(function* (owner) {
335
+ return yield* readNextDeadline(owner, "query next schedule deadline");
336
+ });
337
+ const prearm = Effect.fn("DoScheduleStore.prearm")(function* (deadlineAtMillis) {
338
+ yield* decodeBoundary(ScheduleInstant, deadlineAtMillis, "pre-arm schedule recovery");
339
+ yield* transactions.run((replace) => replaceAlarm(replace, deadlineAtMillis, "pre-arm schedule recovery"));
340
+ yield* scheduleFailpoint.hit("schedule:prearm:after");
341
+ });
342
+ const reconcile = Effect.gen(function* () {
343
+ yield* transactions.run((replace) => Effect.gen(function* () {
344
+ const deadline = yield* readNextDeadline(void 0, "reconcile schedule alarm");
345
+ yield* replaceAlarm(replace, deadline, "reconcile schedule alarm");
346
+ }));
347
+ yield* scheduleFailpoint.hit("schedule:reconcile:after");
348
+ });
349
+ return Context.make(ScheduleStore, {
350
+ insert,
351
+ get,
352
+ list,
353
+ change,
354
+ due,
355
+ nextDeadline
356
+ }).pipe(Context.add(DoScheduleAlarmControl, {
357
+ prearm,
358
+ reconcile
359
+ }));
360
+ });
361
+ /**
362
+ * Durable Object SQLite ScheduleStore. Platform code supplies the one transaction owner that
363
+ * combines these SQL mutations with its logical and native alarm lifecycle.
364
+ */
365
+ const scheduleStoreLayer = Layer.effectContext(makeServices);
366
+ //#endregion
367
+ export { DoScheduleAlarmControl, DoScheduleTransaction, scheduleStoreLayer, DoScheduleStore_exports as t };
368
+
369
+ //# sourceMappingURL=DoScheduleStore.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DoScheduleStore.mjs","names":[],"sources":["../src/DoScheduleStore.ts"],"sourcesContent":["import {\n ScheduleCapacityError,\n ScheduleDueCursor,\n defaultSchedulingLimits,\n ScheduleChange,\n ScheduleConflict,\n ScheduleFailpoint,\n type ScheduleFailpointError,\n ScheduleKey,\n ScheduleId,\n ScheduleInstant,\n ScheduleNotFound,\n ScheduleOwner,\n type SchedulePage,\n SchedulePageRequest,\n ScheduleRecord,\n ScheduleStorageError,\n ScheduleStore,\n} from \"@effect-agent/thread/Schedule\";\nimport {\n applyScheduleChange,\n scheduleUsesCapacity,\n scheduleDeadline,\n} from \"@effect-agent/thread/ScheduleTransition\";\nimport { Context, Effect, Layer, Result, Schema } from \"effect\";\nimport * as SqlClientService from \"effect/unstable/sql/SqlClient\";\n\nconst CURRENT_SCHEDULE_STORE_VERSION = 2;\nconst MAX_STORED_SCHEDULE_BYTES = 1_900_000;\n\nconst StoredScheduleJson = Schema.String.check(Schema.isMaxLength(MAX_STORED_SCHEDULE_BYTES));\nconst StoredDeadline = Schema.NullOr(ScheduleInstant);\n\nclass ScheduleRow extends Schema.Class<ScheduleRow>(\"@effect-agent/storage-cloudflare/ScheduleRow\")(\n {\n tenant_id: ScheduleOwner.fields.tenantId,\n owner_id: ScheduleOwner.fields.ownerId,\n schedule_id: ScheduleId,\n deadline_at_millis: StoredDeadline,\n record_json: StoredScheduleJson,\n },\n) {}\n\nconst ScheduleDueRow = Schema.Struct({\n tenant_id: ScheduleOwner.fields.tenantId,\n owner_id: ScheduleOwner.fields.ownerId,\n schedule_id: ScheduleId,\n deadline_at_millis: ScheduleInstant,\n});\n\nclass ScheduleCountRow extends Schema.Class<ScheduleCountRow>(\n \"@effect-agent/storage-cloudflare/ScheduleCountRow\",\n)({\n schedule_count: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n}) {}\n\nclass ScheduleDeadlineRow extends Schema.Class<ScheduleDeadlineRow>(\n \"@effect-agent/storage-cloudflare/ScheduleDeadlineRow\",\n)({\n deadline_at_millis: StoredDeadline,\n}) {}\n\nclass ScheduleStoreStateRow extends Schema.Class<ScheduleStoreStateRow>(\n \"@effect-agent/storage-cloudflare/ScheduleStoreStateRow\",\n)({\n storage_version: Schema.Int.check(Schema.isGreaterThan(0)),\n alarm_generation: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n}) {}\n\nclass ScheduleTableNameRow extends Schema.Class<ScheduleTableNameRow>(\n \"@effect-agent/storage-cloudflare/ScheduleTableNameRow\",\n)({\n name: Schema.String,\n}) {}\n\nexport interface DoScheduleAlarmReplacement {\n readonly deadlineAtMillis: number | null;\n /** Included in every logical alarm payload so equal-time replacement stays distinguishable. */\n readonly generation: number;\n}\n\nexport type DoScheduleReplaceAlarm = (\n replacement: DoScheduleAlarmReplacement,\n) => Effect.Effect<void, ScheduleStorageError>;\n\n/**\n * Platform-owned transaction boundary for schedule SQL and logical alarm mutation. The callback\n * and its `replaceAlarm` capability belong to one fiber and must not escape or fork.\n */\nexport class DoScheduleTransaction extends Context.Service<\n DoScheduleTransaction,\n {\n readonly run: <A, E, R>(\n body: (replaceAlarm: DoScheduleReplaceAlarm) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | ScheduleStorageError, R>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoScheduleTransaction\") {}\n\n/** Platform driver operations that use the same schedule-state and alarm transaction. */\nexport class DoScheduleAlarmControl extends Context.Service<\n DoScheduleAlarmControl,\n {\n /** Establish a future recovery wake before cross-Object admission starts. */\n readonly prearm: (\n deadlineAtMillis: number,\n ) => Effect.Effect<void, ScheduleStorageError | ScheduleFailpointError>;\n /** Replace or cancel the wake from the object's authoritative indexed deadline. */\n readonly reconcile: Effect.Effect<void, ScheduleStorageError | ScheduleFailpointError>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoScheduleAlarmControl\") {}\n\nconst unavailable = (operation: string): ScheduleStorageError =>\n ScheduleStorageError.make({ operation, reason: \"unavailable\" });\n\nconst corrupt = (operation: string): ScheduleStorageError =>\n ScheduleStorageError.make({ operation, reason: \"corrupt\" });\n\nconst decodeRows = Effect.fn(\"DoScheduleStore.decodeRows\")(function* <A, I, R>(\n schema: Schema.Codec<A, I, R>,\n rows: ReadonlyArray<unknown>,\n operation: string,\n): Effect.fn.Return<A, ScheduleStorageError, R> {\n return yield* Schema.decodeUnknownEffect(schema)(rows).pipe(\n Effect.mapError(() => corrupt(operation)),\n );\n});\n\nconst decodeBoundary = <A, I, R>(\n schema: Schema.Codec<A, I, R>,\n value: unknown,\n operation: string,\n): Effect.Effect<A, ScheduleStorageError, R> =>\n Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(() => corrupt(operation)));\n\nconst decodeRecord = Effect.fn(\"DoScheduleStore.decodeRecord\")(function* (\n row: ScheduleRow,\n): Effect.fn.Return<ScheduleRecord, ScheduleStorageError> {\n const record = yield* Schema.decodeEffect(Schema.fromJsonString(ScheduleRecord))(\n row.record_json,\n ).pipe(Effect.mapError(() => corrupt(\"decode schedule\")));\n\n if (\n record.owner.tenantId !== row.tenant_id ||\n record.owner.ownerId !== row.owner_id ||\n record.scheduleId !== row.schedule_id ||\n scheduleDeadline(record) !== row.deadline_at_millis\n ) {\n return yield* corrupt(\"decode schedule index\");\n }\n\n return record;\n});\n\nconst encodeRecord = Effect.fn(\"DoScheduleStore.encodeRecord\")(function* (\n record: ScheduleRecord,\n): Effect.fn.Return<string, ScheduleStorageError> {\n const encoded = yield* Schema.encodeEffect(Schema.fromJsonString(ScheduleRecord))(record).pipe(\n Effect.mapError(() => corrupt(\"encode schedule\")),\n );\n\n return yield* Schema.decodeUnknownEffect(StoredScheduleJson)(encoded).pipe(\n Effect.mapError(() => corrupt(\"encode schedule bounds\")),\n );\n});\n\nconst initializeScheduleStore = Effect.fn(\"DoScheduleStore.initialize\")(function* () {\n const sql = yield* SqlClientService.SqlClient;\n const operation = \"initialize schedule store\";\n\n const rawTables = yield* sql<Record<string, unknown>>`\n SELECT name\n FROM sqlite_master\n WHERE type = 'table'\n AND name IN (\n 'effect_agent_schedule_store_state',\n 'effect_agent_schedules'\n )\n ORDER BY name\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const tables = yield* decodeRows(Schema.Array(ScheduleTableNameRow), rawTables, operation);\n const hasState = tables.some((row) => row.name === \"effect_agent_schedule_store_state\");\n const hasSchedules = tables.some((row) => row.name === \"effect_agent_schedules\");\n\n if (!hasState) {\n if (hasSchedules) return yield* corrupt(operation);\n yield* sql\n .withTransaction(\n Effect.gen(function* () {\n yield* sql`\n CREATE TABLE effect_agent_schedule_store_state (\n singleton INTEGER PRIMARY KEY NOT NULL CHECK (singleton = 1),\n storage_version INTEGER NOT NULL,\n alarm_generation INTEGER NOT NULL\n )\n `.withoutTransform;\n yield* sql`\n CREATE TABLE effect_agent_schedules (\n tenant_id TEXT NOT NULL,\n owner_id TEXT NOT NULL,\n schedule_id TEXT NOT NULL,\n deadline_at_millis INTEGER,\n record_json TEXT NOT NULL,\n PRIMARY KEY (tenant_id, owner_id, schedule_id)\n )\n `.withoutTransform;\n yield* sql`\n CREATE INDEX effect_agent_schedules_deadline\n ON effect_agent_schedules (deadline_at_millis, tenant_id, owner_id, schedule_id)\n WHERE deadline_at_millis IS NOT NULL\n `.withoutTransform;\n yield* sql`\n CREATE INDEX effect_agent_schedules_owner_deadline\n ON effect_agent_schedules (tenant_id, owner_id, deadline_at_millis, schedule_id)\n WHERE deadline_at_millis IS NOT NULL\n `.withoutTransform;\n yield* sql`\n INSERT INTO effect_agent_schedule_store_state (\n singleton, storage_version, alarm_generation\n ) VALUES (1, ${CURRENT_SCHEDULE_STORE_VERSION}, 0)\n `.withoutTransform;\n }),\n )\n .pipe(Effect.mapError(() => unavailable(operation)));\n\n return;\n }\n\n if (!hasSchedules) return yield* corrupt(operation);\n\n const rawState = yield* sql<Record<string, unknown>>`\n SELECT storage_version, alarm_generation\n FROM effect_agent_schedule_store_state\n WHERE singleton = 1\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const state = yield* decodeRows(Schema.Array(ScheduleStoreStateRow), rawState, operation);\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SCHEDULE_STORE_VERSION) {\n return yield* corrupt(\n state.length === 1\n ? `${operation}: incompatible storage version ${state[0].storage_version}; expected ${CURRENT_SCHEDULE_STORE_VERSION}`\n : `${operation}: invalid storage version row`,\n );\n }\n});\n\nconst makeServices = Effect.gen(function* () {\n const sql = yield* SqlClientService.SqlClient;\n const transactions = yield* DoScheduleTransaction;\n const scheduleFailpoint = yield* ScheduleFailpoint;\n\n yield* initializeScheduleStore();\n\n const readRows = Effect.fn(\"DoScheduleStore.readRows\")(function* (\n key: ScheduleKey,\n operation: string,\n ): Effect.fn.Return<ReadonlyArray<ScheduleRow>, ScheduleStorageError> {\n const rows = yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n FROM effect_agent_schedules\n WHERE tenant_id = ${key.owner.tenantId}\n AND owner_id = ${key.owner.ownerId}\n AND schedule_id = ${key.scheduleId}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n return yield* decodeRows(Schema.Array(ScheduleRow), rows, operation);\n });\n\n const readOne = Effect.fn(\"DoScheduleStore.readOne\")(function* (\n key: ScheduleKey,\n operation: string,\n ): Effect.fn.Return<ScheduleRecord | null, ScheduleStorageError> {\n const rows = yield* readRows(key, operation);\n\n if (rows.length === 0) return null;\n if (rows.length !== 1) return yield* corrupt(operation);\n\n return yield* decodeRecord(rows[0]);\n });\n\n const readNextDeadline = Effect.fn(\"DoScheduleStore.readNextDeadline\")(function* (\n owner: ScheduleOwner | undefined,\n operation: string,\n ): Effect.fn.Return<number | null, ScheduleStorageError> {\n const rows =\n owner === undefined\n ? yield* sql<Record<string, unknown>>`\n SELECT MIN(deadline_at_millis) AS deadline_at_millis\n FROM effect_agent_schedules\n WHERE deadline_at_millis IS NOT NULL\n `.pipe(Effect.mapError(() => unavailable(operation)))\n : yield* sql<Record<string, unknown>>`\n SELECT MIN(deadline_at_millis) AS deadline_at_millis\n FROM effect_agent_schedules\n WHERE tenant_id = ${owner.tenantId}\n AND owner_id = ${owner.ownerId}\n AND deadline_at_millis IS NOT NULL\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const decoded = yield* decodeRows(Schema.Array(ScheduleDeadlineRow), rows, operation);\n\n if (decoded.length !== 1) return yield* corrupt(operation);\n\n return decoded[0].deadline_at_millis;\n });\n\n const replaceAlarm = Effect.fn(\"DoScheduleStore.replaceAlarm\")(function* (\n replace: DoScheduleReplaceAlarm,\n deadlineAtMillis: number | null,\n operation: string,\n ) {\n const rawState = yield* sql<Record<string, unknown>>`\n UPDATE effect_agent_schedule_store_state\n SET alarm_generation = alarm_generation + 1\n WHERE singleton = 1\n RETURNING storage_version, alarm_generation\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const state = yield* decodeRows(Schema.Array(ScheduleStoreStateRow), rawState, operation);\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SCHEDULE_STORE_VERSION) {\n return yield* corrupt(operation);\n }\n yield* scheduleFailpoint.hit(\"schedule:alarm:before\");\n yield* replace({ deadlineAtMillis, generation: state[0].alarm_generation });\n yield* scheduleFailpoint.hit(\"schedule:alarm:after\");\n });\n\n const insert: ScheduleStore[\"Service\"][\"insert\"] = Effect.fn(\"DoScheduleStore.insert\")(\n function* (record, ownerLimit) {\n const operation = \"insert schedule\";\n const canonical = yield* decodeBoundary(ScheduleRecord, record, operation);\n const recordJson = yield* encodeRecord(canonical);\n\n const result = yield* transactions.run((replace) =>\n Effect.gen(function* () {\n const existing = yield* readOne(canonical, operation);\n\n if (existing !== null) {\n if (existing.creationFingerprint === canonical.creationFingerprint) {\n return { record: existing, inserted: false } as const;\n }\n\n return yield* ScheduleConflict.make({ reason: \"creation\", key: canonical });\n }\n\n const rawCounts = yield* sql<Record<string, unknown>>`\n SELECT COUNT(*) AS schedule_count\n FROM effect_agent_schedules\n WHERE tenant_id = ${canonical.owner.tenantId}\n AND owner_id = ${canonical.owner.ownerId}\n AND (json_extract(record_json, '$.pending') IS NOT NULL OR\n (json_extract(record_json, '$.state') != 'cancelled' AND json_extract(record_json, '$.nextAtMillis') IS NOT NULL))\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const counts = yield* decodeRows(Schema.Array(ScheduleCountRow), rawCounts, operation);\n\n if (counts.length !== 1) return yield* corrupt(operation);\n if (counts[0].schedule_count >= ownerLimit) {\n return yield* ScheduleCapacityError.make({ limit: ownerLimit });\n }\n yield* scheduleFailpoint.hit(\"schedule:insert:before\");\n yield* sql`\n INSERT INTO effect_agent_schedules (\n tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n ) VALUES (\n ${canonical.owner.tenantId},\n ${canonical.owner.ownerId},\n ${canonical.scheduleId},\n ${scheduleDeadline(canonical)},\n ${recordJson}\n )\n `.pipe(Effect.mapError(() => unavailable(operation)));\n const deadline = yield* readNextDeadline(undefined, operation);\n\n yield* replaceAlarm(replace, deadline, operation);\n\n return { record: canonical, inserted: true } as const;\n }),\n );\n\n if (result.inserted) yield* scheduleFailpoint.hit(\"schedule:insert:after\");\n\n return result.record;\n },\n );\n\n const get: ScheduleStore[\"Service\"][\"get\"] = Effect.fn(\"DoScheduleStore.get\")(function* (key) {\n const canonical = yield* decodeBoundary(ScheduleKey, key, \"get schedule\");\n\n return yield* readOne(canonical, \"get schedule\");\n });\n\n const list: ScheduleStore[\"Service\"][\"list\"] = Effect.fn(\"DoScheduleStore.list\")(function* (\n requestValue: SchedulePageRequest,\n ): Effect.fn.Return<SchedulePage, ScheduleStorageError> {\n const operation = \"list schedules\";\n const request = yield* decodeBoundary(SchedulePageRequest, requestValue, operation);\n\n const rows =\n request.after === undefined\n ? yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n FROM effect_agent_schedules\n WHERE tenant_id = ${request.owner.tenantId}\n AND owner_id = ${request.owner.ownerId}\n ORDER BY schedule_id\n LIMIT ${request.limit + 1}\n `.pipe(Effect.mapError(() => unavailable(operation)))\n : yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n FROM effect_agent_schedules\n WHERE tenant_id = ${request.owner.tenantId}\n AND owner_id = ${request.owner.ownerId}\n AND schedule_id > ${request.after}\n ORDER BY schedule_id\n LIMIT ${request.limit + 1}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const decoded = yield* decodeRows(Schema.Array(ScheduleRow), rows, operation);\n const records = yield* Effect.forEach(decoded, decodeRecord);\n const hasNext = records.length > request.limit;\n const items = hasNext ? records.slice(0, request.limit) : records;\n\n return { items, next: hasNext ? (items.at(-1)?.scheduleId ?? null) : null };\n });\n\n const change: ScheduleStore[\"Service\"][\"change\"] = Effect.fn(\"DoScheduleStore.change\")(function* (\n key,\n change,\n ownerLimit = defaultSchedulingLimits.maxSchedulesPerOwner,\n ) {\n const operation = \"change schedule\";\n const canonicalKey = yield* decodeBoundary(ScheduleKey, key, operation);\n const canonicalChange = yield* decodeBoundary(ScheduleChange, change, operation);\n\n const result = yield* transactions.run((replace) =>\n Effect.gen(function* () {\n const current = yield* readOne(canonicalKey, operation);\n\n if (current === null) return yield* ScheduleNotFound.make({ key: canonicalKey });\n const transition = applyScheduleChange(current, canonicalChange);\n\n if (Result.isFailure(transition)) return yield* transition.failure;\n const next = transition.success;\n\n if (!scheduleUsesCapacity(current) && scheduleUsesCapacity(next)) {\n const rawCounts = yield* sql<Record<string, unknown>>`\n SELECT COUNT(*) AS schedule_count FROM effect_agent_schedules\n WHERE tenant_id = ${key.owner.tenantId} AND owner_id = ${key.owner.ownerId}\n AND (json_extract(record_json, '$.pending') IS NOT NULL OR\n (json_extract(record_json, '$.state') != 'cancelled' AND json_extract(record_json, '$.nextAtMillis') IS NOT NULL))\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const counts = yield* decodeRows(Schema.Array(ScheduleCountRow), rawCounts, operation);\n\n if (counts.length !== 1) return yield* corrupt(operation);\n if (counts[0].schedule_count >= ownerLimit)\n return yield* ScheduleCapacityError.make({ limit: ownerLimit });\n }\n if (next === current) return { record: current, changed: false } as const;\n const recordJson = yield* encodeRecord(next);\n\n yield* scheduleFailpoint.hit(`schedule:${canonicalChange._tag.toLowerCase()}:before`);\n yield* sql`\n UPDATE effect_agent_schedules\n SET deadline_at_millis = ${scheduleDeadline(next)}, record_json = ${recordJson}\n WHERE tenant_id = ${canonicalKey.owner.tenantId}\n AND owner_id = ${canonicalKey.owner.ownerId}\n AND schedule_id = ${canonicalKey.scheduleId}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n const deadline = yield* readNextDeadline(undefined, operation);\n\n yield* replaceAlarm(replace, deadline, operation);\n\n return { record: next, changed: true } as const;\n }),\n );\n\n if (result.changed) {\n yield* scheduleFailpoint.hit(`schedule:${canonicalChange._tag.toLowerCase()}:after`);\n }\n\n return result.record;\n });\n\n const due: ScheduleStore[\"Service\"][\"due\"] = Effect.fn(\"DoScheduleStore.due\")(function* (\n nowMillis,\n limit,\n owner?: ScheduleOwner,\n after?: ScheduleDueCursor,\n ) {\n const operation = \"query due schedules\";\n\n const cursor =\n after === undefined\n ? undefined\n : yield* Schema.decodeUnknownEffect(ScheduleDueCursor)(after).pipe(\n Effect.mapError(() => corrupt(operation)),\n );\n\n const continuation =\n cursor === undefined\n ? sql`1 = 1`\n : sql`\n (deadline_at_millis, tenant_id, owner_id, schedule_id) >\n (${cursor.deadlineAtMillis}, ${cursor.owner.tenantId}, ${cursor.owner.ownerId}, ${cursor.scheduleId})`;\n\n const rows =\n owner === undefined\n ? yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis\n FROM effect_agent_schedules\n WHERE deadline_at_millis <= ${nowMillis} AND ${continuation}\n ORDER BY deadline_at_millis, tenant_id, owner_id, schedule_id\n LIMIT ${limit}\n `.pipe(Effect.mapError(() => unavailable(operation)))\n : yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis\n FROM effect_agent_schedules\n WHERE tenant_id = ${owner.tenantId}\n AND owner_id = ${owner.ownerId}\n AND deadline_at_millis <= ${nowMillis} AND ${continuation}\n ORDER BY deadline_at_millis, schedule_id\n LIMIT ${limit}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const decoded = yield* decodeRows(Schema.Array(ScheduleDueRow), rows, operation);\n\n return decoded.map((row) => ({\n owner: { tenantId: row.tenant_id, ownerId: row.owner_id },\n scheduleId: row.schedule_id,\n deadlineAtMillis: row.deadline_at_millis,\n }));\n });\n\n const nextDeadline: ScheduleStore[\"Service\"][\"nextDeadline\"] = Effect.fn(\n \"DoScheduleStore.nextDeadline\",\n )(function* (owner?: ScheduleOwner) {\n const operation = \"query next schedule deadline\";\n\n return yield* readNextDeadline(owner, operation);\n });\n\n const prearm = Effect.fn(\"DoScheduleStore.prearm\")(function* (\n deadlineAtMillis: number,\n ): Effect.fn.Return<void, ScheduleStorageError | ScheduleFailpointError> {\n yield* decodeBoundary(ScheduleInstant, deadlineAtMillis, \"pre-arm schedule recovery\");\n yield* transactions.run((replace) =>\n replaceAlarm(replace, deadlineAtMillis, \"pre-arm schedule recovery\"),\n );\n yield* scheduleFailpoint.hit(\"schedule:prearm:after\");\n });\n\n const reconcile = Effect.gen(function* () {\n yield* transactions.run((replace) =>\n Effect.gen(function* () {\n const deadline = yield* readNextDeadline(undefined, \"reconcile schedule alarm\");\n\n yield* replaceAlarm(replace, deadline, \"reconcile schedule alarm\");\n }),\n );\n yield* scheduleFailpoint.hit(\"schedule:reconcile:after\");\n });\n\n return Context.make(ScheduleStore, {\n insert,\n get,\n list,\n change,\n due,\n nextDeadline,\n }).pipe(Context.add(DoScheduleAlarmControl, { prearm, reconcile }));\n});\n\n/**\n * Durable Object SQLite ScheduleStore. Platform code supplies the one transaction owner that\n * combines these SQL mutations with its logical and native alarm lifecycle.\n */\nexport const scheduleStoreLayer: Layer.Layer<\n ScheduleStore | DoScheduleAlarmControl,\n ScheduleStorageError,\n SqlClientService.SqlClient | DoScheduleTransaction\n> = Layer.effectContext(makeServices);\n"],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { Context, Schema } from "effect";
2
+ declare namespace DoStorageConfig_d_exports {
3
+ export { DEFAULT_MAX_STORED_VALUE_BYTES, DoStorageConfig, DoStorageConfigValue };
4
+ }
5
+ /**
6
+ * Default per-value byte bound, kept under the Durable Object platform's 2 MB SQLite value
7
+ * limit with a safety margin. This is the DC analogue of Node's 16 MB `BoundedStoredText`
8
+ * bound: both fail typed before mutating, only the threshold differs (a documented DN/DC
9
+ * behavioral difference; Travel Planner payloads sit orders of magnitude below both).
10
+ */
11
+ declare const DEFAULT_MAX_STORED_VALUE_BYTES = 1900000;
12
+ declare const DoStorageConfigValue_base: Schema.Class<DoStorageConfigValue, Schema.Struct<{
13
+ readonly observationPollInterval: Schema.Int;
14
+ /**
15
+ * Submission ownership lease duration in milliseconds (D5). Inside one Durable Object the
16
+ * object itself is the serialized owner, so the lease's primary DC role is fencing work
17
+ * across DO incarnations (an evicted incarnation's claim becomes reclaimable); correctness
18
+ * never depends on it because every canonical append is fenced by producer epoch.
19
+ */
20
+ readonly ownershipLeaseDuration: Schema.Int;
21
+ /**
22
+ * Maximum bytes for any single stored text value (canonical batch/record JSON, admission
23
+ * input payload, checkpoint JSON). Enforced typed BEFORE any write; must stay under the
24
+ * platform's 2 MB per-value limit.
25
+ */
26
+ readonly maxStoredValueBytes: Schema.Int;
27
+ /**
28
+ * Re-verify every stored payload and digest chain while opening the store. Per-operation
29
+ * Schema decoding and the digest chain already fail clearly on corrupt rows, so the full
30
+ * scan is an explicit opt-in integrity audit rather than a startup requirement.
31
+ */
32
+ readonly verifyOnOpen: Schema.Boolean;
33
+ }>, {}>;
34
+ /**
35
+ * Validated construction configuration consumed by the Durable Object storage Layers. The
36
+ * storage identity itself belongs to the SqlClient Layer (built from `ctx.storage`);
37
+ * duplicating it here could silently diverge from the handle actually in use.
38
+ */
39
+ declare class DoStorageConfigValue extends DoStorageConfigValue_base {}
40
+ declare const DoStorageConfig_base: Context.ServiceClass<DoStorageConfig, "@effect-agent/storage-cloudflare/DoStorageConfig", DoStorageConfigValue>;
41
+ /** Explicit Durable Object storage configuration authority. */
42
+ declare class DoStorageConfig extends DoStorageConfig_base {}
43
+ //#endregion
44
+ export { DEFAULT_MAX_STORED_VALUE_BYTES, DoStorageConfig, DoStorageConfigValue, DoStorageConfig_d_exports as t };
45
+ //# sourceMappingURL=DoStorageConfig.d.mts.map