effect-cf 0.52.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +7 -1
- package/dist/AnalyticsEngine.d.mts +2 -2
- package/dist/AnalyticsEngine.mjs +3 -3
- package/dist/CloudflareOtlp.d.mts +3 -3
- package/dist/CloudflareOtlp.mjs +7 -7
- package/dist/D1.d.mts +1 -1
- package/dist/DurableObject.d.mts +1 -0
- package/dist/DurableObject.mjs +33 -11
- package/dist/DurableObjectAlarm.d.mts +74 -9
- package/dist/DurableObjectAlarm.mjs +245 -35
- package/dist/DurableObjectRpcWebSocket.d.mts +3 -3
- package/dist/DurableObjectRpcWebSocket.mjs +3 -3
- package/dist/DurableObjectSqlite.d.mts +1 -1
- package/dist/DurableObjectSqlite.mjs +2 -2
- package/dist/HyperdrivePg.d.mts +1 -1
- package/dist/Mcp.d.mts +3 -3
- package/dist/Mcp.mjs +3 -3
- package/dist/RateLimit.d.mts +50 -0
- package/dist/RateLimit.mjs +46 -0
- package/dist/RpcWebSocketClient.d.mts +6 -6
- package/dist/RpcWebSocketClient.mjs +3 -3
- package/dist/Worker.d.mts +2 -2
- package/dist/Worker.mjs +4 -4
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/internal/Runtime.mjs +5 -3
- package/dist/internal/Telemetry.mjs +1 -1
- package/package.json +5 -5
- package/src/AnalyticsEngine.ts +4 -4
- package/src/CloudflareOtlp.ts +8 -8
- package/src/D1.ts +1 -1
- package/src/DurableObject.ts +93 -30
- package/src/DurableObjectAlarm.ts +601 -59
- package/src/DurableObjectRpcWebSocket.ts +3 -3
- package/src/DurableObjectSqlite.ts +2 -2
- package/src/HyperdrivePg.ts +1 -1
- package/src/Mcp.ts +4 -4
- package/src/RateLimit.ts +110 -0
- package/src/RpcWebSocketClient.ts +6 -6
- package/src/Worker.ts +4 -4
- package/src/index.ts +1 -0
- package/src/internal/Entrypoint.ts +8 -4
- package/src/internal/Runtime.ts +12 -7
- package/src/internal/Telemetry.ts +1 -1
|
@@ -12,26 +12,34 @@ import * as Exit from "effect/Exit";
|
|
|
12
12
|
import * as Duration from "effect/Duration";
|
|
13
13
|
import * as Clock from "effect/Clock";
|
|
14
14
|
import * as DateTime from "effect/DateTime";
|
|
15
|
+
import * as Deferred from "effect/Deferred";
|
|
16
|
+
import * as Semaphore from "effect/Semaphore";
|
|
15
17
|
//#region src/DurableObjectAlarm.ts
|
|
16
18
|
var DurableObjectAlarm_exports = /* @__PURE__ */ __exportAll({
|
|
17
19
|
AlarmParked: () => AlarmParked,
|
|
18
20
|
AlarmReporter: () => AlarmReporter,
|
|
19
21
|
DEFAULT_MIN_REPEAT_INTERVAL_MS: () => DEFAULT_MIN_REPEAT_INTERVAL_MS,
|
|
22
|
+
DispatchAfterEvent: () => DispatchAfterEvent,
|
|
20
23
|
DurableObjectAlarm: () => DurableObjectAlarm,
|
|
21
24
|
DurableObjectAlarmEvent: () => DurableObjectAlarmEvent,
|
|
25
|
+
HasDueAlarms: () => HasDueAlarms,
|
|
22
26
|
InvalidAlarmPayloadError: () => InvalidAlarmPayloadError,
|
|
23
27
|
InvalidAlarmRefError: () => InvalidAlarmRefError,
|
|
28
|
+
InvalidAlarmRegistrationError: () => InvalidAlarmRegistrationError,
|
|
24
29
|
InvalidProcessDueAlarmsOptionsError: () => InvalidProcessDueAlarmsOptionsError,
|
|
25
30
|
InvalidRepeatEveryError: () => InvalidRepeatEveryError,
|
|
26
31
|
InvalidScheduleConfigurationError: () => InvalidScheduleConfigurationError,
|
|
27
32
|
MIN_REPEAT_INTERVAL_MS: () => MIN_REPEAT_INTERVAL_MS,
|
|
28
33
|
MIN_RETRY_DELAY_MS: () => MIN_RETRY_DELAY_MS,
|
|
29
34
|
PARKED_RETRY_DELAY_MS: () => PARKED_RETRY_DELAY_MS,
|
|
35
|
+
RunAlarm: () => RunAlarm,
|
|
30
36
|
ScheduleConfiguration: () => ScheduleConfiguration,
|
|
31
37
|
StoredAlarmDecodeError: () => StoredAlarmDecodeError,
|
|
32
38
|
Tag: () => Tag,
|
|
33
39
|
UNCHANGED_ATTEMPT_BUDGET: () => 8,
|
|
34
40
|
define: () => define,
|
|
41
|
+
dispatchRawAlarm: () => dispatchRawAlarm,
|
|
42
|
+
mergeAll: () => mergeAll,
|
|
35
43
|
processDue: () => processDue
|
|
36
44
|
});
|
|
37
45
|
const INIT_TABLE_SQL = `
|
|
@@ -39,6 +47,7 @@ CREATE TABLE IF NOT EXISTS effect_cf_scheduled_alarms (
|
|
|
39
47
|
storage_id TEXT PRIMARY KEY,
|
|
40
48
|
alarm_id TEXT NOT NULL,
|
|
41
49
|
tag TEXT NOT NULL,
|
|
50
|
+
lifecycle TEXT NOT NULL DEFAULT 'automatic',
|
|
42
51
|
run_at INTEGER NOT NULL,
|
|
43
52
|
wake_at INTEGER NOT NULL DEFAULT 0,
|
|
44
53
|
repeat_every_ms INTEGER,
|
|
@@ -54,6 +63,7 @@ CREATE TABLE IF NOT EXISTS effect_cf_alarm_attempts (
|
|
|
54
63
|
);
|
|
55
64
|
`;
|
|
56
65
|
const WAKE_INDEX = "idx_effect_cf_scheduled_alarms_wake_at_storage_id";
|
|
66
|
+
const LIFECYCLE_INDEX = "idx_effect_cf_scheduled_alarms_lifecycle_wake_at_storage_id";
|
|
57
67
|
const DEFAULT_PROCESS_DUE_ALARMS_LIMIT = 100;
|
|
58
68
|
const MIN_RETRY_DELAY_MS = 1e3;
|
|
59
69
|
/** Minimum and default parked recovery interval. */
|
|
@@ -65,7 +75,9 @@ const DEFAULT_MIN_REPEAT_INTERVAL_MS = 6e4;
|
|
|
65
75
|
/** Optional policy overrides. Provide with Layer.succeed in the Durable Object's application layer. */
|
|
66
76
|
const ScheduleConfiguration = Context.Reference("effect-cf/DurableObjectAlarm/ScheduleConfiguration", { defaultValue: () => ({}) });
|
|
67
77
|
const safeIntegerAtLeast = (minimum) => S.Int.check(S.isGreaterThanOrEqualTo(minimum), S.isLessThanOrEqualTo(Number.MAX_SAFE_INTEGER));
|
|
78
|
+
const AlarmLifecycleSchema = S.Literals(["automatic", "manual"]);
|
|
68
79
|
const ScheduleConfigurationSchema = S.Struct({
|
|
80
|
+
dispatchAfterEvent: S.Boolean,
|
|
69
81
|
minimumRetryDelay: safeIntegerAtLeast(MIN_RETRY_DELAY_MS),
|
|
70
82
|
unchangedAttemptBudget: safeIntegerAtLeast(1),
|
|
71
83
|
parkedRetryDelay: safeIntegerAtLeast(PARKED_RETRY_DELAY_MS),
|
|
@@ -89,6 +101,9 @@ const AlarmParked = S.TaggedStruct("AlarmParked", {
|
|
|
89
101
|
/** Install with Layer.succeed / Effect.provideService. Reporting cannot undo a committed guard. */
|
|
90
102
|
const AlarmReporter = Context.Reference("effect-cf/DurableObjectAlarm/AlarmReporter", { defaultValue: () => (event) => Effect.logWarning(event) });
|
|
91
103
|
const CurrentAlarmPass = Context.Reference("effect-cf/DurableObjectAlarm/CurrentAlarmPass", { defaultValue: () => void 0 });
|
|
104
|
+
/** One dispatcher's view of a registration pass: its tags, shared manual permits, raw tracking. */
|
|
105
|
+
const CurrentDispatch = Context.Reference("effect-cf/DurableObjectAlarm/CurrentDispatch", { defaultValue: () => void 0 });
|
|
106
|
+
const ManualTags = Symbol("effect-cf/DurableObjectAlarm/ManualTags");
|
|
92
107
|
var InvalidAlarmRefError = class extends Data.TaggedError("InvalidAlarmRefError") {
|
|
93
108
|
get message() {
|
|
94
109
|
return `Invalid Durable Object alarm ref: ${causeMessage(this.cause)}`;
|
|
@@ -114,6 +129,11 @@ var InvalidScheduleConfigurationError = class extends Data.TaggedError("InvalidS
|
|
|
114
129
|
return `Invalid Durable Object alarm configuration: ${causeMessage(this.cause)}`;
|
|
115
130
|
}
|
|
116
131
|
};
|
|
132
|
+
var InvalidAlarmRegistrationError = class extends Data.TaggedError("InvalidAlarmRegistrationError") {
|
|
133
|
+
get message() {
|
|
134
|
+
return `Invalid Durable Object alarm registration: ${causeMessage(this.cause)}`;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
117
137
|
const getScheduleConfiguration = Effect.fnUntraced(function* (defaults) {
|
|
118
138
|
const input = {
|
|
119
139
|
...defaults,
|
|
@@ -121,6 +141,7 @@ const getScheduleConfiguration = Effect.fnUntraced(function* (defaults) {
|
|
|
121
141
|
};
|
|
122
142
|
return yield* Effect.try({
|
|
123
143
|
try: () => S.decodeUnknownSync(ScheduleConfigurationSchema)({
|
|
144
|
+
dispatchAfterEvent: input.dispatchAfterEvent ?? false,
|
|
124
145
|
minimumRetryDelay: Math.ceil(Duration.toMillis(input.minimumRetryDelay ?? 1e3)),
|
|
125
146
|
unchangedAttemptBudget: input.unchangedAttemptBudget ?? 8,
|
|
126
147
|
parkedRetryDelay: Math.ceil(Duration.toMillis(input.parkedRetryDelay ?? 36e5)),
|
|
@@ -146,7 +167,14 @@ const AlarmRefSchema = S.Struct({
|
|
|
146
167
|
tag: S.NonEmptyString
|
|
147
168
|
});
|
|
148
169
|
const decodeAlarmRef = (input) => S.decodeUnknownEffect(AlarmRefSchema)(input).pipe(Effect.mapError((cause) => new InvalidAlarmRefError({ cause })));
|
|
170
|
+
/** @internal */
|
|
171
|
+
const RunAlarm = Symbol("effect-cf/DurableObjectAlarm/RunAlarm");
|
|
172
|
+
/** @internal */
|
|
173
|
+
const DispatchAfterEvent = Symbol("effect-cf/DurableObjectAlarm/DispatchAfterEvent");
|
|
174
|
+
/** @internal */
|
|
175
|
+
const HasDueAlarms = Symbol("effect-cf/DurableObjectAlarm/HasDueAlarms");
|
|
149
176
|
const StoredPayloadString = S.fromJsonString(S.Json);
|
|
177
|
+
const StoredTags = S.fromJsonString(S.Array(S.String));
|
|
150
178
|
const decodeStoredPayload = (row) => S.decodeUnknownEffect(StoredPayloadString)(row.payload).pipe(Effect.mapError((cause) => new StoredAlarmDecodeError({
|
|
151
179
|
cause,
|
|
152
180
|
storageId: row.storage_id
|
|
@@ -154,15 +182,19 @@ const decodeStoredPayload = (row) => S.decodeUnknownEffect(StoredPayloadString)(
|
|
|
154
182
|
const encodeStoredPayload = (payload) => S.encodeEffect(StoredPayloadString)(payload).pipe(Effect.mapError((cause) => new InvalidAlarmPayloadError({ cause })));
|
|
155
183
|
const ensureTable = Effect.fnUntraced(function* (state) {
|
|
156
184
|
yield* state.storage.sql.exec(INIT_TABLE_SQL);
|
|
157
|
-
if ((yield* (yield* state.storage.sql.exec("SELECT name FROM sqlite_master WHERE type = 'index' AND name = ?",
|
|
185
|
+
if ((yield* (yield* state.storage.sql.exec("SELECT name FROM sqlite_master WHERE type = 'index' AND name = ?", LIFECYCLE_INDEX)).toArray()).length > 0) return;
|
|
158
186
|
const columns = yield* state.storage.sql.exec("SELECT name FROM pragma_table_info('effect_cf_scheduled_alarms')");
|
|
159
|
-
|
|
187
|
+
const names = new Set((yield* columns.toArray()).map((column) => column.name));
|
|
188
|
+
if (!names.has("lifecycle")) yield* state.storage.sql.exec("ALTER TABLE effect_cf_scheduled_alarms ADD COLUMN lifecycle TEXT NOT NULL DEFAULT 'automatic'");
|
|
189
|
+
if (!names.has("wake_at")) yield* state.storage.sql.exec("ALTER TABLE effect_cf_scheduled_alarms ADD COLUMN wake_at INTEGER NOT NULL DEFAULT 0");
|
|
160
190
|
yield* state.storage.sql.exec(`UPDATE effect_cf_scheduled_alarms SET
|
|
161
191
|
wake_at = MAX(run_at, COALESCE((SELECT retry_at FROM effect_cf_alarm_attempts s
|
|
162
192
|
WHERE s.storage_id = effect_cf_scheduled_alarms.storage_id), run_at))`);
|
|
163
193
|
yield* state.storage.sql.exec("DROP INDEX IF EXISTS idx_effect_cf_scheduled_alarms_run_at_storage_id");
|
|
164
194
|
yield* state.storage.sql.exec(`CREATE INDEX IF NOT EXISTS ${WAKE_INDEX}
|
|
165
195
|
ON effect_cf_scheduled_alarms (wake_at, storage_id)`);
|
|
196
|
+
yield* state.storage.sql.exec(`CREATE INDEX IF NOT EXISTS ${LIFECYCLE_INDEX}
|
|
197
|
+
ON effect_cf_scheduled_alarms (lifecycle, wake_at, storage_id)`);
|
|
166
198
|
});
|
|
167
199
|
const toRepeatEveryMillis = (input, minimum) => {
|
|
168
200
|
if (input === void 0) return Effect.succeed(null);
|
|
@@ -208,6 +240,71 @@ const processDue = (handle, options = {}) => Effect.gen(function* () {
|
|
|
208
240
|
return yield* (yield* DurableObjectAlarm).processDueAlarms(handle, options);
|
|
209
241
|
});
|
|
210
242
|
const TypedAlarmSchedulerTypeId = Symbol.for("effect-cf/DurableObjectAlarm/TypedScheduler");
|
|
243
|
+
const RegistrationParts = Symbol("effect-cf/DurableObjectAlarm/RegistrationParts");
|
|
244
|
+
const emptyResult = {
|
|
245
|
+
failed: [],
|
|
246
|
+
handled: [],
|
|
247
|
+
parked: []
|
|
248
|
+
};
|
|
249
|
+
const missingAlarm = (tag) => new InvalidAlarmRegistrationError({ cause: /* @__PURE__ */ new Error(`No manual handler registered for alarm tag "${tag}"`) });
|
|
250
|
+
const validateRegistration = (parts) => Effect.try({
|
|
251
|
+
try: () => {
|
|
252
|
+
if (parts.invalid !== void 0) throw new Error(parts.invalid);
|
|
253
|
+
const tags = parts.dispatchers.flatMap((dispatcher) => dispatcher.tags);
|
|
254
|
+
S.decodeUnknownSync(S.Array(S.NonEmptyString))([...parts.services, ...tags]);
|
|
255
|
+
if (new Set(parts.services).size !== parts.services.length || new Set(tags).size !== tags.length) throw new Error("Alarm service keys and definition tags must be unique within a Durable Object");
|
|
256
|
+
},
|
|
257
|
+
catch: (cause) => new InvalidAlarmRegistrationError({ cause })
|
|
258
|
+
});
|
|
259
|
+
const runRegistrations = (parts, rawAlarm) => Effect.gen(function* () {
|
|
260
|
+
yield* validateRegistration(parts);
|
|
261
|
+
const alarms = yield* DurableObjectAlarm;
|
|
262
|
+
const permits = yield* Semaphore.make(4);
|
|
263
|
+
const parentRaw = (yield* CurrentDispatch)?.raw;
|
|
264
|
+
const recoveryScope = {
|
|
265
|
+
tags: parts.dispatchers.flatMap((dispatcher) => dispatcher.tags),
|
|
266
|
+
exclude: true,
|
|
267
|
+
permits,
|
|
268
|
+
raw: parentRaw
|
|
269
|
+
};
|
|
270
|
+
const recovery = rawAlarm === void 0 ? makeDefinition({}).handlers({}).pipe(Effect.provideService(CurrentDispatch, recoveryScope)) : Effect.suspend(() => {
|
|
271
|
+
const raw = { processed: false };
|
|
272
|
+
return rawAlarm.pipe(Effect.onExit(() => raw.processed ? Effect.void : makeDefinition({}).handlers({}).pipe(Effect.asVoid)), Effect.provideService(CurrentDispatch, {
|
|
273
|
+
...recoveryScope,
|
|
274
|
+
raw
|
|
275
|
+
}), Effect.as(emptyResult));
|
|
276
|
+
});
|
|
277
|
+
return yield* alarms.deferWakes(Effect.gen(function* () {
|
|
278
|
+
const run = (dispatchers) => Effect.forEach(dispatchers, (dispatcher) => dispatcher.run.pipe(Effect.catchTag("InvalidProcessDueAlarmsOptionsError", (error) => Effect.fail(error).pipe(Effect.onExit(() => makeDefinition({}).handlers({}).pipe(Effect.asVoid)))), Effect.provideService(CurrentDispatch, {
|
|
279
|
+
tags: dispatcher.tags,
|
|
280
|
+
exclude: false,
|
|
281
|
+
permits,
|
|
282
|
+
raw: parentRaw
|
|
283
|
+
}), Effect.exit), { concurrency: "unbounded" });
|
|
284
|
+
const automatic = parts.dispatchers.filter((dispatcher) => rawAlarm !== void 0 && dispatcher.automatic);
|
|
285
|
+
const independent = parts.dispatchers.filter((dispatcher) => rawAlarm === void 0 || !dispatcher.automatic);
|
|
286
|
+
const exits = (yield* Effect.all([run(independent), run(automatic).pipe(Effect.flatMap((exits) => Effect.map(Effect.exit(recovery), (exit) => [...exits, exit])))], { concurrency: "unbounded" })).flat();
|
|
287
|
+
yield* Exit.asVoidAll(exits);
|
|
288
|
+
return {
|
|
289
|
+
failed: exits.flatMap((exit) => Exit.isSuccess(exit) ? exit.value.failed : []),
|
|
290
|
+
handled: exits.flatMap((exit) => Exit.isSuccess(exit) ? exit.value.handled : []),
|
|
291
|
+
parked: exits.flatMap((exit) => Exit.isSuccess(exit) ? exit.value.parked : [])
|
|
292
|
+
};
|
|
293
|
+
}));
|
|
294
|
+
});
|
|
295
|
+
const makeRegistration = (layer, parts) => ({
|
|
296
|
+
[RegistrationParts]: parts,
|
|
297
|
+
layer: layer.pipe(Layer.provide(Layer.effectDiscard(validateRegistration(parts)))),
|
|
298
|
+
run: runRegistrations(parts)
|
|
299
|
+
});
|
|
300
|
+
function mergeAll(registration, ...others) {
|
|
301
|
+
const parts = [registration, ...others].map((item) => item[RegistrationParts]);
|
|
302
|
+
return makeRegistration(Layer.mergeAll(registration.layer, ...others.map((item) => item.layer)), {
|
|
303
|
+
services: parts.flatMap((part) => part?.services ?? []),
|
|
304
|
+
dispatchers: parts.flatMap((part) => part?.dispatchers ?? []),
|
|
305
|
+
invalid: parts.some((part) => part === void 0) ? "mergeAll requires registrations returned by Tag.handlers" : parts.find((part) => part?.invalid !== void 0)?.invalid
|
|
306
|
+
});
|
|
307
|
+
}
|
|
211
308
|
const isAlarmDefinitionConfig = (definition) => Predicate.isObject(definition) && "payload" in definition;
|
|
212
309
|
const getAlarmDefinitionSchema = (definition) => isAlarmDefinitionConfig(definition) ? definition.payload : definition;
|
|
213
310
|
const getAlarmDefinitionFailureAction = (definition) => {
|
|
@@ -227,7 +324,8 @@ const makeDefinition = (definitions) => {
|
|
|
227
324
|
const payload = yield* S.encodeEffect(getAlarmDefinitionSchema(definition))(input.payload).pipe(Effect.flatMap(S.decodeUnknownEffect(S.Json)), Effect.mapError((cause) => new InvalidAlarmPayloadError({ cause })));
|
|
228
325
|
yield* mutations[method]({
|
|
229
326
|
...input,
|
|
230
|
-
payload
|
|
327
|
+
payload,
|
|
328
|
+
lifecycle: isAlarmDefinitionConfig(definition) ? definition.lifecycle : void 0
|
|
231
329
|
});
|
|
232
330
|
});
|
|
233
331
|
return {
|
|
@@ -243,6 +341,7 @@ const makeDefinition = (definitions) => {
|
|
|
243
341
|
make: (alarms) => ({
|
|
244
342
|
[TypedAlarmSchedulerTypeId]: TypedAlarmSchedulerTypeId,
|
|
245
343
|
...bind(alarms),
|
|
344
|
+
deferWakes: alarms.deferWakes,
|
|
246
345
|
getAlarmStatus: (input) => alarms.getAlarmStatus(input),
|
|
247
346
|
transaction: (closure) => alarms.transaction((tx) => closure(bind(tx)))
|
|
248
347
|
}),
|
|
@@ -264,6 +363,7 @@ const makeDefinition = (definitions) => {
|
|
|
264
363
|
});
|
|
265
364
|
}), {
|
|
266
365
|
...options,
|
|
366
|
+
[ManualTags]: new Set(Object.entries(definitions).filter(([, definition]) => isAlarmDefinitionConfig(definition) && definition.lifecycle === "manual").map(([tag]) => tag)),
|
|
267
367
|
onFailure: (failure) => Effect.gen(function* () {
|
|
268
368
|
const action = getAlarmDefinitionFailureAction(definitionFor(failure.tag));
|
|
269
369
|
const optionAction = options?.onFailure === void 0 ? void 0 : yield* options.onFailure(failure);
|
|
@@ -274,32 +374,70 @@ const makeDefinition = (definitions) => {
|
|
|
274
374
|
};
|
|
275
375
|
/** Handler-only definitions for applications using the raw scheduler. Prefer Tag for typed scheduling. */
|
|
276
376
|
const define = (definitions) => ({ handlers: makeDefinition(definitions).handlers });
|
|
377
|
+
const hasSchedulerTables = Effect.fnUntraced(function* (state) {
|
|
378
|
+
return yield* Effect.gen(function* () {
|
|
379
|
+
if (state.raw.storage.sql === void 0) return false;
|
|
380
|
+
return (yield* (yield* state.storage.sql.exec("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ? LIMIT 1", "effect_cf_scheduled_alarms")).toArray()).length > 0;
|
|
381
|
+
}).pipe(Effect.catchIf((error) => error.cause instanceof Error && (error.cause.message.startsWith("SQL is not enabled for this Durable Object class") || error.cause.message.startsWith("This Durable Object is not backed by SQLite storage")), () => Effect.succeed(false)));
|
|
382
|
+
});
|
|
383
|
+
/** @internal Preserve custom dispatch while recovering retained alarms after deployments. */
|
|
384
|
+
const dispatchRawAlarm = (rawAlarm, registration) => Effect.gen(function* () {
|
|
385
|
+
const parts = registration?.[RegistrationParts];
|
|
386
|
+
if (parts !== void 0) return yield* runRegistrations(parts, rawAlarm).pipe(Effect.asVoid);
|
|
387
|
+
const custom = registration === void 0 ? rawAlarm : registration.run.pipe(Effect.andThen(rawAlarm));
|
|
388
|
+
const state = yield* DurableObjectState;
|
|
389
|
+
if (!(yield* hasSchedulerTables(state))) return yield* custom;
|
|
390
|
+
return yield* runRegistrations({
|
|
391
|
+
services: [],
|
|
392
|
+
dispatchers: []
|
|
393
|
+
}, custom).pipe(Effect.asVoid);
|
|
394
|
+
});
|
|
277
395
|
/** The typed scheduler becomes available when its handlers are registered on a Durable Object. */
|
|
278
396
|
const Tag = () => (id, definitions) => {
|
|
279
397
|
const tag = Context.Service()(id);
|
|
280
398
|
const definition = makeDefinition(definitions);
|
|
281
|
-
return Object.assign(tag, { handlers: (handlers, options) => ({
|
|
282
|
-
|
|
283
|
-
|
|
399
|
+
return Object.assign(tag, { handlers: (handlers, options) => makeRegistration(Layer.effect(tag, Effect.map(DurableObjectAlarm, definition.make)), {
|
|
400
|
+
services: [id],
|
|
401
|
+
dispatchers: [{
|
|
402
|
+
tags: Object.keys(definitions),
|
|
403
|
+
automatic: Object.values(definitions).some((entry) => !isAlarmDefinitionConfig(entry) || entry.lifecycle !== "manual"),
|
|
404
|
+
run: definition.handlers(handlers, options)
|
|
405
|
+
}]
|
|
284
406
|
}) });
|
|
285
407
|
};
|
|
286
408
|
var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("effect-cf/DurableObjectAlarm") {
|
|
287
409
|
static layer = Layer.effect(DurableObjectAlarm, Effect.gen(function* () {
|
|
288
410
|
const state = yield* DurableObjectState;
|
|
289
411
|
const configurationDefaults = { ...yield* ScheduleConfiguration };
|
|
412
|
+
let wakeDeferrals = 0;
|
|
413
|
+
let wakesReady;
|
|
414
|
+
let pendingAlarm;
|
|
415
|
+
let dispatchActive = false;
|
|
416
|
+
let dispatchNeedsReconcile = false;
|
|
417
|
+
let deferredRecoveryDelay = PARKED_RETRY_DELAY_MS;
|
|
418
|
+
let deferredRecoveryAt = 0;
|
|
290
419
|
const readRow = Effect.fnUntraced(function* (storageId) {
|
|
291
420
|
return (yield* (yield* state.storage.sql.exec(`${alarmRowsSql} WHERE a.storage_id = ?`, storageId)).toArray())[0];
|
|
292
421
|
});
|
|
422
|
+
const writeNativeAlarm = (runAt) => Effect.tryPromise({
|
|
423
|
+
try: () => runAt === null ? state.raw.storage.deleteAlarm() : state.raw.storage.setAlarm(runAt),
|
|
424
|
+
catch: (cause) => new StorageOperationError({
|
|
425
|
+
operation: runAt === null ? "deleteAlarm" : "setAlarm",
|
|
426
|
+
cause
|
|
427
|
+
})
|
|
428
|
+
});
|
|
293
429
|
const reconcileAlarm = Effect.fn("DurableObjectAlarm.reconcileAlarm")(function* () {
|
|
430
|
+
if (wakeDeferrals > 0 || dispatchActive) {
|
|
431
|
+
if (dispatchActive) dispatchNeedsReconcile = true;
|
|
432
|
+
const current = yield* state.storage.getAlarm();
|
|
433
|
+
const now = yield* Clock.currentTimeMillis;
|
|
434
|
+
if (deferredRecoveryAt <= now) deferredRecoveryAt = now + deferredRecoveryDelay;
|
|
435
|
+
if (current === null || current <= now || current > deferredRecoveryAt) yield* writeNativeAlarm(deferredRecoveryAt);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
294
438
|
const next = (yield* (yield* state.storage.sql.exec(`SELECT wake_at AS run_at FROM effect_cf_scheduled_alarms
|
|
295
|
-
|
|
296
|
-
yield*
|
|
297
|
-
try: () => next === void 0 ? state.raw.storage.deleteAlarm() : state.raw.storage.setAlarm(next.run_at),
|
|
298
|
-
catch: (cause) => new StorageOperationError({
|
|
299
|
-
operation: next === void 0 ? "deleteAlarm" : "setAlarm",
|
|
300
|
-
cause
|
|
301
|
-
})
|
|
302
|
-
});
|
|
439
|
+
ORDER BY wake_at, storage_id LIMIT 1`)).toArray())[0];
|
|
440
|
+
yield* writeNativeAlarm(next?.run_at ?? null);
|
|
303
441
|
});
|
|
304
442
|
const writeAttempts = Effect.fnUntraced(function* (storageId, attempts, parked, retryAt, progress) {
|
|
305
443
|
yield* state.storage.sql.exec(`INSERT OR REPLACE INTO effect_cf_alarm_attempts
|
|
@@ -318,17 +456,15 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
318
456
|
const scheduleAlarm = Effect.fn("DurableObjectAlarm.scheduleAlarm")(function* (input, earlier, reports) {
|
|
319
457
|
const configuration = yield* getScheduleConfiguration(configurationDefaults);
|
|
320
458
|
const ref = yield* decodeAlarmRef(input);
|
|
459
|
+
const lifecycle = yield* S.decodeUnknownEffect(AlarmLifecycleSchema)(input.lifecycle ?? "automatic").pipe(Effect.mapError((cause) => new InvalidAlarmRefError({ cause })));
|
|
460
|
+
if (lifecycle === "manual" && (input.repeatEvery !== void 0 || input.progress !== void 0)) return yield* Effect.fail(new InvalidAlarmRefError({ cause: /* @__PURE__ */ new Error("Manual alarms own their repeats and progress budgets") }));
|
|
321
461
|
const repeatEveryMillis = yield* toRepeatEveryMillis(input.repeatEvery, configuration.minimumRepeatInterval);
|
|
322
462
|
const payload = yield* encodeStoredPayload(input.payload);
|
|
323
463
|
const storageId = getScheduledEventId(ref);
|
|
324
464
|
const existing = yield* readRow(storageId);
|
|
325
465
|
const pass = yield* CurrentAlarmPass;
|
|
326
|
-
const source = pass?.row;
|
|
466
|
+
const source = lifecycle === "automatic" && pass?.row.lifecycle === "automatic" ? pass.row : void 0;
|
|
327
467
|
const progress = existing?.progress ?? source?.progress ?? -1;
|
|
328
|
-
if (pass !== void 0 && !pass.active) return yield* Effect.fail(new StorageOperationError({
|
|
329
|
-
operation: "alarm.schedule",
|
|
330
|
-
cause: /* @__PURE__ */ new Error("Alarm handlers cannot schedule detached work after their pass ends")
|
|
331
|
-
}));
|
|
332
468
|
if (input.progress !== void 0) yield* S.decodeUnknownEffect(S.Natural)(input.progress).pipe(Effect.mapError((cause) => new InvalidAlarmRefError({ cause })));
|
|
333
469
|
if (source === void 0 && input.progress !== void 0 && input.progress <= progress) return;
|
|
334
470
|
const progressed = input.progress !== void 0 && input.progress > progress;
|
|
@@ -341,11 +477,11 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
341
477
|
const keepEarlier = earlier && existing !== void 0 && existing.run_at <= runAt;
|
|
342
478
|
const scheduledAt = keepEarlier ? existing.run_at : runAt;
|
|
343
479
|
const scheduledPayload = keepEarlier ? existing.payload : payload;
|
|
344
|
-
const scheduledRepeat = keepEarlier ? existing.repeat_every_ms : repeatEveryMillis;
|
|
345
|
-
const nextProgress = Math.max(progress, input.progress ?? -1);
|
|
480
|
+
const scheduledRepeat = lifecycle === "manual" ? null : keepEarlier ? existing.repeat_every_ms : repeatEveryMillis;
|
|
481
|
+
const nextProgress = lifecycle === "manual" ? -1 : Math.max(progress, input.progress ?? -1);
|
|
346
482
|
yield* state.storage.sql.exec(`INSERT OR REPLACE INTO effect_cf_scheduled_alarms
|
|
347
|
-
(storage_id, alarm_id, tag, run_at, repeat_every_ms, payload)
|
|
348
|
-
VALUES (?, ?, ?, ?, ?, ?)`, storageId, ref.id, ref.tag, scheduledAt, scheduledRepeat, scheduledPayload);
|
|
483
|
+
(storage_id, alarm_id, tag, lifecycle, run_at, repeat_every_ms, payload)
|
|
484
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`, storageId, ref.id, ref.tag, lifecycle, scheduledAt, scheduledRepeat, scheduledPayload);
|
|
349
485
|
yield* writeAttempts(storageId, attempts, parked, retryAt, nextProgress);
|
|
350
486
|
if (parked === 1 && retryAt !== null && (existing?.parked ?? source?.parked ?? 0) === 0) reports.push(storageId);
|
|
351
487
|
});
|
|
@@ -365,10 +501,15 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
365
501
|
}
|
|
366
502
|
});
|
|
367
503
|
const transaction = Effect.fnUntraced(function* (closure) {
|
|
504
|
+
const pass = yield* CurrentAlarmPass;
|
|
505
|
+
if (pass !== void 0 && !pass.active) return yield* Effect.fail(new StorageOperationError({
|
|
506
|
+
operation: "alarm.transaction",
|
|
507
|
+
cause: /* @__PURE__ */ new Error("Alarm handlers cannot mutate detached work after their pass ends")
|
|
508
|
+
}));
|
|
368
509
|
const reports = [];
|
|
369
510
|
const result = yield* state.storage.transaction(() => Effect.withFiber((owner) => {
|
|
370
511
|
let active = true;
|
|
371
|
-
const requireActive = (effect) => Effect.withFiber((fiber) => active && fiber === owner ? effect : Effect.fail(new StorageOperationError({
|
|
512
|
+
const requireActive = (effect) => Effect.withFiber((fiber) => active && fiber === owner && (pass === void 0 || pass.active) ? effect : Effect.fail(new StorageOperationError({
|
|
372
513
|
operation: "alarm.transaction",
|
|
373
514
|
cause: /* @__PURE__ */ new Error("Alarm mutations require their active transaction callback")
|
|
374
515
|
})));
|
|
@@ -388,6 +529,50 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
388
529
|
yield* reportParked(reports);
|
|
389
530
|
return result;
|
|
390
531
|
});
|
|
532
|
+
const deferWakes = (body) => Effect.acquireUseRelease(Effect.gen(function* () {
|
|
533
|
+
const configuration = yield* getScheduleConfiguration(configurationDefaults);
|
|
534
|
+
const now = yield* Clock.currentTimeMillis;
|
|
535
|
+
if (wakeDeferrals === 0) {
|
|
536
|
+
deferredRecoveryDelay = configuration.parkedRetryDelay;
|
|
537
|
+
deferredRecoveryAt = now + deferredRecoveryDelay;
|
|
538
|
+
wakesReady ??= Deferred.makeUnsafe();
|
|
539
|
+
}
|
|
540
|
+
wakeDeferrals++;
|
|
541
|
+
}), () => transaction(() => Effect.void).pipe(Effect.andThen(body)), () => Effect.gen(function* () {
|
|
542
|
+
wakeDeferrals--;
|
|
543
|
+
if (wakeDeferrals === 0) yield* (dispatchActive ? Effect.void : transaction(() => Effect.void)).pipe(Effect.ensuring(Effect.sync(() => {
|
|
544
|
+
if (wakeDeferrals === 0 && wakesReady !== void 0) {
|
|
545
|
+
Deferred.doneUnsafe(wakesReady, Effect.void);
|
|
546
|
+
wakesReady = void 0;
|
|
547
|
+
}
|
|
548
|
+
})));
|
|
549
|
+
}));
|
|
550
|
+
const awaitWakes = Effect.suspend(() => wakesReady === void 0 ? Effect.void : Deferred.await(wakesReady).pipe(Effect.andThen(awaitWakes)));
|
|
551
|
+
const runAlarm = (event, native) => Effect.flatMap(hasSchedulerTables(state), (managed) => !managed ? native ? event(Effect.void) : Effect.void : Effect.uninterruptibleMask((restore) => Effect.suspend(() => {
|
|
552
|
+
const pending = pendingAlarm;
|
|
553
|
+
if (pending !== void 0) return restore((native ? transaction(() => Effect.void) : Effect.void).pipe(Effect.andThen(Deferred.await(pending))));
|
|
554
|
+
const completed = Deferred.makeUnsafe();
|
|
555
|
+
let dispatchStarted = false;
|
|
556
|
+
pendingAlarm = completed;
|
|
557
|
+
dispatchNeedsReconcile = native;
|
|
558
|
+
return restore(Effect.gen(function* () {
|
|
559
|
+
if (native && wakesReady !== void 0) yield* transaction(() => Effect.void);
|
|
560
|
+
yield* awaitWakes;
|
|
561
|
+
dispatchActive = true;
|
|
562
|
+
yield* event(Effect.gen(function* () {
|
|
563
|
+
yield* getScheduleConfiguration(configurationDefaults);
|
|
564
|
+
dispatchStarted = true;
|
|
565
|
+
}));
|
|
566
|
+
})).pipe(Effect.onExit((exit) => Effect.gen(function* () {
|
|
567
|
+
const reconcile = dispatchNeedsReconcile || dispatchStarted || Exit.isFailure(exit);
|
|
568
|
+
dispatchActive = Exit.isFailure(exit) && !dispatchStarted;
|
|
569
|
+
const reconciled = yield* (reconcile ? transaction(() => Effect.void) : Effect.void).pipe(Effect.exit);
|
|
570
|
+
dispatchActive = false;
|
|
571
|
+
pendingAlarm = void 0;
|
|
572
|
+
yield* Deferred.done(completed, Exit.asVoidAll([exit, reconciled]));
|
|
573
|
+
yield* reconciled;
|
|
574
|
+
})));
|
|
575
|
+
})));
|
|
391
576
|
const rescheduleFailedAlarm = Effect.fnUntraced(function* (row, initialDelay, configuration, reports) {
|
|
392
577
|
const current = yield* readRow(row.storage_id);
|
|
393
578
|
if (current === void 0 || current.revision !== row.revision) return;
|
|
@@ -411,8 +596,19 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
411
596
|
const limit = yield* getProcessLimit(options);
|
|
412
597
|
const initialDelay = yield* getFailureRetryDelay(options, configuration);
|
|
413
598
|
const now = yield* Clock.currentTimeMillis;
|
|
414
|
-
const
|
|
415
|
-
|
|
599
|
+
const dispatch = yield* CurrentDispatch;
|
|
600
|
+
if (dispatch?.raw !== void 0) dispatch.raw.processed = true;
|
|
601
|
+
const tagFilter = dispatch === void 0 ? "" : ` AND a.tag ${dispatch.exclude ? "NOT IN" : "IN"} (SELECT value FROM json_each(?))`;
|
|
602
|
+
const tagBindings = dispatch === void 0 ? [] : [S.encodeSync(StoredTags)([...dispatch.tags])];
|
|
603
|
+
const select = Effect.fnUntraced(function* (lifecycle, batchLimit) {
|
|
604
|
+
return yield* (yield* state.storage.sql.exec(`${alarmRowsSql} WHERE a.lifecycle = ? AND a.wake_at <= ?${tagFilter}
|
|
605
|
+
ORDER BY a.wake_at ASC, a.storage_id ASC LIMIT ?`, lifecycle, now, ...tagBindings, batchLimit)).toArray();
|
|
606
|
+
});
|
|
607
|
+
const dueRows = yield* select("automatic", limit);
|
|
608
|
+
const manualRows = yield* select("manual", DEFAULT_PROCESS_DUE_ALARMS_LIMIT);
|
|
609
|
+
if (manualRows.length > 0) yield* transaction(() => Effect.gen(function* () {
|
|
610
|
+
for (const row of manualRows) yield* state.storage.sql.exec(`UPDATE effect_cf_scheduled_alarms SET run_at = ?, wake_at = ? WHERE ${sameRevisionSql}`, now + configuration.parkedRetryDelay, now + configuration.parkedRetryDelay, row.storage_id, row.storage_id, row.revision);
|
|
611
|
+
}));
|
|
416
612
|
const handled = [];
|
|
417
613
|
const failed = [];
|
|
418
614
|
const parked = [];
|
|
@@ -437,9 +633,9 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
437
633
|
if (Exit.isFailure(actionExit)) return yield* Effect.failCause(actionExit.cause);
|
|
438
634
|
if (Exit.isFailure(delayExit)) return yield* Effect.failCause(delayExit.cause);
|
|
439
635
|
});
|
|
440
|
-
|
|
636
|
+
const handleRow = Effect.fnUntraced(function* (row) {
|
|
441
637
|
const current = yield* readRow(row.storage_id);
|
|
442
|
-
if (current === void 0 || current.revision !== row.revision)
|
|
638
|
+
if (current === void 0 || current.revision !== row.revision) return;
|
|
443
639
|
const inPass = (effect) => {
|
|
444
640
|
const pass = {
|
|
445
641
|
row,
|
|
@@ -450,21 +646,27 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
450
646
|
pass.active = false;
|
|
451
647
|
})));
|
|
452
648
|
};
|
|
649
|
+
const manual = row.lifecycle === "manual";
|
|
650
|
+
if (manual && !options?.[ManualTags]?.has(row.tag)) return yield* Effect.fail(missingAlarm(row.tag));
|
|
453
651
|
const eventExit = yield* Effect.exit(toAlarmDue(row));
|
|
454
652
|
if (Exit.isFailure(eventExit)) {
|
|
455
|
-
|
|
456
|
-
|
|
653
|
+
if (manual) return yield* Effect.failCause(eventExit.cause);
|
|
654
|
+
return yield* inPass(handleFailure(row, void 0, eventExit.cause));
|
|
457
655
|
}
|
|
458
656
|
const event = eventExit.value;
|
|
459
657
|
const handleExit = yield* Effect.exit(inPass(Effect.suspend(() => handle(event))));
|
|
460
658
|
if (Exit.isFailure(handleExit)) {
|
|
461
|
-
yield*
|
|
462
|
-
|
|
659
|
+
if (manual) return yield* Effect.failCause(handleExit.cause);
|
|
660
|
+
return yield* inPass(handleFailure(row, event, handleExit.cause));
|
|
463
661
|
}
|
|
464
|
-
yield* transaction(() => acknowledgeAlarm(row, configuration));
|
|
662
|
+
if (!manual) yield* transaction(() => acknowledgeAlarm(row, configuration));
|
|
465
663
|
handled.push(event);
|
|
466
|
-
}
|
|
664
|
+
});
|
|
665
|
+
const permits = dispatch?.permits ?? (yield* Semaphore.make(4));
|
|
666
|
+
const automatic = Effect.forEach(dueRows, handleRow, { discard: true }).pipe(Effect.exit);
|
|
667
|
+
const exits = yield* manualRows.length === 0 ? automatic.pipe(Effect.map((exit) => [exit])) : Effect.all([automatic, Effect.forEach(manualRows, (row) => permits.withPermits(1)(handleRow(row)).pipe(Effect.exit), { concurrency: 4 }).pipe(Effect.flatMap(Exit.asVoidAll), Effect.exit)], { concurrency: 2 });
|
|
467
668
|
yield* transaction(() => Effect.void);
|
|
669
|
+
yield* Exit.asVoidAll(exits);
|
|
468
670
|
return {
|
|
469
671
|
failed,
|
|
470
672
|
handled,
|
|
@@ -472,6 +674,14 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
472
674
|
};
|
|
473
675
|
});
|
|
474
676
|
return DurableObjectAlarm.of({
|
|
677
|
+
[RunAlarm]: runAlarm,
|
|
678
|
+
[DispatchAfterEvent]: Effect.map(ScheduleConfiguration, (configuration) => (configuration.dispatchAfterEvent ?? configurationDefaults.dispatchAfterEvent) === true),
|
|
679
|
+
[HasDueAlarms]: Effect.gen(function* () {
|
|
680
|
+
yield* ensureTable(state);
|
|
681
|
+
const now = yield* Clock.currentTimeMillis;
|
|
682
|
+
return (yield* (yield* state.storage.sql.exec("SELECT 1 FROM effect_cf_scheduled_alarms WHERE wake_at <= ? LIMIT 1", now)).toArray()).length > 0;
|
|
683
|
+
}),
|
|
684
|
+
deferWakes,
|
|
475
685
|
cancelAlarm: (input) => transaction((alarms) => alarms.cancelAlarm(input)),
|
|
476
686
|
getAlarmStatus: Effect.fnUntraced(function* (input) {
|
|
477
687
|
const ref = yield* decodeAlarmRef(input);
|
|
@@ -492,4 +702,4 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
492
702
|
}));
|
|
493
703
|
};
|
|
494
704
|
//#endregion
|
|
495
|
-
export { AlarmParked, AlarmReporter, DEFAULT_MIN_REPEAT_INTERVAL_MS, DurableObjectAlarm, DurableObjectAlarmEvent, DurableObjectAlarm_exports, InvalidAlarmPayloadError, InvalidAlarmRefError, InvalidProcessDueAlarmsOptionsError, InvalidRepeatEveryError, InvalidScheduleConfigurationError, MIN_REPEAT_INTERVAL_MS, MIN_RETRY_DELAY_MS, PARKED_RETRY_DELAY_MS, ScheduleConfiguration, StoredAlarmDecodeError, Tag, define, processDue };
|
|
705
|
+
export { AlarmParked, AlarmReporter, DEFAULT_MIN_REPEAT_INTERVAL_MS, DispatchAfterEvent, DurableObjectAlarm, DurableObjectAlarmEvent, DurableObjectAlarm_exports, HasDueAlarms, InvalidAlarmPayloadError, InvalidAlarmRefError, InvalidAlarmRegistrationError, InvalidProcessDueAlarmsOptionsError, InvalidRepeatEveryError, InvalidScheduleConfigurationError, MIN_REPEAT_INTERVAL_MS, MIN_RETRY_DELAY_MS, PARKED_RETRY_DELAY_MS, RunAlarm, ScheduleConfiguration, StoredAlarmDecodeError, Tag, define, dispatchRawAlarm, mergeAll, processDue };
|
|
@@ -5,9 +5,9 @@ import * as Effect from "effect/Effect";
|
|
|
5
5
|
import * as Schema from "effect/Schema";
|
|
6
6
|
import * as Layer from "effect/Layer";
|
|
7
7
|
import * as Option from "effect/Option";
|
|
8
|
-
import * as RpcMessage from "effect/
|
|
9
|
-
import * as RpcSerialization from "effect/
|
|
10
|
-
import * as RpcServer from "effect/
|
|
8
|
+
import * as RpcMessage from "effect/rpc/RpcMessage";
|
|
9
|
+
import * as RpcSerialization from "effect/rpc/RpcSerialization";
|
|
10
|
+
import * as RpcServer from "effect/rpc/RpcServer";
|
|
11
11
|
declare namespace DurableObjectRpcWebSocket_d_exports {
|
|
12
12
|
export { DurableObjectRpcWebSocket, DurableObjectRpcWebSocketService, HeartbeatPolicy, LayerOptions, NativeWebSocketMessage, ResumableStreamDeclaration, RpcWebSocketAttachment, layer, resumableStream };
|
|
13
13
|
}
|
|
@@ -8,9 +8,9 @@ import * as Layer from "effect/Layer";
|
|
|
8
8
|
import * as Predicate from "effect/Predicate";
|
|
9
9
|
import * as Option from "effect/Option";
|
|
10
10
|
import * as Queue from "effect/Queue";
|
|
11
|
-
import * as RpcMessage from "effect/
|
|
12
|
-
import * as RpcSerialization from "effect/
|
|
13
|
-
import * as RpcServer from "effect/
|
|
11
|
+
import * as RpcMessage from "effect/rpc/RpcMessage";
|
|
12
|
+
import * as RpcSerialization from "effect/rpc/RpcSerialization";
|
|
13
|
+
import * as RpcServer from "effect/rpc/RpcServer";
|
|
14
14
|
//#region src/DurableObjectRpcWebSocket.ts
|
|
15
15
|
var DurableObjectRpcWebSocket_exports = /* @__PURE__ */ __exportAll({
|
|
16
16
|
DurableObjectRpcWebSocket: () => DurableObjectRpcWebSocket,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DurableObjectState } from "./DurableObjectState.mjs";
|
|
2
2
|
import * as Layer from "effect/Layer";
|
|
3
3
|
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
4
|
-
import { SqlClient } from "effect/
|
|
4
|
+
import { SqlClient } from "effect/sql";
|
|
5
5
|
declare namespace DurableObjectSqlite_d_exports {
|
|
6
6
|
export { SqliteLayerOptions, layer };
|
|
7
7
|
}
|
|
@@ -5,8 +5,8 @@ import * as Effect from "effect/Effect";
|
|
|
5
5
|
import * as Layer from "effect/Layer";
|
|
6
6
|
import * as Scheduler from "effect/Scheduler";
|
|
7
7
|
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
8
|
-
import * as Reactivity from "effect/
|
|
9
|
-
import { SqlClient } from "effect/
|
|
8
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
9
|
+
import { SqlClient } from "effect/sql";
|
|
10
10
|
//#region src/DurableObjectSqlite.ts
|
|
11
11
|
var DurableObjectSqlite_exports = /* @__PURE__ */ __exportAll({ layer: () => layer });
|
|
12
12
|
const layer = (options) => Layer.effectContext(Effect.gen(function* () {
|
package/dist/HyperdrivePg.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import { WorkerEnvironment } from "./Environment.mjs";
|
|
|
2
2
|
import { BindingNotFoundError, BindingValidationError } from "./Binding.mjs";
|
|
3
3
|
import { LayerOptions, TagClass } from "./Hyperdrive.mjs";
|
|
4
4
|
import * as Layer from "effect/Layer";
|
|
5
|
-
import { SqlClient, SqlError } from "effect/
|
|
5
|
+
import { SqlClient, SqlError } from "effect/sql";
|
|
6
6
|
import { PgClient } from "@effect/sql-pg";
|
|
7
7
|
//#region src/HyperdrivePg.d.ts
|
|
8
8
|
type PgLayerOptions = Omit<Parameters<typeof PgClient.makeClient>[0], "url" | "host" | "port" | "path" | "ssl" | "database" | "username" | "password" | "stream">;
|
package/dist/Mcp.d.mts
CHANGED
|
@@ -2,8 +2,8 @@ import { NativeRequest } from "./Worker.mjs";
|
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Option from "effect/Option";
|
|
4
4
|
import { CreateMcpHandlerOptions, ServerOptions } from "@modelcontextprotocol/server";
|
|
5
|
-
import * as Tool from "effect/
|
|
6
|
-
import { Toolkit } from "effect/
|
|
5
|
+
import * as Tool from "effect/ai/Tool";
|
|
6
|
+
import { Toolkit } from "effect/ai";
|
|
7
7
|
//#region src/Mcp.d.ts
|
|
8
8
|
/**
|
|
9
9
|
* CORS headers applied to MCP responses.
|
|
@@ -96,7 +96,7 @@ type FromToolkitContext<Tools extends Record<string, Tool.Any>> = NativeRequest
|
|
|
96
96
|
*
|
|
97
97
|
* ```ts
|
|
98
98
|
* import { Effect, Layer, Option } from "effect"
|
|
99
|
-
* import { HttpRouter } from "effect/
|
|
99
|
+
* import { HttpRouter } from "effect/http"
|
|
100
100
|
* import { Worker } from "effect-cf"
|
|
101
101
|
* import * as Mcp from "effect-cf/mcp"
|
|
102
102
|
*
|
package/dist/Mcp.mjs
CHANGED
|
@@ -10,8 +10,8 @@ import * as Exit from "effect/Exit";
|
|
|
10
10
|
import * as Stream from "effect/Stream";
|
|
11
11
|
import { McpServer, createMcpHandler, hostHeaderValidationResponse, localhostAllowedHostnames, localhostAllowedOrigins, originValidationResponse } from "@modelcontextprotocol/server";
|
|
12
12
|
import * as Sink from "effect/Sink";
|
|
13
|
-
import * as AiError from "effect/
|
|
14
|
-
import * as Tool from "effect/
|
|
13
|
+
import * as AiError from "effect/ai/AiError";
|
|
14
|
+
import * as Tool from "effect/ai/Tool";
|
|
15
15
|
//#region src/Mcp.ts
|
|
16
16
|
const DEFAULT_CORS_OPTIONS = {
|
|
17
17
|
origin: "*",
|
|
@@ -214,7 +214,7 @@ const registerToolkitTool = (server, built, tool, run) => {
|
|
|
214
214
|
*
|
|
215
215
|
* ```ts
|
|
216
216
|
* import { Effect, Layer, Option } from "effect"
|
|
217
|
-
* import { HttpRouter } from "effect/
|
|
217
|
+
* import { HttpRouter } from "effect/http"
|
|
218
218
|
* import { Worker } from "effect-cf"
|
|
219
219
|
* import * as Mcp from "effect-cf/mcp"
|
|
220
220
|
*
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { WorkerEnvironment } from "./Environment.mjs";
|
|
2
|
+
import { BindingNotFoundError, BindingValidationError } from "./Binding.mjs";
|
|
3
|
+
import * as Context$1 from "effect/Context";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import { Layer } from "effect";
|
|
6
|
+
declare namespace RateLimit_d_exports {
|
|
7
|
+
export { BindingNotFoundError, BindingValidationError, LayerOptions, RateLimitBinding, RateLimitClient, RateLimitDefinition, RateLimitOperationError, RateLimitOptions, RateLimitOutcome, RateLimitService, Tag, TagClass, isRateLimit, layer, make, makeClient };
|
|
8
|
+
}
|
|
9
|
+
type RateLimitBinding = globalThis.RateLimit;
|
|
10
|
+
type RateLimitOptions = globalThis.RateLimitOptions;
|
|
11
|
+
type RateLimitOutcome = globalThis.RateLimitOutcome;
|
|
12
|
+
declare const RateLimitOperationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
13
|
+
readonly _tag: "RateLimitOperationError";
|
|
14
|
+
} & Readonly<A>;
|
|
15
|
+
declare class RateLimitOperationError extends RateLimitOperationError_base<{
|
|
16
|
+
readonly binding: string;
|
|
17
|
+
readonly operation: "limit";
|
|
18
|
+
readonly cause: unknown;
|
|
19
|
+
}> {
|
|
20
|
+
get message(): string;
|
|
21
|
+
}
|
|
22
|
+
interface RateLimitDefinition {
|
|
23
|
+
readonly binding: string;
|
|
24
|
+
}
|
|
25
|
+
interface RateLimitClient {
|
|
26
|
+
/** Denial is a successful result with success: false. Calls are never retried. */
|
|
27
|
+
readonly limit: (options: RateLimitOptions) => Effect.Effect<RateLimitOutcome, RateLimitOperationError>;
|
|
28
|
+
readonly rawUnsafe: Effect.Effect<RateLimitBinding>;
|
|
29
|
+
readonly definition: RateLimitDefinition;
|
|
30
|
+
}
|
|
31
|
+
declare const RateLimitServiceTypeId: unique symbol;
|
|
32
|
+
interface RateLimitService<Id extends string> {
|
|
33
|
+
readonly [RateLimitServiceTypeId]: {
|
|
34
|
+
readonly id: Id;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
type LayerOptions = {
|
|
38
|
+
readonly binding: string;
|
|
39
|
+
};
|
|
40
|
+
interface TagClass<Self, Id extends string> extends Context$1.ServiceClass<Self, Id, RateLimitClient> {
|
|
41
|
+
readonly id: Id;
|
|
42
|
+
readonly layer: (options: LayerOptions) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
43
|
+
}
|
|
44
|
+
declare const isRateLimit: <Candidate>(value: Candidate) => value is Candidate & RateLimitBinding;
|
|
45
|
+
declare const makeClient: (definition: RateLimitDefinition) => (rateLimit: RateLimitBinding) => RateLimitClient;
|
|
46
|
+
declare const layer: <Self>(tag: Context$1.Service<Self, RateLimitClient>, definition: RateLimitDefinition) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
47
|
+
declare const make: <Id extends string>(id: Id) => TagClass<RateLimitService<Id>, Id>;
|
|
48
|
+
declare const Tag: <Self>() => <Id extends string>(id: Id) => TagClass<Self, Id>;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { type BindingNotFoundError, type BindingValidationError, LayerOptions, RateLimitBinding, RateLimitClient, RateLimitDefinition, RateLimitOperationError, RateLimitOptions, RateLimitOutcome, RateLimitService, RateLimit_d_exports, Tag, TagClass, isRateLimit, layer, make, makeClient };
|