@effect-agent/storage-cloudflare 0.1.0-beta.50 → 0.1.0-beta.52

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.
@@ -9,7 +9,7 @@ var DoSubscriptionStore_exports = /* @__PURE__ */ __exportAll({
9
9
  DoSubscriptionTransaction: () => DoSubscriptionTransaction,
10
10
  doSubscriptionStoreLayer: () => doSubscriptionStoreLayer
11
11
  });
12
- const CURRENT_SUBSCRIPTION_STORE_VERSION = 2;
12
+ const CURRENT_SUBSCRIPTION_STORE_VERSION = 3;
13
13
  const ScanRow = Schema.Struct({
14
14
  event_scan_cursor: Schema.String,
15
15
  delivery_scan_cursor: Schema.String,
@@ -58,7 +58,7 @@ const initializeDoSubscriptionStore = Effect.fn("DoSubscriptionStore.initialize"
58
58
  yield* sql`CREATE TABLE effect_agent_subscriptions (
59
59
  tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, owner_id TEXT NOT NULL, subscription_id TEXT NOT NULL,
60
60
  ordinal INTEGER NOT NULL, source_name TEXT NOT NULL, source_version TEXT NOT NULL, matching_key TEXT NOT NULL,
61
- state TEXT NOT NULL, expires_at_millis INTEGER NOT NULL, recovery_at_millis INTEGER, record_json TEXT NOT NULL,
61
+ state TEXT NOT NULL, expires_at_millis INTEGER, recovery_at_millis INTEGER, recovery_present INTEGER NOT NULL DEFAULT 0, record_json TEXT NOT NULL,
62
62
  PRIMARY KEY (tenant_id, source_address, owner_id, subscription_id), UNIQUE (tenant_id, source_address, ordinal)
63
63
  )`.withoutTransform;
64
64
  yield* sql`CREATE INDEX effect_agent_subscriptions_owner ON effect_agent_subscriptions (tenant_id, source_address, owner_id, ordinal)`.withoutTransform;
@@ -67,7 +67,7 @@ const initializeDoSubscriptionStore = Effect.fn("DoSubscriptionStore.initialize"
67
67
  yield* sql`CREATE TABLE effect_agent_subscription_events (
68
68
  tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, event_id TEXT NOT NULL, source_name TEXT NOT NULL,
69
69
  source_version TEXT NOT NULL, matching_key TEXT NOT NULL, payload_digest TEXT NOT NULL, cutoff INTEGER NOT NULL,
70
- cursor INTEGER NOT NULL, routing_complete INTEGER NOT NULL, next_attempt_at_millis INTEGER NOT NULL, record_json TEXT NOT NULL,
70
+ cursor INTEGER NOT NULL, routing_complete INTEGER NOT NULL, tombstone INTEGER NOT NULL DEFAULT 0, next_attempt_at_millis INTEGER NOT NULL, record_json TEXT NOT NULL,
71
71
  PRIMARY KEY (tenant_id, source_address, event_id)
72
72
  )`.withoutTransform;
73
73
  yield* sql`CREATE INDEX effect_agent_subscription_events_pending ON effect_agent_subscription_events (tenant_id, source_address, routing_complete, next_attempt_at_millis, event_id)`.withoutTransform;
@@ -109,7 +109,11 @@ const makeSubscriptionStore = Effect.fn("DoSubscriptionStore.make")(function* (o
109
109
  SELECT next_attempt_at_millis AS deadline FROM effect_agent_subscription_events
110
110
  WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND routing_complete=0
111
111
  UNION ALL SELECT next_attempt_at_millis FROM effect_agent_subscription_deliveries
112
- WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND state NOT IN ('delivered','refused')
112
+ WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND CASE WHEN json_valid(record_json) THEN
113
+ ((state NOT IN ('delivered','refused') AND COALESCE(json_extract(record_json, '$.retry.parked'), 0)=0) OR (state='delivered' AND json_extract(record_json, '$.observeSettlement')=1))
114
+ ELSE state<>'refused' END
115
+ UNION ALL SELECT next_maintenance_at_millis FROM effect_agent_event_retention
116
+ WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address}
113
117
  UNION ALL SELECT recovery_at_millis FROM effect_agent_subscriptions
114
118
  WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND state='active' AND recovery_at_millis IS NOT NULL
115
119
  )
@@ -1 +1 @@
1
- {"version":3,"file":"DoSubscriptionStore.mjs","names":[],"sources":["../src/DoSubscriptionStore.ts"],"sourcesContent":["import {\n makeSqlSubscriptionStore,\n SqlSubscriptionTransaction,\n} from \"@effect-agent/thread/SqlSubscriptionStore\";\nimport {\n SourcePartition,\n SubscriptionError,\n SubscriptionFailpoint,\n type SubscriptionFailpointError,\n SubscriptionStore,\n} from \"@effect-agent/thread/Subscription\";\nimport { Context, Effect, Layer, Schema } from \"effect\";\nimport * as SqlClientService from \"effect/unstable/sql/SqlClient\";\nimport type { SqlError } from \"effect/unstable/sql/SqlError\";\n\nconst CURRENT_SUBSCRIPTION_STORE_VERSION = 2;\n\nconst ScanRow = Schema.Struct({\n event_scan_cursor: Schema.String,\n delivery_scan_cursor: Schema.String,\n recovery_scan_cursor: Schema.Natural,\n});\n\nconst StoreStateRow = Schema.Struct({\n storage_version: Schema.Int,\n alarm_generation: Schema.Natural,\n});\n\nexport interface DoSubscriptionAlarmReplacement {\n readonly deadlineAtMillis: number | null;\n readonly generation: number;\n}\n\nexport type DoSubscriptionReplaceAlarm = (\n replacement: DoSubscriptionAlarmReplacement,\n) => Effect.Effect<void, SubscriptionError>;\n\n/** One Durable Object transaction combining subscription SQL and its single native alarm. */\nexport class DoSubscriptionTransaction extends Context.Service<\n DoSubscriptionTransaction,\n {\n readonly run: <A, E, R>(\n body: (replaceAlarm: DoSubscriptionReplaceAlarm) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | SubscriptionError, R>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoSubscriptionTransaction\") {}\n\nexport class DoSubscriptionAlarmControl extends Context.Service<\n DoSubscriptionAlarmControl,\n {\n readonly prearm: (\n deadlineAtMillis: number,\n ) => Effect.Effect<void, SubscriptionError | SubscriptionFailpointError>;\n readonly reconcile: Effect.Effect<void, SubscriptionError | SubscriptionFailpointError>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoSubscriptionAlarmControl\") {}\n\nconst error = (reason: SubscriptionError[\"reason\"], code: string) =>\n SubscriptionError.make({ reason, code });\n\nconst unavailable = (operation: string) => error(\"storage\", operation);\nconst corrupt = (operation: string) => error(\"corrupt\", operation);\n\nconst validate = <A, I>(schema: Schema.Codec<A, I>, value: unknown, code: string) =>\n Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(() => error(\"validation\", code)));\n\nconst decodeRows = <A, I>(schema: Schema.Codec<A, I>, rows: unknown, code: string) =>\n Schema.decodeUnknownEffect(Schema.Array(schema))(rows).pipe(Effect.mapError(() => corrupt(code)));\n\nconst initializeDoSubscriptionStore = Effect.fn(\"DoSubscriptionStore.initialize\")(function* () {\n const sql = yield* SqlClientService.SqlClient;\n\n const names = yield* sql<Record<string, unknown>>`\n SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'effect_agent_subscription_%'\n `.pipe(Effect.mapError(() => unavailable(\"inspect subscription storage\")));\n\n const decodedNames = yield* decodeRows(\n Schema.Struct({ name: Schema.String }),\n names,\n \"inspect subscription storage\",\n );\n\n const expected = new Set([\n \"effect_agent_subscription_store_state\",\n \"effect_agent_subscription_sequences\",\n \"effect_agent_subscriptions\",\n \"effect_agent_subscription_events\",\n \"effect_agent_subscription_deliveries\",\n ]);\n\n const hasState = decodedNames.some(\n ({ name }) => name === \"effect_agent_subscription_store_state\",\n );\n\n if (!hasState && decodedNames.length > 0) return yield* corrupt(\"partial subscription storage\");\n if (!hasState) {\n yield* sql\n .withTransaction(\n Effect.gen(function* () {\n yield* sql`CREATE TABLE effect_agent_subscription_store_state (\n singleton INTEGER PRIMARY KEY NOT NULL CHECK(singleton=1), storage_version INTEGER NOT NULL, alarm_generation INTEGER NOT NULL\n )`.withoutTransform;\n yield* sql`CREATE TABLE effect_agent_subscription_sequences (\n tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, sequence INTEGER NOT NULL,\n event_scan_cursor TEXT NOT NULL, delivery_scan_cursor TEXT NOT NULL, recovery_scan_cursor INTEGER NOT NULL,\n PRIMARY KEY (tenant_id, source_address)\n )`.withoutTransform;\n yield* sql`CREATE TABLE effect_agent_subscriptions (\n tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, owner_id TEXT NOT NULL, subscription_id TEXT NOT NULL,\n ordinal INTEGER NOT NULL, source_name TEXT NOT NULL, source_version TEXT NOT NULL, matching_key TEXT NOT NULL,\n state TEXT NOT NULL, expires_at_millis INTEGER NOT NULL, recovery_at_millis INTEGER, record_json TEXT NOT NULL,\n PRIMARY KEY (tenant_id, source_address, owner_id, subscription_id), UNIQUE (tenant_id, source_address, ordinal)\n )`.withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscriptions_owner ON effect_agent_subscriptions (tenant_id, source_address, owner_id, ordinal)`\n .withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscriptions_candidates ON effect_agent_subscriptions (tenant_id, source_address, source_name, source_version, matching_key, ordinal)`\n .withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscriptions_recovery ON effect_agent_subscriptions (tenant_id, source_address, recovery_at_millis, ordinal) WHERE recovery_at_millis IS NOT NULL`\n .withoutTransform;\n yield* sql`CREATE TABLE effect_agent_subscription_events (\n tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, event_id TEXT NOT NULL, source_name TEXT NOT NULL,\n source_version TEXT NOT NULL, matching_key TEXT NOT NULL, payload_digest TEXT NOT NULL, cutoff INTEGER NOT NULL,\n cursor INTEGER NOT NULL, routing_complete INTEGER NOT NULL, next_attempt_at_millis INTEGER NOT NULL, record_json TEXT NOT NULL,\n PRIMARY KEY (tenant_id, source_address, event_id)\n )`.withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscription_events_pending ON effect_agent_subscription_events (tenant_id, source_address, routing_complete, next_attempt_at_millis, event_id)`\n .withoutTransform;\n yield* sql`CREATE TABLE effect_agent_subscription_deliveries (\n tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, owner_id TEXT NOT NULL, subscription_id TEXT NOT NULL,\n event_id TEXT NOT NULL, delivery_key TEXT NOT NULL, state TEXT NOT NULL, next_attempt_at_millis INTEGER NOT NULL,\n record_json TEXT NOT NULL, PRIMARY KEY (tenant_id, source_address, owner_id, subscription_id, event_id),\n UNIQUE (tenant_id, source_address, delivery_key)\n )`.withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscription_deliveries_pending ON effect_agent_subscription_deliveries (tenant_id, source_address, state, next_attempt_at_millis, delivery_key)`\n .withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscription_deliveries_registration ON effect_agent_subscription_deliveries (tenant_id, source_address, owner_id, subscription_id, delivery_key)`\n .withoutTransform;\n yield* sql`INSERT INTO effect_agent_subscription_store_state (singleton, storage_version, alarm_generation)\n VALUES (1, ${CURRENT_SUBSCRIPTION_STORE_VERSION}, 0)`.withoutTransform;\n }),\n )\n .pipe(Effect.mapError(() => unavailable(\"initialize subscription storage\")));\n\n return;\n }\n if (decodedNames.length !== expected.size || decodedNames.some(({ name }) => !expected.has(name)))\n return yield* corrupt(\"subscription storage tables\");\n\n const rows = yield* sql<\n Record<string, unknown>\n >`SELECT storage_version, alarm_generation FROM effect_agent_subscription_store_state WHERE singleton=1`.pipe(\n Effect.mapError(() => unavailable(\"read subscription storage version\")),\n );\n\n const state = yield* decodeRows(StoreStateRow, rows, \"read subscription storage version\");\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SUBSCRIPTION_STORE_VERSION)\n return yield* corrupt(\n state.length === 1\n ? `incompatible subscription storage version ${state[0].storage_version}; expected ${CURRENT_SUBSCRIPTION_STORE_VERSION}`\n : \"invalid subscription storage version row\",\n );\n});\n\nconst makeSubscriptionStore = Effect.fn(\"DoSubscriptionStore.make\")(function* (\n owned: SourcePartition,\n) {\n const partition = yield* validate(SourcePartition, owned, \"partition\");\n const sql = yield* SqlClientService.SqlClient;\n const failpoint = yield* SubscriptionFailpoint;\n const transactions = yield* DoSubscriptionTransaction;\n\n yield* initializeDoSubscriptionStore();\n\n const query = <A extends object>(\n effect: Effect.Effect<ReadonlyArray<A>, SqlError>,\n code: string,\n ) => effect.pipe(Effect.mapError(() => unavailable(code)));\n\n const readIndexedDeadline = Effect.fn(\"DoSubscriptionStore.readIndexedDeadline\")(function* () {\n const scanRows = yield* query(\n sql<Record<string, unknown>>`\n SELECT event_scan_cursor, delivery_scan_cursor, recovery_scan_cursor FROM effect_agent_subscription_sequences\n WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address}\n `,\n \"read scan cursor deadline\",\n );\n\n const scans = yield* decodeRows(ScanRow, scanRows, \"read scan cursor deadline\");\n\n if (scans.length !== 1) return yield* corrupt(\"scan cursor deadline\");\n if (\n scans[0].event_scan_cursor !== \"\" ||\n scans[0].delivery_scan_cursor !== \"\" ||\n scans[0].recovery_scan_cursor !== 0\n )\n return 0;\n\n const rows = yield* query(\n sql<Record<string, unknown>>`\n SELECT MIN(deadline) AS deadline FROM (\n SELECT next_attempt_at_millis AS deadline FROM effect_agent_subscription_events\n WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND routing_complete=0\n UNION ALL SELECT next_attempt_at_millis FROM effect_agent_subscription_deliveries\n WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND state NOT IN ('delivered','refused')\n UNION ALL SELECT recovery_at_millis FROM effect_agent_subscriptions\n WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND state='active' AND recovery_at_millis IS NOT NULL\n )\n `,\n \"read subscription deadline\",\n );\n\n const decoded = yield* decodeRows(\n Schema.Struct({ deadline: Schema.NullOr(Schema.Number) }),\n rows,\n \"read subscription deadline\",\n );\n\n if (decoded.length !== 1) return yield* corrupt(\"subscription deadline\");\n\n return decoded[0].deadline;\n });\n\n const replaceAlarm = Effect.fn(\"DoSubscriptionStore.replaceAlarm\")(function* (\n replace: DoSubscriptionReplaceAlarm,\n deadlineAtMillis: number | null,\n ) {\n const rows = yield* query(\n sql<Record<string, unknown>>`\n UPDATE effect_agent_subscription_store_state SET alarm_generation=alarm_generation+1\n WHERE singleton=1 RETURNING storage_version, alarm_generation\n `,\n \"advance subscription alarm generation\",\n );\n\n const state = yield* decodeRows(StoreStateRow, rows, \"advance subscription alarm generation\");\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SUBSCRIPTION_STORE_VERSION)\n return yield* corrupt(\"subscription alarm state\");\n yield* failpoint.hit(\"subscription:alarm:before\");\n yield* replace({ deadlineAtMillis, generation: state[0].alarm_generation });\n yield* failpoint.hit(\"subscription:alarm:after\");\n });\n\n const transact = <A>(effect: Effect.Effect<A, SubscriptionError | SubscriptionFailpointError>) =>\n transactions.run((replace) =>\n Effect.gen(function* () {\n const value = yield* effect;\n\n yield* replaceAlarm(replace, yield* readIndexedDeadline());\n\n return value;\n }),\n );\n\n const store = yield* makeSqlSubscriptionStore(partition, {\n maxStoredJsonLength: 1_900_000,\n }).pipe(Effect.provide(Layer.succeed(SqlSubscriptionTransaction)({ run: transact })));\n\n const prearm = Effect.fn(\"DoSubscriptionStore.prearm\")(function* (deadlineAtMillis: number) {\n yield* transactions.run((replace) => replaceAlarm(replace, deadlineAtMillis));\n yield* failpoint.hit(\"subscription:prearm:after\");\n });\n\n const reconcile = Effect.gen(function* () {\n yield* transactions.run((replace) =>\n Effect.gen(function* () {\n yield* replaceAlarm(replace, yield* readIndexedDeadline());\n }),\n );\n yield* failpoint.hit(\"subscription:reconcile:after\");\n });\n\n return Context.make(SubscriptionStore, store).pipe(\n Context.add(DoSubscriptionAlarmControl, { prearm, reconcile }),\n );\n});\n\nexport const doSubscriptionStoreLayer = (\n partition: SourcePartition,\n): Layer.Layer<\n SubscriptionStore | DoSubscriptionAlarmControl,\n SubscriptionError,\n DoSubscriptionTransaction | SqlClientService.SqlClient\n> => Layer.effectContext(makeSubscriptionStore(partition));\n"],"mappings":"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"}
1
+ {"version":3,"file":"DoSubscriptionStore.mjs","names":[],"sources":["../src/DoSubscriptionStore.ts"],"sourcesContent":["import {\n makeSqlSubscriptionStore,\n SqlSubscriptionTransaction,\n} from \"@effect-agent/thread/SqlSubscriptionStore\";\nimport {\n SourcePartition,\n SubscriptionError,\n SubscriptionFailpoint,\n type SubscriptionFailpointError,\n SubscriptionStore,\n} from \"@effect-agent/thread/Subscription\";\nimport { Context, Effect, Layer, Schema } from \"effect\";\nimport * as SqlClientService from \"effect/unstable/sql/SqlClient\";\nimport type { SqlError } from \"effect/unstable/sql/SqlError\";\n\nconst CURRENT_SUBSCRIPTION_STORE_VERSION = 3;\n\nconst ScanRow = Schema.Struct({\n event_scan_cursor: Schema.String,\n delivery_scan_cursor: Schema.String,\n recovery_scan_cursor: Schema.Natural,\n});\n\nconst StoreStateRow = Schema.Struct({\n storage_version: Schema.Int,\n alarm_generation: Schema.Natural,\n});\n\nexport interface DoSubscriptionAlarmReplacement {\n readonly deadlineAtMillis: number | null;\n readonly generation: number;\n}\n\nexport type DoSubscriptionReplaceAlarm = (\n replacement: DoSubscriptionAlarmReplacement,\n) => Effect.Effect<void, SubscriptionError>;\n\n/** One Durable Object transaction combining subscription SQL and its single native alarm. */\nexport class DoSubscriptionTransaction extends Context.Service<\n DoSubscriptionTransaction,\n {\n readonly run: <A, E, R>(\n body: (replaceAlarm: DoSubscriptionReplaceAlarm) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | SubscriptionError, R>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoSubscriptionTransaction\") {}\n\nexport class DoSubscriptionAlarmControl extends Context.Service<\n DoSubscriptionAlarmControl,\n {\n readonly prearm: (\n deadlineAtMillis: number,\n ) => Effect.Effect<void, SubscriptionError | SubscriptionFailpointError>;\n readonly reconcile: Effect.Effect<void, SubscriptionError | SubscriptionFailpointError>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoSubscriptionAlarmControl\") {}\n\nconst error = (reason: SubscriptionError[\"reason\"], code: string) =>\n SubscriptionError.make({ reason, code });\n\nconst unavailable = (operation: string) => error(\"storage\", operation);\nconst corrupt = (operation: string) => error(\"corrupt\", operation);\n\nconst validate = <A, I>(schema: Schema.Codec<A, I>, value: unknown, code: string) =>\n Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(() => error(\"validation\", code)));\n\nconst decodeRows = <A, I>(schema: Schema.Codec<A, I>, rows: unknown, code: string) =>\n Schema.decodeUnknownEffect(Schema.Array(schema))(rows).pipe(Effect.mapError(() => corrupt(code)));\n\nconst initializeDoSubscriptionStore = Effect.fn(\"DoSubscriptionStore.initialize\")(function* () {\n const sql = yield* SqlClientService.SqlClient;\n\n const names = yield* sql<Record<string, unknown>>`\n SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'effect_agent_subscription_%'\n `.pipe(Effect.mapError(() => unavailable(\"inspect subscription storage\")));\n\n const decodedNames = yield* decodeRows(\n Schema.Struct({ name: Schema.String }),\n names,\n \"inspect subscription storage\",\n );\n\n const expected = new Set([\n \"effect_agent_subscription_store_state\",\n \"effect_agent_subscription_sequences\",\n \"effect_agent_subscriptions\",\n \"effect_agent_subscription_events\",\n \"effect_agent_subscription_deliveries\",\n ]);\n\n const hasState = decodedNames.some(\n ({ name }) => name === \"effect_agent_subscription_store_state\",\n );\n\n if (!hasState && decodedNames.length > 0) return yield* corrupt(\"partial subscription storage\");\n if (!hasState) {\n yield* sql\n .withTransaction(\n Effect.gen(function* () {\n yield* sql`CREATE TABLE effect_agent_subscription_store_state (\n singleton INTEGER PRIMARY KEY NOT NULL CHECK(singleton=1), storage_version INTEGER NOT NULL, alarm_generation INTEGER NOT NULL\n )`.withoutTransform;\n yield* sql`CREATE TABLE effect_agent_subscription_sequences (\n tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, sequence INTEGER NOT NULL,\n event_scan_cursor TEXT NOT NULL, delivery_scan_cursor TEXT NOT NULL, recovery_scan_cursor INTEGER NOT NULL,\n PRIMARY KEY (tenant_id, source_address)\n )`.withoutTransform;\n yield* sql`CREATE TABLE effect_agent_subscriptions (\n tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, owner_id TEXT NOT NULL, subscription_id TEXT NOT NULL,\n ordinal INTEGER NOT NULL, source_name TEXT NOT NULL, source_version TEXT NOT NULL, matching_key TEXT NOT NULL,\n state TEXT NOT NULL, expires_at_millis INTEGER, recovery_at_millis INTEGER, recovery_present INTEGER NOT NULL DEFAULT 0, record_json TEXT NOT NULL,\n PRIMARY KEY (tenant_id, source_address, owner_id, subscription_id), UNIQUE (tenant_id, source_address, ordinal)\n )`.withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscriptions_owner ON effect_agent_subscriptions (tenant_id, source_address, owner_id, ordinal)`\n .withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscriptions_candidates ON effect_agent_subscriptions (tenant_id, source_address, source_name, source_version, matching_key, ordinal)`\n .withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscriptions_recovery ON effect_agent_subscriptions (tenant_id, source_address, recovery_at_millis, ordinal) WHERE recovery_at_millis IS NOT NULL`\n .withoutTransform;\n yield* sql`CREATE TABLE effect_agent_subscription_events (\n tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, event_id TEXT NOT NULL, source_name TEXT NOT NULL,\n source_version TEXT NOT NULL, matching_key TEXT NOT NULL, payload_digest TEXT NOT NULL, cutoff INTEGER NOT NULL,\n cursor INTEGER NOT NULL, routing_complete INTEGER NOT NULL, tombstone INTEGER NOT NULL DEFAULT 0, next_attempt_at_millis INTEGER NOT NULL, record_json TEXT NOT NULL,\n PRIMARY KEY (tenant_id, source_address, event_id)\n )`.withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscription_events_pending ON effect_agent_subscription_events (tenant_id, source_address, routing_complete, next_attempt_at_millis, event_id)`\n .withoutTransform;\n yield* sql`CREATE TABLE effect_agent_subscription_deliveries (\n tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, owner_id TEXT NOT NULL, subscription_id TEXT NOT NULL,\n event_id TEXT NOT NULL, delivery_key TEXT NOT NULL, state TEXT NOT NULL, next_attempt_at_millis INTEGER NOT NULL,\n record_json TEXT NOT NULL, PRIMARY KEY (tenant_id, source_address, owner_id, subscription_id, event_id),\n UNIQUE (tenant_id, source_address, delivery_key)\n )`.withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscription_deliveries_pending ON effect_agent_subscription_deliveries (tenant_id, source_address, state, next_attempt_at_millis, delivery_key)`\n .withoutTransform;\n yield* sql`CREATE INDEX effect_agent_subscription_deliveries_registration ON effect_agent_subscription_deliveries (tenant_id, source_address, owner_id, subscription_id, delivery_key)`\n .withoutTransform;\n yield* sql`INSERT INTO effect_agent_subscription_store_state (singleton, storage_version, alarm_generation)\n VALUES (1, ${CURRENT_SUBSCRIPTION_STORE_VERSION}, 0)`.withoutTransform;\n }),\n )\n .pipe(Effect.mapError(() => unavailable(\"initialize subscription storage\")));\n\n return;\n }\n if (decodedNames.length !== expected.size || decodedNames.some(({ name }) => !expected.has(name)))\n return yield* corrupt(\"subscription storage tables\");\n\n const rows = yield* sql<\n Record<string, unknown>\n >`SELECT storage_version, alarm_generation FROM effect_agent_subscription_store_state WHERE singleton=1`.pipe(\n Effect.mapError(() => unavailable(\"read subscription storage version\")),\n );\n\n const state = yield* decodeRows(StoreStateRow, rows, \"read subscription storage version\");\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SUBSCRIPTION_STORE_VERSION)\n return yield* corrupt(\n state.length === 1\n ? `incompatible subscription storage version ${state[0].storage_version}; expected ${CURRENT_SUBSCRIPTION_STORE_VERSION}`\n : \"invalid subscription storage version row\",\n );\n});\n\nconst makeSubscriptionStore = Effect.fn(\"DoSubscriptionStore.make\")(function* (\n owned: SourcePartition,\n) {\n const partition = yield* validate(SourcePartition, owned, \"partition\");\n const sql = yield* SqlClientService.SqlClient;\n const failpoint = yield* SubscriptionFailpoint;\n const transactions = yield* DoSubscriptionTransaction;\n\n yield* initializeDoSubscriptionStore();\n\n const query = <A extends object>(\n effect: Effect.Effect<ReadonlyArray<A>, SqlError>,\n code: string,\n ) => effect.pipe(Effect.mapError(() => unavailable(code)));\n\n const readIndexedDeadline = Effect.fn(\"DoSubscriptionStore.readIndexedDeadline\")(function* () {\n const scanRows = yield* query(\n sql<Record<string, unknown>>`\n SELECT event_scan_cursor, delivery_scan_cursor, recovery_scan_cursor FROM effect_agent_subscription_sequences\n WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address}\n `,\n \"read scan cursor deadline\",\n );\n\n const scans = yield* decodeRows(ScanRow, scanRows, \"read scan cursor deadline\");\n\n if (scans.length !== 1) return yield* corrupt(\"scan cursor deadline\");\n if (\n scans[0].event_scan_cursor !== \"\" ||\n scans[0].delivery_scan_cursor !== \"\" ||\n scans[0].recovery_scan_cursor !== 0\n )\n return 0;\n\n const rows = yield* query(\n sql<Record<string, unknown>>`\n SELECT MIN(deadline) AS deadline FROM (\n SELECT next_attempt_at_millis AS deadline FROM effect_agent_subscription_events\n WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND routing_complete=0\n UNION ALL SELECT next_attempt_at_millis FROM effect_agent_subscription_deliveries\n WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND CASE WHEN json_valid(record_json) THEN\n ((state NOT IN ('delivered','refused') AND COALESCE(json_extract(record_json, '$.retry.parked'), 0)=0) OR (state='delivered' AND json_extract(record_json, '$.observeSettlement')=1))\n ELSE state<>'refused' END\n UNION ALL SELECT next_maintenance_at_millis FROM effect_agent_event_retention\n WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address}\n UNION ALL SELECT recovery_at_millis FROM effect_agent_subscriptions\n WHERE tenant_id=${partition.tenantId} AND source_address=${partition.address} AND state='active' AND recovery_at_millis IS NOT NULL\n )\n `,\n \"read subscription deadline\",\n );\n\n const decoded = yield* decodeRows(\n Schema.Struct({ deadline: Schema.NullOr(Schema.Number) }),\n rows,\n \"read subscription deadline\",\n );\n\n if (decoded.length !== 1) return yield* corrupt(\"subscription deadline\");\n\n return decoded[0].deadline;\n });\n\n const replaceAlarm = Effect.fn(\"DoSubscriptionStore.replaceAlarm\")(function* (\n replace: DoSubscriptionReplaceAlarm,\n deadlineAtMillis: number | null,\n ) {\n const rows = yield* query(\n sql<Record<string, unknown>>`\n UPDATE effect_agent_subscription_store_state SET alarm_generation=alarm_generation+1\n WHERE singleton=1 RETURNING storage_version, alarm_generation\n `,\n \"advance subscription alarm generation\",\n );\n\n const state = yield* decodeRows(StoreStateRow, rows, \"advance subscription alarm generation\");\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SUBSCRIPTION_STORE_VERSION)\n return yield* corrupt(\"subscription alarm state\");\n yield* failpoint.hit(\"subscription:alarm:before\");\n yield* replace({ deadlineAtMillis, generation: state[0].alarm_generation });\n yield* failpoint.hit(\"subscription:alarm:after\");\n });\n\n const transact = <A>(effect: Effect.Effect<A, SubscriptionError | SubscriptionFailpointError>) =>\n transactions.run((replace) =>\n Effect.gen(function* () {\n const value = yield* effect;\n\n yield* replaceAlarm(replace, yield* readIndexedDeadline());\n\n return value;\n }),\n );\n\n const store = yield* makeSqlSubscriptionStore(partition, {\n maxStoredJsonLength: 1_900_000,\n }).pipe(Effect.provide(Layer.succeed(SqlSubscriptionTransaction)({ run: transact })));\n\n const prearm = Effect.fn(\"DoSubscriptionStore.prearm\")(function* (deadlineAtMillis: number) {\n yield* transactions.run((replace) => replaceAlarm(replace, deadlineAtMillis));\n yield* failpoint.hit(\"subscription:prearm:after\");\n });\n\n const reconcile = Effect.gen(function* () {\n yield* transactions.run((replace) =>\n Effect.gen(function* () {\n yield* replaceAlarm(replace, yield* readIndexedDeadline());\n }),\n );\n yield* failpoint.hit(\"subscription:reconcile:after\");\n });\n\n return Context.make(SubscriptionStore, store).pipe(\n Context.add(DoSubscriptionAlarmControl, { prearm, reconcile }),\n );\n});\n\nexport const doSubscriptionStoreLayer = (\n partition: SourcePartition,\n): Layer.Layer<\n SubscriptionStore | DoSubscriptionAlarmControl,\n SubscriptionError,\n DoSubscriptionTransaction | SqlClientService.SqlClient\n> => Layer.effectContext(makeSubscriptionStore(partition));\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { DoStorageConfig, DoStorageConfigValue } from "./DoStorageConfig.mjs";
3
3
  import { DoAppendConflict, DoCheckpointConflict, DoFenceRejected, DoStorageCompatibilityError, DoStorageCorruptionError, DoStorageError, DoValueBoundExceeded } from "./DoStorageError.mjs";
4
4
  import { DoStorageFailpoint } from "./DoStorageFailpoint.mjs";
5
- import { n as doMigrations } from "./migrations-Bo4GU-pp.mjs";
5
+ import { n as doMigrations } from "./migrations-B-jiT7vx.mjs";
6
6
  import { SqliteClient, SqliteMigrator } from "@effect/sql-sqlite-do";
7
7
  import { Clock, Context, Crypto, Duration, Effect, Layer, Option, Ref, Schema, Stream } from "effect";
8
8
  import * as SqlClient from "effect/unstable/sql/SqlClient";
@@ -160,7 +160,7 @@ const ensureCurrentStorage = Effect.fn("DoJournal.ensureCurrentStorage")(functio
160
160
  `.pipe(Effect.mapError(storageError("inspect unversioned storage")));
161
161
  if ((yield* decodeRows(Schema.Array(DoNameRow), "sqlite_master", "effect_agent_%", existingRows)).length > 0) return yield* DoStorageCompatibilityError.make({
162
162
  actualVersion: 0,
163
- supportedVersion: 2,
163
+ supportedVersion: 3,
164
164
  message: "The Durable Object contains unversioned Effect Agent tables. Reset the development namespace explicitly; refusing to mutate ambiguous stored data."
165
165
  });
166
166
  yield* SqliteMigrator.run({ loader: doMigrations }).pipe(Effect.provideService(SqlClient.SqlClient, sql), Effect.mapError((error) => DoStorageError.make({
@@ -175,12 +175,12 @@ const ensureCurrentStorage = Effect.fn("DoJournal.ensureCurrentStorage")(functio
175
175
  WHERE key = 'storage_version'
176
176
  `.pipe(Effect.mapError(storageError("read storage version")));
177
177
  const version = yield* decodeSingleRow(Schema.Array(DoMetaRow), "effect_agent_meta", "storage_version", versionRows);
178
- if (version.value !== String(2)) {
178
+ if (version.value !== String(3)) {
179
179
  const actualVersion = Number.parseInt(version.value, 10);
180
180
  return yield* DoStorageCompatibilityError.make({
181
181
  actualVersion: Number.isSafeInteger(actualVersion) ? actualVersion : -1,
182
- supportedVersion: 2,
183
- message: `The Durable Object uses private-development storage version ${version.value}; this build supports exactly version 2. Replace the development namespace explicitly; automatic stored-data migrations are not provided during private development.`
182
+ supportedVersion: 3,
183
+ message: `The Durable Object uses private-development storage version ${version.value}; this build supports exactly version 3. Replace the development namespace explicitly; automatic stored-data migrations are not provided during private development.`
184
184
  });
185
185
  }
186
186
  }
@@ -192,8 +192,8 @@ const ensureCurrentStorage = Effect.fn("DoJournal.ensureCurrentStorage")(functio
192
192
  ORDER BY name
193
193
  `.pipe(Effect.mapError(storageError("verify storage tables")));
194
194
  if ((yield* decodeRows(Schema.Array(DoNameRow), "sqlite_master", "required_tables", requiredRows)).length !== REQUIRED_TABLES.length) return yield* DoStorageCompatibilityError.make({
195
- actualVersion: 2,
196
- supportedVersion: 2,
195
+ actualVersion: 3,
196
+ supportedVersion: 3,
197
197
  message: "The Durable Object claims the current format but is missing required tables. Reset the corrupt private-development data."
198
198
  });
199
199
  return makeJournal(sql, failpoint, maxStoredValueBytes);
@@ -1095,4 +1095,4 @@ const layer = (options) => Layer.unwrap(Effect.map(DoStorageConfig, (config) =>
1095
1095
  //#endregion
1096
1096
  export { threadStoreLayer as a, storageFailpointLayer as i, layer as n, decodeRows as o, storageConfigLayer as r, initializeDoJournal as s, DoThreadStore_exports as t };
1097
1097
 
1098
- //# sourceMappingURL=DoThreadStore-D00TdRAa.mjs.map
1098
+ //# sourceMappingURL=DoThreadStore-JqjeFOga.mjs.map