@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.
Files changed (79) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +2042 -0
  3. package/dist/browser.d.ts +384 -0
  4. package/dist/browser.js +2 -0
  5. package/dist/browser.js.map +1 -0
  6. package/dist/index.d.ts +644 -0
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/react.d.ts +416 -0
  10. package/dist/react.js +2 -0
  11. package/dist/react.js.map +1 -0
  12. package/dist/src/alarms.d.ts +47 -0
  13. package/dist/src/alarms.d.ts.map +1 -0
  14. package/dist/src/browser.d.ts +2 -0
  15. package/dist/src/browser.d.ts.map +1 -0
  16. package/dist/src/constants.d.ts +12 -0
  17. package/dist/src/constants.d.ts.map +1 -0
  18. package/dist/src/createAccessToken.d.ts +9 -0
  19. package/dist/src/createAccessToken.d.ts.map +1 -0
  20. package/dist/src/createActorFetch.d.ts +18 -0
  21. package/dist/src/createActorFetch.d.ts.map +1 -0
  22. package/dist/src/createActorKitClient.d.ts +13 -0
  23. package/dist/src/createActorKitClient.d.ts.map +1 -0
  24. package/dist/src/createActorKitContext.d.ts +29 -0
  25. package/dist/src/createActorKitContext.d.ts.map +1 -0
  26. package/dist/src/createActorKitMockClient.d.ts +11 -0
  27. package/dist/src/createActorKitMockClient.d.ts.map +1 -0
  28. package/dist/src/createActorKitRouter.d.ts +4 -0
  29. package/dist/src/createActorKitRouter.d.ts.map +1 -0
  30. package/dist/src/createMachineServer.d.ts +20 -0
  31. package/dist/src/createMachineServer.d.ts.map +1 -0
  32. package/dist/src/durable-object-system.d.ts +36 -0
  33. package/dist/src/durable-object-system.d.ts.map +1 -0
  34. package/dist/src/index.d.ts +7 -0
  35. package/dist/src/index.d.ts.map +1 -0
  36. package/dist/src/react.d.ts +2 -0
  37. package/dist/src/react.d.ts.map +1 -0
  38. package/dist/src/schemas.d.ts +312 -0
  39. package/dist/src/schemas.d.ts.map +1 -0
  40. package/dist/src/server.d.ts +3 -0
  41. package/dist/src/server.d.ts.map +1 -0
  42. package/dist/src/storage.d.ts +64 -0
  43. package/dist/src/storage.d.ts.map +1 -0
  44. package/dist/src/storybook.d.ts +13 -0
  45. package/dist/src/storybook.d.ts.map +1 -0
  46. package/dist/src/test.d.ts +2 -0
  47. package/dist/src/test.d.ts.map +1 -0
  48. package/dist/src/types.d.ts +181 -0
  49. package/dist/src/types.d.ts.map +1 -0
  50. package/dist/src/utils.d.ts +30 -0
  51. package/dist/src/utils.d.ts.map +1 -0
  52. package/dist/src/withActorKit.d.ts +9 -0
  53. package/dist/src/withActorKit.d.ts.map +1 -0
  54. package/dist/src/worker.d.ts +3 -0
  55. package/dist/src/worker.d.ts.map +1 -0
  56. package/package.json +87 -0
  57. package/src/alarms.ts +237 -0
  58. package/src/browser.ts +1 -0
  59. package/src/constants.ts +31 -0
  60. package/src/createAccessToken.ts +29 -0
  61. package/src/createActorFetch.ts +111 -0
  62. package/src/createActorKitClient.ts +224 -0
  63. package/src/createActorKitContext.tsx +228 -0
  64. package/src/createActorKitMockClient.ts +138 -0
  65. package/src/createActorKitRouter.ts +149 -0
  66. package/src/createMachineServer.ts +844 -0
  67. package/src/durable-object-system.ts +212 -0
  68. package/src/global.d.ts +7 -0
  69. package/src/index.ts +6 -0
  70. package/src/react.ts +1 -0
  71. package/src/schemas.ts +95 -0
  72. package/src/server.ts +3 -0
  73. package/src/storage.ts +404 -0
  74. package/src/storybook.ts +42 -0
  75. package/src/test.ts +1 -0
  76. package/src/types.ts +334 -0
  77. package/src/utils.ts +171 -0
  78. package/src/withActorKit.tsx +103 -0
  79. package/src/worker.ts +2 -0
