@methodacting/actor-kit 0.47.1 → 0.47.2
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/browser.d.ts +8 -99
- package/dist/index.d.ts +14 -14
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +11 -101
- package/dist/react.js.map +1 -1
- package/dist/src/createActorFetch.d.ts +3 -3
- package/dist/src/createActorFetch.d.ts.map +1 -1
- package/dist/src/createActorKitContext.d.ts +3 -3
- package/dist/src/createActorKitContext.d.ts.map +1 -1
- package/dist/src/createMachineServer.d.ts +21 -14
- package/dist/src/createMachineServer.d.ts.map +1 -1
- package/dist/src/react.d.ts +1 -0
- package/dist/src/react.d.ts.map +1 -1
- package/dist/src/schemas.d.ts +44 -250
- package/dist/src/schemas.d.ts.map +1 -1
- package/dist/src/types.d.ts +12 -12
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/worker.d.ts +1 -0
- package/dist/src/worker.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/createActorFetch.ts +4 -4
- package/src/createActorKitContext.tsx +2 -3
- package/src/createMachineServer.ts +20 -30
- package/src/react.ts +8 -0
- package/src/schemas.ts +5 -2
- package/src/types.ts +35 -44
- package/src/worker.ts +11 -1
package/dist/browser.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DurableObject } from 'cloudflare:workers';
|
|
2
|
-
import {
|
|
2
|
+
import { AnyStateMachine, SnapshotFrom, EventFromLogic, StateValueFrom } from 'xstate';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
declare const RequestInfoSchema: z.ZodObject<{
|
|
@@ -20,7 +20,7 @@ declare const RequestInfoSchema: z.ZodObject<{
|
|
|
20
20
|
passed: z.ZodBoolean;
|
|
21
21
|
}, z.core.$strip>;
|
|
22
22
|
staticResource: z.ZodBoolean;
|
|
23
|
-
detectionIds: z.ZodRecord<z.
|
|
23
|
+
detectionIds: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
24
24
|
score: z.ZodNumber;
|
|
25
25
|
}, z.core.$strip>;
|
|
26
26
|
}, z.core.$strip>;
|
|
@@ -32,60 +32,12 @@ declare const CallerSchema: z.ZodObject<{
|
|
|
32
32
|
service: "service";
|
|
33
33
|
}>;
|
|
34
34
|
}, z.core.$strip>;
|
|
35
|
-
declare const SystemEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
36
|
-
type: z.ZodLiteral<"INITIALIZE">;
|
|
37
|
-
caller: z.ZodObject<{
|
|
38
|
-
type: z.ZodLiteral<"system">;
|
|
39
|
-
id: z.ZodString;
|
|
40
|
-
}, z.core.$strip>;
|
|
41
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
42
|
-
type: z.ZodLiteral<"CONNECT">;
|
|
43
|
-
caller: z.ZodObject<{
|
|
44
|
-
type: z.ZodLiteral<"system">;
|
|
45
|
-
id: z.ZodString;
|
|
46
|
-
}, z.core.$strip>;
|
|
47
|
-
connectingCaller: z.ZodObject<{
|
|
48
|
-
id: z.ZodString;
|
|
49
|
-
type: z.ZodEnum<{
|
|
50
|
-
client: "client";
|
|
51
|
-
system: "system";
|
|
52
|
-
service: "service";
|
|
53
|
-
}>;
|
|
54
|
-
}, z.core.$strip>;
|
|
55
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
56
|
-
type: z.ZodLiteral<"DISCONNECT">;
|
|
57
|
-
caller: z.ZodObject<{
|
|
58
|
-
type: z.ZodLiteral<"system">;
|
|
59
|
-
id: z.ZodString;
|
|
60
|
-
}, z.core.$strip>;
|
|
61
|
-
disconnectingCaller: z.ZodObject<{
|
|
62
|
-
id: z.ZodString;
|
|
63
|
-
type: z.ZodEnum<{
|
|
64
|
-
client: "client";
|
|
65
|
-
system: "system";
|
|
66
|
-
service: "service";
|
|
67
|
-
}>;
|
|
68
|
-
}, z.core.$strip>;
|
|
69
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
70
|
-
type: z.ZodLiteral<"RESUME">;
|
|
71
|
-
caller: z.ZodObject<{
|
|
72
|
-
type: z.ZodLiteral<"system">;
|
|
73
|
-
id: z.ZodString;
|
|
74
|
-
}, z.core.$strip>;
|
|
75
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
76
|
-
type: z.ZodLiteral<"MIGRATE">;
|
|
77
|
-
caller: z.ZodObject<{
|
|
78
|
-
type: z.ZodLiteral<"system">;
|
|
79
|
-
id: z.ZodString;
|
|
80
|
-
}, z.core.$strip>;
|
|
81
|
-
operations: z.ZodArray<z.ZodAny>;
|
|
82
|
-
}, z.core.$strip>], "type">;
|
|
83
35
|
|
|
84
36
|
type EnvWithDurableObjects = {
|
|
85
37
|
ACTOR_KIT_SECRET: string;
|
|
86
38
|
[key: string]: DurableObjectNamespace<ActorServer<any>> | unknown;
|
|
87
39
|
};
|
|
88
|
-
interface ActorServerMethods<TMachine extends
|
|
40
|
+
interface ActorServerMethods<TMachine extends AnyStateMachine> {
|
|
89
41
|
fetch(request: Request): Promise<Response>;
|
|
90
42
|
spawn(props: {
|
|
91
43
|
actorType: string;
|
|
@@ -104,60 +56,17 @@ interface ActorServerMethods<TMachine extends BaseActorKitStateMachine> {
|
|
|
104
56
|
snapshot: CallerSnapshotFrom<TMachine>;
|
|
105
57
|
}>;
|
|
106
58
|
}
|
|
107
|
-
type ActorServer<TMachine extends
|
|
59
|
+
type ActorServer<TMachine extends AnyStateMachine> = DurableObject & ActorServerMethods<TMachine>;
|
|
108
60
|
type Caller = z.infer<typeof CallerSchema>;
|
|
109
61
|
type RequestInfo = z.infer<typeof RequestInfoSchema>;
|
|
110
62
|
type CallerType = "client" | "system" | "service";
|
|
111
|
-
type
|
|
112
|
-
type: string;
|
|
113
|
-
};
|
|
114
|
-
type BaseActorKitContext<TPublicProps extends {
|
|
115
|
-
[key: string]: unknown;
|
|
116
|
-
}, TPrivateProps extends {
|
|
117
|
-
[key: string]: unknown;
|
|
118
|
-
}> = {
|
|
119
|
-
public: TPublicProps;
|
|
120
|
-
private: Record<string, TPrivateProps>;
|
|
121
|
-
};
|
|
122
|
-
type ActorKitStateMachine<TEvent extends BaseActorKitEvent<EnvWithDurableObjects>, TInput extends {
|
|
123
|
-
id: string;
|
|
124
|
-
caller: Caller;
|
|
125
|
-
storage: DurableObjectStorage;
|
|
126
|
-
}, TContext extends BaseActorKitContext<any, any> & {
|
|
127
|
-
[key: string]: unknown;
|
|
128
|
-
}> = StateMachine<TContext, TEvent & EventObject, any, any, any, any, any, any, any, TInput, any, any, any, any>;
|
|
129
|
-
type BaseActorKitInput<TEnv = EnvWithDurableObjects> = {
|
|
130
|
-
id: string;
|
|
131
|
-
caller: Caller;
|
|
132
|
-
env: TEnv;
|
|
133
|
-
storage: DurableObjectStorage;
|
|
134
|
-
};
|
|
135
|
-
type WithActorKitInput<TInputProps extends {
|
|
136
|
-
[key: string]: unknown;
|
|
137
|
-
}, TEnv extends EnvWithDurableObjects> = TInputProps & BaseActorKitInput<TEnv>;
|
|
138
|
-
type AnyActorKitStateMachine = ActorKitStateMachine<any, any, any>;
|
|
139
|
-
type AnyActorKitEvent = (WithActorKitEvent<AnyEventObject, "client"> | WithActorKitEvent<AnyEventObject, "service"> | ActorKitSystemEvent) & BaseActorKitEvent<EnvWithDurableObjects>;
|
|
140
|
-
type AnyActorKitInput = WithActorKitInput<{
|
|
141
|
-
[key: string]: unknown;
|
|
142
|
-
}, EnvWithDurableObjects> & {
|
|
143
|
-
storage: DurableObjectStorage;
|
|
144
|
-
};
|
|
145
|
-
type AnyActorKitContext = {
|
|
146
|
-
public: {
|
|
147
|
-
[key: string]: unknown;
|
|
148
|
-
};
|
|
149
|
-
private: Record<string, {
|
|
150
|
-
[key: string]: unknown;
|
|
151
|
-
}>;
|
|
152
|
-
};
|
|
153
|
-
type BaseActorKitStateMachine = ActorKitStateMachine<AnyActorKitEvent, AnyActorKitInput, AnyActorKitContext>;
|
|
63
|
+
type AnyActorKitStateMachine = AnyStateMachine;
|
|
154
64
|
interface BaseActorKitEvent<TEnv extends EnvWithDurableObjects> {
|
|
155
65
|
caller: Caller;
|
|
156
66
|
storage: DurableObjectStorage;
|
|
157
67
|
requestInfo?: RequestInfo;
|
|
158
68
|
env: TEnv;
|
|
159
69
|
}
|
|
160
|
-
type ActorKitSystemEvent = z.infer<typeof SystemEventSchema>;
|
|
161
70
|
type WithActorKitEvent<T extends {
|
|
162
71
|
type: string;
|
|
163
72
|
}, C extends CallerType> = T & BaseActorKitEvent<EnvWithDurableObjects> & {
|
|
@@ -180,9 +89,9 @@ type CallerSnapshotFrom<TMachine extends AnyStateMachine> = {
|
|
|
180
89
|
value: infer V;
|
|
181
90
|
} ? V : unknown;
|
|
182
91
|
};
|
|
183
|
-
type ClientEventFrom<T extends
|
|
184
|
-
type ServiceEventFrom<T extends
|
|
185
|
-
type ActorKitClient<TMachine extends
|
|
92
|
+
type ClientEventFrom<T extends AnyStateMachine> = EventFromLogic<T> extends infer TEvent ? TEvent extends WithActorKitEvent<infer E, "client"> ? Omit<E, keyof BaseActorKitEvent<EnvWithDurableObjects>> : Omit<TEvent, keyof BaseActorKitEvent<EnvWithDurableObjects>> : never;
|
|
93
|
+
type ServiceEventFrom<T extends AnyStateMachine> = EventFromLogic<T> extends infer TEvent ? TEvent extends WithActorKitEvent<infer E, "service"> ? Omit<E, keyof BaseActorKitEvent<EnvWithDurableObjects>> : never : never;
|
|
94
|
+
type ActorKitClient<TMachine extends AnyStateMachine> = {
|
|
186
95
|
connect: () => Promise<void>;
|
|
187
96
|
disconnect: () => void;
|
|
188
97
|
send: (event: ClientEventFrom<TMachine>) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DurableObject } from 'cloudflare:workers';
|
|
3
3
|
import { Operation } from 'fast-json-patch';
|
|
4
|
-
import {
|
|
4
|
+
import { AnyStateMachine, EventFromLogic, StateValueFrom, SnapshotFrom, StateMachine, AnyEventObject, AnyActorRef } from 'xstate';
|
|
5
5
|
|
|
6
6
|
declare const BotManagementSchema: z.ZodObject<{
|
|
7
7
|
corporateProxy: z.ZodBoolean;
|
|
@@ -10,7 +10,7 @@ declare const BotManagementSchema: z.ZodObject<{
|
|
|
10
10
|
passed: z.ZodBoolean;
|
|
11
11
|
}, z.core.$strip>;
|
|
12
12
|
staticResource: z.ZodBoolean;
|
|
13
|
-
detectionIds: z.ZodRecord<z.
|
|
13
|
+
detectionIds: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
14
14
|
score: z.ZodNumber;
|
|
15
15
|
}, z.core.$strip>;
|
|
16
16
|
declare const EnvironmentSchema: z.ZodObject<{
|
|
@@ -35,7 +35,7 @@ declare const RequestInfoSchema: z.ZodObject<{
|
|
|
35
35
|
passed: z.ZodBoolean;
|
|
36
36
|
}, z.core.$strip>;
|
|
37
37
|
staticResource: z.ZodBoolean;
|
|
38
|
-
detectionIds: z.ZodRecord<z.
|
|
38
|
+
detectionIds: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
39
39
|
score: z.ZodNumber;
|
|
40
40
|
}, z.core.$strip>;
|
|
41
41
|
}, z.core.$strip>;
|
|
@@ -222,7 +222,7 @@ type EnvWithDurableObjects = {
|
|
|
222
222
|
[key: string]: DurableObjectNamespace<ActorServer<any>> | unknown;
|
|
223
223
|
};
|
|
224
224
|
type AnyEvent = z.infer<typeof AnyEventSchema>;
|
|
225
|
-
interface ActorServerMethods<TMachine extends
|
|
225
|
+
interface ActorServerMethods<TMachine extends AnyStateMachine> {
|
|
226
226
|
fetch(request: Request): Promise<Response>;
|
|
227
227
|
spawn(props: {
|
|
228
228
|
actorType: string;
|
|
@@ -241,7 +241,7 @@ interface ActorServerMethods<TMachine extends BaseActorKitStateMachine> {
|
|
|
241
241
|
snapshot: CallerSnapshotFrom<TMachine>;
|
|
242
242
|
}>;
|
|
243
243
|
}
|
|
244
|
-
type ActorServer<TMachine extends
|
|
244
|
+
type ActorServer<TMachine extends AnyStateMachine> = DurableObject & ActorServerMethods<TMachine>;
|
|
245
245
|
type AnyActorServer = ActorServer<any>;
|
|
246
246
|
type Caller = z.infer<typeof CallerSchema>;
|
|
247
247
|
type RequestInfo = z.infer<typeof RequestInfoSchema>;
|
|
@@ -255,14 +255,14 @@ type CallerType = "client" | "system" | "service";
|
|
|
255
255
|
type EventObject = {
|
|
256
256
|
type: string;
|
|
257
257
|
};
|
|
258
|
-
type EventSchemaUnion = z.ZodDiscriminatedUnion<
|
|
258
|
+
type EventSchemaUnion = z.ZodDiscriminatedUnion<[
|
|
259
259
|
z.ZodObject<z.ZodRawShape & {
|
|
260
260
|
type: z.ZodString;
|
|
261
261
|
}>,
|
|
262
262
|
...z.ZodObject<z.ZodRawShape & {
|
|
263
263
|
type: z.ZodString;
|
|
264
264
|
}>[]
|
|
265
|
-
]>;
|
|
265
|
+
], "type">;
|
|
266
266
|
type EventSchemas = {
|
|
267
267
|
client: EventSchemaUnion;
|
|
268
268
|
service: EventSchemaUnion;
|
|
@@ -291,7 +291,7 @@ type BaseActorKitInput<TEnv = EnvWithDurableObjects> = {
|
|
|
291
291
|
type WithActorKitInput<TInputProps extends {
|
|
292
292
|
[key: string]: unknown;
|
|
293
293
|
}, TEnv extends EnvWithDurableObjects> = TInputProps & BaseActorKitInput<TEnv>;
|
|
294
|
-
type AnyActorKitStateMachine =
|
|
294
|
+
type AnyActorKitStateMachine = AnyStateMachine;
|
|
295
295
|
type AnyActorKitEvent = (WithActorKitEvent<AnyEventObject, "client"> | WithActorKitEvent<AnyEventObject, "service"> | ActorKitSystemEvent) & BaseActorKitEvent<EnvWithDurableObjects>;
|
|
296
296
|
type AnyActorKitInput = WithActorKitInput<{
|
|
297
297
|
[key: string]: unknown;
|
|
@@ -349,14 +349,14 @@ type CallerSnapshotFrom<TMachine extends AnyStateMachine> = {
|
|
|
349
349
|
value: infer V;
|
|
350
350
|
} ? V : unknown;
|
|
351
351
|
};
|
|
352
|
-
type ClientEventFrom<T extends
|
|
353
|
-
type ServiceEventFrom<T extends
|
|
352
|
+
type ClientEventFrom<T extends AnyStateMachine> = EventFromLogic<T> extends infer TEvent ? TEvent extends WithActorKitEvent<infer E, "client"> ? Omit<E, keyof BaseActorKitEvent<EnvWithDurableObjects>> : Omit<TEvent, keyof BaseActorKitEvent<EnvWithDurableObjects>> : never;
|
|
353
|
+
type ServiceEventFrom<T extends AnyStateMachine> = EventFromLogic<T> extends infer TEvent ? TEvent extends WithActorKitEvent<infer E, "service"> ? Omit<E, keyof BaseActorKitEvent<EnvWithDurableObjects>> : never : never;
|
|
354
354
|
type ScreamingSnakeToKebab<S extends string> = S extends `${infer T}_${infer U}` ? `${Lowercase<T>}-${ScreamingSnakeToKebab<U>}` : Lowercase<S>;
|
|
355
|
-
type DurableObjectActor<TMachine extends
|
|
355
|
+
type DurableObjectActor<TMachine extends AnyStateMachine> = ActorServer<TMachine>;
|
|
356
356
|
type CamelToSnakeCase<S extends string> = S extends `${infer T}${infer U}` ? U extends Uncapitalize<U> ? `${Lowercase<T>}${CamelToSnakeCase<U>}` : `${Lowercase<T>}_${CamelToSnakeCase<U>}` : S;
|
|
357
357
|
type KebabToCamelCase<S extends string> = S extends `${infer T}-${infer U}` ? `${T}${Capitalize<KebabToCamelCase<U>>}` : S;
|
|
358
358
|
type KebabToScreamingSnake<S extends string> = Uppercase<CamelToSnakeCase<KebabToCamelCase<S>>>;
|
|
359
|
-
interface MatchesProps<TMachine extends
|
|
359
|
+
interface MatchesProps<TMachine extends AnyStateMachine> {
|
|
360
360
|
state: StateValueFrom<TMachine>;
|
|
361
361
|
and?: StateValueFrom<TMachine>;
|
|
362
362
|
or?: StateValueFrom<TMachine>;
|
|
@@ -368,7 +368,7 @@ type ActorKitEmittedEvent = {
|
|
|
368
368
|
operations: Operation[];
|
|
369
369
|
checksum: string;
|
|
370
370
|
};
|
|
371
|
-
type ActorKitClient<TMachine extends
|
|
371
|
+
type ActorKitClient<TMachine extends AnyStateMachine> = {
|
|
372
372
|
connect: () => Promise<void>;
|
|
373
373
|
disconnect: () => void;
|
|
374
374
|
send: (event: ClientEventFrom<TMachine>) => void;
|
|
@@ -380,7 +380,7 @@ type ExtractEventType<TMachine> = TMachine extends ActorKitStateMachine<infer TE
|
|
|
380
380
|
type ExtractEnvType<TEvent> = TEvent extends {
|
|
381
381
|
env: infer TEnv;
|
|
382
382
|
} ? TEnv : never;
|
|
383
|
-
type EnvFromMachine<TMachine extends
|
|
383
|
+
type EnvFromMachine<TMachine extends AnyStateMachine> = ExtractEnvType<ExtractEventType<TMachine>> extends never ? EnvWithDurableObjects : ExtractEnvType<ExtractEventType<TMachine>> & EnvWithDurableObjects;
|
|
384
384
|
interface MachineServerOptions {
|
|
385
385
|
persisted?: boolean;
|
|
386
386
|
enableAlarms?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{z as e}from"zod";const t=e.object({corporateProxy:e.boolean(),verifiedBot:e.boolean(),jsDetection:e.object({passed:e.boolean()}),staticResource:e.boolean(),detectionIds:e.record(e.any()),score:e.number()}),a=e.object({ACTOR_KIT_SECRET:e.string(),ACTOR_KIT_HOST:e.string()}),s=e.object({longitude:e.string(),latitude:e.string(),continent:e.string(),country:e.string(),city:e.string(),timezone:e.string(),postalCode:e.string(),region:e.string(),regionCode:e.string(),metroCode:e.string(),botManagement:t}),r=e.object({id:e.string(),type:e.enum(["client","system","service"])}),i=e.object({type:e.string()}),n=e.discriminatedUnion("type",[e.object({type:e.literal("INITIALIZE"),caller:e.object({type:e.literal("system"),id:e.string()})}),e.object({type:e.literal("CONNECT"),caller:e.object({type:e.literal("system"),id:e.string()}),connectingCaller:r}),e.object({type:e.literal("DISCONNECT"),caller:e.object({type:e.literal("system"),id:e.string()}),disconnectingCaller:r}),e.object({type:e.literal("RESUME"),caller:e.object({type:e.literal("system"),id:e.string()})}),e.object({type:e.literal("MIGRATE"),caller:e.object({type:e.literal("system"),id:e.string()}),operations:e.array(e.any())})]),l=e.enum(["client","service","system"]),c=e.string().transform((t,a)=>{if("anonymous"===t)return{type:"client",id:"anonymous"};const s=l.safeParse(t.split("-")[0]);if(!s.success)return s.error.issues.forEach(a.addIssue),e.NEVER;const r=s.data,i=t.substring(t.indexOf("-")+1);return e.string().uuid().safeParse(i).success?{type:r,id:i}:(a.addIssue({code:e.ZodIssueCode.custom,message:`Must be a valid uuid or 'anonymous'. Received '${i}' on value '${t}'.`}),e.NEVER)}),o={X_CALLER_ID:"X-Caller-ID",X_CALLER_TYPE:"X-Caller-Type",X_ACTOR_ID:"X-Actor-ID",X_ACTOR_TYPE:"X-Actor-Type"},d={client:"client",system:"system",service:"service"},u={"xstate-delay":"xstate-delay","cache-cleanup":"cache-cleanup",custom:"custom"},p="persistedSnapshot";class h{storage;initialized=!1;sql;constructor(e){this.storage=e,this.sql=e.sql}async ensureInitialized(){if(!this.initialized)try{await this.sql.exec("\n-- Alarms table - supports one-time and recurring alarms\nCREATE TABLE IF NOT EXISTS alarms (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n scheduled_at INTEGER NOT NULL,\n repeat_interval INTEGER,\n payload TEXT,\n created_at INTEGER NOT NULL\n);\n\n-- Index for efficient due alarm queries\nCREATE INDEX IF NOT EXISTS idx_alarms_scheduled_at ON alarms(scheduled_at);\n\n-- Actor metadata (replaces KV keys: actorType, actorId, initialCaller, input)\nCREATE TABLE IF NOT EXISTS actor_meta (\n actor_id TEXT PRIMARY KEY,\n actor_type TEXT NOT NULL,\n initial_caller TEXT NOT NULL,\n input TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Snapshots table (replaces PERSISTED_SNAPSHOT_KEY)\nCREATE TABLE IF NOT EXISTS snapshots (\n actor_id TEXT PRIMARY KEY,\n snapshot TEXT NOT NULL,\n checksum TEXT,\n updated_at INTEGER NOT NULL\n);\n"),this.initialized=!0}catch(e){throw console.error("Failed to initialize database schema:",e),e}}async getAlarms(){await this.ensureInitialized();const e=await this.sql.exec("SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms ORDER BY scheduled_at ASC");return await this.parseRows(e)}async getDueAlarms(e){await this.ensureInitialized();const t=await this.sql.exec("SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms WHERE scheduled_at <= ? ORDER BY scheduled_at ASC",e);return await this.parseRows(t)}async getEarliestAlarm(){await this.ensureInitialized();const e=await this.sql.exec("SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms ORDER BY scheduled_at ASC LIMIT 1");return(await this.parseRows(e))[0]||null}async insertAlarm(e){await this.ensureInitialized(),await this.sql.exec("INSERT INTO alarms (id, type, scheduled_at, repeat_interval, payload, created_at) VALUES (?, ?, ?, ?, ?, ?)",e.id,e.type,e.scheduledAt,e.repeatInterval??null,JSON.stringify(e.payload),Date.now())}async updateAlarm(e){await this.ensureInitialized(),await this.sql.exec("UPDATE alarms SET scheduled_at = ?, repeat_interval = ?, payload = ? WHERE id = ?",e.scheduledAt,e.repeatInterval??null,JSON.stringify(e.payload),e.id)}async deleteAlarm(e){await this.ensureInitialized(),await this.sql.exec("DELETE FROM alarms WHERE id = ?",e)}async deleteAlarmsByType(e){await this.ensureInitialized(),await this.sql.exec("DELETE FROM alarms WHERE type = ?",e)}async getActorMeta(e){if(await this.ensureInitialized(),!e){const e=await this.sql.exec("SELECT actor_id, actor_type, initial_caller, input, created_at, updated_at FROM actor_meta LIMIT 1"),t=await this.parseRows(e);if(0===t.length)return null;const a=t[0];return{actorId:a.actor_id,actorType:a.actor_type,initialCaller:JSON.parse(a.initial_caller),input:JSON.parse(a.input)}}const t=await this.sql.exec("SELECT actor_id, actor_type, initial_caller, input, created_at, updated_at FROM actor_meta WHERE actor_id = ?",e),a=await this.parseRows(t);if(0===a.length)return null;const s=a[0];return{actorId:s.actor_id,actorType:s.actor_type,initialCaller:JSON.parse(s.initial_caller),input:JSON.parse(s.input)}}async setActorMeta(e){await this.ensureInitialized();const t=Date.now();await this.sql.exec("INSERT INTO actor_meta (actor_id, actor_type, initial_caller, input, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(actor_id) DO UPDATE SET\n actor_type = excluded.actor_type,\n initial_caller = excluded.initial_caller,\n input = excluded.input,\n updated_at = excluded.updated_at",e.actorId,e.actorType,JSON.stringify(e.initialCaller),JSON.stringify(e.input),t,t)}async deleteActorMeta(e){await this.ensureInitialized(),await this.sql.exec("DELETE FROM actor_meta WHERE actor_id = ?",e)}async getSnapshot(e){await this.ensureInitialized();const t=await this.sql.exec("SELECT actor_id, snapshot, checksum, updated_at FROM snapshots WHERE actor_id = ?",e),a=await this.parseRows(t);if(0===a.length)return null;const s=a[0];return{actorId:s.actor_id,snapshot:JSON.parse(s.snapshot),checksum:s.checksum??void 0}}async setSnapshot(e,t,a){await this.ensureInitialized(),await this.sql.exec("INSERT INTO snapshots (actor_id, snapshot, checksum, updated_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(actor_id) DO UPDATE SET\n snapshot = excluded.snapshot,\n checksum = excluded.checksum,\n updated_at = excluded.updated_at",e,JSON.stringify(t),a??null,Date.now())}async deleteSnapshot(e){await this.ensureInitialized(),await this.sql.exec("DELETE FROM snapshots WHERE actor_id = ?",e)}async migrateFromKV(e){await this.ensureInitialized();const[t,a,s,r]=await Promise.all([e.get("actorType"),e.get("actorId"),e.get("initialCaller"),e.get("input")]);t&&a&&s&&r&&await this.setActorMeta({actorId:a,actorType:t,initialCaller:JSON.parse(s),input:JSON.parse(r)});const i=await e.get(p);if(i){const e=JSON.parse(i);await this.setSnapshot(a,e)}}async parseRows(e){if(e&&"function"==typeof e[Symbol.asyncIterator]){const t=e,a=[];let s=null;for await(const e of t){s||(s=e.columns);for(const t of e.results){const e={};(s??[]).forEach((a,s)=>{e[a]=t[s]}),a.push(e)}}return a}const t=Array.isArray(e)?e:e?[e]:[];if(0===t.length)return[];const a=t[0],s=a?.columns??a?.columnNames??[],r=a?.rows??a?.results??[];return s.length&&r.length?r.map(e=>{const t={};return s.forEach((a,s)=>{t[a]=e[s]}),t}):[]}}class y{storage;state;currentAlarmId=null;currentAlarmTime=null;constructor(e,t){this.storage=e,this.state=t}async schedule(e){await this.storage.insertAlarm(e),await this.rescheduleNextAlarm()}async cancel(e){await this.storage.deleteAlarm(e),this.currentAlarmId===e&&await this.rescheduleNextAlarm()}async cancelByType(e){await this.storage.deleteAlarmsByType(e),await this.rescheduleNextAlarm()}async getPendingAlarms(){return(await this.storage.getAlarms()).map(this.parseAlarmRecord)}async getDueAlarms(e=Date.now()){return(await this.storage.getDueAlarms(e)).map(this.parseAlarmRecord)}async deleteAlarm(e){await this.storage.deleteAlarm(e)}async updateAlarm(e){await this.storage.updateAlarm(e)}async rescheduleNextAlarm(){const e=await this.storage.getEarliestAlarm();if(!e)return this.currentAlarmId=null,void(this.currentAlarmTime=null);this.currentAlarmId===e.id&&this.currentAlarmTime===e.scheduled_at||(this.currentAlarmId=e.id,this.currentAlarmTime=e.scheduled_at,await this.state.storage.setAlarm(e.scheduled_at))}async handleDueAlarms(e){const t=Date.now(),a=await this.getDueAlarms(t),s=[];for(const r of a){let a=!1,i=!0;if(r.repeatInterval){const e=t+r.repeatInterval;await this.updateAlarm({id:r.id,type:r.type,scheduledAt:e,repeatInterval:r.repeatInterval,payload:r.payload}),a=!0,i=!1}else await this.deleteAlarm(r.id);try{await e(r)}catch(e){console.error(`Error handling alarm ${r.id}:`,e)}s.push({id:r.id,type:r.type,rescheduled:a,deleted:i})}return await this.rescheduleNextAlarm(),s}getCurrentAlarm(){return{id:this.currentAlarmId,time:this.currentAlarmTime}}parseAlarmRecord(e){return{id:e.id,type:e.type,scheduledAt:e.scheduled_at,repeatInterval:e.repeat_interval??void 0,payload:e.payload?JSON.parse(e.payload):{},createdAt:e.created_at}}}function m(){return`alarm-${Date.now()}-${Math.random().toString(36).slice(2,11)}`}function E(e,t,a=Date.now()){let s=e;for(;s<a;)s+=t;return s}const T={setTimeout:()=>Math.random(),clearTimeout:()=>{}},I=new Map;function _(e,t){return{schedule:(t,a,s,r,i=Math.random().toString(36).slice(2))=>{const n=`${t.sessionId}.${i}`,l={sourceSessionId:t.sessionId,targetSessionId:a.sessionId,event:s,delay:r,id:i,startedAt:Date.now()};I.set(n,l);const c=`xstate-${n}`;e.schedule({id:c,type:"xstate-delay",scheduledAt:Date.now()+r,payload:{type:"xstate-delay",sourceSessionId:t.sessionId,targetSessionId:a.sessionId,event:s,scheduledEventId:n,alarmId:c}}).catch(e=>{console.error("[AlarmScheduler] Error scheduling alarm:",e),I.delete(n)})},cancel:(t,a)=>{const s=`${t.sessionId}.${a}`;I.delete(s),e.cancel(`xstate-${s}`).catch(e=>{console.error("[AlarmScheduler] Error canceling alarm:",e)})},cancelAll:t=>{const a=[];for(const[e,s]of I.entries())s.sourceSessionId===t.sessionId&&a.push(e);for(const t of a)I.delete(t),e.cancel(`xstate-${t}`).catch(e=>{console.error("[AlarmScheduler] Error canceling alarm:",e)})}}}async function A(e,t){const{scheduledEventId:a,event:s}=e;I.delete(a);try{t.system&&t.system._relay?t.system._relay(t,t,s):t.send(s)}catch(e){console.error("[AlarmScheduler] Error handling XState alarm:",e)}}function g(){return new Map(I)}function w(e){for(const t of e)if("xstate-delay"===t.payload.type){const{sourceSessionId:e,targetSessionId:a,event:s,scheduledEventId:r}=t.payload,i=t.scheduledAt-Date.now();i>0&&I.set(r,{sourceSessionId:e,targetSessionId:a,event:s,delay:i,id:r.split(".").pop()||r,startedAt:t.scheduledAt-i})}}export{h as ActorKitStorage,y as AlarmManager,u as AlarmTypes,i as AnyEventSchema,t as BotManagementSchema,l as CallerIdTypeSchema,r as CallerSchema,c as CallerStringSchema,d as CallerTypes,a as EnvironmentSchema,o as HEADERS,T as NOOP_CLOCK,p as PERSISTED_SNAPSHOT_KEY,s as RequestInfoSchema,n as SystemEventSchema,E as calculateNextRecurringAlarm,_ as createAlarmScheduler,m as generateAlarmId,g as getScheduledEvents,A as handleXStateAlarm,w as restoreScheduledEvents};
|
|
1
|
+
import{z as e}from"zod";const t=e.object({corporateProxy:e.boolean(),verifiedBot:e.boolean(),jsDetection:e.object({passed:e.boolean()}),staticResource:e.boolean(),detectionIds:e.record(e.string(),e.any()),score:e.number()}),a=e.object({ACTOR_KIT_SECRET:e.string(),ACTOR_KIT_HOST:e.string()}),s=e.object({longitude:e.string(),latitude:e.string(),continent:e.string(),country:e.string(),city:e.string(),timezone:e.string(),postalCode:e.string(),region:e.string(),regionCode:e.string(),metroCode:e.string(),botManagement:t}),r=e.object({id:e.string(),type:e.enum(["client","system","service"])}),i=e.object({type:e.string()}),n=e.discriminatedUnion("type",[e.object({type:e.literal("INITIALIZE"),caller:e.object({type:e.literal("system"),id:e.string()})}),e.object({type:e.literal("CONNECT"),caller:e.object({type:e.literal("system"),id:e.string()}),connectingCaller:r}),e.object({type:e.literal("DISCONNECT"),caller:e.object({type:e.literal("system"),id:e.string()}),disconnectingCaller:r}),e.object({type:e.literal("RESUME"),caller:e.object({type:e.literal("system"),id:e.string()})}),e.object({type:e.literal("MIGRATE"),caller:e.object({type:e.literal("system"),id:e.string()}),operations:e.array(e.any())})]),l=e.enum(["client","service","system"]),c=e.string().transform((t,a)=>{if("anonymous"===t)return{type:"client",id:"anonymous"};const s=l.safeParse(t.split("-")[0]);if(!s.success)return a.addIssue({code:e.ZodIssueCode.custom,message:`Invalid caller type: ${t.split("-")[0]}`}),e.NEVER;const r=s.data,i=t.substring(t.indexOf("-")+1);return e.string().uuid().safeParse(i).success?{type:r,id:i}:(a.addIssue({code:e.ZodIssueCode.custom,message:`Must be a valid uuid or 'anonymous'. Received '${i}' on value '${t}'.`}),e.NEVER)}),o={X_CALLER_ID:"X-Caller-ID",X_CALLER_TYPE:"X-Caller-Type",X_ACTOR_ID:"X-Actor-ID",X_ACTOR_TYPE:"X-Actor-Type"},d={client:"client",system:"system",service:"service"},u={"xstate-delay":"xstate-delay","cache-cleanup":"cache-cleanup",custom:"custom"},p="persistedSnapshot";class h{storage;initialized=!1;sql;constructor(e){this.storage=e,this.sql=e.sql}async ensureInitialized(){if(!this.initialized)try{await this.sql.exec("\n-- Alarms table - supports one-time and recurring alarms\nCREATE TABLE IF NOT EXISTS alarms (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n scheduled_at INTEGER NOT NULL,\n repeat_interval INTEGER,\n payload TEXT,\n created_at INTEGER NOT NULL\n);\n\n-- Index for efficient due alarm queries\nCREATE INDEX IF NOT EXISTS idx_alarms_scheduled_at ON alarms(scheduled_at);\n\n-- Actor metadata (replaces KV keys: actorType, actorId, initialCaller, input)\nCREATE TABLE IF NOT EXISTS actor_meta (\n actor_id TEXT PRIMARY KEY,\n actor_type TEXT NOT NULL,\n initial_caller TEXT NOT NULL,\n input TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Snapshots table (replaces PERSISTED_SNAPSHOT_KEY)\nCREATE TABLE IF NOT EXISTS snapshots (\n actor_id TEXT PRIMARY KEY,\n snapshot TEXT NOT NULL,\n checksum TEXT,\n updated_at INTEGER NOT NULL\n);\n"),this.initialized=!0}catch(e){throw console.error("Failed to initialize database schema:",e),e}}async getAlarms(){await this.ensureInitialized();const e=await this.sql.exec("SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms ORDER BY scheduled_at ASC");return await this.parseRows(e)}async getDueAlarms(e){await this.ensureInitialized();const t=await this.sql.exec("SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms WHERE scheduled_at <= ? ORDER BY scheduled_at ASC",e);return await this.parseRows(t)}async getEarliestAlarm(){await this.ensureInitialized();const e=await this.sql.exec("SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms ORDER BY scheduled_at ASC LIMIT 1");return(await this.parseRows(e))[0]||null}async insertAlarm(e){await this.ensureInitialized(),await this.sql.exec("INSERT INTO alarms (id, type, scheduled_at, repeat_interval, payload, created_at) VALUES (?, ?, ?, ?, ?, ?)",e.id,e.type,e.scheduledAt,e.repeatInterval??null,JSON.stringify(e.payload),Date.now())}async updateAlarm(e){await this.ensureInitialized(),await this.sql.exec("UPDATE alarms SET scheduled_at = ?, repeat_interval = ?, payload = ? WHERE id = ?",e.scheduledAt,e.repeatInterval??null,JSON.stringify(e.payload),e.id)}async deleteAlarm(e){await this.ensureInitialized(),await this.sql.exec("DELETE FROM alarms WHERE id = ?",e)}async deleteAlarmsByType(e){await this.ensureInitialized(),await this.sql.exec("DELETE FROM alarms WHERE type = ?",e)}async getActorMeta(e){if(await this.ensureInitialized(),!e){const e=await this.sql.exec("SELECT actor_id, actor_type, initial_caller, input, created_at, updated_at FROM actor_meta LIMIT 1"),t=await this.parseRows(e);if(0===t.length)return null;const a=t[0];return{actorId:a.actor_id,actorType:a.actor_type,initialCaller:JSON.parse(a.initial_caller),input:JSON.parse(a.input)}}const t=await this.sql.exec("SELECT actor_id, actor_type, initial_caller, input, created_at, updated_at FROM actor_meta WHERE actor_id = ?",e),a=await this.parseRows(t);if(0===a.length)return null;const s=a[0];return{actorId:s.actor_id,actorType:s.actor_type,initialCaller:JSON.parse(s.initial_caller),input:JSON.parse(s.input)}}async setActorMeta(e){await this.ensureInitialized();const t=Date.now();await this.sql.exec("INSERT INTO actor_meta (actor_id, actor_type, initial_caller, input, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(actor_id) DO UPDATE SET\n actor_type = excluded.actor_type,\n initial_caller = excluded.initial_caller,\n input = excluded.input,\n updated_at = excluded.updated_at",e.actorId,e.actorType,JSON.stringify(e.initialCaller),JSON.stringify(e.input),t,t)}async deleteActorMeta(e){await this.ensureInitialized(),await this.sql.exec("DELETE FROM actor_meta WHERE actor_id = ?",e)}async getSnapshot(e){await this.ensureInitialized();const t=await this.sql.exec("SELECT actor_id, snapshot, checksum, updated_at FROM snapshots WHERE actor_id = ?",e),a=await this.parseRows(t);if(0===a.length)return null;const s=a[0];return{actorId:s.actor_id,snapshot:JSON.parse(s.snapshot),checksum:s.checksum??void 0}}async setSnapshot(e,t,a){await this.ensureInitialized(),await this.sql.exec("INSERT INTO snapshots (actor_id, snapshot, checksum, updated_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(actor_id) DO UPDATE SET\n snapshot = excluded.snapshot,\n checksum = excluded.checksum,\n updated_at = excluded.updated_at",e,JSON.stringify(t),a??null,Date.now())}async deleteSnapshot(e){await this.ensureInitialized(),await this.sql.exec("DELETE FROM snapshots WHERE actor_id = ?",e)}async migrateFromKV(e){await this.ensureInitialized();const[t,a,s,r]=await Promise.all([e.get("actorType"),e.get("actorId"),e.get("initialCaller"),e.get("input")]);t&&a&&s&&r&&await this.setActorMeta({actorId:a,actorType:t,initialCaller:JSON.parse(s),input:JSON.parse(r)});const i=await e.get(p);if(i){const e=JSON.parse(i);await this.setSnapshot(a,e)}}async parseRows(e){if(e&&"function"==typeof e[Symbol.asyncIterator]){const t=e,a=[];let s=null;for await(const e of t){s||(s=e.columns);for(const t of e.results){const e={};(s??[]).forEach((a,s)=>{e[a]=t[s]}),a.push(e)}}return a}const t=Array.isArray(e)?e:e?[e]:[];if(0===t.length)return[];const a=t[0],s=a?.columns??a?.columnNames??[],r=a?.rows??a?.results??[];return s.length&&r.length?r.map(e=>{const t={};return s.forEach((a,s)=>{t[a]=e[s]}),t}):[]}}class y{storage;state;currentAlarmId=null;currentAlarmTime=null;constructor(e,t){this.storage=e,this.state=t}async schedule(e){await this.storage.insertAlarm(e),await this.rescheduleNextAlarm()}async cancel(e){await this.storage.deleteAlarm(e),this.currentAlarmId===e&&await this.rescheduleNextAlarm()}async cancelByType(e){await this.storage.deleteAlarmsByType(e),await this.rescheduleNextAlarm()}async getPendingAlarms(){return(await this.storage.getAlarms()).map(this.parseAlarmRecord)}async getDueAlarms(e=Date.now()){return(await this.storage.getDueAlarms(e)).map(this.parseAlarmRecord)}async deleteAlarm(e){await this.storage.deleteAlarm(e)}async updateAlarm(e){await this.storage.updateAlarm(e)}async rescheduleNextAlarm(){const e=await this.storage.getEarliestAlarm();if(!e)return this.currentAlarmId=null,void(this.currentAlarmTime=null);this.currentAlarmId===e.id&&this.currentAlarmTime===e.scheduled_at||(this.currentAlarmId=e.id,this.currentAlarmTime=e.scheduled_at,await this.state.storage.setAlarm(e.scheduled_at))}async handleDueAlarms(e){const t=Date.now(),a=await this.getDueAlarms(t),s=[];for(const r of a){let a=!1,i=!0;if(r.repeatInterval){const e=t+r.repeatInterval;await this.updateAlarm({id:r.id,type:r.type,scheduledAt:e,repeatInterval:r.repeatInterval,payload:r.payload}),a=!0,i=!1}else await this.deleteAlarm(r.id);try{await e(r)}catch(e){console.error(`Error handling alarm ${r.id}:`,e)}s.push({id:r.id,type:r.type,rescheduled:a,deleted:i})}return await this.rescheduleNextAlarm(),s}getCurrentAlarm(){return{id:this.currentAlarmId,time:this.currentAlarmTime}}parseAlarmRecord(e){return{id:e.id,type:e.type,scheduledAt:e.scheduled_at,repeatInterval:e.repeat_interval??void 0,payload:e.payload?JSON.parse(e.payload):{},createdAt:e.created_at}}}function m(){return`alarm-${Date.now()}-${Math.random().toString(36).slice(2,11)}`}function E(e,t,a=Date.now()){let s=e;for(;s<a;)s+=t;return s}const T={setTimeout:()=>Math.random(),clearTimeout:()=>{}},I=new Map;function _(e,t){return{schedule:(t,a,s,r,i=Math.random().toString(36).slice(2))=>{const n=`${t.sessionId}.${i}`,l={sourceSessionId:t.sessionId,targetSessionId:a.sessionId,event:s,delay:r,id:i,startedAt:Date.now()};I.set(n,l);const c=`xstate-${n}`;e.schedule({id:c,type:"xstate-delay",scheduledAt:Date.now()+r,payload:{type:"xstate-delay",sourceSessionId:t.sessionId,targetSessionId:a.sessionId,event:s,scheduledEventId:n,alarmId:c}}).catch(e=>{console.error("[AlarmScheduler] Error scheduling alarm:",e),I.delete(n)})},cancel:(t,a)=>{const s=`${t.sessionId}.${a}`;I.delete(s),e.cancel(`xstate-${s}`).catch(e=>{console.error("[AlarmScheduler] Error canceling alarm:",e)})},cancelAll:t=>{const a=[];for(const[e,s]of I.entries())s.sourceSessionId===t.sessionId&&a.push(e);for(const t of a)I.delete(t),e.cancel(`xstate-${t}`).catch(e=>{console.error("[AlarmScheduler] Error canceling alarm:",e)})}}}async function A(e,t){const{scheduledEventId:a,event:s}=e;I.delete(a);try{t.system&&t.system._relay?t.system._relay(t,t,s):t.send(s)}catch(e){console.error("[AlarmScheduler] Error handling XState alarm:",e)}}function g(){return new Map(I)}function w(e){for(const t of e)if("xstate-delay"===t.payload.type){const{sourceSessionId:e,targetSessionId:a,event:s,scheduledEventId:r}=t.payload,i=t.scheduledAt-Date.now();i>0&&I.set(r,{sourceSessionId:e,targetSessionId:a,event:s,delay:i,id:r.split(".").pop()||r,startedAt:t.scheduledAt-i})}}export{h as ActorKitStorage,y as AlarmManager,u as AlarmTypes,i as AnyEventSchema,t as BotManagementSchema,l as CallerIdTypeSchema,r as CallerSchema,c as CallerStringSchema,d as CallerTypes,a as EnvironmentSchema,o as HEADERS,T as NOOP_CLOCK,p as PERSISTED_SNAPSHOT_KEY,s as RequestInfoSchema,n as SystemEventSchema,E as calculateNextRecurringAlarm,_ as createAlarmScheduler,m as generateAlarmId,g as getScheduledEvents,A as handleXStateAlarm,w as restoreScheduledEvents};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/schemas.ts","../src/constants.ts","../src/storage.ts","../src/alarms.ts","../src/durable-object-system.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const BotManagementSchema = z.object({\n corporateProxy: z.boolean(),\n verifiedBot: z.boolean(),\n jsDetection: z.object({\n passed: z.boolean(),\n }),\n staticResource: z.boolean(),\n detectionIds: z.record(z.any()),\n score: z.number(),\n});\n\nexport const EnvironmentSchema = z.object({\n ACTOR_KIT_SECRET: z.string(),\n ACTOR_KIT_HOST: z.string(),\n});\n\nexport const RequestInfoSchema = z.object({\n longitude: z.string(),\n latitude: z.string(),\n continent: z.string(),\n country: z.string(),\n city: z.string(),\n timezone: z.string(),\n postalCode: z.string(),\n region: z.string(),\n regionCode: z.string(),\n metroCode: z.string(),\n botManagement: BotManagementSchema,\n});\n\nexport const CallerSchema = z.object({\n id: z.string(),\n type: z.enum([\"client\", \"system\", \"service\"]),\n});\n\nexport const AnyEventSchema = z.object({\n type: z.string(),\n});\n\nexport const SystemEventSchema = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"INITIALIZE\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n }),\n z.object({\n type: z.literal(\"CONNECT\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n connectingCaller: CallerSchema,\n }),\n z.object({\n type: z.literal(\"DISCONNECT\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n disconnectingCaller: CallerSchema,\n }),\n z.object({\n type: z.literal(\"RESUME\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n }),\n z.object({\n type: z.literal(\"MIGRATE\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n operations: z.array(z.any()),\n }),\n]);\n\nexport const CallerIdTypeSchema = z.enum([\"client\", \"service\", \"system\"]);\n\nexport const CallerStringSchema = z.string().transform((val, ctx) => {\n if (val === \"anonymous\") {\n return { type: \"client\" as const, id: \"anonymous\" };\n }\n\n // Regular expression to validate the UUID format\n const callerTypeParseResult = CallerIdTypeSchema.safeParse(val.split(\"-\")[0]);\n if (!callerTypeParseResult.success) {\n callerTypeParseResult.error.issues.forEach(ctx.addIssue);\n return z.NEVER;\n }\n const type = callerTypeParseResult.data;\n\n const id = val.substring(val.indexOf(\"-\") + 1);\n if (z.string().uuid().safeParse(id).success) {\n return { type, id };\n } else {\n // If not valid, add a custom issue\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Must be a valid uuid or 'anonymous'. Received '${id}' on value '${val}'.`,\n });\n // Return the special NEVER symbol to indicate a validation failure\n return z.NEVER;\n }\n});\n","import { CallerType } from \"./types\";\nimport type { AlarmType } from \"./alarms\";\n\nexport const HEADERS = {\n X_CALLER_ID: \"X-Caller-ID\",\n X_CALLER_TYPE: \"X-Caller-Type\",\n X_ACTOR_ID: \"X-Actor-ID\",\n X_ACTOR_TYPE: \"X-Actor-Type\",\n};\n\n/**\n * Defines the types of callers that can interact with the actor system.\n * Each type represents a different source of events with varying levels of trust and permissions.\n * Note: SYSTEM events are handled internally by Actor Kit and are not defined by the user.\n */\nexport const CallerTypes: Record<CallerType, CallerType> = {\n client: \"client\",\n system: \"system\", // Handled internally by Actor Kit\n service: \"service\",\n};\n\n/**\n * Alarm types supported by the alarm system\n */\nexport const AlarmTypes: Record<AlarmType, AlarmType> = {\n \"xstate-delay\": \"xstate-delay\",\n \"cache-cleanup\": \"cache-cleanup\",\n custom: \"custom\",\n};\n\nexport const PERSISTED_SNAPSHOT_KEY = \"persistedSnapshot\";\n","import { PERSISTED_SNAPSHOT_KEY } from \"./constants\";\nimport type { Caller } from \"./types\";\n\n/**\n * SQL schema for the actor-kit SQLite storage\n */\nconst SQL_SCHEMA = `\n-- Alarms table - supports one-time and recurring alarms\nCREATE TABLE IF NOT EXISTS alarms (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n scheduled_at INTEGER NOT NULL,\n repeat_interval INTEGER,\n payload TEXT,\n created_at INTEGER NOT NULL\n);\n\n-- Index for efficient due alarm queries\nCREATE INDEX IF NOT EXISTS idx_alarms_scheduled_at ON alarms(scheduled_at);\n\n-- Actor metadata (replaces KV keys: actorType, actorId, initialCaller, input)\nCREATE TABLE IF NOT EXISTS actor_meta (\n actor_id TEXT PRIMARY KEY,\n actor_type TEXT NOT NULL,\n initial_caller TEXT NOT NULL,\n input TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Snapshots table (replaces PERSISTED_SNAPSHOT_KEY)\nCREATE TABLE IF NOT EXISTS snapshots (\n actor_id TEXT PRIMARY KEY,\n snapshot TEXT NOT NULL,\n checksum TEXT,\n updated_at INTEGER NOT NULL\n);\n`;\n\n/**\n * Alarm record from the database\n */\nexport interface AlarmRecord {\n id: string;\n type: string;\n scheduled_at: number;\n repeat_interval: number | null;\n payload: string | null;\n created_at: number;\n}\n\n/**\n * Scheduled alarm options\n */\nexport interface AlarmScheduleOptions {\n id: string;\n type: string;\n scheduledAt: number;\n repeatInterval?: number;\n payload: Record<string, unknown>;\n}\n\n/**\n * Actor metadata record\n */\nexport interface ActorMetaRecord {\n actor_id: string;\n actor_type: string;\n initial_caller: string; // JSON stringified Caller\n input: string; // JSON stringified\n created_at: number;\n updated_at: number;\n}\n\n/**\n * Actor metadata as an object\n */\nexport interface ActorMeta {\n actorId: string;\n actorType: string;\n initialCaller: Caller;\n input: Record<string, unknown>;\n}\n\n/**\n * Snapshot record\n */\nexport interface SnapshotRecord {\n actor_id: string;\n snapshot: string; // JSON stringified\n checksum: string | null;\n updated_at: number;\n}\n\n/**\n * Snapshot as an object\n */\nexport interface Snapshot {\n actorId: string;\n snapshot: unknown;\n checksum?: string;\n}\n\n/**\n * SQLite storage wrapper for actor-kit Durable Objects\n * Provides methods for managing alarms, actor metadata, and snapshots\n */\nexport class ActorKitStorage {\n private initialized = false;\n private sql: DurableObjectStorage[\"sql\"];\n\n constructor(private readonly storage: DurableObjectStorage) {\n this.sql = storage.sql;\n }\n\n /**\n * Initialize the database schema if not already done\n */\n async ensureInitialized(): Promise<void> {\n if (this.initialized) return;\n\n try {\n // Execute schema creation - SQLite will ignore IF NOT EXISTS if tables exist\n await this.sql.exec(SQL_SCHEMA);\n this.initialized = true;\n } catch (error) {\n console.error(\"Failed to initialize database schema:\", error);\n throw error;\n }\n }\n\n // ==================== Alarms ====================\n\n /**\n * Get all alarms, optionally filtered by actor\n */\n async getAlarms(): Promise<AlarmRecord[]> {\n await this.ensureInitialized();\n const result = await this.sql.exec(\n \"SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms ORDER BY scheduled_at ASC\"\n );\n return (await this.parseRows(result)) as AlarmRecord[];\n }\n\n /**\n * Get alarms that are due before a given timestamp\n */\n async getDueAlarms(before: number): Promise<AlarmRecord[]> {\n await this.ensureInitialized();\n const result = await this.sql.exec(\n \"SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms WHERE scheduled_at <= ? ORDER BY scheduled_at ASC\",\n before\n );\n return (await this.parseRows(result)) as AlarmRecord[];\n }\n\n /**\n * Get the earliest scheduled alarm\n */\n async getEarliestAlarm(): Promise<AlarmRecord | null> {\n await this.ensureInitialized();\n const result = await this.sql.exec(\n \"SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms ORDER BY scheduled_at ASC LIMIT 1\"\n );\n const rows = (await this.parseRows(result)) as AlarmRecord[];\n return rows[0] || null;\n }\n\n /**\n * Insert a new alarm\n */\n async insertAlarm(options: AlarmScheduleOptions): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\n \"INSERT INTO alarms (id, type, scheduled_at, repeat_interval, payload, created_at) VALUES (?, ?, ?, ?, ?, ?)\",\n options.id,\n options.type,\n options.scheduledAt,\n options.repeatInterval ?? null,\n JSON.stringify(options.payload),\n Date.now()\n );\n }\n\n /**\n * Update an alarm's scheduled time (for recurring alarms)\n */\n async updateAlarm(options: AlarmScheduleOptions): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\n \"UPDATE alarms SET scheduled_at = ?, repeat_interval = ?, payload = ? WHERE id = ?\",\n options.scheduledAt,\n options.repeatInterval ?? null,\n JSON.stringify(options.payload),\n options.id\n );\n }\n\n /**\n * Delete an alarm by ID\n */\n async deleteAlarm(id: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\"DELETE FROM alarms WHERE id = ?\", id);\n }\n\n /**\n * Delete all alarms of a specific type\n */\n async deleteAlarmsByType(type: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\"DELETE FROM alarms WHERE type = ?\", type);\n }\n\n // ==================== Actor Metadata ====================\n\n /**\n * Get actor metadata by ID\n */\n async getActorMeta(actorId?: string): Promise<ActorMeta | null> {\n await this.ensureInitialized();\n\n if (!actorId) {\n // Get the first (and only) actor metadata\n const result = await this.sql.exec(\n \"SELECT actor_id, actor_type, initial_caller, input, created_at, updated_at FROM actor_meta LIMIT 1\"\n );\n const rows = (await this.parseRows(result)) as ActorMetaRecord[];\n if (rows.length === 0) return null;\n\n const row = rows[0];\n return {\n actorId: row.actor_id,\n actorType: row.actor_type,\n initialCaller: JSON.parse(row.initial_caller) as Caller,\n input: JSON.parse(row.input),\n };\n }\n\n const result = await this.sql.exec(\n \"SELECT actor_id, actor_type, initial_caller, input, created_at, updated_at FROM actor_meta WHERE actor_id = ?\",\n actorId\n );\n const rows = (await this.parseRows(result)) as ActorMetaRecord[];\n if (rows.length === 0) return null;\n\n const row = rows[0];\n return {\n actorId: row.actor_id,\n actorType: row.actor_type,\n initialCaller: JSON.parse(row.initial_caller) as Caller,\n input: JSON.parse(row.input),\n };\n }\n\n /**\n * Set actor metadata\n */\n async setActorMeta(meta: ActorMeta): Promise<void> {\n await this.ensureInitialized();\n const now = Date.now();\n await this.sql.exec(\n `INSERT INTO actor_meta (actor_id, actor_type, initial_caller, input, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(actor_id) DO UPDATE SET\n actor_type = excluded.actor_type,\n initial_caller = excluded.initial_caller,\n input = excluded.input,\n updated_at = excluded.updated_at`,\n meta.actorId,\n meta.actorType,\n JSON.stringify(meta.initialCaller),\n JSON.stringify(meta.input),\n now,\n now\n );\n }\n\n /**\n * Delete actor metadata\n */\n async deleteActorMeta(actorId: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\"DELETE FROM actor_meta WHERE actor_id = ?\", actorId);\n }\n\n // ==================== Snapshots ====================\n\n /**\n * Get a snapshot by actor ID\n */\n async getSnapshot(actorId: string): Promise<Snapshot | null> {\n await this.ensureInitialized();\n const result = await this.sql.exec(\n \"SELECT actor_id, snapshot, checksum, updated_at FROM snapshots WHERE actor_id = ?\",\n actorId\n );\n const rows = (await this.parseRows(result)) as SnapshotRecord[];\n if (rows.length === 0) return null;\n\n const row = rows[0];\n return {\n actorId: row.actor_id,\n snapshot: JSON.parse(row.snapshot),\n checksum: row.checksum ?? undefined,\n };\n }\n\n /**\n * Set a snapshot for an actor\n */\n async setSnapshot(actorId: string, snapshot: unknown, checksum?: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\n `INSERT INTO snapshots (actor_id, snapshot, checksum, updated_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(actor_id) DO UPDATE SET\n snapshot = excluded.snapshot,\n checksum = excluded.checksum,\n updated_at = excluded.updated_at`,\n actorId,\n JSON.stringify(snapshot),\n checksum ?? null,\n Date.now()\n );\n }\n\n /**\n * Delete a snapshot\n */\n async deleteSnapshot(actorId: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\"DELETE FROM snapshots WHERE actor_id = ?\", actorId);\n }\n\n // ==================== Migration Helpers ====================\n\n /**\n * Migrate data from legacy KV storage to SQLite\n * This is a one-time migration helper\n */\n async migrateFromKV(storage: DurableObjectStorage): Promise<void> {\n await this.ensureInitialized();\n\n // Migrate actor metadata\n const [actorType, actorId, initialCallerString, inputString] = await Promise.all([\n storage.get(\"actorType\"),\n storage.get(\"actorId\"),\n storage.get(\"initialCaller\"),\n storage.get(\"input\"),\n ]);\n\n if (actorType && actorId && initialCallerString && inputString) {\n await this.setActorMeta({\n actorId: actorId as string,\n actorType: actorType as string,\n initialCaller: JSON.parse(initialCallerString as string) as Caller,\n input: JSON.parse(inputString as string),\n });\n }\n\n // Migrate persisted snapshot\n const persistedSnapshot = await storage.get(PERSISTED_SNAPSHOT_KEY);\n if (persistedSnapshot) {\n const snapshot = JSON.parse(persistedSnapshot as string);\n await this.setSnapshot(actorId as string, snapshot);\n }\n }\n\n // ==================== Utility Methods ====================\n\n /**\n * Parse SQL result rows - handles both arrays and cursors\n */\n private async parseRows(result: any): Promise<unknown[]> {\n // Check if result is an async iterable (cursor)\n if (result && typeof result[Symbol.asyncIterator] === \"function\") {\n const cursor = result as AsyncIterable<{ columns: string[]; results: (string | number | null)[][] }>;\n const rows: unknown[] = [];\n let columns: string[] | null = null;\n\n for await (const batch of cursor) {\n if (!columns) columns = batch.columns;\n for (const row of batch.results) {\n const obj: Record<string, unknown> = {};\n (columns ?? []).forEach((col, i) => {\n obj[col] = row[i];\n });\n rows.push(obj);\n }\n }\n return rows;\n }\n\n // Handle row batches returned by sql.exec()\n const batches = Array.isArray(result) ? result : result ? [result] : [];\n if (batches.length === 0) return [];\n\n const first = batches[0] as {\n columns?: string[];\n columnNames?: string[];\n rows?: unknown[][];\n results?: unknown[][];\n };\n\n const columns = first?.columns ?? first?.columnNames ?? [];\n const rows = first?.rows ?? first?.results ?? [];\n if (!columns.length || !rows.length) return [];\n\n return rows.map((row: unknown[]) => {\n const obj: Record<string, unknown> = {};\n columns.forEach((col: string, i: number) => {\n obj[col] = row[i];\n });\n return obj;\n });\n }\n}\n","import type {\n ActorKitStorage,\n AlarmRecord,\n AlarmScheduleOptions,\n} from \"./storage\";\n\n/**\n * Supported alarm types\n */\nexport type AlarmType = \"xstate-delay\" | \"cache-cleanup\" | \"custom\";\n\n/**\n * Alarm data from the database with parsed payload\n */\nexport interface Alarm {\n id: string;\n type: AlarmType;\n scheduledAt: number;\n repeatInterval?: number;\n payload: Record<string, unknown>;\n createdAt: number;\n}\n\n/**\n * Options for scheduling a new alarm\n */\nexport interface ScheduleAlarmOptions {\n id: string;\n type: AlarmType;\n scheduledAt: number;\n repeatInterval?: number;\n payload: Record<string, unknown>;\n}\n\n/**\n * Result from handling an alarm\n */\nexport interface AlarmHandleResult {\n id: string;\n type: AlarmType;\n rescheduled?: boolean;\n deleted: boolean;\n}\n\n/**\n * Manages alarms for a Durable Object using SQLite storage\n * and the Durable Object alarm API\n */\nexport class AlarmManager {\n private storage: ActorKitStorage;\n private state: DurableObjectState;\n private currentAlarmId: string | null = null;\n private currentAlarmTime: number | null = null;\n\n constructor(storage: ActorKitStorage, state: DurableObjectState) {\n this.storage = storage;\n this.state = state;\n }\n\n /**\n * Schedule a new alarm\n */\n async schedule(options: ScheduleAlarmOptions): Promise<void> {\n await this.storage.insertAlarm(options);\n await this.rescheduleNextAlarm();\n }\n\n /**\n * Cancel an alarm by ID\n */\n async cancel(id: string): Promise<void> {\n await this.storage.deleteAlarm(id);\n // If we canceled the current alarm, reschedule\n if (this.currentAlarmId === id) {\n await this.rescheduleNextAlarm();\n }\n }\n\n /**\n * Cancel all alarms of a specific type\n */\n async cancelByType(type: AlarmType): Promise<void> {\n await this.storage.deleteAlarmsByType(type);\n await this.rescheduleNextAlarm();\n }\n\n /**\n * Get all pending alarms\n */\n async getPendingAlarms(): Promise<Alarm[]> {\n const records = await this.storage.getAlarms();\n return records.map(this.parseAlarmRecord);\n }\n\n /**\n * Get alarms that are due now or before a given time\n */\n async getDueAlarms(before: number = Date.now()): Promise<Alarm[]> {\n const records = await this.storage.getDueAlarms(before);\n return records.map(this.parseAlarmRecord);\n }\n\n /**\n * Delete an alarm after it has been handled\n */\n async deleteAlarm(id: string): Promise<void> {\n await this.storage.deleteAlarm(id);\n }\n\n /**\n * Update an alarm (for rescheduling recurring alarms)\n */\n async updateAlarm(options: ScheduleAlarmOptions): Promise<void> {\n await this.storage.updateAlarm(options);\n }\n\n /**\n * Reschedule the next DO alarm based on the earliest alarm in storage\n * This sets the actual Durable Object alarm that will trigger the alarm() handler\n */\n async rescheduleNextAlarm(): Promise<void> {\n const earliest = await this.storage.getEarliestAlarm();\n\n if (!earliest) {\n // No alarms pending, clear the DO alarm\n this.currentAlarmId = null;\n this.currentAlarmTime = null;\n // Note: There's no way to \"clear\" a DO alarm, but we can set one far in the future\n // or just let it expire naturally\n return;\n }\n\n // Only set a new alarm if the earliest one is different from current\n if (this.currentAlarmId !== earliest.id || this.currentAlarmTime !== earliest.scheduled_at) {\n this.currentAlarmId = earliest.id;\n this.currentAlarmTime = earliest.scheduled_at;\n await this.state.storage.setAlarm(earliest.scheduled_at);\n }\n }\n\n /**\n * Handle due alarms and return results\n * This should be called from the Durable Object's alarm() handler\n */\n async handleDueAlarms(handler: (alarm: Alarm) => Promise<boolean>): Promise<AlarmHandleResult[]> {\n const now = Date.now();\n const dueAlarms = await this.getDueAlarms(now);\n const results: AlarmHandleResult[] = [];\n\n for (const alarm of dueAlarms) {\n let rescheduled = false;\n let deleted = true;\n\n if (alarm.repeatInterval) {\n // Recurring alarm - reschedule it\n const nextScheduledAt = now + alarm.repeatInterval;\n await this.updateAlarm({\n id: alarm.id,\n type: alarm.type,\n scheduledAt: nextScheduledAt,\n repeatInterval: alarm.repeatInterval,\n payload: alarm.payload,\n });\n rescheduled = true;\n deleted = false;\n } else {\n // One-time alarm - delete it\n await this.deleteAlarm(alarm.id);\n }\n\n // Call the handler and let it perform the alarm-specific action\n try {\n await handler(alarm);\n } catch (error) {\n console.error(`Error handling alarm ${alarm.id}:`, error);\n }\n\n results.push({\n id: alarm.id,\n type: alarm.type,\n rescheduled,\n deleted,\n });\n }\n\n // Reschedule the next DO alarm\n await this.rescheduleNextAlarm();\n\n return results;\n }\n\n /**\n * Get the current scheduled DO alarm info\n */\n getCurrentAlarm(): { id: string | null; time: number | null } {\n return {\n id: this.currentAlarmId,\n time: this.currentAlarmTime,\n };\n }\n\n /**\n * Parse an alarm record from the database into an Alarm object\n */\n private parseAlarmRecord(record: AlarmRecord): Alarm {\n return {\n id: record.id,\n type: record.type as AlarmType,\n scheduledAt: record.scheduled_at,\n repeatInterval: record.repeat_interval ?? undefined,\n payload: record.payload ? JSON.parse(record.payload) : {},\n createdAt: record.created_at,\n };\n }\n}\n\n/**\n * Generate a unique alarm ID\n */\nexport function generateAlarmId(): string {\n return `alarm-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * Calculate the next scheduled time for a recurring alarm\n */\nexport function calculateNextRecurringAlarm(\n baseTime: number,\n interval: number,\n now: number = Date.now()\n): number {\n let next = baseTime;\n while (next < now) {\n next += interval;\n }\n return next;\n}\n","import type { AnyActorRef, AnyEventObject } from \"xstate\";\nimport type { AlarmManager } from \"./alarms\";\n\n/**\n * Serializable data stored with each alarm for XState delayed events\n */\nexport interface XStateAlarmData {\n type: \"xstate-delay\";\n sourceSessionId: string;\n targetSessionId: string;\n event: AnyEventObject;\n scheduledEventId: string;\n alarmId: string;\n [key: string]: unknown; // Index signature for Record<string, unknown> compatibility\n}\n\n/**\n * Snapshot of scheduled events for persistence\n */\nexport interface ScheduledEventSnapshot {\n sourceSessionId: string;\n targetSessionId: string;\n event: AnyEventObject;\n delay: number;\n id: string;\n startedAt: number;\n}\n\n/**\n * Clock interface for compatibility with XState\n */\nexport interface Clock {\n setTimeout: (fn: () => void, delay: number) => unknown;\n clearTimeout: (id: unknown) => void;\n}\n\n/**\n * Simple no-op clock for XState actors that use alarm-based scheduling\n * This clock doesn't actually schedule anything - delays are handled via alarms\n */\nexport const NOOP_CLOCK: Clock = {\n setTimeout: () => Math.random(), // Return a fake ID\n clearTimeout: () => {\n // No-op - alarms manage cancellation\n },\n};\n\n/**\n * Map to track scheduled events by their scheduledEventId\n * This is used to look up event data when an alarm fires\n */\nconst scheduledEventsMap = new Map<string, ScheduledEventSnapshot>();\n\n/**\n * Create an alarm-based scheduler for XState actors\n * This replaces the default setTimeout-based scheduler with one that uses Durable Object alarms\n *\n * @param alarmManager - The alarm manager to schedule alarms with\n * @param system - The XState ActorSystem (used to relay events)\n * @returns A scheduler object with schedule, cancel, and cancelAll methods\n */\nexport function createAlarmScheduler(\n alarmManager: AlarmManager,\n system: any\n): {\n schedule: (\n source: AnyActorRef,\n target: AnyActorRef,\n event: AnyEventObject,\n delay: number,\n id?: string\n ) => void;\n cancel: (source: AnyActorRef, id: string) => void;\n cancelAll: (actorRef: AnyActorRef) => void;\n} {\n return {\n schedule: (\n source: AnyActorRef,\n target: AnyActorRef,\n event: AnyEventObject,\n delay: number,\n id: string = Math.random().toString(36).slice(2)\n ) => {\n const scheduledEventId = `${source.sessionId}.${id}`;\n\n // Store the event data for later retrieval\n const snapshot: ScheduledEventSnapshot = {\n sourceSessionId: source.sessionId,\n targetSessionId: target.sessionId,\n event,\n delay,\n id,\n startedAt: Date.now(),\n };\n scheduledEventsMap.set(scheduledEventId, snapshot);\n\n // Schedule the alarm\n const alarmId = `xstate-${scheduledEventId}`;\n\n alarmManager.schedule({\n id: alarmId,\n type: \"xstate-delay\",\n scheduledAt: Date.now() + delay,\n payload: {\n type: \"xstate-delay\",\n sourceSessionId: source.sessionId,\n targetSessionId: target.sessionId,\n event,\n scheduledEventId,\n alarmId,\n },\n }).catch((error) => {\n console.error(`[AlarmScheduler] Error scheduling alarm:`, error);\n scheduledEventsMap.delete(scheduledEventId);\n });\n },\n\n cancel: (source: AnyActorRef, id: string) => {\n const scheduledEventId = `${source.sessionId}.${id}`;\n\n // Remove from our tracking map\n scheduledEventsMap.delete(scheduledEventId);\n\n // Cancel the alarm\n alarmManager.cancel(`xstate-${scheduledEventId}`).catch((error) => {\n console.error(`[AlarmScheduler] Error canceling alarm:`, error);\n });\n },\n\n cancelAll: (actorRef: AnyActorRef) => {\n // Find all events for this actor\n const eventsToCancel: string[] = [];\n\n for (const [scheduledEventId, snapshot] of scheduledEventsMap.entries()) {\n if (snapshot.sourceSessionId === actorRef.sessionId) {\n eventsToCancel.push(scheduledEventId);\n }\n }\n\n // Cancel each event\n for (const scheduledEventId of eventsToCancel) {\n scheduledEventsMap.delete(scheduledEventId);\n alarmManager.cancel(`xstate-${scheduledEventId}`).catch((error) => {\n console.error(`[AlarmScheduler] Error canceling alarm:`, error);\n });\n }\n },\n };\n}\n\n/**\n * Handle an XState delayed event alarm\n * This should be called from the Durable Object's alarm() handler\n *\n * @param alarmData - The alarm data from the XState alarm\n * @param actor - The actor to send the event to\n */\nexport async function handleXStateAlarm(\n alarmData: XStateAlarmData,\n actor: any\n): Promise<void> {\n const { scheduledEventId, event } = alarmData;\n\n // Remove from tracking map\n scheduledEventsMap.delete(scheduledEventId);\n\n // Send the event to the actor\n try {\n // Use the actor's internal _relay method to deliver the event\n if (actor.system && actor.system._relay) {\n actor.system._relay(actor, actor, event);\n } else {\n // Fallback: send directly to the actor\n actor.send(event);\n }\n } catch (error) {\n console.error(`[AlarmScheduler] Error handling XState alarm:`, error);\n }\n}\n\n/**\n * Get all scheduled events (useful for debugging/inspection)\n */\nexport function getScheduledEvents(): Map<string, ScheduledEventSnapshot> {\n return new Map(scheduledEventsMap);\n}\n\n/**\n * Restore scheduled events from storage (called after DO hibernation)\n */\nexport function restoreScheduledEvents(\n alarms: Array<{ payload: XStateAlarmData; scheduledAt: number }>\n): void {\n for (const alarm of alarms) {\n if (alarm.payload.type === \"xstate-delay\") {\n const { sourceSessionId, targetSessionId, event, scheduledEventId } = alarm.payload;\n const delay = alarm.scheduledAt - Date.now();\n\n // Only restore if the alarm is still in the future\n if (delay > 0) {\n scheduledEventsMap.set(scheduledEventId, {\n sourceSessionId,\n targetSessionId,\n event,\n delay,\n id: scheduledEventId.split(\".\").pop() || scheduledEventId,\n startedAt: alarm.scheduledAt - delay,\n });\n }\n }\n }\n}\n"],"names":["BotManagementSchema","z","object","corporateProxy","boolean","verifiedBot","jsDetection","passed","staticResource","detectionIds","record","any","score","number","EnvironmentSchema","ACTOR_KIT_SECRET","string","ACTOR_KIT_HOST","RequestInfoSchema","longitude","latitude","continent","country","city","timezone","postalCode","region","regionCode","metroCode","botManagement","CallerSchema","id","type","enum","AnyEventSchema","SystemEventSchema","discriminatedUnion","literal","caller","connectingCaller","disconnectingCaller","operations","array","CallerIdTypeSchema","CallerStringSchema","transform","val","ctx","callerTypeParseResult","safeParse","split","success","error","issues","forEach","addIssue","NEVER","data","substring","indexOf","uuid","code","ZodIssueCode","custom","message","HEADERS","X_CALLER_ID","X_CALLER_TYPE","X_ACTOR_ID","X_ACTOR_TYPE","CallerTypes","client","system","service","AlarmTypes","PERSISTED_SNAPSHOT_KEY","ActorKitStorage","storage","initialized","sql","constructor","this","ensureInitialized","exec","console","getAlarms","result","parseRows","getDueAlarms","before","getEarliestAlarm","insertAlarm","options","scheduledAt","repeatInterval","JSON","stringify","payload","Date","now","updateAlarm","deleteAlarm","deleteAlarmsByType","getActorMeta","actorId","rows","length","row","actor_id","actorType","actor_type","initialCaller","parse","initial_caller","input","setActorMeta","meta","deleteActorMeta","getSnapshot","snapshot","checksum","undefined","setSnapshot","deleteSnapshot","migrateFromKV","initialCallerString","inputString","Promise","all","get","persistedSnapshot","Symbol","asyncIterator","cursor","columns","batch","results","obj","col","i","push","batches","Array","isArray","first","columnNames","map","AlarmManager","state","currentAlarmId","currentAlarmTime","schedule","rescheduleNextAlarm","cancel","cancelByType","getPendingAlarms","parseAlarmRecord","earliest","scheduled_at","setAlarm","handleDueAlarms","handler","dueAlarms","alarm","rescheduled","deleted","nextScheduledAt","getCurrentAlarm","time","repeat_interval","createdAt","created_at","generateAlarmId","Math","random","toString","slice","calculateNextRecurringAlarm","baseTime","interval","next","NOOP_CLOCK","setTimeout","clearTimeout","scheduledEventsMap","Map","createAlarmScheduler","alarmManager","source","target","event","delay","scheduledEventId","sessionId","sourceSessionId","targetSessionId","startedAt","set","alarmId","catch","delete","cancelAll","actorRef","eventsToCancel","entries","async","handleXStateAlarm","alarmData","actor","_relay","send","getScheduledEvents","restoreScheduledEvents","alarms","pop"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/schemas.ts","../src/constants.ts","../src/storage.ts","../src/alarms.ts","../src/durable-object-system.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const BotManagementSchema = z.object({\n corporateProxy: z.boolean(),\n verifiedBot: z.boolean(),\n jsDetection: z.object({\n passed: z.boolean(),\n }),\n staticResource: z.boolean(),\n detectionIds: z.record(z.string(), z.any()),\n score: z.number(),\n});\n\nexport const EnvironmentSchema = z.object({\n ACTOR_KIT_SECRET: z.string(),\n ACTOR_KIT_HOST: z.string(),\n});\n\nexport const RequestInfoSchema = z.object({\n longitude: z.string(),\n latitude: z.string(),\n continent: z.string(),\n country: z.string(),\n city: z.string(),\n timezone: z.string(),\n postalCode: z.string(),\n region: z.string(),\n regionCode: z.string(),\n metroCode: z.string(),\n botManagement: BotManagementSchema,\n});\n\nexport const CallerSchema = z.object({\n id: z.string(),\n type: z.enum([\"client\", \"system\", \"service\"]),\n});\n\nexport const AnyEventSchema = z.object({\n type: z.string(),\n});\n\nexport const SystemEventSchema = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"INITIALIZE\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n }),\n z.object({\n type: z.literal(\"CONNECT\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n connectingCaller: CallerSchema,\n }),\n z.object({\n type: z.literal(\"DISCONNECT\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n disconnectingCaller: CallerSchema,\n }),\n z.object({\n type: z.literal(\"RESUME\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n }),\n z.object({\n type: z.literal(\"MIGRATE\"),\n caller: z.object({ type: z.literal(\"system\"), id: z.string() }),\n operations: z.array(z.any()),\n }),\n]);\n\nexport const CallerIdTypeSchema = z.enum([\"client\", \"service\", \"system\"]);\n\nexport const CallerStringSchema = z.string().transform((val, ctx) => {\n if (val === \"anonymous\") {\n return { type: \"client\" as const, id: \"anonymous\" };\n }\n\n // Regular expression to validate the UUID format\n const callerTypeParseResult = CallerIdTypeSchema.safeParse(val.split(\"-\")[0]);\n if (!callerTypeParseResult.success) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid caller type: ${val.split(\"-\")[0]}`,\n });\n return z.NEVER;\n }\n const type = callerTypeParseResult.data;\n\n const id = val.substring(val.indexOf(\"-\") + 1);\n if (z.string().uuid().safeParse(id).success) {\n return { type, id };\n } else {\n // If not valid, add a custom issue\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Must be a valid uuid or 'anonymous'. Received '${id}' on value '${val}'.`,\n });\n // Return the special NEVER symbol to indicate a validation failure\n return z.NEVER;\n }\n});\n","import { CallerType } from \"./types\";\nimport type { AlarmType } from \"./alarms\";\n\nexport const HEADERS = {\n X_CALLER_ID: \"X-Caller-ID\",\n X_CALLER_TYPE: \"X-Caller-Type\",\n X_ACTOR_ID: \"X-Actor-ID\",\n X_ACTOR_TYPE: \"X-Actor-Type\",\n};\n\n/**\n * Defines the types of callers that can interact with the actor system.\n * Each type represents a different source of events with varying levels of trust and permissions.\n * Note: SYSTEM events are handled internally by Actor Kit and are not defined by the user.\n */\nexport const CallerTypes: Record<CallerType, CallerType> = {\n client: \"client\",\n system: \"system\", // Handled internally by Actor Kit\n service: \"service\",\n};\n\n/**\n * Alarm types supported by the alarm system\n */\nexport const AlarmTypes: Record<AlarmType, AlarmType> = {\n \"xstate-delay\": \"xstate-delay\",\n \"cache-cleanup\": \"cache-cleanup\",\n custom: \"custom\",\n};\n\nexport const PERSISTED_SNAPSHOT_KEY = \"persistedSnapshot\";\n","import { PERSISTED_SNAPSHOT_KEY } from \"./constants\";\nimport type { Caller } from \"./types\";\n\n/**\n * SQL schema for the actor-kit SQLite storage\n */\nconst SQL_SCHEMA = `\n-- Alarms table - supports one-time and recurring alarms\nCREATE TABLE IF NOT EXISTS alarms (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n scheduled_at INTEGER NOT NULL,\n repeat_interval INTEGER,\n payload TEXT,\n created_at INTEGER NOT NULL\n);\n\n-- Index for efficient due alarm queries\nCREATE INDEX IF NOT EXISTS idx_alarms_scheduled_at ON alarms(scheduled_at);\n\n-- Actor metadata (replaces KV keys: actorType, actorId, initialCaller, input)\nCREATE TABLE IF NOT EXISTS actor_meta (\n actor_id TEXT PRIMARY KEY,\n actor_type TEXT NOT NULL,\n initial_caller TEXT NOT NULL,\n input TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Snapshots table (replaces PERSISTED_SNAPSHOT_KEY)\nCREATE TABLE IF NOT EXISTS snapshots (\n actor_id TEXT PRIMARY KEY,\n snapshot TEXT NOT NULL,\n checksum TEXT,\n updated_at INTEGER NOT NULL\n);\n`;\n\n/**\n * Alarm record from the database\n */\nexport interface AlarmRecord {\n id: string;\n type: string;\n scheduled_at: number;\n repeat_interval: number | null;\n payload: string | null;\n created_at: number;\n}\n\n/**\n * Scheduled alarm options\n */\nexport interface AlarmScheduleOptions {\n id: string;\n type: string;\n scheduledAt: number;\n repeatInterval?: number;\n payload: Record<string, unknown>;\n}\n\n/**\n * Actor metadata record\n */\nexport interface ActorMetaRecord {\n actor_id: string;\n actor_type: string;\n initial_caller: string; // JSON stringified Caller\n input: string; // JSON stringified\n created_at: number;\n updated_at: number;\n}\n\n/**\n * Actor metadata as an object\n */\nexport interface ActorMeta {\n actorId: string;\n actorType: string;\n initialCaller: Caller;\n input: Record<string, unknown>;\n}\n\n/**\n * Snapshot record\n */\nexport interface SnapshotRecord {\n actor_id: string;\n snapshot: string; // JSON stringified\n checksum: string | null;\n updated_at: number;\n}\n\n/**\n * Snapshot as an object\n */\nexport interface Snapshot {\n actorId: string;\n snapshot: unknown;\n checksum?: string;\n}\n\n/**\n * SQLite storage wrapper for actor-kit Durable Objects\n * Provides methods for managing alarms, actor metadata, and snapshots\n */\nexport class ActorKitStorage {\n private initialized = false;\n private sql: DurableObjectStorage[\"sql\"];\n\n constructor(private readonly storage: DurableObjectStorage) {\n this.sql = storage.sql;\n }\n\n /**\n * Initialize the database schema if not already done\n */\n async ensureInitialized(): Promise<void> {\n if (this.initialized) return;\n\n try {\n // Execute schema creation - SQLite will ignore IF NOT EXISTS if tables exist\n await this.sql.exec(SQL_SCHEMA);\n this.initialized = true;\n } catch (error) {\n console.error(\"Failed to initialize database schema:\", error);\n throw error;\n }\n }\n\n // ==================== Alarms ====================\n\n /**\n * Get all alarms, optionally filtered by actor\n */\n async getAlarms(): Promise<AlarmRecord[]> {\n await this.ensureInitialized();\n const result = await this.sql.exec(\n \"SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms ORDER BY scheduled_at ASC\"\n );\n return (await this.parseRows(result)) as AlarmRecord[];\n }\n\n /**\n * Get alarms that are due before a given timestamp\n */\n async getDueAlarms(before: number): Promise<AlarmRecord[]> {\n await this.ensureInitialized();\n const result = await this.sql.exec(\n \"SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms WHERE scheduled_at <= ? ORDER BY scheduled_at ASC\",\n before\n );\n return (await this.parseRows(result)) as AlarmRecord[];\n }\n\n /**\n * Get the earliest scheduled alarm\n */\n async getEarliestAlarm(): Promise<AlarmRecord | null> {\n await this.ensureInitialized();\n const result = await this.sql.exec(\n \"SELECT id, type, scheduled_at, repeat_interval, payload, created_at FROM alarms ORDER BY scheduled_at ASC LIMIT 1\"\n );\n const rows = (await this.parseRows(result)) as AlarmRecord[];\n return rows[0] || null;\n }\n\n /**\n * Insert a new alarm\n */\n async insertAlarm(options: AlarmScheduleOptions): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\n \"INSERT INTO alarms (id, type, scheduled_at, repeat_interval, payload, created_at) VALUES (?, ?, ?, ?, ?, ?)\",\n options.id,\n options.type,\n options.scheduledAt,\n options.repeatInterval ?? null,\n JSON.stringify(options.payload),\n Date.now()\n );\n }\n\n /**\n * Update an alarm's scheduled time (for recurring alarms)\n */\n async updateAlarm(options: AlarmScheduleOptions): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\n \"UPDATE alarms SET scheduled_at = ?, repeat_interval = ?, payload = ? WHERE id = ?\",\n options.scheduledAt,\n options.repeatInterval ?? null,\n JSON.stringify(options.payload),\n options.id\n );\n }\n\n /**\n * Delete an alarm by ID\n */\n async deleteAlarm(id: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\"DELETE FROM alarms WHERE id = ?\", id);\n }\n\n /**\n * Delete all alarms of a specific type\n */\n async deleteAlarmsByType(type: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\"DELETE FROM alarms WHERE type = ?\", type);\n }\n\n // ==================== Actor Metadata ====================\n\n /**\n * Get actor metadata by ID\n */\n async getActorMeta(actorId?: string): Promise<ActorMeta | null> {\n await this.ensureInitialized();\n\n if (!actorId) {\n // Get the first (and only) actor metadata\n const result = await this.sql.exec(\n \"SELECT actor_id, actor_type, initial_caller, input, created_at, updated_at FROM actor_meta LIMIT 1\"\n );\n const rows = (await this.parseRows(result)) as ActorMetaRecord[];\n if (rows.length === 0) return null;\n\n const row = rows[0];\n return {\n actorId: row.actor_id,\n actorType: row.actor_type,\n initialCaller: JSON.parse(row.initial_caller) as Caller,\n input: JSON.parse(row.input),\n };\n }\n\n const result = await this.sql.exec(\n \"SELECT actor_id, actor_type, initial_caller, input, created_at, updated_at FROM actor_meta WHERE actor_id = ?\",\n actorId\n );\n const rows = (await this.parseRows(result)) as ActorMetaRecord[];\n if (rows.length === 0) return null;\n\n const row = rows[0];\n return {\n actorId: row.actor_id,\n actorType: row.actor_type,\n initialCaller: JSON.parse(row.initial_caller) as Caller,\n input: JSON.parse(row.input),\n };\n }\n\n /**\n * Set actor metadata\n */\n async setActorMeta(meta: ActorMeta): Promise<void> {\n await this.ensureInitialized();\n const now = Date.now();\n await this.sql.exec(\n `INSERT INTO actor_meta (actor_id, actor_type, initial_caller, input, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(actor_id) DO UPDATE SET\n actor_type = excluded.actor_type,\n initial_caller = excluded.initial_caller,\n input = excluded.input,\n updated_at = excluded.updated_at`,\n meta.actorId,\n meta.actorType,\n JSON.stringify(meta.initialCaller),\n JSON.stringify(meta.input),\n now,\n now\n );\n }\n\n /**\n * Delete actor metadata\n */\n async deleteActorMeta(actorId: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\"DELETE FROM actor_meta WHERE actor_id = ?\", actorId);\n }\n\n // ==================== Snapshots ====================\n\n /**\n * Get a snapshot by actor ID\n */\n async getSnapshot(actorId: string): Promise<Snapshot | null> {\n await this.ensureInitialized();\n const result = await this.sql.exec(\n \"SELECT actor_id, snapshot, checksum, updated_at FROM snapshots WHERE actor_id = ?\",\n actorId\n );\n const rows = (await this.parseRows(result)) as SnapshotRecord[];\n if (rows.length === 0) return null;\n\n const row = rows[0];\n return {\n actorId: row.actor_id,\n snapshot: JSON.parse(row.snapshot),\n checksum: row.checksum ?? undefined,\n };\n }\n\n /**\n * Set a snapshot for an actor\n */\n async setSnapshot(actorId: string, snapshot: unknown, checksum?: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\n `INSERT INTO snapshots (actor_id, snapshot, checksum, updated_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(actor_id) DO UPDATE SET\n snapshot = excluded.snapshot,\n checksum = excluded.checksum,\n updated_at = excluded.updated_at`,\n actorId,\n JSON.stringify(snapshot),\n checksum ?? null,\n Date.now()\n );\n }\n\n /**\n * Delete a snapshot\n */\n async deleteSnapshot(actorId: string): Promise<void> {\n await this.ensureInitialized();\n await this.sql.exec(\"DELETE FROM snapshots WHERE actor_id = ?\", actorId);\n }\n\n // ==================== Migration Helpers ====================\n\n /**\n * Migrate data from legacy KV storage to SQLite\n * This is a one-time migration helper\n */\n async migrateFromKV(storage: DurableObjectStorage): Promise<void> {\n await this.ensureInitialized();\n\n // Migrate actor metadata\n const [actorType, actorId, initialCallerString, inputString] = await Promise.all([\n storage.get(\"actorType\"),\n storage.get(\"actorId\"),\n storage.get(\"initialCaller\"),\n storage.get(\"input\"),\n ]);\n\n if (actorType && actorId && initialCallerString && inputString) {\n await this.setActorMeta({\n actorId: actorId as string,\n actorType: actorType as string,\n initialCaller: JSON.parse(initialCallerString as string) as Caller,\n input: JSON.parse(inputString as string),\n });\n }\n\n // Migrate persisted snapshot\n const persistedSnapshot = await storage.get(PERSISTED_SNAPSHOT_KEY);\n if (persistedSnapshot) {\n const snapshot = JSON.parse(persistedSnapshot as string);\n await this.setSnapshot(actorId as string, snapshot);\n }\n }\n\n // ==================== Utility Methods ====================\n\n /**\n * Parse SQL result rows - handles both arrays and cursors\n */\n private async parseRows(result: any): Promise<unknown[]> {\n // Check if result is an async iterable (cursor)\n if (result && typeof result[Symbol.asyncIterator] === \"function\") {\n const cursor = result as AsyncIterable<{ columns: string[]; results: (string | number | null)[][] }>;\n const rows: unknown[] = [];\n let columns: string[] | null = null;\n\n for await (const batch of cursor) {\n if (!columns) columns = batch.columns;\n for (const row of batch.results) {\n const obj: Record<string, unknown> = {};\n (columns ?? []).forEach((col, i) => {\n obj[col] = row[i];\n });\n rows.push(obj);\n }\n }\n return rows;\n }\n\n // Handle row batches returned by sql.exec()\n const batches = Array.isArray(result) ? result : result ? [result] : [];\n if (batches.length === 0) return [];\n\n const first = batches[0] as {\n columns?: string[];\n columnNames?: string[];\n rows?: unknown[][];\n results?: unknown[][];\n };\n\n const columns = first?.columns ?? first?.columnNames ?? [];\n const rows = first?.rows ?? first?.results ?? [];\n if (!columns.length || !rows.length) return [];\n\n return rows.map((row: unknown[]) => {\n const obj: Record<string, unknown> = {};\n columns.forEach((col: string, i: number) => {\n obj[col] = row[i];\n });\n return obj;\n });\n }\n}\n","import type {\n ActorKitStorage,\n AlarmRecord,\n AlarmScheduleOptions,\n} from \"./storage\";\n\n/**\n * Supported alarm types\n */\nexport type AlarmType = \"xstate-delay\" | \"cache-cleanup\" | \"custom\";\n\n/**\n * Alarm data from the database with parsed payload\n */\nexport interface Alarm {\n id: string;\n type: AlarmType;\n scheduledAt: number;\n repeatInterval?: number;\n payload: Record<string, unknown>;\n createdAt: number;\n}\n\n/**\n * Options for scheduling a new alarm\n */\nexport interface ScheduleAlarmOptions {\n id: string;\n type: AlarmType;\n scheduledAt: number;\n repeatInterval?: number;\n payload: Record<string, unknown>;\n}\n\n/**\n * Result from handling an alarm\n */\nexport interface AlarmHandleResult {\n id: string;\n type: AlarmType;\n rescheduled?: boolean;\n deleted: boolean;\n}\n\n/**\n * Manages alarms for a Durable Object using SQLite storage\n * and the Durable Object alarm API\n */\nexport class AlarmManager {\n private storage: ActorKitStorage;\n private state: DurableObjectState;\n private currentAlarmId: string | null = null;\n private currentAlarmTime: number | null = null;\n\n constructor(storage: ActorKitStorage, state: DurableObjectState) {\n this.storage = storage;\n this.state = state;\n }\n\n /**\n * Schedule a new alarm\n */\n async schedule(options: ScheduleAlarmOptions): Promise<void> {\n await this.storage.insertAlarm(options);\n await this.rescheduleNextAlarm();\n }\n\n /**\n * Cancel an alarm by ID\n */\n async cancel(id: string): Promise<void> {\n await this.storage.deleteAlarm(id);\n // If we canceled the current alarm, reschedule\n if (this.currentAlarmId === id) {\n await this.rescheduleNextAlarm();\n }\n }\n\n /**\n * Cancel all alarms of a specific type\n */\n async cancelByType(type: AlarmType): Promise<void> {\n await this.storage.deleteAlarmsByType(type);\n await this.rescheduleNextAlarm();\n }\n\n /**\n * Get all pending alarms\n */\n async getPendingAlarms(): Promise<Alarm[]> {\n const records = await this.storage.getAlarms();\n return records.map(this.parseAlarmRecord);\n }\n\n /**\n * Get alarms that are due now or before a given time\n */\n async getDueAlarms(before: number = Date.now()): Promise<Alarm[]> {\n const records = await this.storage.getDueAlarms(before);\n return records.map(this.parseAlarmRecord);\n }\n\n /**\n * Delete an alarm after it has been handled\n */\n async deleteAlarm(id: string): Promise<void> {\n await this.storage.deleteAlarm(id);\n }\n\n /**\n * Update an alarm (for rescheduling recurring alarms)\n */\n async updateAlarm(options: ScheduleAlarmOptions): Promise<void> {\n await this.storage.updateAlarm(options);\n }\n\n /**\n * Reschedule the next DO alarm based on the earliest alarm in storage\n * This sets the actual Durable Object alarm that will trigger the alarm() handler\n */\n async rescheduleNextAlarm(): Promise<void> {\n const earliest = await this.storage.getEarliestAlarm();\n\n if (!earliest) {\n // No alarms pending, clear the DO alarm\n this.currentAlarmId = null;\n this.currentAlarmTime = null;\n // Note: There's no way to \"clear\" a DO alarm, but we can set one far in the future\n // or just let it expire naturally\n return;\n }\n\n // Only set a new alarm if the earliest one is different from current\n if (this.currentAlarmId !== earliest.id || this.currentAlarmTime !== earliest.scheduled_at) {\n this.currentAlarmId = earliest.id;\n this.currentAlarmTime = earliest.scheduled_at;\n await this.state.storage.setAlarm(earliest.scheduled_at);\n }\n }\n\n /**\n * Handle due alarms and return results\n * This should be called from the Durable Object's alarm() handler\n */\n async handleDueAlarms(handler: (alarm: Alarm) => Promise<boolean>): Promise<AlarmHandleResult[]> {\n const now = Date.now();\n const dueAlarms = await this.getDueAlarms(now);\n const results: AlarmHandleResult[] = [];\n\n for (const alarm of dueAlarms) {\n let rescheduled = false;\n let deleted = true;\n\n if (alarm.repeatInterval) {\n // Recurring alarm - reschedule it\n const nextScheduledAt = now + alarm.repeatInterval;\n await this.updateAlarm({\n id: alarm.id,\n type: alarm.type,\n scheduledAt: nextScheduledAt,\n repeatInterval: alarm.repeatInterval,\n payload: alarm.payload,\n });\n rescheduled = true;\n deleted = false;\n } else {\n // One-time alarm - delete it\n await this.deleteAlarm(alarm.id);\n }\n\n // Call the handler and let it perform the alarm-specific action\n try {\n await handler(alarm);\n } catch (error) {\n console.error(`Error handling alarm ${alarm.id}:`, error);\n }\n\n results.push({\n id: alarm.id,\n type: alarm.type,\n rescheduled,\n deleted,\n });\n }\n\n // Reschedule the next DO alarm\n await this.rescheduleNextAlarm();\n\n return results;\n }\n\n /**\n * Get the current scheduled DO alarm info\n */\n getCurrentAlarm(): { id: string | null; time: number | null } {\n return {\n id: this.currentAlarmId,\n time: this.currentAlarmTime,\n };\n }\n\n /**\n * Parse an alarm record from the database into an Alarm object\n */\n private parseAlarmRecord(record: AlarmRecord): Alarm {\n return {\n id: record.id,\n type: record.type as AlarmType,\n scheduledAt: record.scheduled_at,\n repeatInterval: record.repeat_interval ?? undefined,\n payload: record.payload ? JSON.parse(record.payload) : {},\n createdAt: record.created_at,\n };\n }\n}\n\n/**\n * Generate a unique alarm ID\n */\nexport function generateAlarmId(): string {\n return `alarm-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * Calculate the next scheduled time for a recurring alarm\n */\nexport function calculateNextRecurringAlarm(\n baseTime: number,\n interval: number,\n now: number = Date.now()\n): number {\n let next = baseTime;\n while (next < now) {\n next += interval;\n }\n return next;\n}\n","import type { AnyActorRef, AnyEventObject } from \"xstate\";\nimport type { AlarmManager } from \"./alarms\";\n\n/**\n * Serializable data stored with each alarm for XState delayed events\n */\nexport interface XStateAlarmData {\n type: \"xstate-delay\";\n sourceSessionId: string;\n targetSessionId: string;\n event: AnyEventObject;\n scheduledEventId: string;\n alarmId: string;\n [key: string]: unknown; // Index signature for Record<string, unknown> compatibility\n}\n\n/**\n * Snapshot of scheduled events for persistence\n */\nexport interface ScheduledEventSnapshot {\n sourceSessionId: string;\n targetSessionId: string;\n event: AnyEventObject;\n delay: number;\n id: string;\n startedAt: number;\n}\n\n/**\n * Clock interface for compatibility with XState\n */\nexport interface Clock {\n setTimeout: (fn: () => void, delay: number) => unknown;\n clearTimeout: (id: unknown) => void;\n}\n\n/**\n * Simple no-op clock for XState actors that use alarm-based scheduling\n * This clock doesn't actually schedule anything - delays are handled via alarms\n */\nexport const NOOP_CLOCK: Clock = {\n setTimeout: () => Math.random(), // Return a fake ID\n clearTimeout: () => {\n // No-op - alarms manage cancellation\n },\n};\n\n/**\n * Map to track scheduled events by their scheduledEventId\n * This is used to look up event data when an alarm fires\n */\nconst scheduledEventsMap = new Map<string, ScheduledEventSnapshot>();\n\n/**\n * Create an alarm-based scheduler for XState actors\n * This replaces the default setTimeout-based scheduler with one that uses Durable Object alarms\n *\n * @param alarmManager - The alarm manager to schedule alarms with\n * @param system - The XState ActorSystem (used to relay events)\n * @returns A scheduler object with schedule, cancel, and cancelAll methods\n */\nexport function createAlarmScheduler(\n alarmManager: AlarmManager,\n system: any\n): {\n schedule: (\n source: AnyActorRef,\n target: AnyActorRef,\n event: AnyEventObject,\n delay: number,\n id?: string\n ) => void;\n cancel: (source: AnyActorRef, id: string) => void;\n cancelAll: (actorRef: AnyActorRef) => void;\n} {\n return {\n schedule: (\n source: AnyActorRef,\n target: AnyActorRef,\n event: AnyEventObject,\n delay: number,\n id: string = Math.random().toString(36).slice(2)\n ) => {\n const scheduledEventId = `${source.sessionId}.${id}`;\n\n // Store the event data for later retrieval\n const snapshot: ScheduledEventSnapshot = {\n sourceSessionId: source.sessionId,\n targetSessionId: target.sessionId,\n event,\n delay,\n id,\n startedAt: Date.now(),\n };\n scheduledEventsMap.set(scheduledEventId, snapshot);\n\n // Schedule the alarm\n const alarmId = `xstate-${scheduledEventId}`;\n\n alarmManager.schedule({\n id: alarmId,\n type: \"xstate-delay\",\n scheduledAt: Date.now() + delay,\n payload: {\n type: \"xstate-delay\",\n sourceSessionId: source.sessionId,\n targetSessionId: target.sessionId,\n event,\n scheduledEventId,\n alarmId,\n },\n }).catch((error) => {\n console.error(`[AlarmScheduler] Error scheduling alarm:`, error);\n scheduledEventsMap.delete(scheduledEventId);\n });\n },\n\n cancel: (source: AnyActorRef, id: string) => {\n const scheduledEventId = `${source.sessionId}.${id}`;\n\n // Remove from our tracking map\n scheduledEventsMap.delete(scheduledEventId);\n\n // Cancel the alarm\n alarmManager.cancel(`xstate-${scheduledEventId}`).catch((error) => {\n console.error(`[AlarmScheduler] Error canceling alarm:`, error);\n });\n },\n\n cancelAll: (actorRef: AnyActorRef) => {\n // Find all events for this actor\n const eventsToCancel: string[] = [];\n\n for (const [scheduledEventId, snapshot] of scheduledEventsMap.entries()) {\n if (snapshot.sourceSessionId === actorRef.sessionId) {\n eventsToCancel.push(scheduledEventId);\n }\n }\n\n // Cancel each event\n for (const scheduledEventId of eventsToCancel) {\n scheduledEventsMap.delete(scheduledEventId);\n alarmManager.cancel(`xstate-${scheduledEventId}`).catch((error) => {\n console.error(`[AlarmScheduler] Error canceling alarm:`, error);\n });\n }\n },\n };\n}\n\n/**\n * Handle an XState delayed event alarm\n * This should be called from the Durable Object's alarm() handler\n *\n * @param alarmData - The alarm data from the XState alarm\n * @param actor - The actor to send the event to\n */\nexport async function handleXStateAlarm(\n alarmData: XStateAlarmData,\n actor: any\n): Promise<void> {\n const { scheduledEventId, event } = alarmData;\n\n // Remove from tracking map\n scheduledEventsMap.delete(scheduledEventId);\n\n // Send the event to the actor\n try {\n // Use the actor's internal _relay method to deliver the event\n if (actor.system && actor.system._relay) {\n actor.system._relay(actor, actor, event);\n } else {\n // Fallback: send directly to the actor\n actor.send(event);\n }\n } catch (error) {\n console.error(`[AlarmScheduler] Error handling XState alarm:`, error);\n }\n}\n\n/**\n * Get all scheduled events (useful for debugging/inspection)\n */\nexport function getScheduledEvents(): Map<string, ScheduledEventSnapshot> {\n return new Map(scheduledEventsMap);\n}\n\n/**\n * Restore scheduled events from storage (called after DO hibernation)\n */\nexport function restoreScheduledEvents(\n alarms: Array<{ payload: XStateAlarmData; scheduledAt: number }>\n): void {\n for (const alarm of alarms) {\n if (alarm.payload.type === \"xstate-delay\") {\n const { sourceSessionId, targetSessionId, event, scheduledEventId } = alarm.payload;\n const delay = alarm.scheduledAt - Date.now();\n\n // Only restore if the alarm is still in the future\n if (delay > 0) {\n scheduledEventsMap.set(scheduledEventId, {\n sourceSessionId,\n targetSessionId,\n event,\n delay,\n id: scheduledEventId.split(\".\").pop() || scheduledEventId,\n startedAt: alarm.scheduledAt - delay,\n });\n }\n }\n }\n}\n"],"names":["BotManagementSchema","z","object","corporateProxy","boolean","verifiedBot","jsDetection","passed","staticResource","detectionIds","record","string","any","score","number","EnvironmentSchema","ACTOR_KIT_SECRET","ACTOR_KIT_HOST","RequestInfoSchema","longitude","latitude","continent","country","city","timezone","postalCode","region","regionCode","metroCode","botManagement","CallerSchema","id","type","enum","AnyEventSchema","SystemEventSchema","discriminatedUnion","literal","caller","connectingCaller","disconnectingCaller","operations","array","CallerIdTypeSchema","CallerStringSchema","transform","val","ctx","callerTypeParseResult","safeParse","split","success","addIssue","code","ZodIssueCode","custom","message","NEVER","data","substring","indexOf","uuid","HEADERS","X_CALLER_ID","X_CALLER_TYPE","X_ACTOR_ID","X_ACTOR_TYPE","CallerTypes","client","system","service","AlarmTypes","PERSISTED_SNAPSHOT_KEY","ActorKitStorage","storage","initialized","sql","constructor","this","ensureInitialized","exec","error","console","getAlarms","result","parseRows","getDueAlarms","before","getEarliestAlarm","insertAlarm","options","scheduledAt","repeatInterval","JSON","stringify","payload","Date","now","updateAlarm","deleteAlarm","deleteAlarmsByType","getActorMeta","actorId","rows","length","row","actor_id","actorType","actor_type","initialCaller","parse","initial_caller","input","setActorMeta","meta","deleteActorMeta","getSnapshot","snapshot","checksum","undefined","setSnapshot","deleteSnapshot","migrateFromKV","initialCallerString","inputString","Promise","all","get","persistedSnapshot","Symbol","asyncIterator","cursor","columns","batch","results","obj","forEach","col","i","push","batches","Array","isArray","first","columnNames","map","AlarmManager","state","currentAlarmId","currentAlarmTime","schedule","rescheduleNextAlarm","cancel","cancelByType","getPendingAlarms","parseAlarmRecord","earliest","scheduled_at","setAlarm","handleDueAlarms","handler","dueAlarms","alarm","rescheduled","deleted","nextScheduledAt","getCurrentAlarm","time","repeat_interval","createdAt","created_at","generateAlarmId","Math","random","toString","slice","calculateNextRecurringAlarm","baseTime","interval","next","NOOP_CLOCK","setTimeout","clearTimeout","scheduledEventsMap","Map","createAlarmScheduler","alarmManager","source","target","event","delay","scheduledEventId","sessionId","sourceSessionId","targetSessionId","startedAt","set","alarmId","catch","delete","cancelAll","actorRef","eventsToCancel","entries","async","handleXStateAlarm","alarmData","actor","_relay","send","getScheduledEvents","restoreScheduledEvents","alarms","pop"],"mappings":"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"}
|