@yielded/agent-storage-cloudflare 0.1.0-beta.167 → 0.1.0-beta.169
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.d.mts +1 -1
- package/dist/DoMessageDeliveryStore.mjs +3 -2
- package/dist/DoMessageDeliveryStore.mjs.map +1 -1
- package/dist/DoScheduleStore.mjs +16 -37
- package/dist/DoScheduleStore.mjs.map +1 -1
- package/dist/DoStorageConfig.d.mts +2 -10
- package/dist/DoStorageConfig.mjs +2 -11
- package/dist/DoStorageConfig.mjs.map +1 -1
- package/dist/{DoStorageError-CGuAfSwF.d.mts → DoStorageError-CxjMnzUA.d.mts} +7 -18
- package/dist/DoStorageError.d.mts +2 -2
- package/dist/DoStorageError.mjs +14 -30
- package/dist/DoStorageError.mjs.map +1 -1
- package/dist/DoStorageFailpoint.d.mts +1 -1
- package/dist/DoStorageFailpointTesting.d.mts +1 -1
- package/dist/{DoStorageVersion-iNSyi3cJ.d.mts → DoStorageVersion-DTFoLglB.d.mts} +3 -4
- package/dist/DoStorageVersion.d.mts +1 -1
- package/dist/DoStorageVersion.mjs +2 -2
- package/dist/DoStorageVersion.mjs.map +1 -1
- package/dist/DoSubmissionLedger.d.mts +7 -5
- package/dist/DoSubmissionLedger.mjs +378 -528
- package/dist/DoSubmissionLedger.mjs.map +1 -1
- package/dist/DoSubscriptionStore.mjs +5 -24
- package/dist/DoSubscriptionStore.mjs.map +1 -1
- package/dist/{DoThreadStore-D_83OjCH.d.mts → DoThreadStore-Bd4fTns3.d.mts} +17 -18
- package/dist/DoThreadStore-CwBvTLoq.mjs +468 -0
- package/dist/DoThreadStore-CwBvTLoq.mjs.map +1 -0
- package/dist/DoThreadStore.d.mts +2 -2
- package/dist/DoThreadStore.mjs +4 -529
- package/dist/MemoryProtocol.mjs +3 -3
- package/dist/MemoryProtocol.mjs.map +1 -1
- package/dist/PortProtocol.d.mts +11727 -3410
- package/dist/PortProtocol.mjs +103 -15
- package/dist/PortProtocol.mjs.map +1 -1
- package/dist/PortRouting.d.mts +14 -9
- package/dist/PortRouting.mjs +155 -29
- package/dist/PortRouting.mjs.map +1 -1
- package/dist/do-journal-Cawnsetj.mjs +761 -0
- package/dist/do-journal-Cawnsetj.mjs.map +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +1 -1
- package/dist/migrations-D_EP3KYf.mjs +148 -0
- package/dist/migrations-D_EP3KYf.mjs.map +1 -0
- package/dist/{owned-state-DHm2aRXx.mjs → owned-state-BHzUi0eb.mjs} +50 -19
- package/dist/owned-state-BHzUi0eb.mjs.map +1 -0
- package/package.json +1 -1
- package/src/DoMessageDeliveryStore.ts +2 -1
- package/src/DoScheduleStore.ts +19 -59
- package/src/DoStorageConfig.ts +2 -11
- package/src/DoStorageError.ts +3 -26
- package/src/DoStorageVersion.ts +1 -1
- package/src/DoSubmissionLedger.ts +1806 -2030
- package/src/DoSubscriptionStore.ts +5 -47
- package/src/DoThreadStore.ts +276 -622
- package/src/MemoryProtocol.ts +3 -3
- package/src/PortProtocol.ts +198 -12
- package/src/PortRouting.ts +527 -108
- package/src/internal/canonical-append.ts +15 -0
- package/src/internal/do-journal.ts +548 -1440
- package/src/internal/migrations.ts +184 -287
- package/src/internal/owned-state.ts +81 -30
- package/src/internal/prompt-checkpoint.ts +158 -0
- package/src/internal/storage-span.ts +2 -5
- package/dist/DoThreadStore.mjs.map +0 -1
- package/dist/do-journal-DUhjZkOf.mjs +0 -1352
- package/dist/do-journal-DUhjZkOf.mjs.map +0 -1
- package/dist/migrations-DtKz_Gxr.mjs +0 -306
- package/dist/migrations-DtKz_Gxr.mjs.map +0 -1
- package/dist/owned-state-DHm2aRXx.mjs.map +0 -1
- package/src/internal/message-delivery-schema.ts +0 -24
- package/src/internal/recovery-checkpoint-schema.ts +0 -17
package/dist/DoMemoryStore.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { r as ownedState } from "./owned-state-
|
|
2
|
+
import { r as ownedState } from "./owned-state-BHzUi0eb.mjs";
|
|
3
3
|
import { SqlMemoryLimits, SqlStorageOwner, memoryStoreLayerWithFailpoints } from "@yielded/agent/sql-memory-store";
|
|
4
4
|
import { Effect, Layer, Schema } from "effect";
|
|
5
5
|
import * as SqlClientService from "effect/sql/SqlClient";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as DoStorageCorruptionError, i as DoStorageCompatibilityError, o as DoStorageError } from "./DoStorageError-CxjMnzUA.mjs";
|
|
2
2
|
import { DoStorageConfig } from "./DoStorageConfig.mjs";
|
|
3
3
|
import { DoStorageFailpoint } from "./DoStorageFailpoint.mjs";
|
|
4
4
|
import { MessageDeliveryStore, MessageDeliveryStoreLimits } from "@yielded/agent/message-delivery";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { DoStorageConfig } from "./DoStorageConfig.mjs";
|
|
3
3
|
import { DoStorageFailpoint } from "./DoStorageFailpoint.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { i as initializeDoJournal } from "./do-journal-Cawnsetj.mjs";
|
|
5
|
+
import { BrowserCrypto } from "@effect/platform-browser";
|
|
5
6
|
import { SqlLifecycleSource } from "@yielded/agent-storage-sql/sql-lifecycle-publication";
|
|
6
7
|
import { makeSqlMessageDeliveryStore } from "@yielded/agent-storage-sql/sql-message-delivery-store";
|
|
7
8
|
import { MessageDeliveryStore } from "@yielded/agent/message-delivery";
|
|
@@ -23,7 +24,7 @@ const doMessageDeliveryStoreLayer = (limits) => Layer.effect(MessageDeliveryStor
|
|
|
23
24
|
beforeRetain: (threadId) => journal.flushCanonical(threadId),
|
|
24
25
|
beforePending: journal.flushPublications()
|
|
25
26
|
}));
|
|
26
|
-
}));
|
|
27
|
+
})).pipe(Layer.provide(BrowserCrypto.layer));
|
|
27
28
|
//#endregion
|
|
28
29
|
export { doMessageDeliveryStoreLayer, DoMessageDeliveryStore_exports as t };
|
|
29
30
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DoMessageDeliveryStore.mjs","names":["SqlClient"],"sources":["../src/DoMessageDeliveryStore.ts"],"sourcesContent":["import { SqlLifecycleSource } from \"@yielded/agent-storage-sql/sql-lifecycle-publication\";\nimport { makeSqlMessageDeliveryStore } from \"@yielded/agent-storage-sql/sql-message-delivery-store\";\nimport {\n MessageDeliveryStore,\n type MessageDeliveryStoreLimits,\n} from \"@yielded/agent/message-delivery\";\nimport { SqlStorageOwner } from \"@yielded/agent/sql-memory-store\";\nimport { Effect, Layer } from \"effect\";\nimport * as SqlClient from \"effect/sql/SqlClient\";\n\nimport { DoStorageConfig } from \"./DoStorageConfig.ts\";\nimport { DoStorageFailpoint } from \"./DoStorageFailpoint.ts\";\nimport { initializeDoJournal } from \"./internal/do-journal.ts\";\n\n/**\n * Message obligations in a Thread Object's own SQL storage. The platform must prearm\n * maintenance before insertion and retain its alarm while nextDeadline is present.\n */\nexport const doMessageDeliveryStoreLayer = (limits?: MessageDeliveryStoreLimits) =>\n Layer.effect(\n MessageDeliveryStore,\n Effect.gen(function* () {\n const sql = yield* SqlClient.SqlClient;\n const config = yield* DoStorageConfig;\n const failpoint = yield* DoStorageFailpoint;\n\n const journal = yield* initializeDoJournal(sql, failpoint.hit, config.maxStoredValueBytes);\n\n return yield* makeSqlMessageDeliveryStore(limits, {\n maxStoredValueBytes: config.maxStoredValueBytes,\n }).pipe(\n Effect.provideService(SqlStorageOwner, journal.owner),\n Effect.provideService(SqlLifecycleSource, {\n beforeRetain: (threadId) => journal.flushCanonical(threadId),\n beforePending: journal.flushPublications(),\n }),\n );\n }),\n );\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"DoMessageDeliveryStore.mjs","names":["SqlClient"],"sources":["../src/DoMessageDeliveryStore.ts"],"sourcesContent":["import { BrowserCrypto } from \"@effect/platform-browser\";\nimport { SqlLifecycleSource } from \"@yielded/agent-storage-sql/sql-lifecycle-publication\";\nimport { makeSqlMessageDeliveryStore } from \"@yielded/agent-storage-sql/sql-message-delivery-store\";\nimport {\n MessageDeliveryStore,\n type MessageDeliveryStoreLimits,\n} from \"@yielded/agent/message-delivery\";\nimport { SqlStorageOwner } from \"@yielded/agent/sql-memory-store\";\nimport { Effect, Layer } from \"effect\";\nimport * as SqlClient from \"effect/sql/SqlClient\";\n\nimport { DoStorageConfig } from \"./DoStorageConfig.ts\";\nimport { DoStorageFailpoint } from \"./DoStorageFailpoint.ts\";\nimport { initializeDoJournal } from \"./internal/do-journal.ts\";\n\n/**\n * Message obligations in a Thread Object's own SQL storage. The platform must prearm\n * maintenance before insertion and retain its alarm while nextDeadline is present.\n */\nexport const doMessageDeliveryStoreLayer = (limits?: MessageDeliveryStoreLimits) =>\n Layer.effect(\n MessageDeliveryStore,\n Effect.gen(function* () {\n const sql = yield* SqlClient.SqlClient;\n const config = yield* DoStorageConfig;\n const failpoint = yield* DoStorageFailpoint;\n\n const journal = yield* initializeDoJournal(sql, failpoint.hit, config.maxStoredValueBytes);\n\n return yield* makeSqlMessageDeliveryStore(limits, {\n maxStoredValueBytes: config.maxStoredValueBytes,\n }).pipe(\n Effect.provideService(SqlStorageOwner, journal.owner),\n Effect.provideService(SqlLifecycleSource, {\n beforeRetain: (threadId) => journal.flushCanonical(threadId),\n beforePending: journal.flushPublications(),\n }),\n );\n }),\n ).pipe(Layer.provide(BrowserCrypto.layer));\n"],"mappings":";;;;;;;;;;;;;;;;;AAmBA,MAAa,+BAA+B,WAC1C,MAAM,OACJ,sBACA,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,OAAOA,YAAU;CAC7B,MAAM,SAAS,OAAO;CACtB,MAAM,YAAY,OAAO;CAEzB,MAAM,UAAU,OAAO,oBAAoB,KAAK,UAAU,KAAK,OAAO,mBAAmB;CAEzF,OAAO,OAAO,4BAA4B,QAAQ,EAChD,qBAAqB,OAAO,oBAC9B,CAAC,CAAC,CAAC,KACD,OAAO,eAAe,iBAAiB,QAAQ,KAAK,GACpD,OAAO,eAAe,oBAAoB;EACxC,eAAe,aAAa,QAAQ,eAAe,QAAQ;EAC3D,eAAe,QAAQ,kBAAkB;CAC3C,CAAC,CACH;AACF,CAAC,CACH,CAAC,CAAC,KAAK,MAAM,QAAQ,cAAc,KAAK,CAAC"}
|
package/dist/DoScheduleStore.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { Context, Effect, Layer, Result, Schema } from "effect";
|
|
3
3
|
import * as SqlClientService from "effect/sql/SqlClient";
|
|
4
|
-
import { upgradeV2Schedules } from "@yielded/agent-storage-sql/sql-storage-v2-upgrade";
|
|
5
4
|
import { ScheduleCapacityError, ScheduleChange, ScheduleConflict, ScheduleDueCursor, ScheduleFailpoint, ScheduleId, ScheduleInstant, ScheduleKey, ScheduleNotFound, ScheduleOwner, SchedulePageRequest, ScheduleRecord, ScheduleStorageError, ScheduleStore, defaultSchedulingLimits } from "@yielded/agent/schedule";
|
|
6
5
|
import { applyScheduleChange, scheduleDeadline, scheduleUsesCapacity } from "@yielded/agent/schedule-transition";
|
|
7
6
|
//#region src/DoScheduleStore.ts
|
|
@@ -11,8 +10,7 @@ var DoScheduleStore_exports = /* @__PURE__ */ __exportAll({
|
|
|
11
10
|
scheduleStoreLayer: () => scheduleStoreLayer
|
|
12
11
|
});
|
|
13
12
|
const CURRENT_SCHEDULE_STORE_VERSION = 3;
|
|
14
|
-
const
|
|
15
|
-
const StoredScheduleJson = Schema.String.check(Schema.isMaxLength(MAX_STORED_SCHEDULE_BYTES));
|
|
13
|
+
const StoredScheduleJson = Schema.String.check(Schema.isMaxLength(19e5));
|
|
16
14
|
const StoredDeadline = Schema.NullOr(ScheduleInstant);
|
|
17
15
|
var ScheduleRow = class extends Schema.Class("@effect-agent/storage-cloudflare/ScheduleRow")({
|
|
18
16
|
tenant_id: ScheduleOwner.fields.tenantId,
|
|
@@ -49,20 +47,18 @@ const corrupt = (operation) => ScheduleStorageError.make({
|
|
|
49
47
|
operation,
|
|
50
48
|
reason: "corrupt"
|
|
51
49
|
});
|
|
52
|
-
const decodeRows =
|
|
53
|
-
return yield* Schema.decodeUnknownEffect(schema)(rows).pipe(Effect.mapError(() => corrupt(operation)));
|
|
54
|
-
});
|
|
50
|
+
const decodeRows = (schema, rows, operation) => Schema.decodeUnknownEffect(schema)(rows).pipe(Effect.mapError(() => corrupt(operation)));
|
|
55
51
|
const decodeBoundary = (schema, value, operation) => Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(() => corrupt(operation)));
|
|
56
|
-
const decodeRecord = Effect.
|
|
52
|
+
const decodeRecord = Effect.fnUntraced(function* (row) {
|
|
57
53
|
const record = yield* Schema.decodeEffect(Schema.fromJsonString(ScheduleRecord))(row.record_json).pipe(Effect.mapError(() => corrupt("decode schedule")));
|
|
58
54
|
if (record.owner.tenantId !== row.tenant_id || record.owner.ownerId !== row.owner_id || record.scheduleId !== row.schedule_id || scheduleDeadline(record) !== row.deadline_at_millis) return yield* corrupt("decode schedule index");
|
|
59
55
|
return record;
|
|
60
56
|
});
|
|
61
|
-
const encodeRecord = Effect.
|
|
57
|
+
const encodeRecord = Effect.fnUntraced(function* (record) {
|
|
62
58
|
const encoded = yield* Schema.encodeEffect(Schema.fromJsonString(ScheduleRecord))(record).pipe(Effect.mapError(() => corrupt("encode schedule")));
|
|
63
59
|
return yield* Schema.decodeEffect(StoredScheduleJson)(encoded).pipe(Effect.mapError(() => corrupt("encode schedule bounds")));
|
|
64
60
|
});
|
|
65
|
-
const initializeScheduleStore = Effect.
|
|
61
|
+
const initializeScheduleStore = Effect.fnUntraced(function* () {
|
|
66
62
|
const sql = yield* SqlClientService.SqlClient;
|
|
67
63
|
const operation = "initialize schedule store";
|
|
68
64
|
const rawTables = yield* sql`
|
|
@@ -123,23 +119,6 @@ const initializeScheduleStore = Effect.fn("DoScheduleStore.initialize")(function
|
|
|
123
119
|
WHERE singleton = 1
|
|
124
120
|
`.pipe(Effect.mapError(() => unavailable(operation)));
|
|
125
121
|
const state = yield* decodeRows(Schema.Array(ScheduleStoreStateRow), rawState, operation);
|
|
126
|
-
if (state.length === 1 && state[0].storage_version === 2) {
|
|
127
|
-
const failpoint = yield* ScheduleFailpoint;
|
|
128
|
-
yield* sql.withTransaction(Effect.gen(function* () {
|
|
129
|
-
const current = yield* sql`SELECT storage_version FROM effect_agent_schedule_store_state WHERE singleton=1`;
|
|
130
|
-
if (current.length === 1 && current[0].storage_version === 3) return;
|
|
131
|
-
if (current.length !== 1 || current[0].storage_version !== 2) return yield* corrupt("schedule version changed during upgrade");
|
|
132
|
-
yield* upgradeV2Schedules(MAX_STORED_SCHEDULE_BYTES);
|
|
133
|
-
yield* failpoint.hit("upgrade:before-version");
|
|
134
|
-
yield* sql`UPDATE effect_agent_schedule_store_state SET storage_version=3 WHERE singleton=1`;
|
|
135
|
-
yield* failpoint.hit("upgrade:after-version");
|
|
136
|
-
})).pipe(Effect.catchTag("StorageUpgradeError", (error) => ScheduleStorageError.make({
|
|
137
|
-
reason: "corrupt",
|
|
138
|
-
operation: "upgrade v2 schedules",
|
|
139
|
-
cause: error
|
|
140
|
-
})), Effect.catchTag("SqlError", () => unavailable("upgrade v2 schedules")), Effect.catchTag("ScheduleFailpointError", () => unavailable("upgrade v2 schedules failpoint")));
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
122
|
if (state.length !== 1 || state[0].storage_version !== CURRENT_SCHEDULE_STORE_VERSION) return yield* corrupt(state.length === 1 ? `${operation}: incompatible storage version ${state[0].storage_version}; expected ${CURRENT_SCHEDULE_STORE_VERSION}` : `${operation}: invalid storage version row`);
|
|
144
123
|
});
|
|
145
124
|
const makeServices = Effect.gen(function* () {
|
|
@@ -147,7 +126,7 @@ const makeServices = Effect.gen(function* () {
|
|
|
147
126
|
const transactions = yield* DoScheduleTransaction;
|
|
148
127
|
const scheduleFailpoint = yield* ScheduleFailpoint;
|
|
149
128
|
yield* initializeScheduleStore();
|
|
150
|
-
const readRows = Effect.
|
|
129
|
+
const readRows = Effect.fnUntraced(function* (key, operation) {
|
|
151
130
|
const rows = yield* sql`
|
|
152
131
|
SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json
|
|
153
132
|
FROM effect_agent_schedules
|
|
@@ -157,13 +136,13 @@ const makeServices = Effect.gen(function* () {
|
|
|
157
136
|
`.pipe(Effect.mapError(() => unavailable(operation)));
|
|
158
137
|
return yield* decodeRows(Schema.Array(ScheduleRow), rows, operation);
|
|
159
138
|
});
|
|
160
|
-
const readOne = Effect.
|
|
139
|
+
const readOne = Effect.fnUntraced(function* (key, operation) {
|
|
161
140
|
const rows = yield* readRows(key, operation);
|
|
162
141
|
if (rows.length === 0) return null;
|
|
163
142
|
if (rows.length !== 1) return yield* corrupt(operation);
|
|
164
143
|
return yield* decodeRecord(rows[0]);
|
|
165
144
|
});
|
|
166
|
-
const readNextDeadline = Effect.
|
|
145
|
+
const readNextDeadline = Effect.fnUntraced(function* (owner, operation) {
|
|
167
146
|
const rows = owner === void 0 ? yield* sql`
|
|
168
147
|
SELECT MIN(deadline_at_millis) AS deadline_at_millis
|
|
169
148
|
FROM effect_agent_schedules
|
|
@@ -179,7 +158,7 @@ const makeServices = Effect.gen(function* () {
|
|
|
179
158
|
if (decoded.length !== 1) return yield* corrupt(operation);
|
|
180
159
|
return decoded[0].deadline_at_millis;
|
|
181
160
|
});
|
|
182
|
-
const replaceAlarm = Effect.
|
|
161
|
+
const replaceAlarm = Effect.fnUntraced(function* (replace, deadlineAtMillis, operation) {
|
|
183
162
|
const rawState = yield* sql`
|
|
184
163
|
UPDATE effect_agent_schedule_store_state
|
|
185
164
|
SET alarm_generation = alarm_generation + 1
|
|
@@ -195,7 +174,7 @@ const makeServices = Effect.gen(function* () {
|
|
|
195
174
|
});
|
|
196
175
|
yield* scheduleFailpoint.hit("schedule:alarm:after");
|
|
197
176
|
});
|
|
198
|
-
const insert = Effect.
|
|
177
|
+
const insert = Effect.fnUntraced(function* (record, ownerLimit) {
|
|
199
178
|
const operation = "insert schedule";
|
|
200
179
|
const canonical = yield* decodeBoundary(ScheduleRecord, record, operation);
|
|
201
180
|
const recordJson = yield* encodeRecord(canonical);
|
|
@@ -244,11 +223,11 @@ const makeServices = Effect.gen(function* () {
|
|
|
244
223
|
if (result.inserted) yield* scheduleFailpoint.hit("schedule:insert:after");
|
|
245
224
|
return result.record;
|
|
246
225
|
});
|
|
247
|
-
const get = Effect.
|
|
226
|
+
const get = Effect.fnUntraced(function* (key) {
|
|
248
227
|
const canonical = yield* decodeBoundary(ScheduleKey, key, "get schedule");
|
|
249
228
|
return yield* readOne(canonical, "get schedule");
|
|
250
229
|
});
|
|
251
|
-
const list = Effect.
|
|
230
|
+
const list = Effect.fnUntraced(function* (requestValue) {
|
|
252
231
|
const operation = "list schedules";
|
|
253
232
|
const request = yield* decodeBoundary(SchedulePageRequest, requestValue, operation);
|
|
254
233
|
const rows = request.after === void 0 ? yield* sql`
|
|
@@ -276,7 +255,7 @@ const makeServices = Effect.gen(function* () {
|
|
|
276
255
|
next: hasNext ? items.at(-1)?.scheduleId ?? null : null
|
|
277
256
|
};
|
|
278
257
|
});
|
|
279
|
-
const change = Effect.
|
|
258
|
+
const change = Effect.fnUntraced(function* (key, change, ownerLimit = defaultSchedulingLimits.maxSchedulesPerOwner) {
|
|
280
259
|
const operation = "change schedule";
|
|
281
260
|
const canonicalKey = yield* decodeBoundary(ScheduleKey, key, operation);
|
|
282
261
|
const canonicalChange = yield* decodeBoundary(ScheduleChange, change, operation);
|
|
@@ -320,7 +299,7 @@ const makeServices = Effect.gen(function* () {
|
|
|
320
299
|
if (result.changed) yield* scheduleFailpoint.hit(`schedule:${canonicalChange._tag.toLowerCase()}:after`);
|
|
321
300
|
return result.record;
|
|
322
301
|
});
|
|
323
|
-
const due = Effect.
|
|
302
|
+
const due = Effect.fnUntraced(function* (nowMillis, limit, owner, after) {
|
|
324
303
|
const operation = "query due schedules";
|
|
325
304
|
const cursor = after === void 0 ? void 0 : yield* Schema.decodeEffect(ScheduleDueCursor)(after).pipe(Effect.mapError(() => corrupt(operation)));
|
|
326
305
|
const continuation = cursor === void 0 ? sql`1 = 1` : sql`
|
|
@@ -350,10 +329,10 @@ const makeServices = Effect.gen(function* () {
|
|
|
350
329
|
deadlineAtMillis: row.deadline_at_millis
|
|
351
330
|
}));
|
|
352
331
|
});
|
|
353
|
-
const nextDeadline = Effect.
|
|
332
|
+
const nextDeadline = Effect.fnUntraced(function* (owner) {
|
|
354
333
|
return yield* readNextDeadline(owner, "query next schedule deadline");
|
|
355
334
|
});
|
|
356
|
-
const prearm = Effect.
|
|
335
|
+
const prearm = Effect.fnUntraced(function* (deadlineAtMillis) {
|
|
357
336
|
yield* decodeBoundary(ScheduleInstant, deadlineAtMillis, "pre-arm schedule recovery");
|
|
358
337
|
yield* transactions.run((replace) => replaceAlarm(replace, deadlineAtMillis, "pre-arm schedule recovery"));
|
|
359
338
|
yield* scheduleFailpoint.hit("schedule:prearm:after");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DoScheduleStore.mjs","names":[],"sources":["../src/DoScheduleStore.ts"],"sourcesContent":["import { upgradeV2Schedules } from \"@yielded/agent-storage-sql/sql-storage-v2-upgrade\";\nimport {\n ScheduleCapacityError,\n ScheduleDueCursor,\n defaultSchedulingLimits,\n ScheduleChange,\n ScheduleConflict,\n ScheduleFailpoint,\n type ScheduleFailpointError,\n ScheduleKey,\n ScheduleId,\n ScheduleInstant,\n ScheduleNotFound,\n ScheduleOwner,\n type SchedulePage,\n SchedulePageRequest,\n ScheduleRecord,\n ScheduleStorageError,\n ScheduleStore,\n} from \"@yielded/agent/schedule\";\nimport {\n applyScheduleChange,\n scheduleUsesCapacity,\n scheduleDeadline,\n} from \"@yielded/agent/schedule-transition\";\nimport { Context, Effect, Layer, Result, Schema } from \"effect\";\nimport * as SqlClientService from \"effect/sql/SqlClient\";\n\nconst CURRENT_SCHEDULE_STORE_VERSION = 3;\nconst MAX_STORED_SCHEDULE_BYTES = 1_900_000;\n\nconst StoredScheduleJson = Schema.String.check(Schema.isMaxLength(MAX_STORED_SCHEDULE_BYTES));\nconst StoredDeadline = Schema.NullOr(ScheduleInstant);\n\nclass ScheduleRow extends Schema.Class<ScheduleRow>(\"@effect-agent/storage-cloudflare/ScheduleRow\")(\n {\n tenant_id: ScheduleOwner.fields.tenantId,\n owner_id: ScheduleOwner.fields.ownerId,\n schedule_id: ScheduleId,\n deadline_at_millis: StoredDeadline,\n record_json: StoredScheduleJson,\n },\n) {}\n\nconst ScheduleDueRow = Schema.Struct({\n tenant_id: ScheduleOwner.fields.tenantId,\n owner_id: ScheduleOwner.fields.ownerId,\n schedule_id: ScheduleId,\n deadline_at_millis: ScheduleInstant,\n});\n\nclass ScheduleCountRow extends Schema.Class<ScheduleCountRow>(\n \"@effect-agent/storage-cloudflare/ScheduleCountRow\",\n)({\n schedule_count: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n}) {}\n\nclass ScheduleDeadlineRow extends Schema.Class<ScheduleDeadlineRow>(\n \"@effect-agent/storage-cloudflare/ScheduleDeadlineRow\",\n)({\n deadline_at_millis: StoredDeadline,\n}) {}\n\nclass ScheduleStoreStateRow extends Schema.Class<ScheduleStoreStateRow>(\n \"@effect-agent/storage-cloudflare/ScheduleStoreStateRow\",\n)({\n storage_version: Schema.Int.check(Schema.isGreaterThan(0)),\n alarm_generation: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n}) {}\n\nclass ScheduleTableNameRow extends Schema.Class<ScheduleTableNameRow>(\n \"@effect-agent/storage-cloudflare/ScheduleTableNameRow\",\n)({\n name: Schema.String,\n}) {}\n\nexport interface DoScheduleAlarmReplacement {\n readonly deadlineAtMillis: number | null;\n /** Included in every logical alarm payload so equal-time replacement stays distinguishable. */\n readonly generation: number;\n}\n\nexport type DoScheduleReplaceAlarm = (\n replacement: DoScheduleAlarmReplacement,\n) => Effect.Effect<void, ScheduleStorageError>;\n\n/**\n * Platform-owned transaction boundary for schedule SQL and logical alarm mutation. The callback\n * and its `replaceAlarm` capability belong to one fiber and must not escape or fork.\n */\nexport class DoScheduleTransaction extends Context.Service<\n DoScheduleTransaction,\n {\n readonly run: <A, E, R>(\n body: (replaceAlarm: DoScheduleReplaceAlarm) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | ScheduleStorageError, R>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoScheduleTransaction\") {}\n\n/** Platform driver operations that use the same schedule-state and alarm transaction. */\nexport class DoScheduleAlarmControl extends Context.Service<\n DoScheduleAlarmControl,\n {\n /** Establish a future recovery wake before cross-Object admission starts. */\n readonly prearm: (\n deadlineAtMillis: number,\n ) => Effect.Effect<void, ScheduleStorageError | ScheduleFailpointError>;\n /** Replace or cancel the wake from the object's authoritative indexed deadline. */\n readonly reconcile: Effect.Effect<void, ScheduleStorageError | ScheduleFailpointError>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoScheduleAlarmControl\") {}\n\nconst unavailable = (operation: string): ScheduleStorageError =>\n ScheduleStorageError.make({ operation, reason: \"unavailable\" });\n\nconst corrupt = (operation: string): ScheduleStorageError =>\n ScheduleStorageError.make({ operation, reason: \"corrupt\" });\n\nconst decodeRows = Effect.fn(\"DoScheduleStore.decodeRows\")(function* <A, I, R>(\n schema: Schema.Codec<A, I, R>,\n rows: ReadonlyArray<unknown>,\n operation: string,\n): Effect.fn.Return<A, ScheduleStorageError, R> {\n return yield* Schema.decodeUnknownEffect(schema)(rows).pipe(\n Effect.mapError(() => corrupt(operation)),\n );\n});\n\nconst decodeBoundary = <A, I, R>(\n schema: Schema.Codec<A, I, R>,\n value: unknown,\n operation: string,\n): Effect.Effect<A, ScheduleStorageError, R> =>\n Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(() => corrupt(operation)));\n\nconst decodeRecord = Effect.fn(\"DoScheduleStore.decodeRecord\")(function* (\n row: ScheduleRow,\n): Effect.fn.Return<ScheduleRecord, ScheduleStorageError> {\n const record = yield* Schema.decodeEffect(Schema.fromJsonString(ScheduleRecord))(\n row.record_json,\n ).pipe(Effect.mapError(() => corrupt(\"decode schedule\")));\n\n if (\n record.owner.tenantId !== row.tenant_id ||\n record.owner.ownerId !== row.owner_id ||\n record.scheduleId !== row.schedule_id ||\n scheduleDeadline(record) !== row.deadline_at_millis\n ) {\n return yield* corrupt(\"decode schedule index\");\n }\n\n return record;\n});\n\nconst encodeRecord = Effect.fn(\"DoScheduleStore.encodeRecord\")(function* (\n record: ScheduleRecord,\n): Effect.fn.Return<string, ScheduleStorageError> {\n const encoded = yield* Schema.encodeEffect(Schema.fromJsonString(ScheduleRecord))(record).pipe(\n Effect.mapError(() => corrupt(\"encode schedule\")),\n );\n\n return yield* Schema.decodeEffect(StoredScheduleJson)(encoded).pipe(\n Effect.mapError(() => corrupt(\"encode schedule bounds\")),\n );\n});\n\nconst initializeScheduleStore = Effect.fn(\"DoScheduleStore.initialize\")(function* () {\n const sql = yield* SqlClientService.SqlClient;\n const operation = \"initialize schedule store\";\n\n const rawTables = yield* sql<Record<string, unknown>>`\n SELECT name\n FROM sqlite_master\n WHERE type = 'table'\n AND name IN (\n 'effect_agent_schedule_store_state',\n 'effect_agent_schedules'\n )\n ORDER BY name\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const tables = yield* decodeRows(Schema.Array(ScheduleTableNameRow), rawTables, operation);\n const hasState = tables.some((row) => row.name === \"effect_agent_schedule_store_state\");\n const hasSchedules = tables.some((row) => row.name === \"effect_agent_schedules\");\n\n if (!hasState) {\n if (hasSchedules) return yield* corrupt(operation);\n yield* sql\n .withTransaction(\n Effect.gen(function* () {\n yield* sql`\n CREATE TABLE effect_agent_schedule_store_state (\n singleton INTEGER PRIMARY KEY NOT NULL CHECK (singleton = 1),\n storage_version INTEGER NOT NULL,\n alarm_generation INTEGER NOT NULL\n )\n `.withoutTransform;\n yield* sql`\n CREATE TABLE effect_agent_schedules (\n tenant_id TEXT NOT NULL,\n owner_id TEXT NOT NULL,\n schedule_id TEXT NOT NULL,\n deadline_at_millis INTEGER,\n record_json TEXT NOT NULL,\n PRIMARY KEY (tenant_id, owner_id, schedule_id)\n )\n `.withoutTransform;\n yield* sql`\n CREATE INDEX effect_agent_schedules_deadline\n ON effect_agent_schedules (deadline_at_millis, tenant_id, owner_id, schedule_id)\n WHERE deadline_at_millis IS NOT NULL\n `.withoutTransform;\n yield* sql`\n CREATE INDEX effect_agent_schedules_owner_deadline\n ON effect_agent_schedules (tenant_id, owner_id, deadline_at_millis, schedule_id)\n WHERE deadline_at_millis IS NOT NULL\n `.withoutTransform;\n yield* sql`\n INSERT INTO effect_agent_schedule_store_state (\n singleton, storage_version, alarm_generation\n ) VALUES (1, ${CURRENT_SCHEDULE_STORE_VERSION}, 0)\n `.withoutTransform;\n }),\n )\n .pipe(Effect.mapError(() => unavailable(operation)));\n\n return;\n }\n\n if (!hasSchedules) return yield* corrupt(operation);\n\n const rawState = yield* sql<Record<string, unknown>>`\n SELECT storage_version, alarm_generation\n FROM effect_agent_schedule_store_state\n WHERE singleton = 1\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const state = yield* decodeRows(Schema.Array(ScheduleStoreStateRow), rawState, operation);\n\n if (state.length === 1 && state[0].storage_version === 2) {\n const failpoint = yield* ScheduleFailpoint;\n\n yield* sql\n .withTransaction(\n Effect.gen(function* () {\n const current = yield* sql<{\n storage_version: number;\n }>`SELECT storage_version FROM effect_agent_schedule_store_state WHERE singleton=1`;\n\n if (current.length === 1 && current[0].storage_version === 3) return;\n if (current.length !== 1 || current[0].storage_version !== 2)\n return yield* corrupt(\"schedule version changed during upgrade\");\n yield* upgradeV2Schedules(MAX_STORED_SCHEDULE_BYTES);\n yield* failpoint.hit(\"upgrade:before-version\");\n yield* sql`UPDATE effect_agent_schedule_store_state SET storage_version=3 WHERE singleton=1`;\n yield* failpoint.hit(\"upgrade:after-version\");\n }),\n )\n .pipe(\n Effect.catchTag(\"StorageUpgradeError\", (error) =>\n ScheduleStorageError.make({\n reason: \"corrupt\",\n operation: \"upgrade v2 schedules\",\n cause: error,\n }),\n ),\n Effect.catchTag(\"SqlError\", () => unavailable(\"upgrade v2 schedules\")),\n Effect.catchTag(\"ScheduleFailpointError\", () =>\n unavailable(\"upgrade v2 schedules failpoint\"),\n ),\n );\n\n return;\n }\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SCHEDULE_STORE_VERSION) {\n return yield* corrupt(\n state.length === 1\n ? `${operation}: incompatible storage version ${state[0].storage_version}; expected ${CURRENT_SCHEDULE_STORE_VERSION}`\n : `${operation}: invalid storage version row`,\n );\n }\n});\n\nconst makeServices = Effect.gen(function* () {\n const sql = yield* SqlClientService.SqlClient;\n const transactions = yield* DoScheduleTransaction;\n const scheduleFailpoint = yield* ScheduleFailpoint;\n\n yield* initializeScheduleStore();\n\n const readRows = Effect.fn(\"DoScheduleStore.readRows\")(function* (\n key: ScheduleKey,\n operation: string,\n ): Effect.fn.Return<ReadonlyArray<ScheduleRow>, ScheduleStorageError> {\n const rows = yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n FROM effect_agent_schedules\n WHERE tenant_id = ${key.owner.tenantId}\n AND owner_id = ${key.owner.ownerId}\n AND schedule_id = ${key.scheduleId}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n return yield* decodeRows(Schema.Array(ScheduleRow), rows, operation);\n });\n\n const readOne = Effect.fn(\"DoScheduleStore.readOne\")(function* (\n key: ScheduleKey,\n operation: string,\n ): Effect.fn.Return<ScheduleRecord | null, ScheduleStorageError> {\n const rows = yield* readRows(key, operation);\n\n if (rows.length === 0) return null;\n if (rows.length !== 1) return yield* corrupt(operation);\n\n return yield* decodeRecord(rows[0]);\n });\n\n const readNextDeadline = Effect.fn(\"DoScheduleStore.readNextDeadline\")(function* (\n owner: ScheduleOwner | undefined,\n operation: string,\n ): Effect.fn.Return<number | null, ScheduleStorageError> {\n const rows =\n owner === undefined\n ? yield* sql<Record<string, unknown>>`\n SELECT MIN(deadline_at_millis) AS deadline_at_millis\n FROM effect_agent_schedules\n WHERE deadline_at_millis IS NOT NULL\n `.pipe(Effect.mapError(() => unavailable(operation)))\n : yield* sql<Record<string, unknown>>`\n SELECT MIN(deadline_at_millis) AS deadline_at_millis\n FROM effect_agent_schedules\n WHERE tenant_id = ${owner.tenantId}\n AND owner_id = ${owner.ownerId}\n AND deadline_at_millis IS NOT NULL\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const decoded = yield* decodeRows(Schema.Array(ScheduleDeadlineRow), rows, operation);\n\n if (decoded.length !== 1) return yield* corrupt(operation);\n\n return decoded[0].deadline_at_millis;\n });\n\n const replaceAlarm = Effect.fn(\"DoScheduleStore.replaceAlarm\")(function* (\n replace: DoScheduleReplaceAlarm,\n deadlineAtMillis: number | null,\n operation: string,\n ) {\n const rawState = yield* sql<Record<string, unknown>>`\n UPDATE effect_agent_schedule_store_state\n SET alarm_generation = alarm_generation + 1\n WHERE singleton = 1\n RETURNING storage_version, alarm_generation\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const state = yield* decodeRows(Schema.Array(ScheduleStoreStateRow), rawState, operation);\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SCHEDULE_STORE_VERSION) {\n return yield* corrupt(operation);\n }\n yield* scheduleFailpoint.hit(\"schedule:alarm:before\");\n yield* replace({ deadlineAtMillis, generation: state[0].alarm_generation });\n yield* scheduleFailpoint.hit(\"schedule:alarm:after\");\n });\n\n const insert: ScheduleStore[\"Service\"][\"insert\"] = Effect.fn(\"DoScheduleStore.insert\")(\n function* (record, ownerLimit) {\n const operation = \"insert schedule\";\n const canonical = yield* decodeBoundary(ScheduleRecord, record, operation);\n const recordJson = yield* encodeRecord(canonical);\n\n const result = yield* transactions.run((replace) =>\n Effect.gen(function* () {\n const existing = yield* readOne(canonical, operation);\n\n if (existing !== null) {\n if (existing.creationFingerprint === canonical.creationFingerprint) {\n return { record: existing, inserted: false } as const;\n }\n\n return yield* ScheduleConflict.make({ reason: \"creation\", key: canonical });\n }\n\n const rawCounts = yield* sql<Record<string, unknown>>`\n SELECT COUNT(*) AS schedule_count\n FROM effect_agent_schedules\n WHERE tenant_id = ${canonical.owner.tenantId}\n AND owner_id = ${canonical.owner.ownerId}\n AND (json_extract(record_json, '$.pending') IS NOT NULL OR\n (json_extract(record_json, '$.state') != 'cancelled' AND json_extract(record_json, '$.nextAtMillis') IS NOT NULL))\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const counts = yield* decodeRows(Schema.Array(ScheduleCountRow), rawCounts, operation);\n\n if (counts.length !== 1) return yield* corrupt(operation);\n if (counts[0].schedule_count >= ownerLimit) {\n return yield* ScheduleCapacityError.make({ limit: ownerLimit });\n }\n yield* scheduleFailpoint.hit(\"schedule:insert:before\");\n yield* sql`\n INSERT INTO effect_agent_schedules (\n tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n ) VALUES (\n ${canonical.owner.tenantId},\n ${canonical.owner.ownerId},\n ${canonical.scheduleId},\n ${scheduleDeadline(canonical)},\n ${recordJson}\n )\n `.pipe(Effect.mapError(() => unavailable(operation)));\n const deadline = yield* readNextDeadline(undefined, operation);\n\n yield* replaceAlarm(replace, deadline, operation);\n\n return { record: canonical, inserted: true } as const;\n }),\n );\n\n if (result.inserted) yield* scheduleFailpoint.hit(\"schedule:insert:after\");\n\n return result.record;\n },\n );\n\n const get: ScheduleStore[\"Service\"][\"get\"] = Effect.fn(\"DoScheduleStore.get\")(function* (key) {\n const canonical = yield* decodeBoundary(ScheduleKey, key, \"get schedule\");\n\n return yield* readOne(canonical, \"get schedule\");\n });\n\n const list: ScheduleStore[\"Service\"][\"list\"] = Effect.fn(\"DoScheduleStore.list\")(function* (\n requestValue: SchedulePageRequest,\n ): Effect.fn.Return<SchedulePage, ScheduleStorageError> {\n const operation = \"list schedules\";\n const request = yield* decodeBoundary(SchedulePageRequest, requestValue, operation);\n\n const rows =\n request.after === undefined\n ? yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n FROM effect_agent_schedules\n WHERE tenant_id = ${request.owner.tenantId}\n AND owner_id = ${request.owner.ownerId}\n ORDER BY schedule_id\n LIMIT ${request.limit + 1}\n `.pipe(Effect.mapError(() => unavailable(operation)))\n : yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n FROM effect_agent_schedules\n WHERE tenant_id = ${request.owner.tenantId}\n AND owner_id = ${request.owner.ownerId}\n AND schedule_id > ${request.after}\n ORDER BY schedule_id\n LIMIT ${request.limit + 1}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const decoded = yield* decodeRows(Schema.Array(ScheduleRow), rows, operation);\n const records = yield* Effect.forEach(decoded, decodeRecord);\n const hasNext = records.length > request.limit;\n const items = hasNext ? records.slice(0, request.limit) : records;\n\n return { items, next: hasNext ? (items.at(-1)?.scheduleId ?? null) : null };\n });\n\n const change: ScheduleStore[\"Service\"][\"change\"] = Effect.fn(\"DoScheduleStore.change\")(function* (\n key,\n change,\n ownerLimit = defaultSchedulingLimits.maxSchedulesPerOwner,\n ) {\n const operation = \"change schedule\";\n const canonicalKey = yield* decodeBoundary(ScheduleKey, key, operation);\n const canonicalChange = yield* decodeBoundary(ScheduleChange, change, operation);\n\n const result = yield* transactions.run((replace) =>\n Effect.gen(function* () {\n const current = yield* readOne(canonicalKey, operation);\n\n if (current === null) return yield* ScheduleNotFound.make({ key: canonicalKey });\n const transition = applyScheduleChange(current, canonicalChange);\n\n if (Result.isFailure(transition)) return yield* transition.failure;\n const next = transition.success;\n\n if (!scheduleUsesCapacity(current) && scheduleUsesCapacity(next)) {\n const rawCounts = yield* sql<Record<string, unknown>>`\n SELECT COUNT(*) AS schedule_count FROM effect_agent_schedules\n WHERE tenant_id = ${key.owner.tenantId} AND owner_id = ${key.owner.ownerId}\n AND (json_extract(record_json, '$.pending') IS NOT NULL OR\n (json_extract(record_json, '$.state') != 'cancelled' AND json_extract(record_json, '$.nextAtMillis') IS NOT NULL))\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const counts = yield* decodeRows(Schema.Array(ScheduleCountRow), rawCounts, operation);\n\n if (counts.length !== 1) return yield* corrupt(operation);\n if (counts[0].schedule_count >= ownerLimit)\n return yield* ScheduleCapacityError.make({ limit: ownerLimit });\n }\n if (next === current) return { record: current, changed: false } as const;\n const recordJson = yield* encodeRecord(next);\n\n yield* scheduleFailpoint.hit(`schedule:${canonicalChange._tag.toLowerCase()}:before`);\n yield* sql`\n UPDATE effect_agent_schedules\n SET deadline_at_millis = ${scheduleDeadline(next)}, record_json = ${recordJson}\n WHERE tenant_id = ${canonicalKey.owner.tenantId}\n AND owner_id = ${canonicalKey.owner.ownerId}\n AND schedule_id = ${canonicalKey.scheduleId}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n const deadline = yield* readNextDeadline(undefined, operation);\n\n yield* replaceAlarm(replace, deadline, operation);\n\n return { record: next, changed: true } as const;\n }),\n );\n\n if (result.changed) {\n yield* scheduleFailpoint.hit(`schedule:${canonicalChange._tag.toLowerCase()}:after`);\n }\n\n return result.record;\n });\n\n const due: ScheduleStore[\"Service\"][\"due\"] = Effect.fn(\"DoScheduleStore.due\")(function* (\n nowMillis,\n limit,\n owner?: ScheduleOwner,\n after?: ScheduleDueCursor,\n ) {\n const operation = \"query due schedules\";\n\n const cursor =\n after === undefined\n ? undefined\n : yield* Schema.decodeEffect(ScheduleDueCursor)(after).pipe(\n Effect.mapError(() => corrupt(operation)),\n );\n\n const continuation =\n cursor === undefined\n ? sql`1 = 1`\n : sql`\n (deadline_at_millis, tenant_id, owner_id, schedule_id) >\n (${cursor.deadlineAtMillis}, ${cursor.owner.tenantId}, ${cursor.owner.ownerId}, ${cursor.scheduleId})`;\n\n const rows =\n owner === undefined\n ? yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis\n FROM effect_agent_schedules\n WHERE deadline_at_millis <= ${nowMillis} AND ${continuation}\n ORDER BY deadline_at_millis, tenant_id, owner_id, schedule_id\n LIMIT ${limit}\n `.pipe(Effect.mapError(() => unavailable(operation)))\n : yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis\n FROM effect_agent_schedules\n WHERE tenant_id = ${owner.tenantId}\n AND owner_id = ${owner.ownerId}\n AND deadline_at_millis <= ${nowMillis} AND ${continuation}\n ORDER BY deadline_at_millis, schedule_id\n LIMIT ${limit}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const decoded = yield* decodeRows(Schema.Array(ScheduleDueRow), rows, operation);\n\n return decoded.map((row) => ({\n owner: { tenantId: row.tenant_id, ownerId: row.owner_id },\n scheduleId: row.schedule_id,\n deadlineAtMillis: row.deadline_at_millis,\n }));\n });\n\n const nextDeadline: ScheduleStore[\"Service\"][\"nextDeadline\"] = Effect.fn(\n \"DoScheduleStore.nextDeadline\",\n )(function* (owner?: ScheduleOwner) {\n const operation = \"query next schedule deadline\";\n\n return yield* readNextDeadline(owner, operation);\n });\n\n const prearm = Effect.fn(\"DoScheduleStore.prearm\")(function* (\n deadlineAtMillis: number,\n ): Effect.fn.Return<void, ScheduleStorageError | ScheduleFailpointError> {\n yield* decodeBoundary(ScheduleInstant, deadlineAtMillis, \"pre-arm schedule recovery\");\n yield* transactions.run((replace) =>\n replaceAlarm(replace, deadlineAtMillis, \"pre-arm schedule recovery\"),\n );\n yield* scheduleFailpoint.hit(\"schedule:prearm:after\");\n });\n\n const reconcile = Effect.gen(function* () {\n yield* transactions.run((replace) =>\n Effect.gen(function* () {\n const deadline = yield* readNextDeadline(undefined, \"reconcile schedule alarm\");\n\n yield* replaceAlarm(replace, deadline, \"reconcile schedule alarm\");\n }),\n );\n yield* scheduleFailpoint.hit(\"schedule:reconcile:after\");\n });\n\n return Context.make(ScheduleStore, {\n insert,\n get,\n list,\n change,\n due,\n nextDeadline,\n }).pipe(Context.add(DoScheduleAlarmControl, { prearm, reconcile }));\n});\n\n/**\n * Durable Object SQLite ScheduleStore. Platform code supplies the one transaction owner that\n * combines these SQL mutations with its logical and native alarm lifecycle.\n */\nexport const scheduleStoreLayer: Layer.Layer<\n ScheduleStore | DoScheduleAlarmControl,\n ScheduleStorageError,\n SqlClientService.SqlClient | DoScheduleTransaction\n> = Layer.effectContext(makeServices);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DoScheduleStore.mjs","names":[],"sources":["../src/DoScheduleStore.ts"],"sourcesContent":["import {\n ScheduleCapacityError,\n ScheduleDueCursor,\n defaultSchedulingLimits,\n ScheduleChange,\n ScheduleConflict,\n ScheduleFailpoint,\n type ScheduleFailpointError,\n ScheduleKey,\n ScheduleId,\n ScheduleInstant,\n ScheduleNotFound,\n ScheduleOwner,\n type SchedulePage,\n SchedulePageRequest,\n ScheduleRecord,\n ScheduleStorageError,\n ScheduleStore,\n} from \"@yielded/agent/schedule\";\nimport {\n applyScheduleChange,\n scheduleUsesCapacity,\n scheduleDeadline,\n} from \"@yielded/agent/schedule-transition\";\nimport { Context, Effect, Layer, Result, Schema } from \"effect\";\nimport * as SqlClientService from \"effect/sql/SqlClient\";\n\nconst CURRENT_SCHEDULE_STORE_VERSION = 3;\nconst MAX_STORED_SCHEDULE_BYTES = 1_900_000;\n\nconst StoredScheduleJson = Schema.String.check(Schema.isMaxLength(MAX_STORED_SCHEDULE_BYTES));\nconst StoredDeadline = Schema.NullOr(ScheduleInstant);\n\nclass ScheduleRow extends Schema.Class<ScheduleRow>(\"@effect-agent/storage-cloudflare/ScheduleRow\")(\n {\n tenant_id: ScheduleOwner.fields.tenantId,\n owner_id: ScheduleOwner.fields.ownerId,\n schedule_id: ScheduleId,\n deadline_at_millis: StoredDeadline,\n record_json: StoredScheduleJson,\n },\n) {}\n\nconst ScheduleDueRow = Schema.Struct({\n tenant_id: ScheduleOwner.fields.tenantId,\n owner_id: ScheduleOwner.fields.ownerId,\n schedule_id: ScheduleId,\n deadline_at_millis: ScheduleInstant,\n});\n\nclass ScheduleCountRow extends Schema.Class<ScheduleCountRow>(\n \"@effect-agent/storage-cloudflare/ScheduleCountRow\",\n)({\n schedule_count: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n}) {}\n\nclass ScheduleDeadlineRow extends Schema.Class<ScheduleDeadlineRow>(\n \"@effect-agent/storage-cloudflare/ScheduleDeadlineRow\",\n)({\n deadline_at_millis: StoredDeadline,\n}) {}\n\nclass ScheduleStoreStateRow extends Schema.Class<ScheduleStoreStateRow>(\n \"@effect-agent/storage-cloudflare/ScheduleStoreStateRow\",\n)({\n storage_version: Schema.Int.check(Schema.isGreaterThan(0)),\n alarm_generation: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n}) {}\n\nclass ScheduleTableNameRow extends Schema.Class<ScheduleTableNameRow>(\n \"@effect-agent/storage-cloudflare/ScheduleTableNameRow\",\n)({\n name: Schema.String,\n}) {}\n\nexport interface DoScheduleAlarmReplacement {\n readonly deadlineAtMillis: number | null;\n /** Included in every logical alarm payload so equal-time replacement stays distinguishable. */\n readonly generation: number;\n}\n\nexport type DoScheduleReplaceAlarm = (\n replacement: DoScheduleAlarmReplacement,\n) => Effect.Effect<void, ScheduleStorageError>;\n\n/**\n * Platform-owned transaction boundary for schedule SQL and logical alarm mutation. The callback\n * and its `replaceAlarm` capability belong to one fiber and must not escape or fork.\n */\nexport class DoScheduleTransaction extends Context.Service<\n DoScheduleTransaction,\n {\n readonly run: <A, E, R>(\n body: (replaceAlarm: DoScheduleReplaceAlarm) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | ScheduleStorageError, R>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoScheduleTransaction\") {}\n\n/** Platform driver operations that use the same schedule-state and alarm transaction. */\nexport class DoScheduleAlarmControl extends Context.Service<\n DoScheduleAlarmControl,\n {\n /** Establish a future recovery wake before cross-Object admission starts. */\n readonly prearm: (\n deadlineAtMillis: number,\n ) => Effect.Effect<void, ScheduleStorageError | ScheduleFailpointError>;\n /** Replace or cancel the wake from the object's authoritative indexed deadline. */\n readonly reconcile: Effect.Effect<void, ScheduleStorageError | ScheduleFailpointError>;\n }\n>()(\"@effect-agent/storage-cloudflare/DoScheduleAlarmControl\") {}\n\nconst unavailable = (operation: string): ScheduleStorageError =>\n ScheduleStorageError.make({ operation, reason: \"unavailable\" });\n\nconst corrupt = (operation: string): ScheduleStorageError =>\n ScheduleStorageError.make({ operation, reason: \"corrupt\" });\n\nconst decodeRows = <A, I, R>(\n schema: Schema.Codec<A, I, R>,\n rows: ReadonlyArray<unknown>,\n operation: string,\n): Effect.Effect<A, ScheduleStorageError, R> =>\n Schema.decodeUnknownEffect(schema)(rows).pipe(Effect.mapError(() => corrupt(operation)));\n\nconst decodeBoundary = <A, I, R>(\n schema: Schema.Codec<A, I, R>,\n value: unknown,\n operation: string,\n): Effect.Effect<A, ScheduleStorageError, R> =>\n Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(() => corrupt(operation)));\n\nconst decodeRecord = Effect.fnUntraced(function* (\n row: ScheduleRow,\n): Effect.fn.Return<ScheduleRecord, ScheduleStorageError> {\n const record = yield* Schema.decodeEffect(Schema.fromJsonString(ScheduleRecord))(\n row.record_json,\n ).pipe(Effect.mapError(() => corrupt(\"decode schedule\")));\n\n if (\n record.owner.tenantId !== row.tenant_id ||\n record.owner.ownerId !== row.owner_id ||\n record.scheduleId !== row.schedule_id ||\n scheduleDeadline(record) !== row.deadline_at_millis\n ) {\n return yield* corrupt(\"decode schedule index\");\n }\n\n return record;\n});\n\nconst encodeRecord = Effect.fnUntraced(function* (\n record: ScheduleRecord,\n): Effect.fn.Return<string, ScheduleStorageError> {\n const encoded = yield* Schema.encodeEffect(Schema.fromJsonString(ScheduleRecord))(record).pipe(\n Effect.mapError(() => corrupt(\"encode schedule\")),\n );\n\n return yield* Schema.decodeEffect(StoredScheduleJson)(encoded).pipe(\n Effect.mapError(() => corrupt(\"encode schedule bounds\")),\n );\n});\n\nconst initializeScheduleStore = Effect.fnUntraced(function* () {\n const sql = yield* SqlClientService.SqlClient;\n const operation = \"initialize schedule store\";\n\n const rawTables = yield* sql<Record<string, unknown>>`\n SELECT name\n FROM sqlite_master\n WHERE type = 'table'\n AND name IN (\n 'effect_agent_schedule_store_state',\n 'effect_agent_schedules'\n )\n ORDER BY name\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const tables = yield* decodeRows(Schema.Array(ScheduleTableNameRow), rawTables, operation);\n const hasState = tables.some((row) => row.name === \"effect_agent_schedule_store_state\");\n const hasSchedules = tables.some((row) => row.name === \"effect_agent_schedules\");\n\n if (!hasState) {\n if (hasSchedules) return yield* corrupt(operation);\n yield* sql\n .withTransaction(\n Effect.gen(function* () {\n yield* sql`\n CREATE TABLE effect_agent_schedule_store_state (\n singleton INTEGER PRIMARY KEY NOT NULL CHECK (singleton = 1),\n storage_version INTEGER NOT NULL,\n alarm_generation INTEGER NOT NULL\n )\n `.withoutTransform;\n yield* sql`\n CREATE TABLE effect_agent_schedules (\n tenant_id TEXT NOT NULL,\n owner_id TEXT NOT NULL,\n schedule_id TEXT NOT NULL,\n deadline_at_millis INTEGER,\n record_json TEXT NOT NULL,\n PRIMARY KEY (tenant_id, owner_id, schedule_id)\n )\n `.withoutTransform;\n yield* sql`\n CREATE INDEX effect_agent_schedules_deadline\n ON effect_agent_schedules (deadline_at_millis, tenant_id, owner_id, schedule_id)\n WHERE deadline_at_millis IS NOT NULL\n `.withoutTransform;\n yield* sql`\n CREATE INDEX effect_agent_schedules_owner_deadline\n ON effect_agent_schedules (tenant_id, owner_id, deadline_at_millis, schedule_id)\n WHERE deadline_at_millis IS NOT NULL\n `.withoutTransform;\n yield* sql`\n INSERT INTO effect_agent_schedule_store_state (\n singleton, storage_version, alarm_generation\n ) VALUES (1, ${CURRENT_SCHEDULE_STORE_VERSION}, 0)\n `.withoutTransform;\n }),\n )\n .pipe(Effect.mapError(() => unavailable(operation)));\n\n return;\n }\n\n if (!hasSchedules) return yield* corrupt(operation);\n\n const rawState = yield* sql<Record<string, unknown>>`\n SELECT storage_version, alarm_generation\n FROM effect_agent_schedule_store_state\n WHERE singleton = 1\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const state = yield* decodeRows(Schema.Array(ScheduleStoreStateRow), rawState, operation);\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SCHEDULE_STORE_VERSION) {\n return yield* corrupt(\n state.length === 1\n ? `${operation}: incompatible storage version ${state[0].storage_version}; expected ${CURRENT_SCHEDULE_STORE_VERSION}`\n : `${operation}: invalid storage version row`,\n );\n }\n});\n\nconst makeServices = Effect.gen(function* () {\n const sql = yield* SqlClientService.SqlClient;\n const transactions = yield* DoScheduleTransaction;\n const scheduleFailpoint = yield* ScheduleFailpoint;\n\n yield* initializeScheduleStore();\n\n const readRows = Effect.fnUntraced(function* (\n key: ScheduleKey,\n operation: string,\n ): Effect.fn.Return<ReadonlyArray<ScheduleRow>, ScheduleStorageError> {\n const rows = yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n FROM effect_agent_schedules\n WHERE tenant_id = ${key.owner.tenantId}\n AND owner_id = ${key.owner.ownerId}\n AND schedule_id = ${key.scheduleId}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n return yield* decodeRows(Schema.Array(ScheduleRow), rows, operation);\n });\n\n const readOne = Effect.fnUntraced(function* (\n key: ScheduleKey,\n operation: string,\n ): Effect.fn.Return<ScheduleRecord | null, ScheduleStorageError> {\n const rows = yield* readRows(key, operation);\n\n if (rows.length === 0) return null;\n if (rows.length !== 1) return yield* corrupt(operation);\n\n return yield* decodeRecord(rows[0]);\n });\n\n const readNextDeadline = Effect.fnUntraced(function* (\n owner: ScheduleOwner | undefined,\n operation: string,\n ): Effect.fn.Return<number | null, ScheduleStorageError> {\n const rows =\n owner === undefined\n ? yield* sql<Record<string, unknown>>`\n SELECT MIN(deadline_at_millis) AS deadline_at_millis\n FROM effect_agent_schedules\n WHERE deadline_at_millis IS NOT NULL\n `.pipe(Effect.mapError(() => unavailable(operation)))\n : yield* sql<Record<string, unknown>>`\n SELECT MIN(deadline_at_millis) AS deadline_at_millis\n FROM effect_agent_schedules\n WHERE tenant_id = ${owner.tenantId}\n AND owner_id = ${owner.ownerId}\n AND deadline_at_millis IS NOT NULL\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const decoded = yield* decodeRows(Schema.Array(ScheduleDeadlineRow), rows, operation);\n\n if (decoded.length !== 1) return yield* corrupt(operation);\n\n return decoded[0].deadline_at_millis;\n });\n\n const replaceAlarm = Effect.fnUntraced(function* (\n replace: DoScheduleReplaceAlarm,\n deadlineAtMillis: number | null,\n operation: string,\n ) {\n const rawState = yield* sql<Record<string, unknown>>`\n UPDATE effect_agent_schedule_store_state\n SET alarm_generation = alarm_generation + 1\n WHERE singleton = 1\n RETURNING storage_version, alarm_generation\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const state = yield* decodeRows(Schema.Array(ScheduleStoreStateRow), rawState, operation);\n\n if (state.length !== 1 || state[0].storage_version !== CURRENT_SCHEDULE_STORE_VERSION) {\n return yield* corrupt(operation);\n }\n yield* scheduleFailpoint.hit(\"schedule:alarm:before\");\n yield* replace({ deadlineAtMillis, generation: state[0].alarm_generation });\n yield* scheduleFailpoint.hit(\"schedule:alarm:after\");\n });\n\n const insert: ScheduleStore[\"Service\"][\"insert\"] = Effect.fnUntraced(\n function* (record, ownerLimit) {\n const operation = \"insert schedule\";\n const canonical = yield* decodeBoundary(ScheduleRecord, record, operation);\n const recordJson = yield* encodeRecord(canonical);\n\n const result = yield* transactions.run((replace) =>\n Effect.gen(function* () {\n const existing = yield* readOne(canonical, operation);\n\n if (existing !== null) {\n if (existing.creationFingerprint === canonical.creationFingerprint) {\n return { record: existing, inserted: false } as const;\n }\n\n return yield* ScheduleConflict.make({ reason: \"creation\", key: canonical });\n }\n\n const rawCounts = yield* sql<Record<string, unknown>>`\n SELECT COUNT(*) AS schedule_count\n FROM effect_agent_schedules\n WHERE tenant_id = ${canonical.owner.tenantId}\n AND owner_id = ${canonical.owner.ownerId}\n AND (json_extract(record_json, '$.pending') IS NOT NULL OR\n (json_extract(record_json, '$.state') != 'cancelled' AND json_extract(record_json, '$.nextAtMillis') IS NOT NULL))\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const counts = yield* decodeRows(Schema.Array(ScheduleCountRow), rawCounts, operation);\n\n if (counts.length !== 1) return yield* corrupt(operation);\n if (counts[0].schedule_count >= ownerLimit) {\n return yield* ScheduleCapacityError.make({ limit: ownerLimit });\n }\n yield* scheduleFailpoint.hit(\"schedule:insert:before\");\n yield* sql`\n INSERT INTO effect_agent_schedules (\n tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n ) VALUES (\n ${canonical.owner.tenantId},\n ${canonical.owner.ownerId},\n ${canonical.scheduleId},\n ${scheduleDeadline(canonical)},\n ${recordJson}\n )\n `.pipe(Effect.mapError(() => unavailable(operation)));\n const deadline = yield* readNextDeadline(undefined, operation);\n\n yield* replaceAlarm(replace, deadline, operation);\n\n return { record: canonical, inserted: true } as const;\n }),\n );\n\n if (result.inserted) yield* scheduleFailpoint.hit(\"schedule:insert:after\");\n\n return result.record;\n },\n );\n\n const get: ScheduleStore[\"Service\"][\"get\"] = Effect.fnUntraced(function* (key) {\n const canonical = yield* decodeBoundary(ScheduleKey, key, \"get schedule\");\n\n return yield* readOne(canonical, \"get schedule\");\n });\n\n const list: ScheduleStore[\"Service\"][\"list\"] = Effect.fnUntraced(function* (\n requestValue: SchedulePageRequest,\n ): Effect.fn.Return<SchedulePage, ScheduleStorageError> {\n const operation = \"list schedules\";\n const request = yield* decodeBoundary(SchedulePageRequest, requestValue, operation);\n\n const rows =\n request.after === undefined\n ? yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n FROM effect_agent_schedules\n WHERE tenant_id = ${request.owner.tenantId}\n AND owner_id = ${request.owner.ownerId}\n ORDER BY schedule_id\n LIMIT ${request.limit + 1}\n `.pipe(Effect.mapError(() => unavailable(operation)))\n : yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis, record_json\n FROM effect_agent_schedules\n WHERE tenant_id = ${request.owner.tenantId}\n AND owner_id = ${request.owner.ownerId}\n AND schedule_id > ${request.after}\n ORDER BY schedule_id\n LIMIT ${request.limit + 1}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const decoded = yield* decodeRows(Schema.Array(ScheduleRow), rows, operation);\n const records = yield* Effect.forEach(decoded, decodeRecord);\n const hasNext = records.length > request.limit;\n const items = hasNext ? records.slice(0, request.limit) : records;\n\n return { items, next: hasNext ? (items.at(-1)?.scheduleId ?? null) : null };\n });\n\n const change: ScheduleStore[\"Service\"][\"change\"] = Effect.fnUntraced(function* (\n key,\n change,\n ownerLimit = defaultSchedulingLimits.maxSchedulesPerOwner,\n ) {\n const operation = \"change schedule\";\n const canonicalKey = yield* decodeBoundary(ScheduleKey, key, operation);\n const canonicalChange = yield* decodeBoundary(ScheduleChange, change, operation);\n\n const result = yield* transactions.run((replace) =>\n Effect.gen(function* () {\n const current = yield* readOne(canonicalKey, operation);\n\n if (current === null) return yield* ScheduleNotFound.make({ key: canonicalKey });\n const transition = applyScheduleChange(current, canonicalChange);\n\n if (Result.isFailure(transition)) return yield* transition.failure;\n const next = transition.success;\n\n if (!scheduleUsesCapacity(current) && scheduleUsesCapacity(next)) {\n const rawCounts = yield* sql<Record<string, unknown>>`\n SELECT COUNT(*) AS schedule_count FROM effect_agent_schedules\n WHERE tenant_id = ${key.owner.tenantId} AND owner_id = ${key.owner.ownerId}\n AND (json_extract(record_json, '$.pending') IS NOT NULL OR\n (json_extract(record_json, '$.state') != 'cancelled' AND json_extract(record_json, '$.nextAtMillis') IS NOT NULL))\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const counts = yield* decodeRows(Schema.Array(ScheduleCountRow), rawCounts, operation);\n\n if (counts.length !== 1) return yield* corrupt(operation);\n if (counts[0].schedule_count >= ownerLimit)\n return yield* ScheduleCapacityError.make({ limit: ownerLimit });\n }\n if (next === current) return { record: current, changed: false } as const;\n const recordJson = yield* encodeRecord(next);\n\n yield* scheduleFailpoint.hit(`schedule:${canonicalChange._tag.toLowerCase()}:before`);\n yield* sql`\n UPDATE effect_agent_schedules\n SET deadline_at_millis = ${scheduleDeadline(next)}, record_json = ${recordJson}\n WHERE tenant_id = ${canonicalKey.owner.tenantId}\n AND owner_id = ${canonicalKey.owner.ownerId}\n AND schedule_id = ${canonicalKey.scheduleId}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n const deadline = yield* readNextDeadline(undefined, operation);\n\n yield* replaceAlarm(replace, deadline, operation);\n\n return { record: next, changed: true } as const;\n }),\n );\n\n if (result.changed) {\n yield* scheduleFailpoint.hit(`schedule:${canonicalChange._tag.toLowerCase()}:after`);\n }\n\n return result.record;\n });\n\n const due: ScheduleStore[\"Service\"][\"due\"] = Effect.fnUntraced(function* (\n nowMillis,\n limit,\n owner?: ScheduleOwner,\n after?: ScheduleDueCursor,\n ) {\n const operation = \"query due schedules\";\n\n const cursor =\n after === undefined\n ? undefined\n : yield* Schema.decodeEffect(ScheduleDueCursor)(after).pipe(\n Effect.mapError(() => corrupt(operation)),\n );\n\n const continuation =\n cursor === undefined\n ? sql`1 = 1`\n : sql`\n (deadline_at_millis, tenant_id, owner_id, schedule_id) >\n (${cursor.deadlineAtMillis}, ${cursor.owner.tenantId}, ${cursor.owner.ownerId}, ${cursor.scheduleId})`;\n\n const rows =\n owner === undefined\n ? yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis\n FROM effect_agent_schedules\n WHERE deadline_at_millis <= ${nowMillis} AND ${continuation}\n ORDER BY deadline_at_millis, tenant_id, owner_id, schedule_id\n LIMIT ${limit}\n `.pipe(Effect.mapError(() => unavailable(operation)))\n : yield* sql<Record<string, unknown>>`\n SELECT tenant_id, owner_id, schedule_id, deadline_at_millis\n FROM effect_agent_schedules\n WHERE tenant_id = ${owner.tenantId}\n AND owner_id = ${owner.ownerId}\n AND deadline_at_millis <= ${nowMillis} AND ${continuation}\n ORDER BY deadline_at_millis, schedule_id\n LIMIT ${limit}\n `.pipe(Effect.mapError(() => unavailable(operation)));\n\n const decoded = yield* decodeRows(Schema.Array(ScheduleDueRow), rows, operation);\n\n return decoded.map((row) => ({\n owner: { tenantId: row.tenant_id, ownerId: row.owner_id },\n scheduleId: row.schedule_id,\n deadlineAtMillis: row.deadline_at_millis,\n }));\n });\n\n const nextDeadline: ScheduleStore[\"Service\"][\"nextDeadline\"] = Effect.fnUntraced(function* (\n owner?: ScheduleOwner,\n ) {\n const operation = \"query next schedule deadline\";\n\n return yield* readNextDeadline(owner, operation);\n });\n\n const prearm = Effect.fnUntraced(function* (\n deadlineAtMillis: number,\n ): Effect.fn.Return<void, ScheduleStorageError | ScheduleFailpointError> {\n yield* decodeBoundary(ScheduleInstant, deadlineAtMillis, \"pre-arm schedule recovery\");\n yield* transactions.run((replace) =>\n replaceAlarm(replace, deadlineAtMillis, \"pre-arm schedule recovery\"),\n );\n yield* scheduleFailpoint.hit(\"schedule:prearm:after\");\n });\n\n const reconcile = Effect.gen(function* () {\n yield* transactions.run((replace) =>\n Effect.gen(function* () {\n const deadline = yield* readNextDeadline(undefined, \"reconcile schedule alarm\");\n\n yield* replaceAlarm(replace, deadline, \"reconcile schedule alarm\");\n }),\n );\n yield* scheduleFailpoint.hit(\"schedule:reconcile:after\");\n });\n\n return Context.make(ScheduleStore, {\n insert,\n get,\n list,\n change,\n due,\n nextDeadline,\n }).pipe(Context.add(DoScheduleAlarmControl, { prearm, reconcile }));\n});\n\n/**\n * Durable Object SQLite ScheduleStore. Platform code supplies the one transaction owner that\n * combines these SQL mutations with its logical and native alarm lifecycle.\n */\nexport const scheduleStoreLayer: Layer.Layer<\n ScheduleStore | DoScheduleAlarmControl,\n ScheduleStorageError,\n SqlClientService.SqlClient | DoScheduleTransaction\n> = Layer.effectContext(makeServices);\n"],"mappings":"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"}
|
|
@@ -11,13 +11,6 @@ declare namespace DoStorageConfig_d_exports {
|
|
|
11
11
|
export declare const DEFAULT_MAX_STORED_VALUE_BYTES = 1900000;
|
|
12
12
|
declare const DoStorageConfigValue_base: Schema.Class<DoStorageConfigValue, Schema.Struct<{
|
|
13
13
|
readonly observationPollInterval: Schema.Int;
|
|
14
|
-
/**
|
|
15
|
-
* Submission ownership lease duration in milliseconds (D5). Inside one Durable Object the
|
|
16
|
-
* object itself is the serialized owner, so the lease's primary DC role is fencing work
|
|
17
|
-
* across DO incarnations (an evicted incarnation's claim becomes reclaimable); correctness
|
|
18
|
-
* never depends on it because every canonical append is fenced by producer epoch.
|
|
19
|
-
*/
|
|
20
|
-
readonly ownershipLeaseDuration: Schema.Int;
|
|
21
14
|
/**
|
|
22
15
|
* Maximum bytes for any single stored text value (canonical batch/record JSON, admission
|
|
23
16
|
* input payload, checkpoint JSON). Enforced typed BEFORE any write; must stay under the
|
|
@@ -25,9 +18,8 @@ declare const DoStorageConfigValue_base: Schema.Class<DoStorageConfigValue, Sche
|
|
|
25
18
|
*/
|
|
26
19
|
readonly maxStoredValueBytes: Schema.Int;
|
|
27
20
|
/**
|
|
28
|
-
*
|
|
29
|
-
* Schema decoding
|
|
30
|
-
* scan is an explicit opt-in integrity audit rather than a startup requirement.
|
|
21
|
+
* Audit stored payload schemas, identities, and batch coverage while opening the store.
|
|
22
|
+
* Per-operation Schema decoding remains enabled; this complete scan is an explicit opt-in.
|
|
31
23
|
*/
|
|
32
24
|
readonly verifyOnOpen: Schema.Boolean;
|
|
33
25
|
}>, {}>;
|
package/dist/DoStorageConfig.mjs
CHANGED
|
@@ -7,7 +7,6 @@ var DoStorageConfig_exports = /* @__PURE__ */ __exportAll({
|
|
|
7
7
|
DoStorageConfigValue: () => DoStorageConfigValue
|
|
8
8
|
});
|
|
9
9
|
const ObservationPollInterval = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
10
|
-
const OwnershipLeaseMillis = Schema.Int.check(Schema.isGreaterThan(0));
|
|
11
10
|
/**
|
|
12
11
|
* Default per-value byte bound, kept under the Durable Object platform's 2 MB SQLite value
|
|
13
12
|
* limit with a safety margin. This is the DC analogue of Node's 16 MB `BoundedStoredText`
|
|
@@ -25,22 +24,14 @@ const MaxStoredValueBytes = Schema.Int.check(Schema.isGreaterThan(0), Schema.isL
|
|
|
25
24
|
var DoStorageConfigValue = class extends Schema.Class("@effect-agent/storage-cloudflare/DoStorageConfigValue")({
|
|
26
25
|
observationPollInterval: ObservationPollInterval,
|
|
27
26
|
/**
|
|
28
|
-
* Submission ownership lease duration in milliseconds (D5). Inside one Durable Object the
|
|
29
|
-
* object itself is the serialized owner, so the lease's primary DC role is fencing work
|
|
30
|
-
* across DO incarnations (an evicted incarnation's claim becomes reclaimable); correctness
|
|
31
|
-
* never depends on it because every canonical append is fenced by producer epoch.
|
|
32
|
-
*/
|
|
33
|
-
ownershipLeaseDuration: OwnershipLeaseMillis,
|
|
34
|
-
/**
|
|
35
27
|
* Maximum bytes for any single stored text value (canonical batch/record JSON, admission
|
|
36
28
|
* input payload, checkpoint JSON). Enforced typed BEFORE any write; must stay under the
|
|
37
29
|
* platform's 2 MB per-value limit.
|
|
38
30
|
*/
|
|
39
31
|
maxStoredValueBytes: MaxStoredValueBytes,
|
|
40
32
|
/**
|
|
41
|
-
*
|
|
42
|
-
* Schema decoding
|
|
43
|
-
* scan is an explicit opt-in integrity audit rather than a startup requirement.
|
|
33
|
+
* Audit stored payload schemas, identities, and batch coverage while opening the store.
|
|
34
|
+
* Per-operation Schema decoding remains enabled; this complete scan is an explicit opt-in.
|
|
44
35
|
*/
|
|
45
36
|
verifyOnOpen: Schema.Boolean
|
|
46
37
|
}) {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DoStorageConfig.mjs","names":[],"sources":["../src/DoStorageConfig.ts"],"sourcesContent":["import { Context, Schema } from \"effect\";\n\nconst ObservationPollInterval = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));\
|
|
1
|
+
{"version":3,"file":"DoStorageConfig.mjs","names":[],"sources":["../src/DoStorageConfig.ts"],"sourcesContent":["import { Context, Schema } from \"effect\";\n\nconst ObservationPollInterval = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));\n\n/**\n * Default per-value byte bound, kept under the Durable Object platform's 2 MB SQLite value\n * limit with a safety margin. This is the DC analogue of Node's 16 MB `BoundedStoredText`\n * bound: both fail typed before mutating, only the threshold differs (a documented DN/DC\n * behavioral difference; Travel Planner payloads sit orders of magnitude below both).\n */\nexport const DEFAULT_MAX_STORED_VALUE_BYTES = 1_900_000;\n\n/** The hard schema ceiling for the configurable bound: never at or above the platform limit. */\nconst MaxStoredValueBytes = Schema.Int.check(\n Schema.isGreaterThan(0),\n Schema.isLessThanOrEqualTo(2_000_000),\n);\n\n/**\n * Validated construction configuration consumed by the Durable Object storage Layers. The\n * storage identity itself belongs to the SqlClient Layer (built from `ctx.storage`);\n * duplicating it here could silently diverge from the handle actually in use.\n */\nexport class DoStorageConfigValue extends Schema.Class<DoStorageConfigValue>(\n \"@effect-agent/storage-cloudflare/DoStorageConfigValue\",\n)({\n observationPollInterval: ObservationPollInterval,\n /**\n * Maximum bytes for any single stored text value (canonical batch/record JSON, admission\n * input payload, checkpoint JSON). Enforced typed BEFORE any write; must stay under the\n * platform's 2 MB per-value limit.\n */\n maxStoredValueBytes: MaxStoredValueBytes,\n /**\n * Audit stored payload schemas, identities, and batch coverage while opening the store.\n * Per-operation Schema decoding remains enabled; this complete scan is an explicit opt-in.\n */\n verifyOnOpen: Schema.Boolean,\n}) {}\n\n/** Explicit Durable Object storage configuration authority. */\nexport class DoStorageConfig extends Context.Service<DoStorageConfig, DoStorageConfigValue>()(\n \"@effect-agent/storage-cloudflare/DoStorageConfig\",\n) {}\n"],"mappings":";;;;;;;;AAEA,MAAM,0BAA0B,OAAO,IAAI,MAAM,OAAO,uBAAuB,CAAC,CAAC;;;;;;;AAQjF,MAAa,iCAAiC;;AAG9C,MAAM,sBAAsB,OAAO,IAAI,MACrC,OAAO,cAAc,CAAC,GACtB,OAAO,oBAAoB,GAAS,CACtC;;;;;;AAOA,IAAa,uBAAb,cAA0C,OAAO,MAC/C,uDACF,CAAC,CAAC;CACA,yBAAyB;;;;;;CAMzB,qBAAqB;;;;;CAKrB,cAAc,OAAO;AACvB,CAAC,CAAC,CAAC,CAAC;;AAGJ,IAAa,kBAAb,cAAqC,QAAQ,QAA+C,CAAC,CAC3F,kDACF,CAAC,CAAC,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
import { ThreadStoreDiagnostic } from "@yielded/agent/thread-store";
|
|
3
3
|
declare namespace DoStorageError_d_exports {
|
|
4
|
-
export { DoAppendConflict, DoCheckpointConflict,
|
|
4
|
+
export { DoAppendConflict, DoCheckpointConflict, DoLedgerError, DoStorageCompatibilityError, DoStorageCorruptionError, DoStorageError, DoStorageFailpointError, DoStorageFailpointLocation, DoValueBoundExceeded };
|
|
5
5
|
}
|
|
6
6
|
declare const DoStorageCompatibilityError_base: Schema.Class<DoStorageCompatibilityError, Schema.TaggedStruct<"DoStorageCompatibilityError", {
|
|
7
7
|
readonly actualVersion: Schema.Int;
|
|
@@ -54,27 +54,16 @@ declare class DoValueBoundExceeded extends DoValueBoundExceeded_base {
|
|
|
54
54
|
}
|
|
55
55
|
declare const DoAppendConflict_base: Schema.Class<DoAppendConflict, Schema.TaggedStruct<"DoAppendConflict", {
|
|
56
56
|
readonly message: Schema.String;
|
|
57
|
-
readonly reason: Schema.Literals<readonly ["batch-
|
|
57
|
+
readonly reason: Schema.Literals<readonly ["batch-content", "record-identity", "tail", "stale-command"]>;
|
|
58
58
|
readonly actualTailSequence: Schema.optionalKey<Schema.brand<Schema.Natural, "@effect-agent/thread/CanonicalSequence">>;
|
|
59
|
-
readonly actualTailDigest: Schema.optionalKey<Schema.String>;
|
|
60
59
|
}>, import("effect/Cause").YieldableError>;
|
|
61
60
|
/**
|
|
62
61
|
* A canonical batch retry conflicts with existing append state. Tail conflicts carry the
|
|
63
62
|
* actual committed tail as a diagnostic resume hint.
|
|
64
63
|
*/
|
|
65
64
|
declare class DoAppendConflict extends DoAppendConflict_base {}
|
|
66
|
-
declare const DoFenceRejected_base: Schema.Class<DoFenceRejected, Schema.TaggedStruct<"DoFenceRejected", {
|
|
67
|
-
readonly actualEpoch: Schema.brand<Schema.Natural, "@effect-agent/thread/ProducerEpoch">;
|
|
68
|
-
readonly message: Schema.String;
|
|
69
|
-
readonly producerEpoch: Schema.brand<Schema.Natural, "@effect-agent/thread/ProducerEpoch">;
|
|
70
|
-
}>, import("effect/Cause").YieldableError>;
|
|
71
|
-
/**
|
|
72
|
-
* A producer epoch does not match the Thread's current writer registration. Appends
|
|
73
|
-
* require the exact registered epoch, so both older and newer unregistered epochs are fenced;
|
|
74
|
-
* a newer epoch takes over by materializing first.
|
|
75
|
-
*/
|
|
76
|
-
declare class DoFenceRejected extends DoFenceRejected_base {}
|
|
77
65
|
declare const DoCheckpointConflict_base: Schema.Class<DoCheckpointConflict, Schema.TaggedStruct<"DoCheckpointConflict", {
|
|
66
|
+
readonly reason: Schema.Literals<readonly ["ahead-of-tail", "not-batch-boundary", "corrupt"]>;
|
|
78
67
|
readonly message: Schema.String;
|
|
79
68
|
}>, import("effect/Cause").YieldableError>;
|
|
80
69
|
/** A checkpoint conflicts with a previously stored checkpoint at the same offset. */
|
|
@@ -87,15 +76,15 @@ declare class DoCheckpointConflict extends DoCheckpointConflict_base {}
|
|
|
87
76
|
* both platforms — the DN process-kill evidence and the DC eviction evidence address identical
|
|
88
77
|
* locations. There is intentionally no Cloudflare-only location.
|
|
89
78
|
*/
|
|
90
|
-
declare const DoStorageFailpointLocation: Schema.Literals<readonly ["
|
|
79
|
+
declare const DoStorageFailpointLocation: Schema.Literals<readonly ["materialize:before", "materialize:after", "append:before", "append:after-batch-insert", "append:after-record-insert", "append:after-tail-update", "append:after", "export:after-thread-read", "save-checkpoint:before", "save-checkpoint:after", "ledger:admit:before", "ledger:admit:after", "ledger:mark-ready:before", "ledger:mark-ready:after", "ledger:claim:before", "ledger:claim:after", "ledger:mark-input-applied:before", "ledger:mark-input-applied:after", "ledger:finalize-settlement:before", "ledger:finalize-settlement:after", "ledger:request-abort:before", "ledger:request-abort:after", "ledger:claim-joining:before", "ledger:claim-joining:after", "ledger:mark-joined:before", "ledger:mark-joined:after", "ledger:revert-joining:before", "ledger:revert-joining:after", "ledger:suspend:before", "ledger:suspend:after", "ledger:approval-decision:before", "ledger:approval-decision:after", "ledger:mark-unknown:before", "ledger:mark-unknown:after", "ledger:unknown-resolution:before", "ledger:unknown-resolution:after", "ledger:child-reservation:before", "ledger:child-reservation:after", "ledger:child-attach:before", "ledger:child-attach:after", "ledger:child-release-pending:before", "ledger:child-release-pending:after", "ledger:child-release:before", "ledger:child-release:after", "ledger:child-settled:before", "ledger:child-settled:after"]>;
|
|
91
80
|
type DoStorageFailpointLocation = typeof DoStorageFailpointLocation.Type;
|
|
92
81
|
declare const DoStorageFailpointError_base: Schema.Class<DoStorageFailpointError, Schema.TaggedStruct<"DoStorageFailpointError", {
|
|
93
|
-
readonly location: Schema.Literals<readonly ["
|
|
82
|
+
readonly location: Schema.Literals<readonly ["materialize:before", "materialize:after", "append:before", "append:after-batch-insert", "append:after-record-insert", "append:after-tail-update", "append:after", "export:after-thread-read", "save-checkpoint:before", "save-checkpoint:after", "ledger:admit:before", "ledger:admit:after", "ledger:mark-ready:before", "ledger:mark-ready:after", "ledger:claim:before", "ledger:claim:after", "ledger:mark-input-applied:before", "ledger:mark-input-applied:after", "ledger:finalize-settlement:before", "ledger:finalize-settlement:after", "ledger:request-abort:before", "ledger:request-abort:after", "ledger:claim-joining:before", "ledger:claim-joining:after", "ledger:mark-joined:before", "ledger:mark-joined:after", "ledger:revert-joining:before", "ledger:revert-joining:after", "ledger:suspend:before", "ledger:suspend:after", "ledger:approval-decision:before", "ledger:approval-decision:after", "ledger:mark-unknown:before", "ledger:mark-unknown:after", "ledger:unknown-resolution:before", "ledger:unknown-resolution:after", "ledger:child-reservation:before", "ledger:child-reservation:after", "ledger:child-attach:before", "ledger:child-attach:after", "ledger:child-release-pending:before", "ledger:child-release-pending:after", "ledger:child-release:before", "ledger:child-release:after", "ledger:child-settled:before", "ledger:child-settled:after"]>;
|
|
94
83
|
}>, import("effect/Cause").YieldableError>;
|
|
95
84
|
/** Deterministic test-only fault or pause injected at a Durable Object storage boundary. */
|
|
96
85
|
declare class DoStorageFailpointError extends DoStorageFailpointError_base {
|
|
97
86
|
get message(): string;
|
|
98
87
|
}
|
|
99
88
|
//#endregion
|
|
100
|
-
export {
|
|
101
|
-
//# sourceMappingURL=DoStorageError-
|
|
89
|
+
export { DoStorageCorruptionError as a, DoStorageFailpointError as c, DoStorageCompatibilityError as i, DoStorageFailpointLocation as l, DoCheckpointConflict as n, DoStorageError as o, DoLedgerError as r, DoStorageError_d_exports as s, DoAppendConflict as t, DoValueBoundExceeded as u };
|
|
90
|
+
//# sourceMappingURL=DoStorageError-CxjMnzUA.d.mts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { DoAppendConflict, DoCheckpointConflict,
|
|
1
|
+
import { a as DoStorageCorruptionError, c as DoStorageFailpointError, i as DoStorageCompatibilityError, l as DoStorageFailpointLocation, n as DoCheckpointConflict, o as DoStorageError, r as DoLedgerError, t as DoAppendConflict, u as DoValueBoundExceeded } from "./DoStorageError-CxjMnzUA.mjs";
|
|
2
|
+
export { DoAppendConflict, DoCheckpointConflict, DoLedgerError, DoStorageCompatibilityError, DoStorageCorruptionError, DoStorageError, DoStorageFailpointError, DoStorageFailpointLocation, DoValueBoundExceeded };
|