@@ -0,0 +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 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 [\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 /**\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, options.repeatInterval ?? null, JSON.stringify(options.payload), 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 [\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 /**\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, JSON.stringify(snapshot), checksum ?? null, 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[] = [];\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 array format\n if (Array.isArray(result) && result.length === 0) return [];\n const { columns, rows } = result[0];\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","Array","isArray","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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"}
@@ -0,0 +1,416 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { AnyEventObject, StateMachine, StateValueFrom, AnyStateMachine, SnapshotFrom } from 'xstate';
3
+ import { DurableObject } from 'cloudflare:workers';
4
+ import { z } from 'zod';
5
+
6
+ declare const RequestInfoSchema: z.ZodObject<{
7
+ longitude: z.ZodString;
8
+ latitude: z.ZodString;
9
+ continent: z.ZodString;
10
+ country: z.ZodString;
11
+ city: z.ZodString;
12
+ timezone: z.ZodString;
13
+ postalCode: z.ZodString;
14
+ region: z.ZodString;
15
+ regionCode: z.ZodString;
16
+ metroCode: z.ZodString;
17
+ botManagement: z.ZodObject<{
18
+ corporateProxy: z.ZodBoolean;
19
+ verifiedBot: z.ZodBoolean;
20
+ jsDetection: z.ZodObject<{
21
+ passed: z.ZodBoolean;
22
+ }, "strip", z.ZodTypeAny, {
23
+ passed: boolean;
24
+ }, {
25
+ passed: boolean;
26
+ }>;
27
+ staticResource: z.ZodBoolean;
28
+ detectionIds: z.ZodRecord<z.ZodString, z.ZodAny>;
29
+ score: z.ZodNumber;
30
+ }, "strip", z.ZodTypeAny, {
31
+ corporateProxy: boolean;
32
+ verifiedBot: boolean;
33
+ jsDetection: {
34
+ passed: boolean;
35
+ };
36
+ staticResource: boolean;
37
+ detectionIds: Record<string, any>;
38
+ score: number;
39
+ }, {
40
+ corporateProxy: boolean;
41
+ verifiedBot: boolean;
42
+ jsDetection: {
43
+ passed: boolean;
44
+ };
45
+ staticResource: boolean;
46
+ detectionIds: Record<string, any>;
47
+ score: number;
48
+ }>;
49
+ }, "strip", z.ZodTypeAny, {
50
+ longitude: string;
51
+ latitude: string;
52
+ continent: string;
53
+ country: string;
54
+ city: string;
55
+ timezone: string;
56
+ postalCode: string;
57
+ region: string;
58
+ regionCode: string;
59
+ metroCode: string;
60
+ botManagement: {
61
+ corporateProxy: boolean;
62
+ verifiedBot: boolean;
63
+ jsDetection: {
64
+ passed: boolean;
65
+ };
66
+ staticResource: boolean;
67
+ detectionIds: Record<string, any>;
68
+ score: number;
69
+ };
70
+ }, {
71
+ longitude: string;
72
+ latitude: string;
73
+ continent: string;
74
+ country: string;
75
+ city: string;
76
+ timezone: string;
77
+ postalCode: string;
78
+ region: string;
79
+ regionCode: string;
80
+ metroCode: string;
81
+ botManagement: {
82
+ corporateProxy: boolean;
83
+ verifiedBot: boolean;
84
+ jsDetection: {
85
+ passed: boolean;
86
+ };
87
+ staticResource: boolean;
88
+ detectionIds: Record<string, any>;
89
+ score: number;
90
+ };
91
+ }>;
92
+ declare const CallerSchema: z.ZodObject<{
93
+ id: z.ZodString;
94
+ type: z.ZodEnum<["client", "system", "service"]>;
95
+ }, "strip", z.ZodTypeAny, {
96
+ type: "client" | "system" | "service";
97
+ id: string;
98
+ }, {
99
+ type: "client" | "system" | "service";
100
+ id: string;
101
+ }>;
102
+ declare const SystemEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
103
+ type: z.ZodLiteral<"INITIALIZE">;
104
+ caller: z.ZodObject<{
105
+ type: z.ZodLiteral<"system">;
106
+ id: z.ZodString;
107
+ }, "strip", z.ZodTypeAny, {
108
+ type: "system";
109
+ id: string;
110
+ }, {
111
+ type: "system";
112
+ id: string;
113
+ }>;
114
+ }, "strip", z.ZodTypeAny, {
115
+ type: "INITIALIZE";
116
+ caller: {
117
+ type: "system";
118
+ id: string;
119
+ };
120
+ }, {
121
+ type: "INITIALIZE";
122
+ caller: {
123
+ type: "system";
124
+ id: string;
125
+ };
126
+ }>, z.ZodObject<{
127
+ type: z.ZodLiteral<"CONNECT">;
128
+ caller: z.ZodObject<{
129
+ type: z.ZodLiteral<"system">;
130
+ id: z.ZodString;
131
+ }, "strip", z.ZodTypeAny, {
132
+ type: "system";
133
+ id: string;
134
+ }, {
135
+ type: "system";
136
+ id: string;
137
+ }>;
138
+ connectingCaller: z.ZodObject<{
139
+ id: z.ZodString;
140
+ type: z.ZodEnum<["client", "system", "service"]>;
141
+ }, "strip", z.ZodTypeAny, {
142
+ type: "client" | "system" | "service";
143
+ id: string;
144
+ }, {
145
+ type: "client" | "system" | "service";
146
+ id: string;
147
+ }>;
148
+ }, "strip", z.ZodTypeAny, {
149
+ type: "CONNECT";
150
+ caller: {
151
+ type: "system";
152
+ id: string;
153
+ };
154
+ connectingCaller: {
155
+ type: "client" | "system" | "service";
156
+ id: string;
157
+ };
158
+ }, {
159
+ type: "CONNECT";
160
+ caller: {
161
+ type: "system";
162
+ id: string;
163
+ };
164
+ connectingCaller: {
165
+ type: "client" | "system" | "service";
166
+ id: string;
167
+ };
168
+ }>, z.ZodObject<{
169
+ type: z.ZodLiteral<"DISCONNECT">;
170
+ caller: z.ZodObject<{
171
+ type: z.ZodLiteral<"system">;
172
+ id: z.ZodString;
173
+ }, "strip", z.ZodTypeAny, {
174
+ type: "system";
175
+ id: string;
176
+ }, {
177
+ type: "system";
178
+ id: string;
179
+ }>;
180
+ disconnectingCaller: z.ZodObject<{
181
+ id: z.ZodString;
182
+ type: z.ZodEnum<["client", "system", "service"]>;
183
+ }, "strip", z.ZodTypeAny, {
184
+ type: "client" | "system" | "service";
185
+ id: string;
186
+ }, {
187
+ type: "client" | "system" | "service";
188
+ id: string;
189
+ }>;
190
+ }, "strip", z.ZodTypeAny, {
191
+ type: "DISCONNECT";
192
+ caller: {
193
+ type: "system";
194
+ id: string;
195
+ };
196
+ disconnectingCaller: {
197
+ type: "client" | "system" | "service";
198
+ id: string;
199
+ };
200
+ }, {
201
+ type: "DISCONNECT";
202
+ caller: {
203
+ type: "system";
204
+ id: string;
205
+ };
206
+ disconnectingCaller: {
207
+ type: "client" | "system" | "service";
208
+ id: string;
209
+ };
210
+ }>, z.ZodObject<{
211
+ type: z.ZodLiteral<"RESUME">;
212
+ caller: z.ZodObject<{
213
+ type: z.ZodLiteral<"system">;
214
+ id: z.ZodString;
215
+ }, "strip", z.ZodTypeAny, {
216
+ type: "system";
217
+ id: string;
218
+ }, {
219
+ type: "system";
220
+ id: string;
221
+ }>;
222
+ }, "strip", z.ZodTypeAny, {
223
+ type: "RESUME";
224
+ caller: {
225
+ type: "system";
226
+ id: string;
227
+ };
228
+ }, {
229
+ type: "RESUME";
230
+ caller: {
231
+ type: "system";
232
+ id: string;
233
+ };
234
+ }>, z.ZodObject<{
235
+ type: z.ZodLiteral<"MIGRATE">;
236
+ caller: z.ZodObject<{
237
+ type: z.ZodLiteral<"system">;
238
+ id: z.ZodString;
239
+ }, "strip", z.ZodTypeAny, {
240
+ type: "system";
241
+ id: string;
242
+ }, {
243
+ type: "system";
244
+ id: string;
245
+ }>;
246
+ operations: z.ZodArray<z.ZodAny, "many">;
247
+ }, "strip", z.ZodTypeAny, {
248
+ type: "MIGRATE";
249
+ caller: {
250
+ type: "system";
251
+ id: string;
252
+ };
253
+ operations: any[];
254
+ }, {
255
+ type: "MIGRATE";
256
+ caller: {
257
+ type: "system";
258
+ id: string;
259
+ };
260
+ operations: any[];
261
+ }>]>;
262
+
263
+ type EnvWithDurableObjects = {
264
+ ACTOR_KIT_SECRET: string;
265
+ [key: string]: DurableObjectNamespace<ActorServer<any>> | unknown;
266
+ };
267
+ interface ActorServerMethods<TMachine extends BaseActorKitStateMachine> {
268
+ fetch(request: Request): Promise<Response>;
269
+ spawn(props: {
270
+ actorType: string;
271
+ actorId: string;
272
+ caller: Caller;
273
+ input: Record<string, unknown>;
274
+ }): void;
275
+ send(event: ClientEventFrom<TMachine> | ServiceEventFrom<TMachine>): void;
276
+ getSnapshot(caller: Caller, options?: {
277
+ waitForEvent?: ClientEventFrom<TMachine>;
278
+ waitForState?: StateValueFrom<TMachine>;
279
+ timeout?: number;
280
+ errorOnWaitTimeout?: boolean;
281
+ }): Promise<{
282
+ checksum: string;
283
+ snapshot: CallerSnapshotFrom<TMachine>;
284
+ }>;
285
+ }
286
+ type ActorServer<TMachine extends AnyActorKitStateMachine> = DurableObject & ActorServerMethods<TMachine>;
287
+ type Caller = z.infer<typeof CallerSchema>;
288
+ type RequestInfo = z.infer<typeof RequestInfoSchema>;
289
+ type CallerType = "client" | "system" | "service";
290
+ type EventObject = {
291
+ type: string;
292
+ };
293
+ type BaseActorKitContext<TPublicProps extends {
294
+ [key: string]: unknown;
295
+ }, TPrivateProps extends {
296
+ [key: string]: unknown;
297
+ }> = {
298
+ public: TPublicProps;
299
+ private: Record<string, TPrivateProps>;
300
+ };
301
+ type ActorKitStateMachine<TEvent extends BaseActorKitEvent<EnvWithDurableObjects>, TInput extends {
302
+ id: string;
303
+ caller: Caller;
304
+ storage: DurableObjectStorage;
305
+ }, TContext extends BaseActorKitContext<any, any> & {
306
+ [key: string]: unknown;
307
+ }> = StateMachine<TContext, TEvent & EventObject, any, any, any, any, any, any, any, TInput, any, any, any, any>;
308
+ type BaseActorKitInput<TEnv = EnvWithDurableObjects> = {
309
+ id: string;
310
+ caller: Caller;
311
+ env: TEnv;
312
+ storage: DurableObjectStorage;
313
+ };
314
+ type WithActorKitInput<TInputProps extends {
315
+ [key: string]: unknown;
316
+ }, TEnv extends EnvWithDurableObjects> = TInputProps & BaseActorKitInput<TEnv>;
317
+ type AnyActorKitStateMachine = ActorKitStateMachine<any, any, any>;
318
+ type AnyActorKitEvent = (WithActorKitEvent<AnyEventObject, "client"> | WithActorKitEvent<AnyEventObject, "service"> | ActorKitSystemEvent) & BaseActorKitEvent<EnvWithDurableObjects>;
319
+ type AnyActorKitInput = WithActorKitInput<{
320
+ [key: string]: unknown;
321
+ }, EnvWithDurableObjects> & {
322
+ storage: DurableObjectStorage;
323
+ };
324
+ type AnyActorKitContext = {
325
+ public: {
326
+ [key: string]: unknown;
327
+ };
328
+ private: Record<string, {
329
+ [key: string]: unknown;
330
+ }>;
331
+ };
332
+ type BaseActorKitStateMachine = ActorKitStateMachine<AnyActorKitEvent, AnyActorKitInput, AnyActorKitContext>;
333
+ interface BaseActorKitEvent<TEnv extends EnvWithDurableObjects> {
334
+ caller: Caller;
335
+ storage: DurableObjectStorage;
336
+ requestInfo?: RequestInfo;
337
+ env: TEnv;
338
+ }
339
+ type ActorKitSystemEvent = z.infer<typeof SystemEventSchema>;
340
+ type WithActorKitEvent<T extends {
341
+ type: string;
342
+ }, C extends CallerType> = T & BaseActorKitEvent<EnvWithDurableObjects> & {
343
+ caller: {
344
+ type: C;
345
+ };
346
+ };
347
+ type CallerSnapshotFrom<TMachine extends AnyStateMachine> = {
348
+ public: SnapshotFrom<TMachine> extends {
349
+ context: {
350
+ public: infer P;
351
+ };
352
+ } ? P : unknown;
353
+ private: SnapshotFrom<TMachine> extends {
354
+ context: {
355
+ private: Partial<Record<string, infer PR>>;
356
+ };
357
+ } ? PR : unknown;
358
+ value: SnapshotFrom<TMachine> extends {
359
+ value: infer V;
360
+ } ? V : unknown;
361
+ };
362
+ type ClientEventFrom<T extends AnyActorKitStateMachine> = T extends StateMachine<any, infer TEvent, any, any, any, any, any, any, any, any, any, any, any, any> ? TEvent extends WithActorKitEvent<infer E, "client"> ? Omit<E, keyof BaseActorKitEvent<EnvWithDurableObjects>> : never : never;
363
+ type ServiceEventFrom<T extends AnyActorKitStateMachine> = T extends StateMachine<any, infer TEvent, any, any, any, any, any, any, any, any, any, any, any, any> ? TEvent extends WithActorKitEvent<infer E, "service"> ? Omit<E, keyof BaseActorKitEvent<EnvWithDurableObjects>> : never : never;
364
+ interface MatchesProps<TMachine extends AnyActorKitStateMachine> {
365
+ state: StateValueFrom<TMachine>;
366
+ and?: StateValueFrom<TMachine>;
367
+ or?: StateValueFrom<TMachine>;
368
+ not?: boolean;
369
+ initialValueOverride?: boolean;
370
+ }
371
+ type ActorKitClient<TMachine extends AnyActorKitStateMachine> = {
372
+ connect: () => Promise<void>;
373
+ disconnect: () => void;
374
+ send: (event: ClientEventFrom<TMachine>) => void;
375
+ getState: () => CallerSnapshotFrom<TMachine>;
376
+ subscribe: (listener: (state: CallerSnapshotFrom<TMachine>) => void) => () => void;
377
+ waitFor: (predicateFn: (state: CallerSnapshotFrom<TMachine>) => boolean, timeoutMs?: number) => Promise<void>;
378
+ };
379
+
380
+ type ActorKitClientProps<TMachine extends AnyActorKitStateMachine> = {
381
+ host: string;
382
+ actorType: string;
383
+ actorId: string;
384
+ checksum: string;
385
+ accessToken: string;
386
+ initialSnapshot: CallerSnapshotFrom<TMachine>;
387
+ onStateChange?: (newState: CallerSnapshotFrom<TMachine>) => void;
388
+ onError?: (error: Error) => void;
389
+ };
390
+
391
+ declare function createActorKitContext<TMachine extends AnyActorKitStateMachine>(actorType: string): {
392
+ Provider: React.FC<{
393
+ children: ReactNode;
394
+ } & Omit<ActorKitClientProps<TMachine>, "actorType">>;
395
+ ProviderFromClient: React.FC<{
396
+ children: ReactNode;
397
+ client: ActorKitClient<TMachine>;
398
+ }>;
399
+ useClient: () => ActorKitClient<TMachine>;
400
+ useSelector: <T>(selector: (snapshot: CallerSnapshotFrom<TMachine>) => T) => T;
401
+ useSend: () => (event: ClientEventFrom<TMachine>) => void;
402
+ useMatches: (stateValue: StateValueFrom<TMachine>) => boolean;
403
+ Matches: React.FC<MatchesProps<TMachine> & {
404
+ children: ReactNode;
405
+ }> & {
406
+ create: (state: StateValueFrom<TMachine>, options?: {
407
+ and?: StateValueFrom<TMachine>;
408
+ or?: StateValueFrom<TMachine>;
409
+ not?: boolean;
410
+ }) => React.FC<Omit<MatchesProps<TMachine>, "state" | "and" | "or" | "not"> & {
411
+ children: ReactNode;
412
+ }>;
413
+ };
414
+ };
415
+
416
+ export { createActorKitContext };
package/dist/react.js ADDED
@@ -0,0 +1,2 @@
1
+ "use client";import e,{createContext as t,memo as r,useRef as n,useEffect as o,useContext as c,useMemo as s,useCallback as i,useSyncExternalStore as a}from"react";import{matchesState as l}from"xstate";import{applyPatch as u}from"fast-json-patch";import{produce as d}from"immer";function m(e){let t=e.initialSnapshot,r=null;const n=new Set;let o=0;const c=async()=>{const s=function(e){const{host:t,actorId:r,actorType:n,accessToken:o,checksum:c}=e,s=`${/^(localhost|127\.0\.0\.1|192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.)/.test(t)?"ws":"wss"}://${t}/api/${n}/${r}`,i=new URLSearchParams({accessToken:o});c&&i.append("checksum",c);return`${s}?${i.toString()}`}(e);return r=new WebSocket(s),r.addEventListener("open",()=>{o=0}),r.addEventListener("message",r=>{try{const o=JSON.parse("string"==typeof r.data?r.data:(new TextDecoder).decode(r.data));t=d(t,e=>{u(e,o.operations)}),e.onStateChange?.(t),n.forEach(e=>e(t))}catch(t){console.error("[ActorKitClient] Error processing message:",t),e.onError?.(t)}}),r.addEventListener("error",t=>{console.error("[ActorKitClient] WebSocket error:",t),console.error("[ActorKitClient] Error details:",{message:t.message,type:t.type,target:t.target,eventPhase:t.eventPhase}),e.onError?.(new Error(`WebSocket error: ${JSON.stringify(t)}`))}),r.addEventListener("close",e=>{if(o<5){o++;const e=Math.min(1e3*Math.pow(2,o),3e4);setTimeout(c,e)}else console.error("[ActorKitClient] Max reconnection attempts reached")}),new Promise(e=>{r.addEventListener("open",()=>e())})},s=e=>(n.add(e),()=>{n.delete(e)});return{connect:c,disconnect:()=>{r&&(r.close(),r=null)},send:t=>{r&&r.readyState===WebSocket.OPEN?r.send(JSON.stringify(t)):e.onError?.(new Error("Cannot send event: WebSocket is not connected"))},getState:()=>t,subscribe:s,waitFor:async(e,r=5e3)=>e(t)?Promise.resolve():new Promise((t,n)=>{let o=null;r>0&&(o=setTimeout(()=>{c(),n(new Error(`Timeout waiting for condition after ${r}ms`))},r));const c=s(r=>{e(r)&&(o&&clearTimeout(o),c(),t())})})}}function h(u){const d=t(null),h=r(t=>{const r=n(m({host:t.host,actorId:t.actorId,accessToken:t.accessToken,checksum:t.checksum,initialSnapshot:t.initialSnapshot,actorType:u})),c=n(!1);return o(()=>{c.current||(c.current=!0,r.current.connect().then(()=>{}))},[c]),e.createElement(d.Provider,{value:r.current},t.children)});function f(){const e=c(d);if(!e)throw new Error("useClient must be used within an ActorKitContext.Provider");return e}const v=e=>{const t=f();return function(e,t,r,n,o){const[c,l]=s(()=>{let e,c,s=!1;const i=t=>{if(!s)return s=!0,e=t,c=n(t),c;if(Object.is(e,t))return c;const r=n(t);return o&&o(c,r)?(e=t,c):(e=t,c=r,r)};return[()=>i(t()),r?()=>i(r()):void 0]},[t,r,n,o]),u=i(t=>{let r=c();return e(()=>{const e=c();o&&o(r,e)||(r=e,t())})},[e,c,o]);return a(u,c,l)}(t.subscribe,t.getState,t.getState,e,p)};function S(e){return v(t=>l(e,t.value))}const E=t=>{const r=S(t.state),n=!t.and||S(t.and),o=!!t.or&&S(t.or),c="boolean"==typeof t.initialValueOverride?t.initialValueOverride:r&&n||o;return(t.not?!c:c)?e.createElement(e.Fragment,null,t.children):null};return E.create=(t,r={})=>{const n=({children:n,initialValueOverride:o})=>e.createElement(E,{state:t,and:r.and,or:r.or,not:r.not,initialValueOverride:o},n);return n.displayName=`MatchesComponent(${t.toString()})`,n},{Provider:h,ProviderFromClient:({children:t,client:r})=>e.createElement(d.Provider,{value:r},t),useClient:f,useSelector:v,useSend:function(){return f().send},useMatches:S,Matches:E}}function p(e,t){return e===t}export{h as createActorKitContext};
2
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","sources":["../src/createActorKitClient.ts","../src/createActorKitContext.tsx"],"sourcesContent":["import { applyPatch } from \"fast-json-patch\";\nimport { produce } from \"immer\";\n\nimport {\n ActorKitClient,\n ActorKitEmittedEvent,\n AnyActorKitStateMachine,\n CallerSnapshotFrom,\n ClientEventFrom,\n} from \"./types\";\n\nexport type ActorKitClientProps<TMachine extends AnyActorKitStateMachine> = {\n host: string;\n actorType: string;\n actorId: string;\n checksum: string;\n accessToken: string;\n initialSnapshot: CallerSnapshotFrom<TMachine>;\n onStateChange?: (newState: CallerSnapshotFrom<TMachine>) => void;\n onError?: (error: Error) => void;\n};\n\ntype Listener<T> = (state: T) => void;\n\n/**\n * Creates an Actor Kit client for managing state and communication with the server.\n *\n * @template TMachine - The type of the state machine.\n * @param {ActorKitClientProps<TMachine>} props - Configuration options for the client.\n * @returns {ActorKitClient<TMachine>} An object with methods to interact with the actor.\n */\nexport function createActorKitClient<TMachine extends AnyActorKitStateMachine>(\n props: ActorKitClientProps<TMachine>\n): ActorKitClient<TMachine> {\n let currentSnapshot = props.initialSnapshot;\n let socket: WebSocket | null = null;\n const listeners: Set<Listener<CallerSnapshotFrom<TMachine>>> = new Set();\n let reconnectAttempts = 0;\n const maxReconnectAttempts = 5;\n\n /**\n * Notifies all registered listeners with the current state.\n */\n const notifyListeners = () => {\n listeners.forEach((listener) => listener(currentSnapshot));\n };\n\n /**\n * Establishes a WebSocket connection to the Actor Kit server.\n * @returns {Promise<void>} A promise that resolves when the connection is established.\n */\n const connect = async () => {\n const url = getWebSocketUrl(props);\n\n socket = new WebSocket(url);\n\n socket.addEventListener(\"open\", () => {\n reconnectAttempts = 0;\n });\n\n socket.addEventListener(\"message\", (event: MessageEvent) => {\n try {\n const data = JSON.parse(\n typeof event.data === \"string\"\n ? event.data\n : new TextDecoder().decode(event.data)\n ) as ActorKitEmittedEvent;\n\n currentSnapshot = produce(currentSnapshot, (draft) => {\n applyPatch(draft, data.operations);\n });\n\n props.onStateChange?.(currentSnapshot);\n notifyListeners();\n } catch (error) {\n console.error(`[ActorKitClient] Error processing message:`, error);\n props.onError?.(error as Error);\n }\n });\n\n socket.addEventListener(\"error\", (error: any) => {\n console.error(`[ActorKitClient] WebSocket error:`, error);\n console.error(`[ActorKitClient] Error details:`, {\n message: error.message,\n type: error.type,\n target: error.target,\n eventPhase: error.eventPhase,\n });\n props.onError?.(new Error(`WebSocket error: ${JSON.stringify(error)}`));\n });\n\n // todo, how do we reconnect when a user returns to the tab\n // later after it's disconnected\n\n socket.addEventListener(\"close\", (event) => {\n // Implement reconnection logic\n if (reconnectAttempts < maxReconnectAttempts) {\n reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);\n setTimeout(connect, delay);\n } else {\n console.error(`[ActorKitClient] Max reconnection attempts reached`);\n }\n });\n\n return new Promise<void>((resolve) => {\n socket!.addEventListener(\"open\", () => resolve());\n });\n };\n\n /**\n * Closes the WebSocket connection to the Actor Kit server.\n */\n const disconnect = () => {\n if (socket) {\n socket.close();\n socket = null;\n }\n };\n\n /**\n * Sends an event to the Actor Kit server.\n * @param {ClientEventFrom<TMachine>} event - The event to send.\n */\n const send = (event: ClientEventFrom<TMachine>) => {\n if (socket && socket.readyState === WebSocket.OPEN) {\n socket.send(JSON.stringify(event));\n } else {\n props.onError?.(\n new Error(\"Cannot send event: WebSocket is not connected\")\n );\n }\n };\n\n /**\n * Retrieves the current state of the actor.\n * @returns {CallerSnapshotFrom<TMachine>} The current state.\n */\n const getState = () => currentSnapshot;\n\n /**\n * Subscribes a listener to state changes.\n * @param {Listener<CallerSnapshotFrom<TMachine>>} listener - The listener function to be called on state changes.\n * @returns {() => void} A function to unsubscribe the listener.\n */\n const subscribe = (listener: Listener<CallerSnapshotFrom<TMachine>>) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n };\n\n /**\n * Waits for a state condition to be met.\n * @param {(state: CallerSnapshotFrom<TMachine>) => boolean} predicateFn - Function that returns true when condition is met\n * @param {number} [timeoutMs=5000] - Maximum time to wait in milliseconds\n * @returns {Promise<void>} Resolves when condition is met, rejects on timeout\n */\n const waitFor = async (\n predicateFn: (state: CallerSnapshotFrom<TMachine>) => boolean,\n timeoutMs: number = 5000\n ): Promise<void> => {\n // Check if condition is already met\n if (predicateFn(currentSnapshot)) {\n return Promise.resolve();\n }\n return new Promise((resolve, reject) => {\n let timeoutId: number | null = null;\n\n // Set up timeout to reject if condition isn't met in time\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n unsubscribe();\n reject(\n new Error(`Timeout waiting for condition after ${timeoutMs}ms`)\n );\n }, timeoutMs);\n }\n\n // Subscribe to state changes\n const unsubscribe = subscribe((state) => {\n if (predicateFn(state)) {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n unsubscribe();\n resolve();\n }\n });\n });\n };\n\n return {\n connect,\n disconnect,\n send,\n getState,\n subscribe,\n waitFor,\n };\n}\n\nfunction getWebSocketUrl(props: ActorKitClientProps<any>): string {\n const { host, actorId, actorType, accessToken, checksum } = props;\n\n // Determine protocol (ws or wss)\n const protocol =\n /^(localhost|127\\.0\\.0\\.1|192\\.168\\.|10\\.|172\\.(1[6-9]|2[0-9]|3[0-1])\\.)/.test(\n host\n )\n ? \"ws\"\n : \"wss\";\n\n // Construct base URL\n const baseUrl = `${protocol}://${host}/api/${actorType}/${actorId}`;\n\n // Add query parameters\n const params = new URLSearchParams({ accessToken });\n if (checksum) params.append(\"checksum\", checksum);\n\n const finalUrl = `${baseUrl}?${params.toString()}`;\n\n return finalUrl;\n}\n","\"use client\";\n\nimport React, {\n createContext,\n memo,\n ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport { matchesState, StateValueFrom } from \"xstate\";\nimport type { ActorKitClientProps } from \"./createActorKitClient\";\nimport { createActorKitClient } from \"./createActorKitClient\";\nimport type {\n ActorKitClient,\n AnyActorKitStateMachine,\n CallerSnapshotFrom,\n ClientEventFrom,\n MatchesProps,\n} from \"./types\";\n\nexport function createActorKitContext<TMachine extends AnyActorKitStateMachine>(\n actorType: string\n) {\n const ActorKitContext = createContext<ActorKitClient<TMachine> | null>(null);\n\n const ProviderFromClient: React.FC<{\n children: ReactNode;\n client: ActorKitClient<TMachine>;\n }> = ({ children, client }) => {\n return (\n <ActorKitContext.Provider value={client}>\n {children}\n </ActorKitContext.Provider>\n );\n };\n\n const Provider: React.FC<\n {\n children: ReactNode;\n } & Omit<ActorKitClientProps<TMachine>, \"actorType\">\n > = memo((props) => {\n const clientRef = useRef(\n createActorKitClient<TMachine>({\n host: props.host,\n actorId: props.actorId,\n accessToken: props.accessToken,\n checksum: props.checksum,\n initialSnapshot: props.initialSnapshot,\n actorType,\n })\n );\n const initializedRef = useRef(false);\n\n useEffect(() => {\n if (!initializedRef.current) {\n initializedRef.current = true;\n clientRef.current.connect().then(() => {});\n }\n }, [initializedRef]);\n\n return (\n <ActorKitContext.Provider value={clientRef.current}>\n {props.children}\n </ActorKitContext.Provider>\n );\n });\n\n function useClient(): ActorKitClient<TMachine> {\n const client = useContext(ActorKitContext);\n if (!client) {\n throw new Error(\n \"useClient must be used within an ActorKitContext.Provider\"\n );\n }\n return client;\n }\n\n const useSelector = <T,>(\n selector: (snapshot: CallerSnapshotFrom<TMachine>) => T\n ) => {\n const client = useClient();\n\n return useSyncExternalStoreWithSelector(\n client.subscribe,\n client.getState,\n client.getState,\n selector,\n defaultCompare\n );\n };\n\n function useSend(): (event: ClientEventFrom<TMachine>) => void {\n const client = useClient();\n return client.send;\n }\n\n function useMatches(stateValue: StateValueFrom<TMachine>): boolean {\n return useSelector((state) => matchesState(stateValue, state.value as any));\n }\n\n const Matches: React.FC<MatchesProps<TMachine> & { children: ReactNode }> & {\n create: (\n state: StateValueFrom<TMachine>,\n options?: {\n and?: StateValueFrom<TMachine>;\n or?: StateValueFrom<TMachine>;\n not?: boolean;\n }\n ) => React.FC<\n Omit<MatchesProps<TMachine>, \"state\" | \"and\" | \"or\" | \"not\"> & {\n children: ReactNode;\n }\n >;\n } = (props) => {\n const active = useMatches(props.state);\n const matchesAnd = props.and ? useMatches(props.and) : true;\n const matchesOr = props.or ? useMatches(props.or) : false;\n const value =\n typeof props.initialValueOverride === \"boolean\"\n ? props.initialValueOverride\n : (active && matchesAnd) || matchesOr;\n const finalValue = props.not ? !value : value;\n return finalValue ? <>{props.children}</> : null;\n };\n\n Matches.create = (state, options = {}) => {\n const Component: React.FC<\n Omit<MatchesProps<TMachine>, \"state\" | \"and\" | \"or\" | \"not\"> & {\n children: ReactNode;\n }\n > = ({ children, initialValueOverride }) => (\n <Matches\n state={state}\n and={options.and}\n or={options.or}\n not={options.not}\n initialValueOverride={initialValueOverride}\n >\n {children}\n </Matches>\n );\n Component.displayName = `MatchesComponent(${state.toString()})`;\n return Component;\n };\n\n return {\n Provider,\n ProviderFromClient,\n useClient,\n useSelector,\n useSend,\n useMatches,\n Matches,\n };\n}\n\nfunction useSyncExternalStoreWithSelector<Snapshot, Selection>(\n subscribe: (onStoreChange: () => void) => () => void,\n getSnapshot: () => Snapshot,\n getServerSnapshot: undefined | null | (() => Snapshot),\n selector: (snapshot: Snapshot) => Selection,\n isEqual?: (a: Selection, b: Selection) => boolean\n): Selection {\n const [getSelection, getServerSelection] = useMemo(() => {\n let hasMemo = false;\n let memoizedSnapshot: Snapshot;\n let memoizedSelection: Selection;\n\n const memoizedSelector = (nextSnapshot: Snapshot) => {\n if (!hasMemo) {\n hasMemo = true;\n memoizedSnapshot = nextSnapshot;\n memoizedSelection = selector(nextSnapshot);\n return memoizedSelection;\n }\n\n if (Object.is(memoizedSnapshot, nextSnapshot)) {\n return memoizedSelection;\n }\n\n const nextSelection = selector(nextSnapshot);\n\n if (isEqual && isEqual(memoizedSelection, nextSelection)) {\n memoizedSnapshot = nextSnapshot;\n return memoizedSelection;\n }\n\n memoizedSnapshot = nextSnapshot;\n memoizedSelection = nextSelection;\n return nextSelection;\n };\n\n const getSnapshotWithSelector = () => memoizedSelector(getSnapshot());\n const getServerSnapshotWithSelector = getServerSnapshot\n ? () => memoizedSelector(getServerSnapshot())\n : undefined;\n\n return [getSnapshotWithSelector, getServerSnapshotWithSelector];\n }, [getSnapshot, getServerSnapshot, selector, isEqual]);\n\n const subscribeWithSelector = useCallback(\n (onStoreChange: () => void) => {\n let previousSelection = getSelection();\n return subscribe(() => {\n const nextSelection = getSelection();\n if (!isEqual || !isEqual(previousSelection, nextSelection)) {\n previousSelection = nextSelection;\n onStoreChange();\n }\n });\n },\n [subscribe, getSelection, isEqual]\n );\n\n return useSyncExternalStore(\n subscribeWithSelector,\n getSelection,\n getServerSelection\n );\n}\n\nfunction defaultCompare<T>(a: T, b: T) {\n return a === b;\n}\n"],"names":["createActorKitClient","props","currentSnapshot","initialSnapshot","socket","listeners","Set","reconnectAttempts","connect","async","url","host","actorId","actorType","accessToken","checksum","baseUrl","test","params","URLSearchParams","append","toString","getWebSocketUrl","WebSocket","addEventListener","event","data","JSON","parse","TextDecoder","decode","produce","draft","applyPatch","operations","onStateChange","forEach","listener","error","console","onError","message","type","target","eventPhase","Error","stringify","delay","Math","min","pow","setTimeout","Promise","resolve","subscribe","add","delete","disconnect","close","send","readyState","OPEN","getState","waitFor","predicateFn","timeoutMs","reject","timeoutId","unsubscribe","state","clearTimeout","createActorKitContext","ActorKitContext","createContext","Provider","memo","clientRef","useRef","initializedRef","useEffect","current","then","React","createElement","value","children","useClient","client","useContext","useSelector","selector","getSnapshot","getServerSnapshot","isEqual","getSelection","getServerSelection","useMemo","memoizedSnapshot","memoizedSelection","hasMemo","memoizedSelector","nextSnapshot","Object","is","nextSelection","undefined","subscribeWithSelector","useCallback","onStoreChange","previousSelection","useSyncExternalStore","useSyncExternalStoreWithSelector","defaultCompare","useMatches","stateValue","matchesState","Matches","active","matchesAnd","and","matchesOr","or","initialValueOverride","not","Fragment","create","options","Component","displayName","ProviderFromClient","useSend","a","b"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { ActorKitStorage } from "./storage";
2
+ export type AlarmType = "xstate-delay" | "cache-cleanup" | "custom";
3
+ export interface Alarm {
4
+ id: string;
5
+ type: AlarmType;
6
+ scheduledAt: number;
7
+ repeatInterval?: number;
8
+ payload: Record<string, unknown>;
9
+ createdAt: number;
10
+ }
11
+ export interface ScheduleAlarmOptions {
12
+ id: string;
13
+ type: AlarmType;
14
+ scheduledAt: number;
15
+ repeatInterval?: number;
16
+ payload: Record<string, unknown>;
17
+ }
18
+ export interface AlarmHandleResult {
19
+ id: string;
20
+ type: AlarmType;
21
+ rescheduled?: boolean;
22
+ deleted: boolean;
23
+ }
24
+ export declare class AlarmManager {
25
+ private storage;
26
+ private state;
27
+ private currentAlarmId;
28
+ private currentAlarmTime;
29
+ constructor(storage: ActorKitStorage, state: DurableObjectState);
30
+ schedule(options: ScheduleAlarmOptions): Promise<void>;
31
+ cancel(id: string): Promise<void>;
32
+ cancelByType(type: AlarmType): Promise<void>;
33
+ getPendingAlarms(): Promise<Alarm[]>;
34
+ getDueAlarms(before?: number): Promise<Alarm[]>;
35
+ deleteAlarm(id: string): Promise<void>;
36
+ updateAlarm(options: ScheduleAlarmOptions): Promise<void>;
37
+ rescheduleNextAlarm(): Promise<void>;
38
+ handleDueAlarms(handler: (alarm: Alarm) => Promise<boolean>): Promise<AlarmHandleResult[]>;
39
+ getCurrentAlarm(): {
40
+ id: string | null;
41
+ time: number | null;
42
+ };
43
+ private parseAlarmRecord;
44
+ }
45
+ export declare function generateAlarmId(): string;
46
+ export declare function calculateNextRecurringAlarm(baseTime: number, interval: number, now?: number): number;
47
+ //# sourceMappingURL=alarms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alarms.d.ts","sourceRoot":"","sources":["../../src/alarms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,WAAW,CAAC;AAKnB,MAAM,MAAM,SAAS,GAAG,cAAc,GAAG,eAAe,GAAG,QAAQ,CAAC;AAKpE,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAKD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,gBAAgB,CAAuB;gBAEnC,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,kBAAkB;IAQzD,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjC,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5C,gBAAgB,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAQpC,YAAY,CAAC,MAAM,GAAE,MAAmB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAQ3D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtC,WAAW,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzD,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBpC,eAAe,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAkDhG,eAAe,IAAI;QAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;IAU7D,OAAO,CAAC,gBAAgB;CAUzB;AAKD,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAKD,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAmB,GACvB,MAAM,CAMR"}
@@ -0,0 +1,2 @@
1
+ export { createActorKitClient } from "./createActorKitClient";
2
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { CallerType } from "./types";
2
+ import type { AlarmType } from "./alarms";
3
+ export declare const HEADERS: {
4
+ X_CALLER_ID: string;
5
+ X_CALLER_TYPE: string;
6
+ X_ACTOR_ID: string;
7
+ X_ACTOR_TYPE: string;
8
+ };
9
+ export declare const CallerTypes: Record<CallerType, CallerType>;
10
+ export declare const AlarmTypes: Record<AlarmType, AlarmType>;
11
+ export declare const PERSISTED_SNAPSHOT_KEY = "persistedSnapshot";
12
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,eAAO,MAAM,OAAO;;;;;CAKnB,CAAC;AAOF,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,CAItD,CAAC;AAKF,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,CAInD,CAAC;AAEF,eAAO,MAAM,sBAAsB,sBAAsB,CAAC"}