effect-cf 0.53.0 → 0.55.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 +6 -0
- package/dist/DurableObject.d.mts +1 -0
- package/dist/DurableObject.mjs +33 -11
- package/dist/DurableObjectAlarm.d.mts +76 -9
- package/dist/DurableObjectAlarm.mjs +265 -36
- package/dist/RateLimit.d.mts +50 -0
- package/dist/RateLimit.mjs +46 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/internal/Runtime.mjs +5 -3
- package/package.json +1 -1
- package/src/DurableObject.ts +93 -30
- package/src/DurableObjectAlarm.ts +647 -60
- package/src/RateLimit.ts +110 -0
- package/src/index.ts +1 -0
- package/src/internal/Entrypoint.ts +8 -4
- package/src/internal/Runtime.ts +12 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# effect-cf
|
|
2
2
|
|
|
3
|
+
## 0.55.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#211](https://github.com/danieljvdm/effect-cf/pull/211) [`2764143`](https://github.com/danieljvdm/effect-cf/commit/276414374c3fe71f619c26ef1c447ab0f52f9ab4) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Keep in-flight Durable Object work recoverable through a configurable short alarm deadline while preserving hourly parked recovery. Coalesce native deliveries with active processing without starting another pass.
|
|
8
|
+
|
|
9
|
+
## 0.54.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#208](https://github.com/danieljvdm/effect-cf/pull/208) [`be9befa`](https://github.com/danieljvdm/effect-cf/commit/be9befaf7e07cdfff2a5c92e886065725edf90e6) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add an Effect-native RateLimit binding client with service layers, native admission outcomes, and typed operation errors preserving the original cause.
|
|
14
|
+
|
|
15
|
+
- [#210](https://github.com/danieljvdm/effect-cf/pull/210) [`abcdb42`](https://github.com/danieljvdm/effect-cf/commit/abcdb4204b3b32d7e979f449e36d9727693e5d73) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Compose typed alarm services with `DurableObjectAlarm.mergeAll` under one native Durable Object alarm owner. Use `lifecycle: "manual"` for queues that own completion and retry policy, and `deferWakes` to coalesce native alarm changes during processing while retaining durable recovery.
|
|
16
|
+
|
|
17
|
+
Enable `ScheduleConfiguration.dispatchAfterEvent` to dispatch due alarms after RPC/fetch responses unwind, using the same scoped pass as native delivery. Overlapping native alarms join the pass, deferred regions delay dispatch, and durable native scheduling retains recovery authority. Cold Objects can deliver responses later because post-response processing shares the same CPU.
|
|
18
|
+
|
|
3
19
|
## 0.53.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -220,6 +220,12 @@ Applications own SERVER spans. Override the exported `DurableObject.RunSymbol` o
|
|
|
220
220
|
|
|
221
221
|
This metadata belongs only to the live native call. Do not store it in domain envelopes, alarms, queues, or WebSocket attachments, or reuse it for resumed work. Sampling and exporter configuration remain application choices.
|
|
222
222
|
|
|
223
|
+
## Native rate limiting
|
|
224
|
+
|
|
225
|
+
Use `RateLimit.Tag` or `RateLimit.make` to call a native binding as an Effect:
|
|
226
|
+
`yield* requests.limit({ key })` returns `{ success }`, including ordinary denial.
|
|
227
|
+
See [binding configuration and usage](../../docs/rate-limiting.md).
|
|
228
|
+
|
|
223
229
|
## API
|
|
224
230
|
|
|
225
231
|
See the [exports](src/index.ts) and [tests](https://github.com/danieljvdm/effect-cf/tree/main/packages/effect-cf/tests) for the remaining APIs.
|
package/dist/DurableObject.d.mts
CHANGED
|
@@ -94,6 +94,7 @@ type DurableObjectOptions<RRuntime, REvent = never, EventLayerError = never, Rpc
|
|
|
94
94
|
* Cloudflare `DurableObject` constructor produced by {@link make}.
|
|
95
95
|
*/
|
|
96
96
|
type DurableObjectClass<Rpc extends DurableObjectRpc<ROut>, ROut> = new (state: globalThis.DurableObjectState, env: WorkerEnv) => DurableObject<WorkerEnv> & DurableObjectRpcApi<Rpc, ROut> & {
|
|
97
|
+
alarm(alarmInfo?: globalThis.AlarmInvocationInfo): Promise<void> | void;
|
|
97
98
|
[RunSymbol]<A, E>(effect: Effect.Effect<A, E, HandlerContext<ROut>>, options?: RunOptions): Promise<A>;
|
|
98
99
|
};
|
|
99
100
|
/**
|
package/dist/DurableObject.mjs
CHANGED
|
@@ -3,10 +3,10 @@ import { fromWebSocket } from "./DurableObjectWebSocket.mjs";
|
|
|
3
3
|
import { DurableObjectState, fromDurableObjectState } from "./DurableObjectState.mjs";
|
|
4
4
|
import { reservedMethodNames as reservedMethodNames$1 } from "./RpcDefinition.mjs";
|
|
5
5
|
import { assumeEntrypointClass, defineEntrypointRpcMethods } from "./internal/Entrypoint.mjs";
|
|
6
|
-
import { makeEntrypointRuntime, runEventPromise } from "./internal/Runtime.mjs";
|
|
6
|
+
import { makeEntrypointRuntime, runEventPromise, scopeEvent } from "./internal/Runtime.mjs";
|
|
7
7
|
import { scheduleTelemetryFlush as scheduleTelemetryFlush$1 } from "./internal/Telemetry.mjs";
|
|
8
8
|
import { NativeRequest } from "./Worker.mjs";
|
|
9
|
-
import { DurableObjectAlarm } from "./DurableObjectAlarm.mjs";
|
|
9
|
+
import { DispatchAfterEvent, DurableObjectAlarm, HasDueAlarms, RunAlarm, dispatchRawAlarm } from "./DurableObjectAlarm.mjs";
|
|
10
10
|
import { Tag, implement, method, native } from "./DurableObjectDefinition.mjs";
|
|
11
11
|
import * as Effect from "effect/Effect";
|
|
12
12
|
import * as Layer from "effect/Layer";
|
|
@@ -28,7 +28,7 @@ const RunSymbol = Symbol.for("effect-cf/DurableObject/run");
|
|
|
28
28
|
const scheduleTelemetryFlush = scheduleTelemetryFlush$1((flush) => Effect.flatMap(DurableObjectState, (state) => state.waitUntil(flush)));
|
|
29
29
|
function make(layer, options = {}) {
|
|
30
30
|
const registration = options.alarms !== void 0 && !Effect.isEffect(options.alarms) ? options.alarms : void 0;
|
|
31
|
-
const
|
|
31
|
+
const legacyAlarms = Effect.isEffect(options.alarms) ? options.alarms.pipe(Effect.asVoid) : void 0;
|
|
32
32
|
class EffectDurableObject extends DurableObject {
|
|
33
33
|
runtime;
|
|
34
34
|
constructor(state, env) {
|
|
@@ -46,8 +46,18 @@ function make(layer, options = {}) {
|
|
|
46
46
|
const eventLayer = runOptions.eventLayer === false ? void 0 : options.eventLayer;
|
|
47
47
|
const parent = runOptions.rpc?.parent;
|
|
48
48
|
const parentSpan = parent === void 0 ? void 0 : Tracer.externalSpan(parent);
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const afterResponse = runOptions.event === "rpc" || runOptions.event === "fetch";
|
|
50
|
+
let dispatchAfterEvent = false;
|
|
51
|
+
const handler = afterResponse ? effect.pipe(Effect.onExit(() => Effect.flatMap(DurableObjectAlarm, (alarms) => Effect.map(alarms[DispatchAfterEvent], (enabled) => {
|
|
52
|
+
dispatchAfterEvent = enabled;
|
|
53
|
+
})))) : effect;
|
|
54
|
+
let response;
|
|
55
|
+
if (eventLayer === void 0) response = runEventPromise(this.runtime, handler, void 0, parentSpan, runOptions.onFailure);
|
|
56
|
+
else response = runEventPromise(this.runtime, handler, eventLayer, parentSpan, runOptions.onFailure);
|
|
57
|
+
if (!afterResponse) return response;
|
|
58
|
+
return response.finally(() => {
|
|
59
|
+
if (dispatchAfterEvent) this.ctx.waitUntil(Effect.runPromise(Effect.yieldNow.pipe(Effect.andThen(Effect.promise(() => this.#runAlarm(false))))));
|
|
60
|
+
});
|
|
51
61
|
}
|
|
52
62
|
fetch(request) {
|
|
53
63
|
const fetchHandler = options.fetch;
|
|
@@ -55,12 +65,24 @@ function make(layer, options = {}) {
|
|
|
55
65
|
return this[RunSymbol](Effect.provideService(fetchHandler, NativeRequest, request), { event: "fetch" });
|
|
56
66
|
}
|
|
57
67
|
alarm(alarmInfo) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
return this.#runAlarm(true, alarmInfo);
|
|
69
|
+
}
|
|
70
|
+
#runAlarm(native, alarmInfo) {
|
|
71
|
+
const event = (beginDispatch) => {
|
|
72
|
+
const alarmEffect = Effect.gen(function* () {
|
|
73
|
+
const alarms = yield* DurableObjectAlarm;
|
|
74
|
+
if (!native && !(yield* alarms[HasDueAlarms])) return;
|
|
75
|
+
const rawAlarm = options.alarm?.(alarmInfo);
|
|
76
|
+
const customAlarm = legacyAlarms === void 0 ? rawAlarm ?? Effect.void : legacyAlarms.pipe(Effect.andThen(rawAlarm ?? Effect.void));
|
|
77
|
+
yield* beginDispatch;
|
|
78
|
+
yield* registration === void 0 || rawAlarm !== void 0 ? dispatchRawAlarm(customAlarm, registration) : registration.run.pipe(Effect.asVoid);
|
|
79
|
+
}).pipe(Effect.onExit(() => scheduleTelemetryFlush));
|
|
80
|
+
return scopeEvent(options.eventLayer === void 0 ? alarmEffect : alarmEffect.pipe(Effect.provide(options.eventLayer, { local: true })));
|
|
81
|
+
};
|
|
82
|
+
return this[RunSymbol](Effect.flatMap(DurableObjectAlarm, (alarms) => alarms[RunAlarm](event, native)), {
|
|
83
|
+
event: "alarm",
|
|
84
|
+
eventLayer: false
|
|
85
|
+
});
|
|
64
86
|
}
|
|
65
87
|
webSocketMessage(socket, message) {
|
|
66
88
|
if (options.webSocketMessage !== void 0) return this[RunSymbol](options.webSocketMessage(fromWebSocket(socket), message), { event: "webSocketMessage" });
|
|
@@ -7,7 +7,7 @@ import * as Layer from "effect/Layer";
|
|
|
7
7
|
import * as Duration from "effect/Duration";
|
|
8
8
|
import * as DateTime from "effect/DateTime";
|
|
9
9
|
declare namespace DurableObjectAlarm_d_exports {
|
|
10
|
-
export { AlarmDefinitionConfig, AlarmDefinitionEntry, AlarmDefinitionPayload, AlarmDefinitions, AlarmFailurePolicy, AlarmParked, AlarmPayload, AlarmPayloadSchema, AlarmRef, AlarmRegistration, AlarmReporter, AlarmRetryPolicy, AlarmScheduler, AlarmService, AlarmStatus, AlarmTagClass, AlarmTransaction, DEFAULT_MIN_REPEAT_INTERVAL_MS, DefinedAlarmEvent, DefinedAlarmHandlers, DefinedAlarmScheduler, DefinedAlarmTransaction, DefinedScheduleAlarmInput, DurableObjectAlarm, DurableObjectAlarmError, DurableObjectAlarmEvent, InvalidAlarmPayloadError, InvalidAlarmRefError, InvalidProcessDueAlarmsOptionsError, InvalidRepeatEveryError, InvalidScheduleConfigurationError, MIN_REPEAT_INTERVAL_MS, MIN_RETRY_DELAY_MS, PARKED_RETRY_DELAY_MS, ProcessDueAlarmsFailure, ProcessDueAlarmsFailureAction, ProcessDueAlarmsHandler, ProcessDueAlarmsOptions, ProcessDueAlarmsResult, ScheduleAlarmInput, ScheduleConfiguration, StoredAlarmDecodeError, Tag, UNCHANGED_ATTEMPT_BUDGET, define, processDue };
|
|
10
|
+
export { AlarmDefinitionConfig, AlarmDefinitionEntry, AlarmDefinitionPayload, AlarmDefinitions, AlarmFailurePolicy, AlarmLifecycle, AlarmParked, AlarmPayload, AlarmPayloadSchema, AlarmRef, AlarmRegistration, AlarmReporter, AlarmRetryPolicy, AlarmScheduler, AlarmService, AlarmStatus, AlarmTagClass, AlarmTransaction, DEFAULT_MIN_REPEAT_INTERVAL_MS, DefinedAlarmEvent, DefinedAlarmHandlers, DefinedAlarmScheduler, DefinedAlarmTransaction, DefinedScheduleAlarmInput, DispatchAfterEvent, DurableObjectAlarm, DurableObjectAlarmError, DurableObjectAlarmEvent, HasDueAlarms, InvalidAlarmPayloadError, InvalidAlarmRefError, InvalidAlarmRegistrationError, InvalidProcessDueAlarmsOptionsError, InvalidRepeatEveryError, InvalidScheduleConfigurationError, MIN_REPEAT_INTERVAL_MS, MIN_RETRY_DELAY_MS, PARKED_RETRY_DELAY_MS, ProcessDueAlarmsFailure, ProcessDueAlarmsFailureAction, ProcessDueAlarmsHandler, ProcessDueAlarmsOptions, ProcessDueAlarmsResult, RunAlarm, ScheduleAlarmInput, ScheduleConfiguration, StoredAlarmDecodeError, Tag, UNCHANGED_ATTEMPT_BUDGET, define, dispatchRawAlarm, mergeAll, processDue };
|
|
11
11
|
}
|
|
12
12
|
declare const MIN_RETRY_DELAY_MS = 1000;
|
|
13
13
|
/** Default unchanged-attempt budget. */
|
|
@@ -19,6 +19,10 @@ declare const MIN_REPEAT_INTERVAL_MS = 1000;
|
|
|
19
19
|
/** Default product schedule floor. Never use repeats to poll state. */
|
|
20
20
|
declare const DEFAULT_MIN_REPEAT_INTERVAL_MS = 60000;
|
|
21
21
|
interface ScheduleConfiguration {
|
|
22
|
+
/** Check for due alarms after RPC/fetch responses unwind. Native alarms remain recovery authority. */
|
|
23
|
+
readonly dispatchAfterEvent?: boolean;
|
|
24
|
+
/** Positive recovery deadline while dispatch or deferWakes is active. Defaults to one second. */
|
|
25
|
+
readonly inFlightRecovery?: Duration.Input;
|
|
22
26
|
/** Retry floor, at least one second. Defaults to one second. */
|
|
23
27
|
readonly minimumRetryDelay?: Duration.Input;
|
|
24
28
|
/** Positive safe integer. Defaults to eight unchanged attempts. */
|
|
@@ -30,6 +34,8 @@ interface ScheduleConfiguration {
|
|
|
30
34
|
}
|
|
31
35
|
/** Optional policy overrides. Provide with Layer.succeed in the Durable Object's application layer. */
|
|
32
36
|
declare const ScheduleConfiguration: Context.Reference<ScheduleConfiguration>;
|
|
37
|
+
/** Automatic alarms acknowledge/retry on handler exit; manual alarms retain consumer control. */
|
|
38
|
+
type AlarmLifecycle = "automatic" | "manual";
|
|
33
39
|
type AlarmPayload = S.Json;
|
|
34
40
|
/** Content-free: no alarm identifiers, payload, error text or consumer state. */
|
|
35
41
|
declare const AlarmParked: S.TaggedStruct<"AlarmParked", {
|
|
@@ -39,6 +45,7 @@ declare const AlarmParked: S.TaggedStruct<"AlarmParked", {
|
|
|
39
45
|
type AlarmParked = typeof AlarmParked.Type;
|
|
40
46
|
/** Install with Layer.succeed / Effect.provideService. Reporting cannot undo a committed guard. */
|
|
41
47
|
declare const AlarmReporter: Context.Reference<(event: AlarmParked) => Effect.Effect<void>>;
|
|
48
|
+
declare const ManualTags: unique symbol;
|
|
42
49
|
declare const InvalidAlarmRefError_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 & {
|
|
43
50
|
readonly _tag: "InvalidAlarmRefError";
|
|
44
51
|
} & Readonly<A>;
|
|
@@ -79,6 +86,14 @@ declare class InvalidScheduleConfigurationError extends InvalidScheduleConfigura
|
|
|
79
86
|
}> {
|
|
80
87
|
get message(): string;
|
|
81
88
|
}
|
|
89
|
+
declare const InvalidAlarmRegistrationError_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 & {
|
|
90
|
+
readonly _tag: "InvalidAlarmRegistrationError";
|
|
91
|
+
} & Readonly<A>;
|
|
92
|
+
declare class InvalidAlarmRegistrationError extends InvalidAlarmRegistrationError_base<{
|
|
93
|
+
readonly cause: unknown;
|
|
94
|
+
}> {
|
|
95
|
+
get message(): string;
|
|
96
|
+
}
|
|
82
97
|
declare const StoredAlarmDecodeError_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 & {
|
|
83
98
|
readonly _tag: "StoredAlarmDecodeError";
|
|
84
99
|
} & Readonly<A>;
|
|
@@ -88,7 +103,7 @@ declare class StoredAlarmDecodeError extends StoredAlarmDecodeError_base<{
|
|
|
88
103
|
}> {
|
|
89
104
|
get message(): string;
|
|
90
105
|
}
|
|
91
|
-
type DurableObjectAlarmError = InvalidAlarmPayloadError | InvalidAlarmRefError | InvalidProcessDueAlarmsOptionsError | InvalidRepeatEveryError | InvalidScheduleConfigurationError | StorageOperationError | StoredAlarmDecodeError;
|
|
106
|
+
type DurableObjectAlarmError = InvalidAlarmRegistrationError | InvalidAlarmPayloadError | InvalidAlarmRefError | InvalidProcessDueAlarmsOptionsError | InvalidRepeatEveryError | InvalidScheduleConfigurationError | StorageOperationError | StoredAlarmDecodeError;
|
|
92
107
|
declare const DurableObjectAlarmEvent: S.TaggedUnion<{
|
|
93
108
|
readonly AlarmDue: S.TaggedStruct<"AlarmDue", {
|
|
94
109
|
readonly id: S.NonEmptyString;
|
|
@@ -108,6 +123,8 @@ type AlarmRef<Tag extends string = string> = {
|
|
|
108
123
|
* Reusing `{tag, id}` replaces an alarm. Product repeats use the configured floor and run after completion.
|
|
109
124
|
*/
|
|
110
125
|
type ScheduleAlarmInput<Tag extends string = string> = AlarmRef<Tag> & {
|
|
126
|
+
/** Prefer selecting the lifecycle in a typed Tag definition. Defaults to automatic. */
|
|
127
|
+
readonly lifecycle?: AlarmLifecycle;
|
|
111
128
|
readonly payload: AlarmPayload;
|
|
112
129
|
readonly repeatEvery?: Duration.Input;
|
|
113
130
|
readonly runAt: DateTime.Utc;
|
|
@@ -133,6 +150,7 @@ type ProcessDueAlarmsFailureAction = "retry" | "skip-and-advance-repeat" | {
|
|
|
133
150
|
readonly mode: "skip-and-advance-repeat";
|
|
134
151
|
};
|
|
135
152
|
interface ProcessDueAlarmsOptions<OnFailureR = never, OnFailureE = never> {
|
|
153
|
+
readonly [ManualTags]?: ReadonlySet<string>;
|
|
136
154
|
readonly limit?: number;
|
|
137
155
|
readonly onFailure?: (failure: ProcessDueAlarmsFailure) => Effect.Effect<ProcessDueAlarmsFailureAction | void, OnFailureE, OnFailureR>;
|
|
138
156
|
readonly retryFailedAfter?: Duration.Input;
|
|
@@ -149,8 +167,29 @@ interface AlarmStatus {
|
|
|
149
167
|
readonly runAt: DateTime.Utc;
|
|
150
168
|
readonly retryAt: DateTime.Utc | undefined;
|
|
151
169
|
}
|
|
170
|
+
/** @internal */
|
|
171
|
+
declare const RunAlarm: unique symbol;
|
|
172
|
+
/** @internal */
|
|
173
|
+
declare const DispatchAfterEvent: unique symbol;
|
|
174
|
+
/** @internal */
|
|
175
|
+
declare const HasDueAlarms: unique symbol;
|
|
152
176
|
/** Own `storage.setAlarm()` exclusively: a Durable Object has one platform alarm timestamp. */
|
|
153
177
|
type AlarmScheduler = {
|
|
178
|
+
/** @internal DurableObject.make shares this scoped event across native and post-event dispatch. */
|
|
179
|
+
readonly [RunAlarm]: <R>(event: (beginDispatch: Effect.Effect<void, InvalidScheduleConfigurationError>) => Effect.Effect<void, unknown, R>, native: boolean) => Effect.Effect<void, unknown, R>;
|
|
180
|
+
/** @internal Read the current event's opt-in without acquiring another event layer. */
|
|
181
|
+
readonly [DispatchAfterEvent]: Effect.Effect<boolean>;
|
|
182
|
+
/** @internal Check inside the alarm event so its clock and configuration apply. */
|
|
183
|
+
readonly [HasDueAlarms]: Effect.Effect<boolean, StorageOperationError>;
|
|
184
|
+
/**
|
|
185
|
+
* Keep a native recovery alarm armed while coalescing checkpoint changes across this
|
|
186
|
+
* object's concurrent and nested scopes. Source/checkpoint transactions still commit;
|
|
187
|
+
* the last scope reconciles their current deadlines on success, failure or interruption.
|
|
188
|
+
* Run outside transactions, around bounded maintenance or inline work. The first scope's
|
|
189
|
+
* inFlightRecovery bounds the shared guard; renew it if it expires and is consumed while
|
|
190
|
+
* scopes remain active. A process loss before exit recovers at that retained alarm.
|
|
191
|
+
*/
|
|
192
|
+
readonly deferWakes: <A, E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E | InvalidScheduleConfigurationError | StorageOperationError, R>;
|
|
154
193
|
/**
|
|
155
194
|
* Commits local application storage and logical alarms in one native SQLite
|
|
156
195
|
* Durable Object transaction, reconciling the native alarm before commit.
|
|
@@ -183,11 +222,17 @@ type AlarmFailurePolicy = "retry" | "skip-and-advance-repeat";
|
|
|
183
222
|
interface AlarmRetryPolicy {
|
|
184
223
|
readonly initialDelay?: Duration.Input;
|
|
185
224
|
}
|
|
186
|
-
|
|
187
|
-
readonly failure?: AlarmFailurePolicy;
|
|
225
|
+
type AlarmDefinitionConfig<Payload extends AlarmPayloadSchema = AlarmPayloadSchema> = {
|
|
188
226
|
readonly payload: Payload;
|
|
227
|
+
} & ({
|
|
228
|
+
readonly lifecycle?: "automatic";
|
|
229
|
+
readonly failure?: AlarmFailurePolicy;
|
|
189
230
|
readonly retry?: AlarmRetryPolicy;
|
|
190
|
-
}
|
|
231
|
+
} | {
|
|
232
|
+
readonly lifecycle: "manual";
|
|
233
|
+
readonly failure?: never;
|
|
234
|
+
readonly retry?: never;
|
|
235
|
+
});
|
|
191
236
|
type AlarmDefinitionEntry = AlarmDefinitionConfig | AlarmPayloadSchema;
|
|
192
237
|
type AlarmDefinitions = Readonly<Record<string, AlarmDefinitionEntry>>;
|
|
193
238
|
type AlarmDefinitionSchema<Definition> = Definition extends AlarmDefinitionConfig<infer Payload> ? Payload : Definition;
|
|
@@ -198,9 +243,14 @@ type DefinedAlarmEvent<Tag extends string, Payload> = Omit<DurableObjectAlarmEve
|
|
|
198
243
|
};
|
|
199
244
|
type DefinedAlarmHandlers<Definitions extends AlarmDefinitions, R = never, E = never> = { readonly [Tag in keyof Definitions & string]: (event: DefinedAlarmEvent<Tag, AlarmDefinitionPayload<Definitions[Tag]>>) => Effect.Effect<void, E, R>; };
|
|
200
245
|
/** A discriminated union keeps each tag paired with its decoded payload type. */
|
|
201
|
-
type DefinedScheduleAlarmInput<Definitions extends AlarmDefinitions> = { readonly [Tag in keyof Definitions & string]: Omit<ScheduleAlarmInput<Tag>, "payload"> & {
|
|
246
|
+
type DefinedScheduleAlarmInput<Definitions extends AlarmDefinitions> = { readonly [Tag in keyof Definitions & string]: Omit<ScheduleAlarmInput<Tag>, "payload" | "lifecycle" | "repeatEvery" | "progress"> & {
|
|
202
247
|
readonly payload: AlarmDefinitionPayload<Definitions[Tag]>;
|
|
203
|
-
}
|
|
248
|
+
} & (Definitions[Tag] extends {
|
|
249
|
+
readonly lifecycle: "manual";
|
|
250
|
+
} ? {
|
|
251
|
+
readonly repeatEvery?: never;
|
|
252
|
+
readonly progress?: never;
|
|
253
|
+
} : Pick<ScheduleAlarmInput<Tag>, "repeatEvery" | "progress">); }[keyof Definitions & string];
|
|
204
254
|
interface DefinedAlarmTransaction<Definitions extends AlarmDefinitions> {
|
|
205
255
|
readonly scheduleAlarm: (input: DefinedScheduleAlarmInput<Definitions>) => ReturnType<AlarmScheduler["scheduleAlarm"]>;
|
|
206
256
|
readonly scheduleAlarmEarlier: DefinedAlarmTransaction<Definitions>["scheduleAlarm"];
|
|
@@ -215,14 +265,29 @@ interface AlarmService {
|
|
|
215
265
|
}
|
|
216
266
|
interface DefinedAlarmScheduler<Definitions extends AlarmDefinitions> extends DefinedAlarmTransaction<Definitions> {
|
|
217
267
|
readonly [TypedAlarmSchedulerTypeId]: typeof TypedAlarmSchedulerTypeId;
|
|
268
|
+
readonly deferWakes: AlarmScheduler["deferWakes"];
|
|
218
269
|
readonly getAlarmStatus: (input: AlarmRef<keyof Definitions & string>) => ReturnType<AlarmScheduler["getAlarmStatus"]>;
|
|
219
270
|
readonly transaction: <A, E, R>(closure: (alarms: DefinedAlarmTransaction<Definitions>) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | StorageOperationError, R>;
|
|
220
271
|
}
|
|
221
272
|
/** Registers a dispatcher and the service authorized to schedule its alarms. */
|
|
222
273
|
interface AlarmRegistration<Self, R = never, E = never> {
|
|
223
|
-
readonly layer: Layer.Layer<Self,
|
|
274
|
+
readonly layer: Layer.Layer<Self, InvalidAlarmRegistrationError, DurableObjectAlarm>;
|
|
224
275
|
readonly run: Effect.Effect<ProcessDueAlarmsResult, E | DurableObjectAlarmError, R | DurableObjectAlarm>;
|
|
276
|
+
readonly [RegistrationParts]?: RegistrationParts<R, E>;
|
|
277
|
+
}
|
|
278
|
+
declare const RegistrationParts: unique symbol;
|
|
279
|
+
interface AlarmDispatcher<R, E> {
|
|
280
|
+
readonly tags: readonly string[];
|
|
281
|
+
readonly automatic: boolean;
|
|
282
|
+
readonly run: AlarmRegistration<never, R, E>["run"];
|
|
283
|
+
}
|
|
284
|
+
interface RegistrationParts<R, E> {
|
|
285
|
+
readonly services: readonly string[];
|
|
286
|
+
readonly dispatchers: readonly AlarmDispatcher<R, E>[];
|
|
287
|
+
readonly invalid?: string;
|
|
225
288
|
}
|
|
289
|
+
/** Compose independent typed alarm registrations under one native alarm owner. */
|
|
290
|
+
declare function mergeAll<const Registrations extends readonly [AlarmRegistration<never, unknown, unknown>, ...AlarmRegistration<never, unknown, unknown>[]]>(...registrations: Registrations): AlarmRegistration<Layer.Success<Registrations[number]["layer"]>, Exclude<Effect.Services<Registrations[number]["run"]>, DurableObjectAlarm>, Exclude<Effect.Error<Registrations[number]["run"]>, DurableObjectAlarmError>>;
|
|
226
291
|
interface AlarmTagClass<Self, Id extends string, Definitions extends AlarmDefinitions> extends Context.ServiceClass<Self, Id, DefinedAlarmScheduler<Definitions>> {
|
|
227
292
|
readonly handlers: <R = never, E = never>(handlers: DefinedAlarmHandlers<Definitions, R, E>, options?: ProcessDueAlarmsOptions<R, E>) => AlarmRegistration<Self, R, E>;
|
|
228
293
|
}
|
|
@@ -230,6 +295,8 @@ interface AlarmTagClass<Self, Id extends string, Definitions extends AlarmDefini
|
|
|
230
295
|
declare const define: <const Definitions extends AlarmDefinitions>(definitions: Definitions) => {
|
|
231
296
|
handlers: <R = never, E = never>(handlers: DefinedAlarmHandlers<Definitions, R, E>, options?: ProcessDueAlarmsOptions<R, E> | undefined) => Effect.Effect<ProcessDueAlarmsResult, E | DurableObjectAlarmError, R | DurableObjectAlarm>;
|
|
232
297
|
};
|
|
298
|
+
/** @internal Preserve custom dispatch while recovering retained alarms after deployments. */
|
|
299
|
+
declare const dispatchRawAlarm: <Self, E, R>(rawAlarm: Effect.Effect<void, E, R>, registration?: AlarmRegistration<Self, R, E>) => Effect.Effect<void, E | DurableObjectAlarmError, R | DurableObjectAlarm | DurableObjectState>;
|
|
233
300
|
/** The typed scheduler becomes available when its handlers are registered on a Durable Object. */
|
|
234
301
|
declare const Tag: <Self>() => <const Id extends string, const Definitions extends AlarmDefinitions>(id: Id, definitions: Definitions) => AlarmTagClass<Self, Id, Definitions>;
|
|
235
302
|
declare const DurableObjectAlarm_base: Context.ServiceClass<DurableObjectAlarm, "effect-cf/DurableObjectAlarm", AlarmScheduler>;
|
|
@@ -237,4 +304,4 @@ declare class DurableObjectAlarm extends DurableObjectAlarm_base {
|
|
|
237
304
|
static readonly layer: Layer.Layer<DurableObjectAlarm, never, DurableObjectState>;
|
|
238
305
|
}
|
|
239
306
|
//#endregion
|
|
240
|
-
export { AlarmDefinitionConfig, AlarmDefinitionEntry, AlarmDefinitionPayload, AlarmDefinitions, AlarmFailurePolicy, AlarmParked, AlarmPayload, AlarmPayloadSchema, AlarmRef, AlarmRegistration, AlarmReporter, AlarmRetryPolicy, AlarmScheduler, AlarmService, AlarmStatus, AlarmTagClass, AlarmTransaction, DEFAULT_MIN_REPEAT_INTERVAL_MS, DefinedAlarmEvent, DefinedAlarmHandlers, DefinedAlarmScheduler, DefinedAlarmTransaction, DefinedScheduleAlarmInput, DurableObjectAlarm, DurableObjectAlarmError, DurableObjectAlarmEvent, DurableObjectAlarm_d_exports, InvalidAlarmPayloadError, InvalidAlarmRefError, InvalidProcessDueAlarmsOptionsError, InvalidRepeatEveryError, InvalidScheduleConfigurationError, MIN_REPEAT_INTERVAL_MS, MIN_RETRY_DELAY_MS, PARKED_RETRY_DELAY_MS, ProcessDueAlarmsFailure, ProcessDueAlarmsFailureAction, ProcessDueAlarmsHandler, ProcessDueAlarmsOptions, ProcessDueAlarmsResult, ScheduleAlarmInput, ScheduleConfiguration, StoredAlarmDecodeError, Tag, UNCHANGED_ATTEMPT_BUDGET, define, processDue };
|
|
307
|
+
export { AlarmDefinitionConfig, AlarmDefinitionEntry, AlarmDefinitionPayload, AlarmDefinitions, AlarmFailurePolicy, AlarmLifecycle, AlarmParked, AlarmPayload, AlarmPayloadSchema, AlarmRef, AlarmRegistration, AlarmReporter, AlarmRetryPolicy, AlarmScheduler, AlarmService, AlarmStatus, AlarmTagClass, AlarmTransaction, DEFAULT_MIN_REPEAT_INTERVAL_MS, DefinedAlarmEvent, DefinedAlarmHandlers, DefinedAlarmScheduler, DefinedAlarmTransaction, DefinedScheduleAlarmInput, DispatchAfterEvent, DurableObjectAlarm, DurableObjectAlarmError, DurableObjectAlarmEvent, DurableObjectAlarm_d_exports, HasDueAlarms, InvalidAlarmPayloadError, InvalidAlarmRefError, InvalidAlarmRegistrationError, InvalidProcessDueAlarmsOptionsError, InvalidRepeatEveryError, InvalidScheduleConfigurationError, MIN_REPEAT_INTERVAL_MS, MIN_RETRY_DELAY_MS, PARKED_RETRY_DELAY_MS, ProcessDueAlarmsFailure, ProcessDueAlarmsFailureAction, ProcessDueAlarmsHandler, ProcessDueAlarmsOptions, ProcessDueAlarmsResult, RunAlarm, ScheduleAlarmInput, ScheduleConfiguration, StoredAlarmDecodeError, Tag, UNCHANGED_ATTEMPT_BUDGET, define, dispatchRawAlarm, mergeAll, processDue };
|