UNPKG

actor-kit

Version:

Actor Kit is a library for running state machines in Cloudflare Workers, leveraging XState for robust state management. It provides a framework for managing the logic, lifecycle, persistence, synchronization, and access control of actors in a distributed

417 lines (411 loc) 12.4 kB
import React, { ReactNode } from 'react'; import { AnyStateMachine, SnapshotFrom, StateMachine, StateValueFrom, AnyEventObject } from 'xstate'; import { DurableObject } from 'cloudflare:workers'; import { z } from 'zod'; declare const RequestInfoSchema: z.ZodObject<{ longitude: z.ZodString; latitude: z.ZodString; continent: z.ZodString; country: z.ZodString; city: z.ZodString; timezone: z.ZodString; postalCode: z.ZodString; region: z.ZodString; regionCode: z.ZodString; metroCode: z.ZodString; botManagement: z.ZodObject<{ corporateProxy: z.ZodBoolean; verifiedBot: z.ZodBoolean; jsDetection: z.ZodObject<{ passed: z.ZodBoolean; }, "strip", z.ZodTypeAny, { passed: boolean; }, { passed: boolean; }>; staticResource: z.ZodBoolean; detectionIds: z.ZodRecord<z.ZodString, z.ZodAny>; score: z.ZodNumber; }, "strip", z.ZodTypeAny, { corporateProxy: boolean; verifiedBot: boolean; jsDetection: { passed: boolean; }; staticResource: boolean; detectionIds: Record<string, any>; score: number; }, { corporateProxy: boolean; verifiedBot: boolean; jsDetection: { passed: boolean; }; staticResource: boolean; detectionIds: Record<string, any>; score: number; }>; }, "strip", z.ZodTypeAny, { longitude: string; latitude: string; continent: string; country: string; city: string; timezone: string; postalCode: string; region: string; regionCode: string; metroCode: string; botManagement: { corporateProxy: boolean; verifiedBot: boolean; jsDetection: { passed: boolean; }; staticResource: boolean; detectionIds: Record<string, any>; score: number; }; }, { longitude: string; latitude: string; continent: string; country: string; city: string; timezone: string; postalCode: string; region: string; regionCode: string; metroCode: string; botManagement: { corporateProxy: boolean; verifiedBot: boolean; jsDetection: { passed: boolean; }; staticResource: boolean; detectionIds: Record<string, any>; score: number; }; }>; declare const CallerSchema: z.ZodObject<{ id: z.ZodString; type: z.ZodEnum<["client", "system", "service"]>; }, "strip", z.ZodTypeAny, { type: "client" | "system" | "service"; id: string; }, { type: "client" | "system" | "service"; id: string; }>; declare const SystemEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{ type: z.ZodLiteral<"INITIALIZE">; caller: z.ZodObject<{ type: z.ZodLiteral<"system">; id: z.ZodString; }, "strip", z.ZodTypeAny, { type: "system"; id: string; }, { type: "system"; id: string; }>; }, "strip", z.ZodTypeAny, { type: "INITIALIZE"; caller: { type: "system"; id: string; }; }, { type: "INITIALIZE"; caller: { type: "system"; id: string; }; }>, z.ZodObject<{ type: z.ZodLiteral<"CONNECT">; caller: z.ZodObject<{ type: z.ZodLiteral<"system">; id: z.ZodString; }, "strip", z.ZodTypeAny, { type: "system"; id: string; }, { type: "system"; id: string; }>; connectingCaller: z.ZodObject<{ id: z.ZodString; type: z.ZodEnum<["client", "system", "service"]>; }, "strip", z.ZodTypeAny, { type: "client" | "system" | "service"; id: string; }, { type: "client" | "system" | "service"; id: string; }>; }, "strip", z.ZodTypeAny, { type: "CONNECT"; caller: { type: "system"; id: string; }; connectingCaller: { type: "client" | "system" | "service"; id: string; }; }, { type: "CONNECT"; caller: { type: "system"; id: string; }; connectingCaller: { type: "client" | "system" | "service"; id: string; }; }>, z.ZodObject<{ type: z.ZodLiteral<"DISCONNECT">; caller: z.ZodObject<{ type: z.ZodLiteral<"system">; id: z.ZodString; }, "strip", z.ZodTypeAny, { type: "system"; id: string; }, { type: "system"; id: string; }>; disconnectingCaller: z.ZodObject<{ id: z.ZodString; type: z.ZodEnum<["client", "system", "service"]>; }, "strip", z.ZodTypeAny, { type: "client" | "system" | "service"; id: string; }, { type: "client" | "system" | "service"; id: string; }>; }, "strip", z.ZodTypeAny, { type: "DISCONNECT"; caller: { type: "system"; id: string; }; disconnectingCaller: { type: "client" | "system" | "service"; id: string; }; }, { type: "DISCONNECT"; caller: { type: "system"; id: string; }; disconnectingCaller: { type: "client" | "system" | "service"; id: string; }; }>, z.ZodObject<{ type: z.ZodLiteral<"RESUME">; caller: z.ZodObject<{ type: z.ZodLiteral<"system">; id: z.ZodString; }, "strip", z.ZodTypeAny, { type: "system"; id: string; }, { type: "system"; id: string; }>; }, "strip", z.ZodTypeAny, { type: "RESUME"; caller: { type: "system"; id: string; }; }, { type: "RESUME"; caller: { type: "system"; id: string; }; }>, z.ZodObject<{ type: z.ZodLiteral<"MIGRATE">; caller: z.ZodObject<{ type: z.ZodLiteral<"system">; id: z.ZodString; }, "strip", z.ZodTypeAny, { type: "system"; id: string; }, { type: "system"; id: string; }>; operations: z.ZodArray<z.ZodAny, "many">; }, "strip", z.ZodTypeAny, { type: "MIGRATE"; caller: { type: "system"; id: string; }; operations: any[]; }, { type: "MIGRATE"; caller: { type: "system"; id: string; }; operations: any[]; }>]>; type EnvWithDurableObjects = { ACTOR_KIT_SECRET: string; [key: string]: DurableObjectNamespace<ActorServer<any>> | unknown; }; interface ActorServerMethods<TMachine extends BaseActorKitStateMachine> { fetch(request: Request): Promise<Response>; spawn(props: { actorType: string; actorId: string; caller: Caller; input: Record<string, unknown>; }): void; send(event: ClientEventFrom<TMachine> | ServiceEventFrom<TMachine>): void; getSnapshot(caller: Caller, options?: { waitForEvent?: ClientEventFrom<TMachine>; waitForState?: StateValueFrom<TMachine>; timeout?: number; errorOnWaitTimeout?: boolean; }): Promise<{ checksum: string; snapshot: CallerSnapshotFrom<TMachine>; }>; } type ActorServer<TMachine extends AnyActorKitStateMachine> = DurableObject & ActorServerMethods<TMachine>; type Caller = z.infer<typeof CallerSchema>; type RequestInfo = z.infer<typeof RequestInfoSchema>; type CallerType = "client" | "system" | "service"; type EventObject = { type: string; }; type BaseActorKitContext<TPublicProps extends { [key: string]: unknown; }, TPrivateProps extends { [key: string]: unknown; }> = { public: TPublicProps; private: Record<string, TPrivateProps>; }; type ActorKitStateMachine<TEvent extends BaseActorKitEvent<EnvWithDurableObjects>, TInput extends { id: string; caller: Caller; storage: DurableObjectStorage; }, TContext extends BaseActorKitContext<any, any> & { [key: string]: unknown; }> = StateMachine<TContext, TEvent & EventObject, any, any, any, any, any, any, any, TInput, any, any, any, any>; type BaseActorKitInput<TEnv = EnvWithDurableObjects> = { id: string; caller: Caller; env: TEnv; storage: DurableObjectStorage; }; type WithActorKitInput<TInputProps extends { [key: string]: unknown; }, TEnv extends EnvWithDurableObjects> = TInputProps & BaseActorKitInput<TEnv>; type AnyActorKitStateMachine = ActorKitStateMachine<any, any, any>; type AnyActorKitEvent = (WithActorKitEvent<AnyEventObject, "client"> | WithActorKitEvent<AnyEventObject, "service"> | ActorKitSystemEvent) & BaseActorKitEvent<EnvWithDurableObjects>; type AnyActorKitInput = WithActorKitInput<{ [key: string]: unknown; }, EnvWithDurableObjects> & { storage: DurableObjectStorage; }; type AnyActorKitContext = { public: { [key: string]: unknown; }; private: Record<string, { [key: string]: unknown; }>; }; type BaseActorKitStateMachine = ActorKitStateMachine<AnyActorKitEvent, AnyActorKitInput, AnyActorKitContext>; interface BaseActorKitEvent<TEnv extends EnvWithDurableObjects> { caller: Caller; storage: DurableObjectStorage; requestInfo?: RequestInfo; env: TEnv; } type ActorKitSystemEvent = z.infer<typeof SystemEventSchema>; type WithActorKitEvent<T extends { type: string; }, C extends CallerType> = T & BaseActorKitEvent<EnvWithDurableObjects> & { caller: { type: C; }; }; type CallerSnapshotFrom<TMachine extends AnyStateMachine> = { public: SnapshotFrom<TMachine> extends { context: { public: infer P; }; } ? P : unknown; private: SnapshotFrom<TMachine> extends { context: { private: Partial<Record<string, infer PR>>; }; } ? PR : unknown; value: SnapshotFrom<TMachine> extends { value: infer V; } ? V : unknown; }; 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; 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; interface MatchesProps<TMachine extends AnyActorKitStateMachine> { state: StateValueFrom<TMachine>; and?: StateValueFrom<TMachine>; or?: StateValueFrom<TMachine>; not?: boolean; initialValueOverride?: boolean; } type ActorKitClient<TMachine extends AnyActorKitStateMachine> = { connect: () => Promise<void>; disconnect: () => void; send: (event: ClientEventFrom<TMachine>) => void; getState: () => CallerSnapshotFrom<TMachine>; subscribe: (listener: (state: CallerSnapshotFrom<TMachine>) => void) => () => void; waitFor: (predicateFn: (state: CallerSnapshotFrom<TMachine>) => boolean, timeoutMs?: number) => Promise<void>; }; type ActorKitClientProps<TMachine extends AnyActorKitStateMachine> = { host: string; actorType: string; actorId: string; checksum: string; accessToken: string; initialSnapshot: CallerSnapshotFrom<TMachine>; onStateChange?: (newState: CallerSnapshotFrom<TMachine>) => void; onError?: (error: Error) => void; }; declare function createActorKitContext<TMachine extends AnyActorKitStateMachine>(actorType: string): { Provider: React.FC<{ children: ReactNode; } & Omit<ActorKitClientProps<TMachine>, "actorType">>; ProviderFromClient: React.FC<{ children: ReactNode; client: ActorKitClient<TMachine>; }>; useClient: () => ActorKitClient<TMachine>; useSelector: <T>(selector: (snapshot: CallerSnapshotFrom<TMachine>) => T) => T; useSend: () => (event: ClientEventFrom<TMachine>) => void; useMatches: (stateValue: StateValueFrom<TMachine>) => boolean; Matches: React.FC<MatchesProps<TMachine> & { children: ReactNode; }> & { create: (state: StateValueFrom<TMachine>, options?: { and?: StateValueFrom<TMachine>; or?: StateValueFrom<TMachine>; not?: boolean; }) => React.FC<Omit<MatchesProps<TMachine>, "state" | "and" | "or" | "not"> & { children: ReactNode; }>; }; }; export { createActorKitContext };