@methodacting/actor-kit 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +7 -0
- package/README.md +2042 -0
- package/dist/browser.d.ts +384 -0
- package/dist/browser.js +2 -0
- package/dist/browser.js.map +1 -0
- package/dist/index.d.ts +644 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +416 -0
- package/dist/react.js +2 -0
- package/dist/react.js.map +1 -0
- package/dist/src/alarms.d.ts +47 -0
- package/dist/src/alarms.d.ts.map +1 -0
- package/dist/src/browser.d.ts +2 -0
- package/dist/src/browser.d.ts.map +1 -0
- package/dist/src/constants.d.ts +12 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/createAccessToken.d.ts +9 -0
- package/dist/src/createAccessToken.d.ts.map +1 -0
- package/dist/src/createActorFetch.d.ts +18 -0
- package/dist/src/createActorFetch.d.ts.map +1 -0
- package/dist/src/createActorKitClient.d.ts +13 -0
- package/dist/src/createActorKitClient.d.ts.map +1 -0
- package/dist/src/createActorKitContext.d.ts +29 -0
- package/dist/src/createActorKitContext.d.ts.map +1 -0
- package/dist/src/createActorKitMockClient.d.ts +11 -0
- package/dist/src/createActorKitMockClient.d.ts.map +1 -0
- package/dist/src/createActorKitRouter.d.ts +4 -0
- package/dist/src/createActorKitRouter.d.ts.map +1 -0
- package/dist/src/createMachineServer.d.ts +20 -0
- package/dist/src/createMachineServer.d.ts.map +1 -0
- package/dist/src/durable-object-system.d.ts +36 -0
- package/dist/src/durable-object-system.d.ts.map +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/react.d.ts +2 -0
- package/dist/src/react.d.ts.map +1 -0
- package/dist/src/schemas.d.ts +312 -0
- package/dist/src/schemas.d.ts.map +1 -0
- package/dist/src/server.d.ts +3 -0
- package/dist/src/server.d.ts.map +1 -0
- package/dist/src/storage.d.ts +64 -0
- package/dist/src/storage.d.ts.map +1 -0
- package/dist/src/storybook.d.ts +13 -0
- package/dist/src/storybook.d.ts.map +1 -0
- package/dist/src/test.d.ts +2 -0
- package/dist/src/test.d.ts.map +1 -0
- package/dist/src/types.d.ts +181 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils.d.ts +30 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/withActorKit.d.ts +9 -0
- package/dist/src/withActorKit.d.ts.map +1 -0
- package/dist/src/worker.d.ts +3 -0
- package/dist/src/worker.d.ts.map +1 -0
- package/package.json +87 -0
- package/src/alarms.ts +237 -0
- package/src/browser.ts +1 -0
- package/src/constants.ts +31 -0
- package/src/createAccessToken.ts +29 -0
- package/src/createActorFetch.ts +111 -0
- package/src/createActorKitClient.ts +224 -0
- package/src/createActorKitContext.tsx +228 -0
- package/src/createActorKitMockClient.ts +138 -0
- package/src/createActorKitRouter.ts +149 -0
- package/src/createMachineServer.ts +844 -0
- package/src/durable-object-system.ts +212 -0
- package/src/global.d.ts +7 -0
- package/src/index.ts +6 -0
- package/src/react.ts +1 -0
- package/src/schemas.ts +95 -0
- package/src/server.ts +3 -0
- package/src/storage.ts +404 -0
- package/src/storybook.ts +42 -0
- package/src/test.ts +1 -0
- package/src/types.ts +334 -0
- package/src/utils.ts +171 -0
- package/src/withActorKit.tsx +103 -0
- package/src/worker.ts +2 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type { AnyActorRef, AnyEventObject } from "xstate";
|
|
2
|
+
import type { AlarmManager } from "./alarms";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Serializable data stored with each alarm for XState delayed events
|
|
6
|
+
*/
|
|
7
|
+
export interface XStateAlarmData {
|
|
8
|
+
type: "xstate-delay";
|
|
9
|
+
sourceSessionId: string;
|
|
10
|
+
targetSessionId: string;
|
|
11
|
+
event: AnyEventObject;
|
|
12
|
+
scheduledEventId: string;
|
|
13
|
+
alarmId: string;
|
|
14
|
+
[key: string]: unknown; // Index signature for Record<string, unknown> compatibility
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Snapshot of scheduled events for persistence
|
|
19
|
+
*/
|
|
20
|
+
export interface ScheduledEventSnapshot {
|
|
21
|
+
sourceSessionId: string;
|
|
22
|
+
targetSessionId: string;
|
|
23
|
+
event: AnyEventObject;
|
|
24
|
+
delay: number;
|
|
25
|
+
id: string;
|
|
26
|
+
startedAt: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Clock interface for compatibility with XState
|
|
31
|
+
*/
|
|
32
|
+
export interface Clock {
|
|
33
|
+
setTimeout: (fn: () => void, delay: number) => unknown;
|
|
34
|
+
clearTimeout: (id: unknown) => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Simple no-op clock for XState actors that use alarm-based scheduling
|
|
39
|
+
* This clock doesn't actually schedule anything - delays are handled via alarms
|
|
40
|
+
*/
|
|
41
|
+
export const NOOP_CLOCK: Clock = {
|
|
42
|
+
setTimeout: () => Math.random(), // Return a fake ID
|
|
43
|
+
clearTimeout: () => {
|
|
44
|
+
// No-op - alarms manage cancellation
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Map to track scheduled events by their scheduledEventId
|
|
50
|
+
* This is used to look up event data when an alarm fires
|
|
51
|
+
*/
|
|
52
|
+
const scheduledEventsMap = new Map<string, ScheduledEventSnapshot>();
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create an alarm-based scheduler for XState actors
|
|
56
|
+
* This replaces the default setTimeout-based scheduler with one that uses Durable Object alarms
|
|
57
|
+
*
|
|
58
|
+
* @param alarmManager - The alarm manager to schedule alarms with
|
|
59
|
+
* @param system - The XState ActorSystem (used to relay events)
|
|
60
|
+
* @returns A scheduler object with schedule, cancel, and cancelAll methods
|
|
61
|
+
*/
|
|
62
|
+
export function createAlarmScheduler(
|
|
63
|
+
alarmManager: AlarmManager,
|
|
64
|
+
system: any
|
|
65
|
+
): {
|
|
66
|
+
schedule: (
|
|
67
|
+
source: AnyActorRef,
|
|
68
|
+
target: AnyActorRef,
|
|
69
|
+
event: AnyEventObject,
|
|
70
|
+
delay: number,
|
|
71
|
+
id?: string
|
|
72
|
+
) => void;
|
|
73
|
+
cancel: (source: AnyActorRef, id: string) => void;
|
|
74
|
+
cancelAll: (actorRef: AnyActorRef) => void;
|
|
75
|
+
} {
|
|
76
|
+
return {
|
|
77
|
+
schedule: (
|
|
78
|
+
source: AnyActorRef,
|
|
79
|
+
target: AnyActorRef,
|
|
80
|
+
event: AnyEventObject,
|
|
81
|
+
delay: number,
|
|
82
|
+
id: string = Math.random().toString(36).slice(2)
|
|
83
|
+
) => {
|
|
84
|
+
const scheduledEventId = `${source.sessionId}.${id}`;
|
|
85
|
+
|
|
86
|
+
// Store the event data for later retrieval
|
|
87
|
+
const snapshot: ScheduledEventSnapshot = {
|
|
88
|
+
sourceSessionId: source.sessionId,
|
|
89
|
+
targetSessionId: target.sessionId,
|
|
90
|
+
event,
|
|
91
|
+
delay,
|
|
92
|
+
id,
|
|
93
|
+
startedAt: Date.now(),
|
|
94
|
+
};
|
|
95
|
+
scheduledEventsMap.set(scheduledEventId, snapshot);
|
|
96
|
+
|
|
97
|
+
// Schedule the alarm
|
|
98
|
+
const alarmId = `xstate-${scheduledEventId}`;
|
|
99
|
+
|
|
100
|
+
alarmManager.schedule({
|
|
101
|
+
id: alarmId,
|
|
102
|
+
type: "xstate-delay",
|
|
103
|
+
scheduledAt: Date.now() + delay,
|
|
104
|
+
payload: {
|
|
105
|
+
type: "xstate-delay",
|
|
106
|
+
sourceSessionId: source.sessionId,
|
|
107
|
+
targetSessionId: target.sessionId,
|
|
108
|
+
event,
|
|
109
|
+
scheduledEventId,
|
|
110
|
+
alarmId,
|
|
111
|
+
},
|
|
112
|
+
}).catch((error) => {
|
|
113
|
+
console.error(`[AlarmScheduler] Error scheduling alarm:`, error);
|
|
114
|
+
scheduledEventsMap.delete(scheduledEventId);
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
cancel: (source: AnyActorRef, id: string) => {
|
|
119
|
+
const scheduledEventId = `${source.sessionId}.${id}`;
|
|
120
|
+
|
|
121
|
+
// Remove from our tracking map
|
|
122
|
+
scheduledEventsMap.delete(scheduledEventId);
|
|
123
|
+
|
|
124
|
+
// Cancel the alarm
|
|
125
|
+
alarmManager.cancel(`xstate-${scheduledEventId}`).catch((error) => {
|
|
126
|
+
console.error(`[AlarmScheduler] Error canceling alarm:`, error);
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
cancelAll: (actorRef: AnyActorRef) => {
|
|
131
|
+
// Find all events for this actor
|
|
132
|
+
const eventsToCancel: string[] = [];
|
|
133
|
+
|
|
134
|
+
for (const [scheduledEventId, snapshot] of scheduledEventsMap.entries()) {
|
|
135
|
+
if (snapshot.sourceSessionId === actorRef.sessionId) {
|
|
136
|
+
eventsToCancel.push(scheduledEventId);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Cancel each event
|
|
141
|
+
for (const scheduledEventId of eventsToCancel) {
|
|
142
|
+
scheduledEventsMap.delete(scheduledEventId);
|
|
143
|
+
alarmManager.cancel(`xstate-${scheduledEventId}`).catch((error) => {
|
|
144
|
+
console.error(`[AlarmScheduler] Error canceling alarm:`, error);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Handle an XState delayed event alarm
|
|
153
|
+
* This should be called from the Durable Object's alarm() handler
|
|
154
|
+
*
|
|
155
|
+
* @param alarmData - The alarm data from the XState alarm
|
|
156
|
+
* @param actor - The actor to send the event to
|
|
157
|
+
*/
|
|
158
|
+
export async function handleXStateAlarm(
|
|
159
|
+
alarmData: XStateAlarmData,
|
|
160
|
+
actor: any
|
|
161
|
+
): Promise<void> {
|
|
162
|
+
const { scheduledEventId, event } = alarmData;
|
|
163
|
+
|
|
164
|
+
// Remove from tracking map
|
|
165
|
+
scheduledEventsMap.delete(scheduledEventId);
|
|
166
|
+
|
|
167
|
+
// Send the event to the actor
|
|
168
|
+
try {
|
|
169
|
+
// Use the actor's internal _relay method to deliver the event
|
|
170
|
+
if (actor.system && actor.system._relay) {
|
|
171
|
+
actor.system._relay(actor, actor, event);
|
|
172
|
+
} else {
|
|
173
|
+
// Fallback: send directly to the actor
|
|
174
|
+
actor.send(event);
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error(`[AlarmScheduler] Error handling XState alarm:`, error);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get all scheduled events (useful for debugging/inspection)
|
|
183
|
+
*/
|
|
184
|
+
export function getScheduledEvents(): Map<string, ScheduledEventSnapshot> {
|
|
185
|
+
return new Map(scheduledEventsMap);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Restore scheduled events from storage (called after DO hibernation)
|
|
190
|
+
*/
|
|
191
|
+
export function restoreScheduledEvents(
|
|
192
|
+
alarms: Array<{ payload: XStateAlarmData; scheduledAt: number }>
|
|
193
|
+
): void {
|
|
194
|
+
for (const alarm of alarms) {
|
|
195
|
+
if (alarm.payload.type === "xstate-delay") {
|
|
196
|
+
const { sourceSessionId, targetSessionId, event, scheduledEventId } = alarm.payload;
|
|
197
|
+
const delay = alarm.scheduledAt - Date.now();
|
|
198
|
+
|
|
199
|
+
// Only restore if the alarm is still in the future
|
|
200
|
+
if (delay > 0) {
|
|
201
|
+
scheduledEventsMap.set(scheduledEventId, {
|
|
202
|
+
sourceSessionId,
|
|
203
|
+
targetSessionId,
|
|
204
|
+
event,
|
|
205
|
+
delay,
|
|
206
|
+
id: scheduledEventId.split(".").pop() || scheduledEventId,
|
|
207
|
+
startedAt: alarm.scheduledAt - delay,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
package/src/global.d.ts
ADDED
package/src/index.ts
ADDED
package/src/react.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createActorKitContext } from "./createActorKitContext";
|
package/src/schemas.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const BotManagementSchema = z.object({
|
|
4
|
+
corporateProxy: z.boolean(),
|
|
5
|
+
verifiedBot: z.boolean(),
|
|
6
|
+
jsDetection: z.object({
|
|
7
|
+
passed: z.boolean(),
|
|
8
|
+
}),
|
|
9
|
+
staticResource: z.boolean(),
|
|
10
|
+
detectionIds: z.record(z.any()),
|
|
11
|
+
score: z.number(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const EnvironmentSchema = z.object({
|
|
15
|
+
ACTOR_KIT_SECRET: z.string(),
|
|
16
|
+
ACTOR_KIT_HOST: z.string(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const RequestInfoSchema = z.object({
|
|
20
|
+
longitude: z.string(),
|
|
21
|
+
latitude: z.string(),
|
|
22
|
+
continent: z.string(),
|
|
23
|
+
country: z.string(),
|
|
24
|
+
city: z.string(),
|
|
25
|
+
timezone: z.string(),
|
|
26
|
+
postalCode: z.string(),
|
|
27
|
+
region: z.string(),
|
|
28
|
+
regionCode: z.string(),
|
|
29
|
+
metroCode: z.string(),
|
|
30
|
+
botManagement: BotManagementSchema,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const CallerSchema = z.object({
|
|
34
|
+
id: z.string(),
|
|
35
|
+
type: z.enum(["client", "system", "service"]),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const AnyEventSchema = z.object({
|
|
39
|
+
type: z.string(),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export const SystemEventSchema = z.discriminatedUnion("type", [
|
|
43
|
+
z.object({
|
|
44
|
+
type: z.literal("INITIALIZE"),
|
|
45
|
+
caller: z.object({ type: z.literal("system"), id: z.string() }),
|
|
46
|
+
}),
|
|
47
|
+
z.object({
|
|
48
|
+
type: z.literal("CONNECT"),
|
|
49
|
+
caller: z.object({ type: z.literal("system"), id: z.string() }),
|
|
50
|
+
connectingCaller: CallerSchema,
|
|
51
|
+
}),
|
|
52
|
+
z.object({
|
|
53
|
+
type: z.literal("DISCONNECT"),
|
|
54
|
+
caller: z.object({ type: z.literal("system"), id: z.string() }),
|
|
55
|
+
disconnectingCaller: CallerSchema,
|
|
56
|
+
}),
|
|
57
|
+
z.object({
|
|
58
|
+
type: z.literal("RESUME"),
|
|
59
|
+
caller: z.object({ type: z.literal("system"), id: z.string() }),
|
|
60
|
+
}),
|
|
61
|
+
z.object({
|
|
62
|
+
type: z.literal("MIGRATE"),
|
|
63
|
+
caller: z.object({ type: z.literal("system"), id: z.string() }),
|
|
64
|
+
operations: z.array(z.any()),
|
|
65
|
+
}),
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
export const CallerIdTypeSchema = z.enum(["client", "service", "system"]);
|
|
69
|
+
|
|
70
|
+
export const CallerStringSchema = z.string().transform((val, ctx) => {
|
|
71
|
+
if (val === "anonymous") {
|
|
72
|
+
return { type: "client" as const, id: "anonymous" };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Regular expression to validate the UUID format
|
|
76
|
+
const callerTypeParseResult = CallerIdTypeSchema.safeParse(val.split("-")[0]);
|
|
77
|
+
if (!callerTypeParseResult.success) {
|
|
78
|
+
callerTypeParseResult.error.issues.forEach(ctx.addIssue);
|
|
79
|
+
return z.NEVER;
|
|
80
|
+
}
|
|
81
|
+
const type = callerTypeParseResult.data;
|
|
82
|
+
|
|
83
|
+
const id = val.substring(val.indexOf("-") + 1);
|
|
84
|
+
if (z.string().uuid().safeParse(id).success) {
|
|
85
|
+
return { type, id };
|
|
86
|
+
} else {
|
|
87
|
+
// If not valid, add a custom issue
|
|
88
|
+
ctx.addIssue({
|
|
89
|
+
code: z.ZodIssueCode.custom,
|
|
90
|
+
message: `Must be a valid uuid or 'anonymous'. Received '${id}' on value '${val}'.`,
|
|
91
|
+
});
|
|
92
|
+
// Return the special NEVER symbol to indicate a validation failure
|
|
93
|
+
return z.NEVER;
|
|
94
|
+
}
|
|
95
|
+
});
|
package/src/server.ts
ADDED