@yielded/agent-storage-cloudflare 0.1.0-beta.173 → 0.1.0-beta.175
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DoMemoryStore.mjs +1 -1
- package/dist/DoMessageDeliveryStore.mjs +1 -1
- package/dist/DoStorageFailpoint.d.mts +3 -1
- package/dist/DoStorageFailpoint.mjs +7 -2
- package/dist/DoStorageFailpoint.mjs.map +1 -1
- package/dist/DoStorageFailpointTesting.mjs +1 -4
- package/dist/DoStorageFailpointTesting.mjs.map +1 -1
- package/dist/{DoStorageVersion-NKnQU3eR.d.mts → DoStorageVersion-Mc7CXMdN.d.mts} +2 -2
- package/dist/DoStorageVersion.d.mts +1 -1
- package/dist/DoStorageVersion.mjs +2 -2
- package/dist/DoSubmissionLedger.mjs +121 -67
- package/dist/DoSubmissionLedger.mjs.map +1 -1
- package/dist/DoSubscriptionStore.mjs.map +1 -1
- package/dist/{DoThreadStore-CtyahRTW.mjs → DoThreadStore-CgIZQUNR.mjs} +30 -25
- package/dist/DoThreadStore-CgIZQUNR.mjs.map +1 -0
- package/dist/DoThreadStore.mjs +1 -1
- package/dist/PortProtocol.d.mts +12 -0
- package/dist/PortRouting.mjs +6 -1
- package/dist/PortRouting.mjs.map +1 -1
- package/dist/{do-journal-_MdLGTd3.mjs → do-journal-7P3DUBz0.mjs} +140 -65
- package/dist/do-journal-7P3DUBz0.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{migrations-C3N9GN6A.mjs → migrations-CAO_akhD.mjs} +45 -22
- package/dist/migrations-CAO_akhD.mjs.map +1 -0
- package/dist/{owned-state-BHzUi0eb.mjs → owned-state-B4QhezMp.mjs} +8 -6
- package/dist/owned-state-B4QhezMp.mjs.map +1 -0
- package/package.json +1 -1
- package/src/DoStorageFailpoint.ts +4 -0
- package/src/DoStorageFailpointTesting.ts +9 -7
- package/src/DoSubmissionLedger.ts +271 -150
- package/src/DoSubscriptionStore.ts +1 -0
- package/src/DoThreadStore.ts +27 -50
- package/src/PortRouting.ts +10 -2
- package/src/internal/canonical-append.ts +1 -1
- package/src/internal/do-journal.ts +987 -800
- package/src/internal/migrations.ts +53 -10
- package/src/internal/owned-state.ts +18 -7
- package/src/internal/prompt-checkpoint.ts +19 -13
- package/src/internal/storage-span.ts +22 -13
- package/dist/DoThreadStore-CtyahRTW.mjs.map +0 -1
- package/dist/do-journal-_MdLGTd3.mjs.map +0 -1
- package/dist/migrations-C3N9GN6A.mjs.map +0 -1
- package/dist/owned-state-BHzUi0eb.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DoSubscriptionStore.mjs","names":[],"sources":["../src/DoSubscriptionStore.ts"],"sourcesContent":["import {\n backfillSubscriptionSettlementObservation,\n makeSqlSubscriptionStore,\n} from \"@yielded/agent-storage-sql/sql-subscription-store\";\nimport { sameSqliteLayoutStatement } from \"@yielded/agent-storage-sql/sqlite-layout-inspection\";\nimport {\n SourcePartition,\n SubscriptionError,\n SubscriptionFailpoint,\n type SubscriptionFailpointError,\n SubscriptionStore,\n} from \"@yielded/agent/subscription\";\nimport { Context, Effect, Layer, Schema } from \"effect\";\nimport * as SqlClientService from \"effect/sql/SqlClient\";\nimport type { SqlError } from \"effect/sql/SqlError\";\n\nconst CURRENT_SUBSCRIPTION_STORE_VERSION = 4;\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 layoutStatements = [\n \"CREATE TABLE effect_agent_subscription_store_state ( singleton INTEGER PRIMARY KEY NOT NULL CHECK(singleton=1), storage_version INTEGER NOT NULL, alarm_generation INTEGER NOT NULL )\",\n \"CREATE TABLE effect_agent_subscription_sequences ( tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, sequence INTEGER NOT NULL, event_scan_cursor TEXT NOT NULL, delivery_scan_cursor TEXT NOT NULL, recovery_scan_cursor INTEGER NOT NULL, PRIMARY KEY (tenant_id, source_address) )\",\n \"CREATE TABLE effect_agent_subscriptions ( tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, owner_id TEXT NOT NULL, subscription_id TEXT NOT NULL, ordinal INTEGER NOT NULL, source_name TEXT NOT NULL, source_version TEXT NOT NULL, matching_key TEXT NOT NULL, state TEXT NOT NULL, expires_at_millis INTEGER, recovery_at_millis INTEGER, recovery_present INTEGER NOT NULL DEFAULT 0, record_json TEXT NOT NULL, PRIMARY KEY (tenant_id, source_address, owner_id, subscription_id), UNIQUE (tenant_id, source_address, ordinal) )\",\n \"CREATE INDEX effect_agent_subscriptions_owner ON effect_agent_subscriptions (tenant_id, source_address, owner_id, ordinal)\",\n \"CREATE INDEX effect_agent_subscriptions_capacity ON effect_agent_subscriptions (tenant_id, source_address, expires_at_millis) WHERE state IN ('active', 'paused')\",\n \"CREATE INDEX effect_agent_subscriptions_owner_capacity ON effect_agent_subscriptions (tenant_id, source_address, owner_id, expires_at_millis) WHERE state IN ('active', 'paused')\",\n \"CREATE INDEX effect_agent_subscriptions_candidates ON effect_agent_subscriptions (tenant_id, source_address, source_name, source_version, matching_key, ordinal)\",\n \"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 \"CREATE TABLE effect_agent_subscription_events ( tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, event_id TEXT NOT NULL, source_name TEXT NOT NULL, source_version TEXT NOT NULL, matching_key TEXT NOT NULL, payload_digest TEXT NOT NULL, cutoff INTEGER NOT NULL, 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, PRIMARY KEY (tenant_id, source_address, event_id) )\",\n \"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 \"CREATE TABLE effect_agent_subscription_deliveries ( tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, owner_id TEXT NOT NULL, subscription_id TEXT NOT NULL, event_id TEXT NOT NULL, delivery_key TEXT NOT NULL, state TEXT NOT NULL, next_attempt_at_millis INTEGER NOT NULL, record_json TEXT NOT NULL, observe_settlement INTEGER NOT NULL DEFAULT 0 CHECK (observe_settlement IN (0, 1)), PRIMARY KEY (tenant_id, source_address, owner_id, subscription_id, event_id), UNIQUE (tenant_id, source_address, delivery_key) )\",\n \"CREATE INDEX effect_agent_subscription_deliveries_pending ON effect_agent_subscription_deliveries (tenant_id, source_address, state, next_attempt_at_millis, delivery_key)\",\n \"CREATE INDEX effect_agent_subscription_deliveries_registration ON effect_agent_subscription_deliveries (tenant_id, source_address, owner_id, subscription_id, delivery_key)\",\n \"CREATE INDEX effect_agent_subscription_deliveries_capacity ON effect_agent_subscription_deliveries (tenant_id, source_address, owner_id) WHERE state IN ('selected', 'prepared')\",\n \"CREATE INDEX effect_agent_subscription_deliveries_observing ON effect_agent_subscription_deliveries (tenant_id, source_address, owner_id) WHERE state='delivered' AND observe_settlement=1\",\n] as const;\n\nconst layoutObjects = layoutStatements.map((statement, index) => {\n const name = /^CREATE (TABLE|INDEX) ([a-z_][a-z_0-9]*)/.exec(statement);\n\n if (name === null) throw new Error(\"Invalid subscription layout statement\");\n\n return [name[1].toLowerCase(), name[2], index] as const;\n});\n\nconst addedIndexes = new Set([\n \"effect_agent_subscriptions_capacity\",\n \"effect_agent_subscriptions_owner_capacity\",\n \"effect_agent_subscription_deliveries_capacity\",\n \"effect_agent_subscription_deliveries_observing\",\n]);\n\nconst LayoutObject = Schema.Struct({\n name: Schema.String,\n type: Schema.String,\n sql: Schema.NullOr(Schema.String),\n});\n\n/** Only the released v3 layout may upgrade; schema, backfill and version publish commit together. */\nconst initializeDoSubscriptionStore = Effect.fnUntraced(function* () {\n const sql = (yield* SqlClientService.SqlClient).withoutTransforms();\n const tables = layoutObjects.filter(([type]) => type === \"table\").map(([, name]) => name);\n\n const readObjects = sql`SELECT name, type, sql FROM sqlite_master\n WHERE name GLOB 'effect_agent_subscription*' OR (type='trigger' AND tbl_name IN ${sql.in(tables)})`.pipe(\n Effect.flatMap((rows) => decodeRows(LayoutObject, rows, \"subscription storage layout\")),\n );\n\n const checkLayout = Effect.fnUntraced(function* (\n objects: ReadonlyArray<typeof LayoutObject.Type>,\n version: number,\n ) {\n if (\n objects.some(\n ({ name, type }) =>\n (type === \"table\" && !tables.includes(name)) ||\n type === \"trigger\" ||\n (version === 3 && addedIndexes.has(name)),\n )\n )\n return yield* corrupt(\"ambiguous subscription storage layout\");\n for (const [type, name, index] of layoutObjects) {\n if (version === 3 && addedIndexes.has(name)) continue;\n\n const expected =\n version === 3\n ? layoutStatements[index].replace(\n \", observe_settlement INTEGER NOT NULL DEFAULT 0 CHECK (observe_settlement IN (0, 1))\",\n \"\",\n )\n : layoutStatements[index];\n\n const actual = objects.find((row) => row.name === name);\n\n if (\n actual?.type !== type ||\n actual.sql === null ||\n !sameSqliteLayoutStatement(actual.sql, expected)\n )\n return yield* corrupt(\"incompatible subscription storage layout \" + name);\n }\n });\n\n yield* sql\n .withTransaction(\n Effect.gen(function* () {\n const objects = yield* readObjects;\n\n const hasState = objects.some(\n ({ name }) => name === \"effect_agent_subscription_store_state\",\n );\n\n if (!hasState) {\n if (objects.length > 0) return yield* corrupt(\"partial subscription storage\");\n for (const statement of layoutStatements) yield* sql.unsafe(statement).withoutTransform;\n yield* sql`INSERT INTO effect_agent_subscription_store_state (singleton, storage_version, alarm_generation)\n VALUES (1, ${CURRENT_SUBSCRIPTION_STORE_VERSION}, 0)`;\n\n return;\n }\n\n const state = yield* decodeRows(\n StoreStateRow,\n yield* sql`SELECT storage_version, alarm_generation FROM effect_agent_subscription_store_state`,\n \"read subscription storage version\",\n );\n\n if (state.length !== 1) return yield* corrupt(\"invalid subscription storage version row\");\n const version = state[0].storage_version;\n\n if (version !== 3 && version !== CURRENT_SUBSCRIPTION_STORE_VERSION)\n return yield* corrupt(\n `incompatible subscription storage version ${version}; expected ${CURRENT_SUBSCRIPTION_STORE_VERSION}`,\n );\n yield* checkLayout(objects, version);\n if (version === CURRENT_SUBSCRIPTION_STORE_VERSION) return;\n\n yield* sql`ALTER TABLE effect_agent_subscription_deliveries ADD COLUMN observe_settlement INTEGER NOT NULL DEFAULT 0 CHECK (observe_settlement IN (0, 1))`;\n yield* backfillSubscriptionSettlementObservation();\n for (const [, name, index] of layoutObjects)\n if (addedIndexes.has(name)) yield* sql.unsafe(layoutStatements[index]).withoutTransform;\n yield* sql`UPDATE effect_agent_subscription_store_state SET storage_version=${CURRENT_SUBSCRIPTION_STORE_VERSION} WHERE singleton=1`;\n yield* checkLayout(yield* readObjects, CURRENT_SUBSCRIPTION_STORE_VERSION);\n }),\n )\n .pipe(Effect.catchTag(\"SqlError\", () => unavailable(\"initialize subscription storage\")));\n});\n\nconst makeSubscriptionStore = Effect.fnUntraced(function* (owned: SourcePartition) {\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.fnUntraced(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.fnUntraced(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 transaction: transact,\n });\n\n const prearm = Effect.fnUntraced(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 backfillSubscriptionSettlementObservation,\n makeSqlSubscriptionStore,\n} from \"@yielded/agent-storage-sql/sql-subscription-store\";\nimport { sameSqliteLayoutStatement } from \"@yielded/agent-storage-sql/sqlite-layout-inspection\";\nimport {\n SourcePartition,\n SubscriptionError,\n SubscriptionFailpoint,\n type SubscriptionFailpointError,\n SubscriptionStore,\n} from \"@yielded/agent/subscription\";\nimport { Context, Effect, Layer, Schema } from \"effect\";\nimport * as SqlClientService from \"effect/sql/SqlClient\";\nimport type { SqlError } from \"effect/sql/SqlError\";\n\nconst CURRENT_SUBSCRIPTION_STORE_VERSION = 4;\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 layoutStatements = [\n \"CREATE TABLE effect_agent_subscription_store_state ( singleton INTEGER PRIMARY KEY NOT NULL CHECK(singleton=1), storage_version INTEGER NOT NULL, alarm_generation INTEGER NOT NULL )\",\n \"CREATE TABLE effect_agent_subscription_sequences ( tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, sequence INTEGER NOT NULL, event_scan_cursor TEXT NOT NULL, delivery_scan_cursor TEXT NOT NULL, recovery_scan_cursor INTEGER NOT NULL, PRIMARY KEY (tenant_id, source_address) )\",\n \"CREATE TABLE effect_agent_subscriptions ( tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, owner_id TEXT NOT NULL, subscription_id TEXT NOT NULL, ordinal INTEGER NOT NULL, source_name TEXT NOT NULL, source_version TEXT NOT NULL, matching_key TEXT NOT NULL, state TEXT NOT NULL, expires_at_millis INTEGER, recovery_at_millis INTEGER, recovery_present INTEGER NOT NULL DEFAULT 0, record_json TEXT NOT NULL, PRIMARY KEY (tenant_id, source_address, owner_id, subscription_id), UNIQUE (tenant_id, source_address, ordinal) )\",\n \"CREATE INDEX effect_agent_subscriptions_owner ON effect_agent_subscriptions (tenant_id, source_address, owner_id, ordinal)\",\n \"CREATE INDEX effect_agent_subscriptions_capacity ON effect_agent_subscriptions (tenant_id, source_address, expires_at_millis) WHERE state IN ('active', 'paused')\",\n \"CREATE INDEX effect_agent_subscriptions_owner_capacity ON effect_agent_subscriptions (tenant_id, source_address, owner_id, expires_at_millis) WHERE state IN ('active', 'paused')\",\n \"CREATE INDEX effect_agent_subscriptions_candidates ON effect_agent_subscriptions (tenant_id, source_address, source_name, source_version, matching_key, ordinal)\",\n \"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 \"CREATE TABLE effect_agent_subscription_events ( tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, event_id TEXT NOT NULL, source_name TEXT NOT NULL, source_version TEXT NOT NULL, matching_key TEXT NOT NULL, payload_digest TEXT NOT NULL, cutoff INTEGER NOT NULL, 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, PRIMARY KEY (tenant_id, source_address, event_id) )\",\n \"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 \"CREATE TABLE effect_agent_subscription_deliveries ( tenant_id TEXT NOT NULL, source_address TEXT NOT NULL, owner_id TEXT NOT NULL, subscription_id TEXT NOT NULL, event_id TEXT NOT NULL, delivery_key TEXT NOT NULL, state TEXT NOT NULL, next_attempt_at_millis INTEGER NOT NULL, record_json TEXT NOT NULL, observe_settlement INTEGER NOT NULL DEFAULT 0 CHECK (observe_settlement IN (0, 1)), PRIMARY KEY (tenant_id, source_address, owner_id, subscription_id, event_id), UNIQUE (tenant_id, source_address, delivery_key) )\",\n \"CREATE INDEX effect_agent_subscription_deliveries_pending ON effect_agent_subscription_deliveries (tenant_id, source_address, state, next_attempt_at_millis, delivery_key)\",\n \"CREATE INDEX effect_agent_subscription_deliveries_registration ON effect_agent_subscription_deliveries (tenant_id, source_address, owner_id, subscription_id, delivery_key)\",\n \"CREATE INDEX effect_agent_subscription_deliveries_capacity ON effect_agent_subscription_deliveries (tenant_id, source_address, owner_id) WHERE state IN ('selected', 'prepared')\",\n \"CREATE INDEX effect_agent_subscription_deliveries_observing ON effect_agent_subscription_deliveries (tenant_id, source_address, owner_id) WHERE state='delivered' AND observe_settlement=1\",\n] as const;\n\nconst layoutObjects = layoutStatements.map((statement, index) => {\n const name = /^CREATE (TABLE|INDEX) ([a-z_][a-z_0-9]*)/.exec(statement);\n\n // oxlint-disable-next-line effect/no-untyped-throw, effect/no-native-error -- Module initialization validates developer-authored SQL constants before any storage workflow starts.\n if (name === null) throw new Error(\"Invalid subscription layout statement\");\n\n return [name[1].toLowerCase(), name[2], index] as const;\n});\n\nconst addedIndexes = new Set([\n \"effect_agent_subscriptions_capacity\",\n \"effect_agent_subscriptions_owner_capacity\",\n \"effect_agent_subscription_deliveries_capacity\",\n \"effect_agent_subscription_deliveries_observing\",\n]);\n\nconst LayoutObject = Schema.Struct({\n name: Schema.String,\n type: Schema.String,\n sql: Schema.NullOr(Schema.String),\n});\n\n/** Only the released v3 layout may upgrade; schema, backfill and version publish commit together. */\nconst initializeDoSubscriptionStore = Effect.fnUntraced(function* () {\n const sql = (yield* SqlClientService.SqlClient).withoutTransforms();\n const tables = layoutObjects.filter(([type]) => type === \"table\").map(([, name]) => name);\n\n const readObjects = sql`SELECT name, type, sql FROM sqlite_master\n WHERE name GLOB 'effect_agent_subscription*' OR (type='trigger' AND tbl_name IN ${sql.in(tables)})`.pipe(\n Effect.flatMap((rows) => decodeRows(LayoutObject, rows, \"subscription storage layout\")),\n );\n\n const checkLayout = Effect.fnUntraced(function* (\n objects: ReadonlyArray<typeof LayoutObject.Type>,\n version: number,\n ) {\n if (\n objects.some(\n ({ name, type }) =>\n (type === \"table\" && !tables.includes(name)) ||\n type === \"trigger\" ||\n (version === 3 && addedIndexes.has(name)),\n )\n )\n return yield* corrupt(\"ambiguous subscription storage layout\");\n for (const [type, name, index] of layoutObjects) {\n if (version === 3 && addedIndexes.has(name)) continue;\n\n const expected =\n version === 3\n ? layoutStatements[index].replace(\n \", observe_settlement INTEGER NOT NULL DEFAULT 0 CHECK (observe_settlement IN (0, 1))\",\n \"\",\n )\n : layoutStatements[index];\n\n const actual = objects.find((row) => row.name === name);\n\n if (\n actual?.type !== type ||\n actual.sql === null ||\n !sameSqliteLayoutStatement(actual.sql, expected)\n )\n return yield* corrupt(\"incompatible subscription storage layout \" + name);\n }\n });\n\n yield* sql\n .withTransaction(\n Effect.gen(function* () {\n const objects = yield* readObjects;\n\n const hasState = objects.some(\n ({ name }) => name === \"effect_agent_subscription_store_state\",\n );\n\n if (!hasState) {\n if (objects.length > 0) return yield* corrupt(\"partial subscription storage\");\n for (const statement of layoutStatements) yield* sql.unsafe(statement).withoutTransform;\n yield* sql`INSERT INTO effect_agent_subscription_store_state (singleton, storage_version, alarm_generation)\n VALUES (1, ${CURRENT_SUBSCRIPTION_STORE_VERSION}, 0)`;\n\n return;\n }\n\n const state = yield* decodeRows(\n StoreStateRow,\n yield* sql`SELECT storage_version, alarm_generation FROM effect_agent_subscription_store_state`,\n \"read subscription storage version\",\n );\n\n if (state.length !== 1) return yield* corrupt(\"invalid subscription storage version row\");\n const version = state[0].storage_version;\n\n if (version !== 3 && version !== CURRENT_SUBSCRIPTION_STORE_VERSION)\n return yield* corrupt(\n `incompatible subscription storage version ${version}; expected ${CURRENT_SUBSCRIPTION_STORE_VERSION}`,\n );\n yield* checkLayout(objects, version);\n if (version === CURRENT_SUBSCRIPTION_STORE_VERSION) return;\n\n yield* sql`ALTER TABLE effect_agent_subscription_deliveries ADD COLUMN observe_settlement INTEGER NOT NULL DEFAULT 0 CHECK (observe_settlement IN (0, 1))`;\n yield* backfillSubscriptionSettlementObservation();\n for (const [, name, index] of layoutObjects)\n if (addedIndexes.has(name)) yield* sql.unsafe(layoutStatements[index]).withoutTransform;\n yield* sql`UPDATE effect_agent_subscription_store_state SET storage_version=${CURRENT_SUBSCRIPTION_STORE_VERSION} WHERE singleton=1`;\n yield* checkLayout(yield* readObjects, CURRENT_SUBSCRIPTION_STORE_VERSION);\n }),\n )\n .pipe(Effect.catchTag(\"SqlError\", () => unavailable(\"initialize subscription storage\")));\n});\n\nconst makeSubscriptionStore = Effect.fnUntraced(function* (owned: SourcePartition) {\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.fnUntraced(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.fnUntraced(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 transaction: transact,\n });\n\n const prearm = Effect.fnUntraced(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,19 +2,19 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
|
2
2
|
import { DoStorageConfig, DoStorageConfigValue } from "./DoStorageConfig.mjs";
|
|
3
3
|
import { DoStorageFailpoint } from "./DoStorageFailpoint.mjs";
|
|
4
4
|
import { DoAppendConflict, DoCheckpointConflict, DoStorageCorruptionError, DoStorageError } from "./DoStorageError.mjs";
|
|
5
|
-
import { r as readDoStorageHeader } from "./migrations-
|
|
6
|
-
import { r as ownedState, t as invalidateOwnedState } from "./owned-state-
|
|
7
|
-
import { a as isAppendContention, i as initializeDoJournal, n as RawReadRequest, o as withStorageSpan, t as RawCheckpoint } from "./do-journal-
|
|
5
|
+
import { r as readDoStorageHeader } from "./migrations-CAO_akhD.mjs";
|
|
6
|
+
import { r as ownedState, t as invalidateOwnedState } from "./owned-state-B4QhezMp.mjs";
|
|
7
|
+
import { a as isAppendContention, i as initializeDoJournal, n as RawReadRequest, o as withStorageSpan, t as RawCheckpoint } from "./do-journal-7P3DUBz0.mjs";
|
|
8
8
|
import { BrowserCrypto } from "@effect/platform-browser";
|
|
9
9
|
import { SqlStorageOwner } from "@yielded/agent/sql-memory-store";
|
|
10
10
|
import { Clock, Context, Crypto, Effect, Layer, Option, Ref, Schema, Stream } from "effect";
|
|
11
11
|
import * as SqlClientService from "effect/sql/SqlClient";
|
|
12
12
|
import { SqlClient } from "effect/sql/SqlClient";
|
|
13
|
+
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
13
14
|
import { CanonicalRecordEnvelope, CanonicalSequence, ObservationOffset } from "@yielded/agent/records";
|
|
14
|
-
import { AppendConflict,
|
|
15
|
+
import { AppendConflict, CheckpointRejected, LoadCheckpointRequest, MAX_PROMPT_CHECKPOINT_BYTES, PreparedAppend, PromptCheckpoint, PromptCheckpointHead, PromptCheckpointRead, SaveCheckpointRequest, ThreadCheckpoint, ThreadMaterialization, ThreadNotMaterialized, ThreadObservation, ThreadReadRequest, ThreadReader, ThreadStore, ThreadStoreDiagnostic, ThreadStoreError, ThreadTail, ThreadTailRequest } from "@yielded/agent/thread-store";
|
|
15
16
|
import { isSqlError } from "effect/sql/SqlError";
|
|
16
17
|
import { SelectedReadOwner, makeSelectedReads } from "@yielded/agent-storage-sql/sql-thread-native-reads";
|
|
17
|
-
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
18
18
|
import { StorageOwner } from "@yielded/agent/run-storage";
|
|
19
19
|
import { makeSqlThreadImport } from "@yielded/agent-storage-sql/sql-thread-import";
|
|
20
20
|
import { decodeExportRecordJson } from "@yielded/agent/record-format";
|
|
@@ -55,7 +55,8 @@ const keyFor = (prefix, chunk) => prefix + String(chunk).padStart(5, "0");
|
|
|
55
55
|
/**
|
|
56
56
|
* Versioned derivative keys use the adapter's existing metadata store. Canonical layout and
|
|
57
57
|
* export are unchanged. Chunking keeps SQL values below the DO limit; loading is one bounded
|
|
58
|
-
* query followed by one parse of the native prompt.
|
|
58
|
+
* query followed by one parse of the native prompt. Retain unchanged chunks when replacing
|
|
59
|
+
* the checkpoint, so append-only growth writes at most the old tail and new chunks.
|
|
59
60
|
*/
|
|
60
61
|
const makePromptCheckpoints = (sql, journal, maxValueBytes) => ({
|
|
61
62
|
load: (input) => journal.state.read(Effect.gen(function* () {
|
|
@@ -86,7 +87,7 @@ const makePromptCheckpoints = (sql, journal, maxValueBytes) => ({
|
|
|
86
87
|
promptJson: rows.slice(1).map((row) => row.value).join("")
|
|
87
88
|
});
|
|
88
89
|
})).pipe(Effect.orElseSucceed(() => Option.none())),
|
|
89
|
-
save:
|
|
90
|
+
save: Effect.fnUntraced(function* (input) {
|
|
90
91
|
const checkpoint = yield* decodeWrite(input);
|
|
91
92
|
if (utf8ByteLength(checkpoint.promptJson) > MAX_PROMPT_CHECKPOINT_BYTES || checkpoint.historyThrough >= checkpoint.throughSequence) return;
|
|
92
93
|
const prefix = promptCheckpointPrefix(checkpoint.threadId);
|
|
@@ -108,14 +109,16 @@ const makePromptCheckpoints = (sql, journal, maxValueBytes) => ({
|
|
|
108
109
|
yield* journal.state.transaction(Effect.gen(function* () {
|
|
109
110
|
const [head] = yield* journal.getThread(checkpoint.threadId);
|
|
110
111
|
if (head === void 0 || head.tail_sequence !== checkpoint.throughSequence) return;
|
|
111
|
-
yield* sql`DELETE FROM effect_agent_meta WHERE key >= ${prefix} AND key < ${prefix + "~"}`;
|
|
112
|
-
for (const [index, value] of [header, ...chunks].entries()) yield* sql`INSERT INTO effect_agent_meta (key, value) VALUES (${keyFor(prefix, index)}, ${value})
|
|
112
|
+
yield* sql`DELETE FROM effect_agent_meta WHERE key >= ${keyFor(prefix, chunks.length + 1)} AND key < ${prefix + "~"}`;
|
|
113
|
+
for (const [index, value] of [header, ...chunks].entries()) yield* sql`INSERT INTO effect_agent_meta (key, value) VALUES (${keyFor(prefix, index)}, ${value})
|
|
114
|
+
ON CONFLICT (key) DO UPDATE SET value = excluded.value
|
|
115
|
+
WHERE effect_agent_meta.value <> excluded.value`;
|
|
113
116
|
})).pipe(Effect.provideService(SqlClient, sql));
|
|
114
|
-
}).pipe(Effect.mapError((cause) => ThreadStoreError.make({
|
|
117
|
+
}, (effect) => effect.pipe(Effect.mapError((cause) => ThreadStoreError.make({
|
|
115
118
|
operation: "save prompt checkpoint",
|
|
116
119
|
message: "Unable to retain a disposable prompt checkpoint",
|
|
117
120
|
cause
|
|
118
|
-
})))
|
|
121
|
+
}))))
|
|
119
122
|
});
|
|
120
123
|
//#endregion
|
|
121
124
|
//#region src/DoThreadStore.ts
|
|
@@ -134,6 +137,10 @@ const isDoAppendConflict = Schema.is(DoAppendConflict);
|
|
|
134
137
|
const isDoCheckpointConflict = Schema.is(DoCheckpointConflict);
|
|
135
138
|
const ThreadCheckpointJson = Schema.fromJsonString(ThreadCheckpoint);
|
|
136
139
|
const decodeCanonicalRecord = decodeExportRecordJson;
|
|
140
|
+
const decodeThreadMaterializationType = Schema.decodeEffect(Schema.toType(ThreadMaterialization));
|
|
141
|
+
const decodeThreadReadRequestType = Schema.decodeEffect(Schema.toType(ThreadReadRequest));
|
|
142
|
+
const decodeThreadTailRequestType = Schema.decodeEffect(Schema.toType(ThreadTailRequest));
|
|
143
|
+
const decodeStorageConfig = Schema.decodeEffect(DoStorageConfigValue);
|
|
137
144
|
const storeError = (operation, error) => ThreadStoreError.make({
|
|
138
145
|
cause: error,
|
|
139
146
|
operation,
|
|
@@ -149,7 +156,6 @@ const schemaStoreError = (operation, error) => ThreadStoreError.make({
|
|
|
149
156
|
issueTag: error.issue._tag
|
|
150
157
|
})
|
|
151
158
|
});
|
|
152
|
-
const makeOffset = (threadId, sequence) => Schema.decodeEffect(CanonicalSequence)(sequence).pipe(Effect.flatMap((validatedSequence) => Schema.decodeEffect(ObservationOffset)(`${DO_OFFSET_PREFIX}${encodeURIComponent(threadId)}:${validatedSequence}`)), Effect.mapError((error) => schemaStoreError("encode observation offset", error)));
|
|
153
159
|
const parseOffset = Effect.fnUntraced(function* (threadId, offset) {
|
|
154
160
|
if (offset === void 0) return ZERO_CANONICAL_SEQUENCE;
|
|
155
161
|
const text = yield* Schema.decodeEffect(OffsetText)(offset).pipe(Effect.mapError((error) => schemaStoreError("decode observation offset", error)));
|
|
@@ -187,10 +193,9 @@ const decodeEnvelope = Effect.fnUntraced(function* (row) {
|
|
|
187
193
|
"storage.failure.sequence": row.sequence,
|
|
188
194
|
"storage.failure.issue": error.diagnostic?.issueTag
|
|
189
195
|
})));
|
|
190
|
-
const
|
|
191
|
-
const offset =
|
|
192
|
-
const
|
|
193
|
-
const envelope = new CanonicalRecordEnvelope({
|
|
196
|
+
const { thread_id: threadId, batch_id: batchId } = row;
|
|
197
|
+
const offset = ObservationOffset.make(`${DO_OFFSET_PREFIX}${encodeURIComponent(threadId)}:${row.sequence}`);
|
|
198
|
+
const envelope = CanonicalRecordEnvelope.make({
|
|
194
199
|
threadId,
|
|
195
200
|
batchId,
|
|
196
201
|
sequence: row.sequence,
|
|
@@ -238,7 +243,7 @@ const makeServices = Effect.fnUntraced(function* () {
|
|
|
238
243
|
})));
|
|
239
244
|
const hitFailpoint = (location) => failpoint.hit(location).pipe(Effect.mapError((error) => storeError(`storage failpoint ${location}`, error)));
|
|
240
245
|
const materialize = Effect.fnUntraced(function* (request) {
|
|
241
|
-
const validated = yield*
|
|
246
|
+
const validated = yield* decodeThreadMaterializationType(request).pipe(Effect.mapError((error) => schemaStoreError("validate materialization", error)));
|
|
242
247
|
const now = yield* Clock.currentTimeMillis;
|
|
243
248
|
yield* hitFailpoint("materialize:before");
|
|
244
249
|
yield* journal.materialize(validated.threadId, new Date(now).toISOString()).pipe(Effect.mapError((error) => storeError("materialize thread", error)));
|
|
@@ -261,7 +266,7 @@ const makeServices = Effect.fnUntraced(function* () {
|
|
|
261
266
|
reason: error.reason
|
|
262
267
|
});
|
|
263
268
|
return storeError("append canonical batch", error);
|
|
264
|
-
})
|
|
269
|
+
}));
|
|
265
270
|
yield* hitFailpoint("append:after");
|
|
266
271
|
return result;
|
|
267
272
|
}, withStorageSpan("DoThreadStore.append", isAppendContention));
|
|
@@ -273,7 +278,7 @@ const makeServices = Effect.fnUntraced(function* () {
|
|
|
273
278
|
};
|
|
274
279
|
});
|
|
275
280
|
const readEffect = Effect.fnUntraced(function* (request) {
|
|
276
|
-
const validated = yield*
|
|
281
|
+
const validated = yield* decodeThreadReadRequestType(request).pipe(Effect.mapError((error) => schemaStoreError("validate thread read", error)));
|
|
277
282
|
if ("selection" in validated) return Stream.fromIterable(yield* selectedReads.read(validated));
|
|
278
283
|
yield* requireThread(journal, validated.threadId);
|
|
279
284
|
return (yield* loadRecords(RawReadRequest.make({
|
|
@@ -320,17 +325,17 @@ const makeServices = Effect.fnUntraced(function* () {
|
|
|
320
325
|
owner: journal.state.owner,
|
|
321
326
|
offsetPrefix: DO_OFFSET_PREFIX,
|
|
322
327
|
maxValueBytes: config.maxStoredValueBytes,
|
|
323
|
-
afterImport:
|
|
328
|
+
afterImport: Effect.fnUntraced(function* ({ result }) {
|
|
324
329
|
const prefix = promptCheckpointPrefix(result.threadId);
|
|
325
330
|
yield* sql`DELETE FROM effect_agent_meta WHERE key >= ${prefix} AND key < ${prefix + "~"}`;
|
|
326
331
|
if (journal.lifecycle !== void 0) yield* sql`INSERT INTO effect_agent_lifecycle_cursors(thread_id, through_sequence) VALUES (${result.threadId}, ${result.tailSequence})`;
|
|
327
|
-
}).pipe(Effect.catchTag("SqlError", (cause) => storeError("rebuild imported derivatives", cause))),
|
|
332
|
+
}, (effect) => effect.pipe(Effect.catchTag("SqlError", (cause) => storeError("rebuild imported derivatives", cause)))),
|
|
328
333
|
afterThreadRead: hitFailpoint("export:after-thread-read"),
|
|
329
334
|
read: (body) => journal.owner.transaction(body).pipe(Effect.provideService(SqlClientService.SqlClient, sql), Effect.catchIf(isSqlError, (cause) => storeError("export transaction", cause))),
|
|
330
335
|
write: (body) => journal.owner.transaction(body.pipe(Effect.tap(() => journal.state.invalidate))).pipe(Effect.provideService(SqlClientService.SqlClient, sql), Effect.catchIf(isSqlError, (cause) => storeError("import transaction", cause)))
|
|
331
336
|
});
|
|
332
337
|
const inspectTail = Effect.fnUntraced(function* (request) {
|
|
333
|
-
const validated = yield*
|
|
338
|
+
const validated = yield* decodeThreadTailRequestType(request).pipe(Effect.mapError((error) => schemaStoreError("validate tail inspection", error)));
|
|
334
339
|
const thread = yield* requireThread(journal, validated.threadId);
|
|
335
340
|
return ThreadTail.make({
|
|
336
341
|
threadId: validated.threadId,
|
|
@@ -378,7 +383,7 @@ const makeServices = Effect.fnUntraced(function* () {
|
|
|
378
383
|
});
|
|
379
384
|
const selectedReads = yield* makeSelectedReads(decodeEnvelope).pipe(Effect.provideService(SelectedReadOwner, {
|
|
380
385
|
snapshot: journal.state.read,
|
|
381
|
-
tail: (threadId) => journal.getThread(threadId).pipe(Effect.
|
|
386
|
+
tail: (threadId) => journal.getThread(threadId).pipe(Effect.map((rows) => rows[0]), Effect.mapError((error) => storeError("native thread tail", error)))
|
|
382
387
|
}));
|
|
383
388
|
const threadStore = ThreadStore.of({
|
|
384
389
|
archives: journal.archives,
|
|
@@ -414,7 +419,7 @@ const threadStoreLayer = ThreadReader.layer().pipe(Layer.provideMerge(Layer.effe
|
|
|
414
419
|
* Shared by the ThreadStore and SubmissionLedger convenience layers so their defaults
|
|
415
420
|
* cannot drift.
|
|
416
421
|
*/
|
|
417
|
-
const storageConfigLayer = (options) => Layer.effect(DoStorageConfig)(
|
|
422
|
+
const storageConfigLayer = (options) => Layer.effect(DoStorageConfig)(decodeStorageConfig({
|
|
418
423
|
observationPollInterval: options.observationPollInterval ?? 25,
|
|
419
424
|
maxStoredValueBytes: options.maxStoredValueBytes ?? 19e5,
|
|
420
425
|
verifyOnOpen: options.verifyOnOpen ?? false
|
|
@@ -464,4 +469,4 @@ const sqlOwnerLayer = Layer.effectContext(Effect.flatMap(SqlClientService.SqlCli
|
|
|
464
469
|
//#endregion
|
|
465
470
|
export { sqlOwnerLayer as a, threadStoreLayer as c, layer as i, prepareCanonicalAppend as l, exportThread as n, storageConfigLayer as o, invalidate as r, storageFailpointLayer as s, DoThreadStore_exports as t };
|
|
466
471
|
|
|
467
|
-
//# sourceMappingURL=DoThreadStore-
|
|
472
|
+
//# sourceMappingURL=DoThreadStore-CgIZQUNR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DoThreadStore-CgIZQUNR.mjs","names":[],"sources":["../src/internal/canonical-append.ts","../src/internal/prompt-checkpoint.ts","../src/DoThreadStore.ts"],"sourcesContent":["import { prepareSqlAppend } from \"@yielded/agent-storage-sql/sql-thread-store\";\nimport type { AppendRequest } from \"@yielded/agent/thread-store\";\nimport { PreparedAppend } from \"@yielded/agent/thread-store\";\nimport { Effect } from \"effect\";\n\nexport const DO_OFFSET_PREFIX = \"effect-agent-do@1:\";\n\n/** Prepare the publisher's privately captured canonical request before the writer. */\nexport const prepareCanonicalAppend = Effect.fnUntraced(function* (input: AppendRequest) {\n const request: PreparedAppend = yield* PreparedAppend.capture(input);\n\n const raw = yield* prepareSqlAppend(request, DO_OFFSET_PREFIX);\n\n return { request, raw };\n});\n","import { utf8ByteLength } from \"@yielded/agent/digest\";\nimport {\n MAX_PROMPT_CHECKPOINT_BYTES,\n PromptCheckpoint,\n PromptCheckpointHead,\n PromptCheckpointRead,\n ThreadStoreError,\n type PromptCheckpoints,\n} from \"@yielded/agent/thread-store\";\nimport { Effect, Option, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\n\nimport type { DoJournal } from \"./do-journal.ts\";\n\nconst Header = Schema.Struct({\n ...PromptCheckpointHead.fields,\n chunks: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 64 })),\n});\n\nconst decodeHeader = Schema.decodeEffect(Schema.fromJsonString(Header));\nconst encodeHeader = Schema.encodeEffect(Schema.fromJsonString(Header));\n\nconst decodeRows = Schema.decodeUnknownEffect(\n Schema.Array(\n Schema.Struct({\n key: Schema.String,\n value: Schema.String.check(Schema.isMaxLength(2_000_000)),\n }),\n ).check(Schema.isMaxLength(65)),\n);\n\nconst decodeWrite = Schema.decodeEffect(PromptCheckpoint);\nconst decodeRead = Schema.decodeEffect(PromptCheckpointRead);\n\nexport const promptCheckpointPrefix = (threadId: string) =>\n `prompt-checkpoint/${JSON.stringify(threadId)}/`;\n\nconst keyFor = (prefix: string, chunk: number) => prefix + String(chunk).padStart(5, \"0\");\n\n/**\n * Versioned derivative keys use the adapter's existing metadata store. Canonical layout and\n * export are unchanged. Chunking keeps SQL values below the DO limit; loading is one bounded\n * query followed by one parse of the native prompt. Retain unchanged chunks when replacing\n * the checkpoint, so append-only growth writes at most the old tail and new chunks.\n */\nexport const makePromptCheckpoints = (\n sql: SqlClient,\n journal: DoJournal,\n maxValueBytes: number,\n): PromptCheckpoints => ({\n load: (input) =>\n journal.state\n .read(\n Effect.gen(function* () {\n const request = yield* decodeRead(input);\n const prefix = promptCheckpointPrefix(request.threadId);\n\n // Every row repeats the Thread ID. Bound those known key bytes separately from\n // the prompt and header so supported long IDs do not consume the prompt allowance.\n const maxHydratedBytes =\n MAX_PROMPT_CHECKPOINT_BYTES + 16_384 + 65 * utf8ByteLength(keyFor(prefix, 0));\n\n const rows = yield* decodeRows(\n yield* sql`\n SELECT key, value FROM effect_agent_meta\n WHERE key >= ${prefix} AND key < ${prefix + \"~\"}\n AND (SELECT sum(length(CAST(key AS BLOB)) + length(CAST(value AS BLOB)))\n FROM effect_agent_meta\n WHERE key >= ${prefix} AND key < ${prefix + \"~\"})\n <= ${maxHydratedBytes}\n ORDER BY key LIMIT 66`,\n );\n\n const first = rows[0];\n\n if (first === undefined || first.key !== keyFor(prefix, 0)) return Option.none();\n const header = yield* decodeHeader(first.value);\n\n if (\n header.threadId !== request.threadId ||\n header.historyThrough >= header.throughSequence ||\n header.chunks !== rows.length - 1 ||\n rows.some((row, index) => row.key !== keyFor(prefix, index))\n )\n return Option.none();\n const [head] = yield* journal.getThread(request.threadId);\n\n if (\n head === undefined ||\n head.tail_sequence !== request.throughSequence ||\n head.tail_sequence < header.throughSequence\n )\n return Option.none();\n let bytes = 0;\n\n for (const row of rows) {\n bytes += utf8ByteLength(row.value);\n if (bytes > MAX_PROMPT_CHECKPOINT_BYTES + 16_384) return Option.none();\n }\n\n return Option.some({\n ...header,\n promptJson: rows\n .slice(1)\n .map((row) => row.value)\n .join(\"\"),\n });\n }),\n )\n .pipe(Effect.orElseSucceed(() => Option.none())),\n save: Effect.fnUntraced(\n function* (input) {\n const checkpoint = yield* decodeWrite(input);\n\n if (\n utf8ByteLength(checkpoint.promptJson) > MAX_PROMPT_CHECKPOINT_BYTES ||\n checkpoint.historyThrough >= checkpoint.throughSequence\n )\n return;\n const prefix = promptCheckpointPrefix(checkpoint.threadId);\n const chunks: Array<string> = [];\n // Three UTF-8 bytes per UTF-16 code unit is a conservative bound. Keep surrogate pairs\n // together so SQLite never normalizes an isolated half while persisting a chunk.\n const chars = Math.floor(Math.min(maxValueBytes - 4_096, 1_000_000) / 3);\n\n if (chars < 1) return;\n for (let offset = 0; offset < checkpoint.promptJson.length;) {\n let end = Math.min(offset + chars, checkpoint.promptJson.length);\n const last = checkpoint.promptJson.charCodeAt(end - 1);\n\n if (last >= 0xd800 && last <= 0xdbff) end--;\n if (end <= offset || chunks.length >= 64) return;\n chunks.push(checkpoint.promptJson.slice(offset, end));\n offset = end;\n }\n const header = yield* encodeHeader({ ...checkpoint, chunks: chunks.length });\n\n yield* journal.state\n .transaction(\n Effect.gen(function* () {\n const [head] = yield* journal.getThread(checkpoint.threadId);\n\n if (head === undefined || head.tail_sequence !== checkpoint.throughSequence) return;\n yield* sql`DELETE FROM effect_agent_meta WHERE key >= ${keyFor(prefix, chunks.length + 1)} AND key < ${prefix + \"~\"}`;\n for (const [index, value] of [header, ...chunks].entries())\n yield* sql`INSERT INTO effect_agent_meta (key, value) VALUES (${keyFor(prefix, index)}, ${value})\n ON CONFLICT (key) DO UPDATE SET value = excluded.value\n WHERE effect_agent_meta.value <> excluded.value`;\n }),\n )\n .pipe(Effect.provideService(SqlClient, sql));\n },\n (effect) =>\n effect.pipe(\n Effect.mapError((cause) =>\n ThreadStoreError.make({\n operation: \"save prompt checkpoint\",\n message: \"Unable to retain a disposable prompt checkpoint\",\n cause,\n }),\n ),\n ),\n ),\n});\n","import { BrowserCrypto } from \"@effect/platform-browser\";\nimport { SqliteClient } from \"@effect/sql-sqlite-do\";\nimport { makeSqlThreadImport } from \"@yielded/agent-storage-sql/sql-thread-import\";\nimport {\n makeSelectedReads,\n SelectedReadOwner,\n} from \"@yielded/agent-storage-sql/sql-thread-native-reads\";\nimport { decodeExportRecordJson } from \"@yielded/agent/record-format\";\nimport {\n CanonicalRecordEnvelope,\n CanonicalSequence,\n ObservationOffset,\n} from \"@yielded/agent/records\";\nimport { StorageOwner } from \"@yielded/agent/run-storage\";\nimport { SqlStorageOwner } from \"@yielded/agent/sql-memory-store\";\nimport { MAX_ARCHIVE_RANGE_PAGE } from \"@yielded/agent/thread-archive-range\";\nimport { ThreadImport } from \"@yielded/agent/thread-import\";\nimport {\n type ThreadExportRequest,\n AppendConflict,\n CheckpointRejected,\n ThreadCheckpoint,\n ThreadMaterialization,\n ThreadNotMaterialized,\n ThreadObservation,\n ThreadReadRequest,\n ThreadStore,\n ThreadReader,\n type ThreadCheckpoints,\n ThreadStoreError,\n ThreadStoreDiagnostic,\n ThreadTail,\n ThreadTailRequest,\n type AppendRequest,\n PreparedAppend,\n LoadCheckpointRequest,\n SaveCheckpointRequest,\n} from \"@yielded/agent/thread-store\";\nimport { checkExportSource } from \"@yielded/agent/thread-transfer\";\nimport { Clock, Context, Crypto, Effect, Layer, Option, Ref, Schema, Stream } from \"effect\";\nimport * as SqlClientService from \"effect/sql/SqlClient\";\nimport { isSqlError } from \"effect/sql/SqlError\";\n\nimport {\n DEFAULT_MAX_STORED_VALUE_BYTES,\n DoStorageConfig,\n DoStorageConfigValue,\n} from \"./DoStorageConfig.ts\";\nimport {\n type DoStorageCompatibilityError,\n DoAppendConflict,\n DoCheckpointConflict,\n type DoStorageFailpointLocation,\n DoStorageCorruptionError,\n DoStorageError,\n} from \"./DoStorageError.ts\";\nimport { DoStorageFailpoint, type DoStorageFailpointHandler } from \"./DoStorageFailpoint.ts\";\nimport { DO_OFFSET_PREFIX, prepareCanonicalAppend } from \"./internal/canonical-append.ts\";\nimport {\n initializeDoJournal,\n RawCheckpoint,\n RawReadRequest,\n type DoJournal,\n} from \"./internal/do-journal.ts\";\nimport { readDoStorageHeader } from \"./internal/migrations.ts\";\nimport { invalidateOwnedState, ownedState } from \"./internal/owned-state.ts\";\nimport { makePromptCheckpoints, promptCheckpointPrefix } from \"./internal/prompt-checkpoint.ts\";\nimport { isAppendContention, withStorageSpan } from \"./internal/storage-span.ts\";\n\n/**\n * Convenience-layer construction options. `storage` is the Durable Object's own\n * `ctx.storage` handle, injected as a value (DEPLOY-010: platform bindings enter only\n * through Layers; this package never imports `cloudflare:workers`).\n */\nexport interface DoStorageOptions {\n readonly storage: DurableObjectStorage;\n readonly observationPollInterval?: number | undefined;\n /**\n * Maximum bytes for any single stored value; must stay under the platform's 2 MB\n * per-value limit. Defaults to `DEFAULT_MAX_STORED_VALUE_BYTES`.\n */\n readonly maxStoredValueBytes?: number | undefined;\n /**\n * Audit journal payloads, ownership, and batch coverage in bounded pages on open, including\n * orphan rows and rows outside declared ranges. Defaults to false. Full reads validate\n * canonical records; readPrompt trusts write-time validation of the omitted fields.\n */\n readonly verifyOnOpen?: boolean | undefined;\n readonly failpoint?: DoStorageFailpointHandler | undefined;\n}\n\nexport type DoStorageInitializationError =\n | DoStorageCompatibilityError\n | DoStorageCorruptionError\n | DoStorageError;\n\nconst OffsetText = Schema.String.check(Schema.isMaxLength(4 * 1024));\nconst ZERO_CANONICAL_SEQUENCE = Schema.decodeSync(CanonicalSequence)(0);\nconst isDoAppendConflict = Schema.is(DoAppendConflict);\nconst isDoCheckpointConflict = Schema.is(DoCheckpointConflict);\n// Reuse the same AST/parser across reads. Reconstructing a JSON codec per row\n// defeats Schema's parser cache and repeatedly walks the canonical union.\nconst ThreadCheckpointJson = Schema.fromJsonString(ThreadCheckpoint);\nconst decodeCanonicalRecord = decodeExportRecordJson;\n\nconst decodeThreadMaterializationType = Schema.decodeEffect(Schema.toType(ThreadMaterialization));\nconst decodeThreadReadRequestType = Schema.decodeEffect(Schema.toType(ThreadReadRequest));\nconst decodeThreadTailRequestType = Schema.decodeEffect(Schema.toType(ThreadTailRequest));\nconst decodeStorageConfig = Schema.decodeEffect(DoStorageConfigValue);\n\nconst storeError = (\n operation: string,\n error: { readonly message: string; readonly diagnostic?: ThreadStoreDiagnostic },\n) =>\n ThreadStoreError.make({\n cause: error,\n operation,\n message: error.message,\n ...(error.diagnostic === undefined ? {} : { diagnostic: error.diagnostic }),\n });\n\nconst schemaStoreError = (operation: string, error: Schema.SchemaError) =>\n ThreadStoreError.make({\n operation,\n message: \"A Thread storage value does not satisfy its schema\",\n diagnostic: ThreadStoreDiagnostic.make({\n causeTag: error._tag,\n operation,\n issueTag: error.issue._tag,\n }),\n });\n\nconst parseOffset = Effect.fnUntraced(function* (\n threadId: ThreadMaterialization[\"threadId\"],\n offset: ObservationOffset | undefined,\n): Effect.fn.Return<CanonicalSequence, ThreadStoreError> {\n if (offset === undefined) return ZERO_CANONICAL_SEQUENCE;\n\n const text = yield* Schema.decodeEffect(OffsetText)(offset).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode observation offset\", error)),\n );\n\n const threadPrefix = `${DO_OFFSET_PREFIX}${encodeURIComponent(threadId)}:`;\n\n if (!text.startsWith(threadPrefix)) {\n return yield* ThreadStoreError.make({\n operation: \"decode observation offset\",\n message: \"The observation offset belongs to a different adapter, storage version, or Thread.\",\n });\n }\n const sequenceText = text.slice(threadPrefix.length);\n\n if (!/^(0|[1-9][0-9]*)$/.test(sequenceText)) {\n return yield* ThreadStoreError.make({\n operation: \"decode observation offset\",\n message: \"The observation offset is malformed.\",\n });\n }\n\n return yield* Schema.decodeEffect(CanonicalSequence)(Number(sequenceText)).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode observation offset\", error)),\n );\n});\n\nconst encodeCheckpoint = (checkpoint: ThreadCheckpoint): Effect.Effect<string, ThreadStoreError> =>\n Schema.encodeEffect(ThreadCheckpointJson)(checkpoint).pipe(\n Effect.mapError((error) => schemaStoreError(\"encode checkpoint\", error)),\n );\n\nconst envelopes = new WeakMap<object, CanonicalRecordEnvelope>();\n\nconst decodeEnvelope = Effect.fnUntraced(function* (row: {\n readonly batch_id: CanonicalRecordEnvelope[\"batchId\"];\n readonly thread_id: CanonicalRecordEnvelope[\"threadId\"];\n readonly record_json: string;\n readonly sequence: CanonicalSequence;\n}) {\n const cached = envelopes.get(row);\n\n if (cached !== undefined) return cached;\n\n const record = yield* decodeCanonicalRecord(row.record_json).pipe(\n Effect.mapError((error) =>\n ThreadStoreError.make({\n operation: \"decode canonical record\",\n message: \"The canonical record does not satisfy its schema\",\n diagnostic: ThreadStoreDiagnostic.make({\n causeTag: error._tag,\n operation: \"decode canonical record\",\n decoder: \"CanonicalRecord\",\n sequence: row.sequence,\n issueTag: error.issue._tag,\n }),\n }),\n ),\n Effect.tapError((error) =>\n Effect.annotateCurrentSpan({\n \"storage.failure.operation\": error.diagnostic?.operation,\n \"storage.failure.cause\": error.diagnostic?.causeTag,\n \"storage.failure.decoder\": error.diagnostic?.decoder,\n \"storage.failure.sequence\": row.sequence,\n \"storage.failure.issue\": error.diagnostic?.issueTag,\n }),\n ),\n );\n\n const { thread_id: threadId, batch_id: batchId } = row;\n\n const offset = ObservationOffset.make(\n `${DO_OFFSET_PREFIX}${encodeURIComponent(threadId)}:${row.sequence}`,\n );\n\n const envelope = CanonicalRecordEnvelope.make(\n { threadId, batchId, sequence: row.sequence, offset, record },\n { disableChecks: true },\n );\n\n envelopes.set(row, envelope);\n\n return envelope;\n});\n\nconst decodeCheckpoint = (\n checkpointJson: string,\n): Effect.Effect<ThreadCheckpoint, ThreadStoreError> =>\n Schema.decodeEffect(Schema.fromJsonString(ThreadCheckpoint))(checkpointJson).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode checkpoint\", error)),\n );\n\nconst requireThread = Effect.fnUntraced(function* (\n journal: DoJournal,\n threadId: ThreadMaterialization[\"threadId\"],\n) {\n const rows = yield* journal\n .getThread(threadId)\n .pipe(Effect.mapError((error) => storeError(\"read thread\", error)));\n\n if (rows.length === 0) {\n return yield* ThreadNotMaterialized.make({ threadId });\n }\n\n return rows[0];\n});\n\nconst requireBatchBoundary = Effect.fnUntraced(function* (\n journal: DoJournal,\n threadId: ThreadMaterialization[\"threadId\"],\n sequence: CanonicalSequence,\n) {\n const valid = yield* journal\n .isBatchBoundary(threadId, sequence)\n .pipe(Effect.mapError((error) => storeError(\"read checkpoint boundary\", error)));\n\n if (!valid) {\n return yield* CheckpointRejected.make({\n threadId,\n reason: \"not-batch-boundary\",\n });\n }\n});\n\n/** Audit excluded rows before paging owners and bounded ranges; never collect Thread payloads. */\nconst decodeStartupPayloads = Effect.fnUntraced(function* (journal: DoJournal) {\n yield* journal.archiveRanges.verifyCoverage;\n let afterThreadId: string | undefined;\n\n while (true) {\n const owners = yield* journal.archiveRanges.threadPage(afterThreadId);\n\n for (const owner of owners) {\n yield* journal.archiveRanges.verifyThread(owner.thread_id);\n afterThreadId = owner.thread_id;\n }\n if (owners.length < MAX_ARCHIVE_RANGE_PAGE) break;\n }\n});\n\nconst makeServices = Effect.fnUntraced(function* () {\n const config = yield* DoStorageConfig;\n const failpoint = yield* DoStorageFailpoint;\n const sql = yield* SqlClientService.SqlClient;\n const crypto = yield* Crypto.Crypto;\n const journal = yield* initializeDoJournal(sql, failpoint.hit, config.maxStoredValueBytes);\n\n if (config.verifyOnOpen) {\n yield* journal.state.read(decodeStartupPayloads(journal)).pipe(\n Effect.mapError((cause) =>\n DoStorageCorruptionError.make({\n table: \"effect_agent_journal_ranges\",\n rowKey: \"verification\",\n message: cause.message,\n }),\n ),\n );\n }\n\n const hitFailpoint = (\n location: DoStorageFailpointLocation,\n ): Effect.Effect<void, ThreadStoreError> =>\n failpoint\n .hit(location)\n .pipe(Effect.mapError((error) => storeError(`storage failpoint ${location}`, error)));\n\n const materialize: ThreadStore[\"Service\"][\"materialize\"] = Effect.fnUntraced(function* (\n request: ThreadMaterialization,\n ) {\n const validated = yield* decodeThreadMaterializationType(request).pipe(\n Effect.mapError((error) => schemaStoreError(\"validate materialization\", error)),\n );\n\n const now = yield* Clock.currentTimeMillis;\n\n yield* hitFailpoint(\"materialize:before\");\n yield* journal\n .materialize(validated.threadId, new Date(now).toISOString())\n .pipe(Effect.mapError((error) => storeError(\"materialize thread\", error)));\n yield* hitFailpoint(\"materialize:after\");\n }, withStorageSpan(\"DoThreadStore.materialize\"));\n\n const append: ThreadStore[\"Service\"][\"append\"] = Effect.fnUntraced(\n function* (request: AppendRequest) {\n const validated = yield* PreparedAppend.capture(request);\n const observed = yield* requireThread(journal, validated.threadId);\n\n const { raw: rawRequest } = yield* prepareCanonicalAppend(validated).pipe(\n Effect.provideService(Crypto.Crypto, crypto),\n );\n\n yield* hitFailpoint(\"append:before\");\n\n const result = yield* journal.state.owner\n .withProgress(rawRequest.threadId, journal.append(rawRequest, observed))\n .pipe(\n Effect.mapError((error) => {\n if (isDoAppendConflict(error)) {\n return error.actualTailSequence !== undefined\n ? AppendConflict.make({\n threadId: validated.threadId,\n batchId: validated.batch.batchId,\n reason: error.reason,\n actualTailSequence: error.actualTailSequence,\n })\n : AppendConflict.make({\n threadId: validated.threadId,\n batchId: validated.batch.batchId,\n reason: error.reason,\n });\n }\n\n return storeError(\"append canonical batch\", error);\n }),\n );\n\n yield* hitFailpoint(\"append:after\");\n\n return result;\n },\n withStorageSpan(\"DoThreadStore.append\", isAppendContention),\n );\n\n const loadRecords = Effect.fnUntraced(function* (request: RawReadRequest) {\n const result = yield* journal\n .read(request)\n .pipe(Effect.mapError((error) => storeError(\"read canonical records\", error)));\n\n return {\n count: result.count,\n records: result.records.pipe(\n Stream.mapError((error) => storeError(\"read canonical records\", error)),\n Stream.mapEffect(decodeEnvelope),\n ),\n };\n });\n\n const readEffect = Effect.fnUntraced(function* (request: ThreadReadRequest) {\n const validated = yield* decodeThreadReadRequestType(request).pipe(\n Effect.mapError((error) => schemaStoreError(\"validate thread read\", error)),\n );\n\n if (\"selection\" in validated) return Stream.fromIterable(yield* selectedReads.read(validated));\n yield* requireThread(journal, validated.threadId);\n\n const result = yield* loadRecords(\n RawReadRequest.make({\n threadId: validated.threadId,\n fromSequenceExclusive: validated.afterSequence ?? ZERO_CANONICAL_SEQUENCE,\n limit: validated.limit,\n }),\n );\n\n return result.records;\n });\n\n const read: ThreadStore[\"Service\"][\"read\"] = (request) => Stream.unwrap(readEffect(request));\n\n const observeEffect = Effect.fnUntraced(function* (request: ThreadObservation) {\n const validated = yield* Schema.decodeEffect(Schema.toType(ThreadObservation))(request).pipe(\n Effect.mapError((error) => schemaStoreError(\"validate thread observation\", error)),\n );\n\n yield* requireThread(journal, validated.threadId);\n const initialSequence = yield* parseOffset(validated.threadId, validated.afterOffset);\n const cursor = yield* Ref.make(initialSequence);\n let polls = 0;\n let emptyPolls = 0;\n let deliveredRecords = 0;\n\n const poll = Effect.fnUntraced(function* () {\n polls++;\n const fromSequenceExclusive = yield* Ref.get(cursor);\n\n const result = yield* loadRecords(\n RawReadRequest.make({\n threadId: validated.threadId,\n fromSequenceExclusive,\n limit: 1_024,\n }),\n );\n\n if (result.count === 0) {\n emptyPolls++;\n yield* Effect.sleep(config.observationPollInterval);\n\n return Stream.empty;\n }\n\n return result.records.pipe(\n Stream.tap((record) => {\n deliveredRecords++;\n\n return Ref.set(cursor, record.sequence);\n }),\n );\n });\n\n return Stream.fromEffectRepeat(poll()).pipe(\n Stream.flatten,\n Stream.ensuring(\n Effect.suspend(() =>\n Effect.annotateCurrentSpan({\n \"effect_agent.observation.polls\": polls,\n \"effect_agent.observation.empty_polls\": emptyPolls,\n \"effect_agent.observation.records\": deliveredRecords,\n }),\n ),\n ),\n );\n });\n\n const observe: ThreadStore[\"Service\"][\"observe\"] = (request) =>\n Stream.unwrap(observeEffect(request)).pipe(Stream.withSpan(\"DoThreadStore.observe\"));\n\n const transfer = yield* makeSqlThreadImport({\n owner: journal.state.owner,\n offsetPrefix: DO_OFFSET_PREFIX,\n maxValueBytes: config.maxStoredValueBytes,\n // Import establishes a new sequence space; discard derivatives in this same transaction.\n afterImport: Effect.fnUntraced(\n function* ({ result }) {\n const prefix = promptCheckpointPrefix(result.threadId);\n\n yield* sql`DELETE FROM effect_agent_meta WHERE key >= ${prefix} AND key < ${prefix + \"~\"}`;\n // Closed imported history must not emit historical lifecycle notifications again.\n if (journal.lifecycle !== undefined)\n yield* sql`INSERT INTO effect_agent_lifecycle_cursors(thread_id, through_sequence) VALUES (${result.threadId}, ${result.tailSequence})`;\n },\n (effect) =>\n effect.pipe(\n Effect.catchTag(\"SqlError\", (cause) => storeError(\"rebuild imported derivatives\", cause)),\n ),\n ),\n afterThreadRead: hitFailpoint(\"export:after-thread-read\"),\n read: (body) =>\n journal.owner.transaction(body).pipe(\n Effect.provideService(SqlClientService.SqlClient, sql),\n Effect.catchIf(isSqlError, (cause) => storeError(\"export transaction\", cause)),\n ),\n write: (body) =>\n journal.owner.transaction(body.pipe(Effect.tap(() => journal.state.invalidate))).pipe(\n Effect.provideService(SqlClientService.SqlClient, sql),\n Effect.catchIf(isSqlError, (cause) => storeError(\"import transaction\", cause)),\n ),\n });\n\n const inspectTail: ThreadStore[\"Service\"][\"inspectTail\"] = Effect.fnUntraced(function* (\n request: ThreadTailRequest,\n ) {\n const validated = yield* decodeThreadTailRequestType(request).pipe(\n Effect.mapError((error) => schemaStoreError(\"validate tail inspection\", error)),\n );\n\n const thread = yield* requireThread(journal, validated.threadId);\n\n return ThreadTail.make({\n threadId: validated.threadId,\n tailSequence: thread.tail_sequence,\n });\n });\n\n const saveCheckpoint: ThreadCheckpoints[\"save\"] = Effect.fnUntraced(function* (\n request: SaveCheckpointRequest,\n ) {\n const validated = yield* Schema.decodeEffect(Schema.toType(SaveCheckpointRequest))(\n request,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"validate checkpoint\", error)));\n\n const thread = yield* requireThread(journal, validated.checkpoint.threadId);\n\n if (validated.checkpoint.throughSequence > thread.tail_sequence) {\n return yield* CheckpointRejected.make({\n threadId: validated.checkpoint.threadId,\n reason: \"ahead-of-tail\",\n });\n }\n\n yield* requireBatchBoundary(\n journal,\n validated.checkpoint.threadId,\n validated.checkpoint.throughSequence,\n );\n const checkpointJson = yield* encodeCheckpoint(validated.checkpoint);\n\n const raw = RawCheckpoint.make({\n threadId: validated.checkpoint.threadId,\n throughSequence: validated.checkpoint.throughSequence,\n checkpointJson,\n });\n\n yield* hitFailpoint(\"save-checkpoint:before\");\n yield* journal.saveCheckpoint(raw).pipe(\n Effect.mapError((error) =>\n isDoCheckpointConflict(error)\n ? CheckpointRejected.make({\n threadId: validated.checkpoint.threadId,\n reason: error.reason,\n })\n : storeError(\"save checkpoint\", error),\n ),\n );\n yield* hitFailpoint(\"save-checkpoint:after\");\n });\n\n const loadCheckpoint: ThreadCheckpoints[\"load\"] = Effect.fnUntraced(function* (\n request: LoadCheckpointRequest,\n ) {\n const validated = yield* Schema.decodeEffect(Schema.toType(LoadCheckpointRequest))(\n request,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"validate checkpoint lookup\", error)));\n\n const thread = yield* requireThread(journal, validated.threadId);\n\n const rows = yield* journal\n .loadCheckpoint(validated.threadId, validated.atOrBeforeSequence ?? thread.tail_sequence)\n .pipe(Effect.mapError((error) => storeError(\"load checkpoint\", error)));\n\n if (rows.length === 0) return Option.none();\n if (rows.length !== 1) {\n return yield* ThreadStoreError.make({\n operation: \"load checkpoint\",\n message: `Expected at most one checkpoint row but found ${rows.length}.`,\n });\n }\n const row = rows[0];\n const checkpoint = yield* decodeCheckpoint(row.checkpoint_json);\n\n if (\n row.thread_id !== validated.threadId ||\n checkpoint.threadId !== row.thread_id ||\n checkpoint.throughSequence !== row.through_sequence\n ) {\n return yield* ThreadStoreError.make({\n operation: \"load checkpoint\",\n message: \"Stored checkpoint metadata does not match its canonical row.\",\n });\n }\n\n yield* requireBatchBoundary(journal, checkpoint.threadId, checkpoint.throughSequence);\n\n return Option.some(checkpoint);\n });\n\n const selectedReads = yield* makeSelectedReads(decodeEnvelope).pipe(\n Effect.provideService(SelectedReadOwner, {\n snapshot: journal.state.read,\n tail: (threadId) =>\n journal.getThread(threadId).pipe(\n Effect.map((rows) => rows[0]),\n Effect.mapError((error) => storeError(\"native thread tail\", error)),\n ),\n }),\n );\n\n const threadStore = ThreadStore.of({\n archives: journal.archives,\n work: journal.work.storage,\n ...(journal.lifecycle === undefined\n ? {}\n : { lifecyclePublications: journal.lifecycle.storage }),\n readIdentity: selectedReads.readIdentity,\n readExecution: (request) =>\n journal.state.read(\n requireThread(journal, request.threadId).pipe(\n Effect.andThen(journal.readExecution(request)),\n ),\n ),\n readWorkerCapacity: selectedReads.readWorkerCapacity,\n verification: transfer.verification,\n countPeerMessages: selectedReads.countPeerMessages,\n append,\n export: transfer.export,\n inspectTail,\n materialize,\n observe,\n read,\n readPrompt: (request) => Stream.fromIterableEffect(selectedReads.readPrompt(request)),\n checkpoints: { save: saveCheckpoint, load: loadCheckpoint },\n promptCheckpoints: makePromptCheckpoints(sql, journal, config.maxStoredValueBytes),\n });\n\n return Context.make(ThreadStore, threadStore).pipe(\n Context.add(ThreadImport, transfer.importer),\n Context.add(StorageOwner, journal.state.owner),\n );\n});\n\n/**\n * Durable Object Thread Store implementation with configuration, failpoint, SQL, and\n * Crypto authority kept visible in its input channel.\n */\nexport const threadStoreLayer: Layer.Layer<\n ThreadStore | ThreadReader | ThreadImport | StorageOwner,\n DoStorageInitializationError,\n DoStorageConfig | DoStorageFailpoint | SqlClientService.SqlClient | Crypto.Crypto\n> = ThreadReader.layer().pipe(Layer.provideMerge(Layer.effectContext(makeServices())));\n\n/**\n * Validated Durable Object storage configuration Layer with the documented defaults applied.\n * Shared by the ThreadStore and SubmissionLedger convenience layers so their defaults\n * cannot drift.\n */\nexport const storageConfigLayer = (\n options: DoStorageOptions,\n): Layer.Layer<DoStorageConfig, DoStorageError> =>\n Layer.effect(DoStorageConfig)(\n decodeStorageConfig({\n observationPollInterval: options.observationPollInterval ?? 25,\n maxStoredValueBytes: options.maxStoredValueBytes ?? DEFAULT_MAX_STORED_VALUE_BYTES,\n verifyOnOpen: options.verifyOnOpen ?? false,\n }).pipe(\n Effect.mapError((error) =>\n DoStorageError.make({\n cause: error,\n operation: \"configure Durable Object storage\",\n message: error.message,\n }),\n ),\n ),\n );\n\n/** The failpoint Layer selected by convenience options: explicit handler or the no-op default. */\nexport const storageFailpointLayer = (\n options: DoStorageOptions,\n): Layer.Layer<DoStorageFailpoint> =>\n options.failpoint === undefined\n ? DoStorageFailpoint.layer\n : Layer.succeed(DoStorageFailpoint)({ hit: options.failpoint });\n\n/**\n * A composition-root convenience Layer for canonical Threads inside one Durable Object,\n * built over `ctx.storage`. Durable accepted work is served by the separate SubmissionLedger\n * port; point both at the SAME `ctx.storage` so both share the same scoped storage owner\n * (ADR-0011 D7's \"same file\" rule, transposed to one object's private database).\n */\nexport const layer = (\n options: DoStorageOptions,\n): Layer.Layer<\n ThreadStore | ThreadReader | ThreadImport | StorageOwner,\n DoStorageInitializationError\n> =>\n Layer.unwrap(\n Effect.map(DoStorageConfig, (config) =>\n threadStoreLayer.pipe(\n Layer.provide(\n Layer.mergeAll(\n Layer.succeed(DoStorageConfig)(config),\n storageFailpointLayer(options),\n SqliteClient.layer({ storage: options.storage }),\n BrowserCrypto.layer,\n ),\n ),\n ),\n ),\n ).pipe(Layer.provide(storageConfigLayer(options)));\n\n/** Read a quiesced current-layout Object without initializing its layout or ownership. */\nexport const exportThread = Effect.fn(\"DoThreadStore.exportThread\")(function* (\n options: Pick<DoStorageOptions, \"storage\">,\n request: ThreadExportRequest,\n) {\n yield* checkExportSource(request.threadId);\n\n return yield* Effect.gen(function* () {\n const sql = yield* SqlClientService.SqlClient;\n const state = yield* ownedState(sql);\n\n return yield* state\n .transaction(\n Effect.gen(function* () {\n yield* readDoStorageHeader();\n\n const transfer = yield* makeSqlThreadImport({\n owner: state.owner,\n offsetPrefix: DO_OFFSET_PREFIX,\n read: (body) => body,\n write: () => Effect.die(\"A read-only exporter cannot import\"),\n });\n\n return yield* transfer.export(request);\n }),\n )\n .pipe(\n Effect.catchTag(\"SqlError\", (cause) =>\n DoStorageError.make({\n operation: \"export Thread snapshot\",\n message: cause.message,\n cause,\n }),\n ),\n );\n }).pipe(\n Effect.provide(\n Layer.merge(SqliteClient.layer({ storage: options.storage }), BrowserCrypto.layer),\n ),\n );\n});\n\n/**\n * Discard the Object's derived thread and ledger state after direct SQL maintenance.\n * Quiesce port operations during the raw write and invalidation, and enroll the write with\n * the host mutation gate. Ordinary ThreadStore/SubmissionLedger writes maintain this view.\n */\nexport const invalidate = invalidateOwnedState;\n\n/** Share the Object's transaction gate with owner-local SQL Memory compositions. */\nexport const sqlOwnerLayer = Layer.effectContext(\n Effect.flatMap(SqlClientService.SqlClient, ownedState).pipe(\n Effect.map((state) =>\n Context.make(SqlStorageOwner, state).pipe(Context.add(StorageOwner, state.owner)),\n ),\n ),\n);\n"],"mappings":"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"}
|
package/dist/DoThreadStore.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import "./DoStorageConfig.mjs";
|
|
2
2
|
import "./DoStorageFailpoint.mjs";
|
|
3
|
-
import { a as sqlOwnerLayer, c as threadStoreLayer, i as layer, n as exportThread, o as storageConfigLayer, r as invalidate, s as storageFailpointLayer } from "./DoThreadStore-
|
|
3
|
+
import { a as sqlOwnerLayer, c as threadStoreLayer, i as layer, n as exportThread, o as storageConfigLayer, r as invalidate, s as storageFailpointLayer } from "./DoThreadStore-CgIZQUNR.mjs";
|
|
4
4
|
export { exportThread, invalidate, layer, sqlOwnerLayer, storageConfigLayer, storageFailpointLayer, threadStoreLayer };
|
package/dist/PortProtocol.d.mts
CHANGED
|
@@ -9756,6 +9756,8 @@ export declare const encodePortResponse: (input: PortFailed | PortSucceeded, opt
|
|
|
9756
9756
|
readonly inputPayload: Schema.Json;
|
|
9757
9757
|
readonly inputDigest: string;
|
|
9758
9758
|
readonly settledOutcome?: "aborted" | "completed" | "failed" | undefined;
|
|
9759
|
+
readonly settledAt?: string | undefined;
|
|
9760
|
+
readonly settledRecordId?: string | undefined;
|
|
9759
9761
|
readonly createdAt: string;
|
|
9760
9762
|
readonly readyAt?: string | undefined;
|
|
9761
9763
|
readonly admissionGroup?: string | undefined;
|
|
@@ -10002,6 +10004,8 @@ export declare const encodePortResponse: (input: PortFailed | PortSucceeded, opt
|
|
|
10002
10004
|
readonly inputPayload: Schema.Json;
|
|
10003
10005
|
readonly inputDigest: string;
|
|
10004
10006
|
readonly settledOutcome?: "aborted" | "completed" | "failed" | undefined;
|
|
10007
|
+
readonly settledAt?: string | undefined;
|
|
10008
|
+
readonly settledRecordId?: string | undefined;
|
|
10005
10009
|
readonly createdAt: string;
|
|
10006
10010
|
readonly readyAt?: string | undefined;
|
|
10007
10011
|
readonly admissionGroup?: string | undefined;
|
|
@@ -11267,6 +11271,8 @@ export declare const encodePortResponse: (input: PortFailed | PortSucceeded, opt
|
|
|
11267
11271
|
readonly inputPayload: Schema.Json;
|
|
11268
11272
|
readonly inputDigest: string;
|
|
11269
11273
|
readonly settledOutcome?: "aborted" | "completed" | "failed" | undefined;
|
|
11274
|
+
readonly settledAt?: string | undefined;
|
|
11275
|
+
readonly settledRecordId?: string | undefined;
|
|
11270
11276
|
readonly createdAt: string;
|
|
11271
11277
|
readonly readyAt?: string | undefined;
|
|
11272
11278
|
readonly admissionGroup?: string | undefined;
|
|
@@ -11519,6 +11525,8 @@ export declare const encodePortResponse: (input: PortFailed | PortSucceeded, opt
|
|
|
11519
11525
|
readonly inputPayload: Schema.Json;
|
|
11520
11526
|
readonly inputDigest: string;
|
|
11521
11527
|
readonly settledOutcome?: "aborted" | "completed" | "failed" | undefined;
|
|
11528
|
+
readonly settledAt?: string | undefined;
|
|
11529
|
+
readonly settledRecordId?: string | undefined;
|
|
11522
11530
|
readonly createdAt: string;
|
|
11523
11531
|
readonly readyAt?: string | undefined;
|
|
11524
11532
|
readonly admissionGroup?: string | undefined;
|
|
@@ -13852,6 +13860,8 @@ export declare const encodePortResponse: (input: PortFailed | PortSucceeded, opt
|
|
|
13852
13860
|
readonly inputPayload: Schema.Json;
|
|
13853
13861
|
readonly inputDigest: string;
|
|
13854
13862
|
readonly settledOutcome?: "aborted" | "completed" | "failed" | undefined;
|
|
13863
|
+
readonly settledAt?: string | undefined;
|
|
13864
|
+
readonly settledRecordId?: string | undefined;
|
|
13855
13865
|
readonly createdAt: string;
|
|
13856
13866
|
readonly readyAt?: string | undefined;
|
|
13857
13867
|
readonly admissionGroup?: string | undefined;
|
|
@@ -14098,6 +14108,8 @@ export declare const encodePortResponse: (input: PortFailed | PortSucceeded, opt
|
|
|
14098
14108
|
readonly inputPayload: Schema.Json;
|
|
14099
14109
|
readonly inputDigest: string;
|
|
14100
14110
|
readonly settledOutcome?: "aborted" | "completed" | "failed" | undefined;
|
|
14111
|
+
readonly settledAt?: string | undefined;
|
|
14112
|
+
readonly settledRecordId?: string | undefined;
|
|
14101
14113
|
readonly createdAt: string;
|
|
14102
14114
|
readonly readyAt?: string | undefined;
|
|
14103
14115
|
readonly admissionGroup?: string | undefined;
|
package/dist/PortRouting.mjs
CHANGED
|
@@ -258,7 +258,7 @@ const makeRoutedLedgerServices = Effect.fnUntraced(function* (options) {
|
|
|
258
258
|
});
|
|
259
259
|
const routed = SubmissionLedger.of({
|
|
260
260
|
capabilities: local.capabilities,
|
|
261
|
-
admit: (request) => options.ownsThread(request.threadId) ? local.admit(request) : foreignLedgerCall("ledger admit", request.threadId, LedgerAdmitCall.make({ request }), LedgerAdmitResult, Schema.Union([AdmissionConflict, AdmissionPolicyError])).pipe(Effect.map((reply) => reply.result)),
|
|
261
|
+
admit: (request, admissionOptions) => options.ownsThread(request.threadId) ? local.admit(request, admissionOptions) : foreignLedgerCall("ledger admit", request.threadId, LedgerAdmitCall.make({ request }), LedgerAdmitResult, Schema.Union([AdmissionConflict, AdmissionPolicyError])).pipe(Effect.map((reply) => reply.result)),
|
|
262
262
|
markReady: (request) => submissionTarget("ledger mark ready", request.submissionId).pipe(Effect.flatMap((target) => target._tag === "local" ? local.markReady(request) : foreignLedgerCall("ledger mark ready", target.threadId, LedgerMarkReadyCall.make({ request }), LedgerMarkReadyResult, NoAdditionalPortFailure).pipe(Effect.asVoid))),
|
|
263
263
|
lookup: (request) => request._tag === "SubmissionLookupById" ? submissionTarget("ledger lookup", request.submissionId).pipe(Effect.flatMap((target) => target._tag === "local" ? local.lookup(request) : foreignLookupById("ledger lookup", target.threadId, request.submissionId))) : options.ownsThread(request.threadId) ? local.lookup(request) : foreignLedgerCall("ledger lookup", request.threadId, LedgerLookupCall.make({ request }), LedgerLookupResult, NoAdditionalPortFailure).pipe(Effect.map((result) => result.submission === void 0 ? Option.none() : Option.some(result.submission))),
|
|
264
264
|
resolveFundingOwner: (request) => (options.ownsThread(request.threadId) ? local.resolveFundingOwner === void 0 ? Effect.fail(LedgerError.make({
|
|
@@ -294,6 +294,7 @@ const makeRoutedLedgerServices = Effect.fnUntraced(function* (options) {
|
|
|
294
294
|
beginChildBudgetRelease: local.beginChildBudgetRelease,
|
|
295
295
|
releaseChildBudget: local.releaseChildBudget,
|
|
296
296
|
scanNonterminal: local.scanNonterminal,
|
|
297
|
+
...local.listNonterminal === void 0 ? {} : { listNonterminal: local.listNonterminal },
|
|
297
298
|
readAbortIntent: (request) => submissionTarget("ledger read abort intent", request.submissionId).pipe(Effect.flatMap((target) => target._tag === "local" ? local.readAbortIntent(request) : Effect.fail(crossThreadLedgerError("ledger read abort intent", target.threadId)))),
|
|
298
299
|
loadRecoverySnapshot: (request) => submissionTarget("ledger load recovery snapshot", request.submissionId).pipe(Effect.flatMap((target) => target._tag === "local" ? local.loadRecoverySnapshot(request).pipe(Effect.flatMap(enrichChildAttachments)) : Effect.fail(crossThreadLedgerError("ledger load recovery snapshot", target.threadId))))
|
|
299
300
|
});
|
|
@@ -378,6 +379,10 @@ const makeRoutedStoreServices = Effect.fnUntraced(function* (options) {
|
|
|
378
379
|
verify: (request) => options.ownsThread(request.threadId) ? local.archives === void 0 ? Effect.fail(crossThreadStoreError("archive unavailable", request.threadId)) : local.archives.verify(request) : foreignStoreCall("archive verify", request.threadId, StoreRangeVerifyCall.make({ request }), StoreRangeVerifyResult, ThreadNotMaterialized).pipe(Effect.map((reply) => reply.range))
|
|
379
380
|
},
|
|
380
381
|
work: {
|
|
382
|
+
isOnlyFreshAdmission: (request) => {
|
|
383
|
+
const prove = local.work?.isOnlyFreshAdmission;
|
|
384
|
+
return prove !== void 0 && options.ownsThread(request.threadId) ? prove(request) : Effect.succeed(false);
|
|
385
|
+
},
|
|
381
386
|
threads: (request) => Effect.flatMap(CurrentNativeSource, (nativeSource) => nativeSource && local.work !== void 0 ? local.work.threads(request) : Effect.fail(ThreadStoreError.make({
|
|
382
387
|
operation: "work threads",
|
|
383
388
|
message: nativeSource ? "The local Thread owner does not provide work inventory." : "Global Thread enumeration is unsupported by the owner-local Durable Object namespace. Use the local owner's work storage."
|