UNPKG

inngest

Version:

Official SDK for Inngest.com. Inngest is the reliability layer for modern applications. Inngest combines durable execution, events, and queues into a zero-infra platform with built-in observability.

1 lines 24.8 kB
{"version":3,"file":"react.cjs","names":["interval: ReturnType<typeof setInterval> | null","realtimeSubscribe"],"sources":["../src/react.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { Inngest } from \"./components/Inngest.ts\";\nimport {\n getClientSubscriptionToken,\n subscribe as realtimeSubscribe,\n} from \"./components/realtime/subscribe/index.ts\";\nimport type { Realtime } from \"./components/realtime/types.ts\";\n\nexport type UseRealtimeConnectionStatus =\n | \"idle\"\n | \"connecting\"\n | \"open\"\n | \"paused\"\n | \"closed\"\n | \"error\";\n\nexport type UseRealtimeRunStatus =\n | \"unknown\"\n | \"running\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\nexport type ClientSubscriptionToken = Realtime.Subscribe.ClientToken;\n\ntype TokenFactory = () => Promise<\n string | ClientSubscriptionToken | Realtime.Subscribe.Token\n>;\ntype UseRealtimePauseReason = \"hidden\" | \"disabled\" | null;\n\n//\n// Extract the topic configs map from a channel input. Returns the full\n// TopicsConfig when the channel is a typed ChannelInstance, otherwise\n// falls back to a broad Record<string, TopicConfig> so data is untyped.\ntype InferTopicConfigs<TChannel extends Realtime.ChannelInput> =\n TChannel extends Realtime.ChannelInstance<string, infer TTopicConfigs>\n ? TTopicConfigs\n : Record<string, Realtime.TopicConfig>;\n\n//\n// Produce the per-topic typed message for a single topic key. When the\n// channel is a typed ChannelInstance and the key matches a known topic,\n// the `data` field is typed to that topic's schema. Otherwise falls\n// back to untyped Realtime.Message.\ntype TopicLatestMessage<\n TChannel extends Realtime.ChannelInput,\n TKey extends string,\n TConfigs = InferTopicConfigs<TChannel>,\n> = TKey extends keyof TConfigs\n ? Extract<\n Realtime.Message<string, Pick<TConfigs, TKey & keyof TConfigs>>,\n { topic: TKey }\n >\n : Realtime.Message;\n\n//\n// Map of topic name → last message with per-topic typed data.\n// Falls back to bare Realtime.Message when the channel is a plain string.\ntype MessagesByTopicMap<\n TChannel extends Realtime.ChannelInput,\n TTopics extends readonly string[] | undefined,\n> = TTopics extends readonly (infer K extends string)[]\n ? { [P in K]?: TopicLatestMessage<TChannel, P> }\n : Record<string, Realtime.Message | undefined>;\n\n//\n// Discriminated union of all messages across subscribed topics. Used for\n// message collections where the user narrows by\n// `msg.topic` to get per-topic typing.\ntype SubscribedMessage<\n TChannel extends Realtime.ChannelInput,\n TTopics extends readonly string[] | undefined,\n> = TTopics extends readonly (infer K extends string)[]\n ? Realtime.Message<\n string,\n Pick<InferTopicConfigs<TChannel>, K & keyof InferTopicConfigs<TChannel>>\n >\n : Realtime.Message;\n\nexport interface UseRealtimeResult<\n TChannel extends Realtime.ChannelInput = Realtime.ChannelInput,\n TTopics extends readonly string[] | undefined = readonly string[] | undefined,\n> {\n connectionStatus: UseRealtimeConnectionStatus;\n runStatus: UseRealtimeRunStatus;\n isPaused: boolean;\n pauseReason: UseRealtimePauseReason;\n\n messages: {\n byTopic: MessagesByTopicMap<TChannel, TTopics>;\n all: SubscribedMessage<TChannel, TTopics>[];\n last: SubscribedMessage<TChannel, TTopics> | null;\n delta: SubscribedMessage<TChannel, TTopics>[];\n };\n\n result: unknown;\n error: Error | null;\n reset: () => void;\n}\n\nexport interface UseRealtimeOptions<\n TChannel extends Realtime.ChannelInput = Realtime.ChannelInput,\n TTopics extends readonly string[] | undefined = readonly string[] | undefined,\n> {\n //\n // Spec-style inputs. If `token` is a function and returns a string, both\n // `channel` and `topics` are required so the hook can construct a token object.\n channel?: TChannel;\n topics?: TTopics;\n\n //\n // Either a pre-minted subscription token or a token factory that returns\n // a token key string, a client token from\n // `getClientSubscriptionToken()`, or a full token object.\n token?: Realtime.Subscribe.Token | TokenFactory;\n\n key?: string;\n enabled?: boolean;\n bufferInterval?: number;\n\n //\n // Validation is enabled by default. Set to false to skip subscriber-side\n // schema validation for performance-sensitive use cases.\n validate?: boolean;\n\n //\n // Bound the number of messages retained in `messages.all`.\n // Set to `null` to disable the cap.\n historyLimit?: number | null;\n\n //\n // Override the base URL used for the realtime WebSocket connection.\n // Normally this is resolved automatically via getClientSubscriptionToken.\n apiBaseUrl?: string;\n\n reconnect?: boolean;\n reconnectMinMs?: number;\n reconnectMaxMs?: number;\n pauseOnHidden?: boolean;\n autoCloseOnTerminal?: boolean;\n}\n\ntype RunLifecycleUpdate = {\n runStatus?: UseRealtimeRunStatus;\n result?: unknown;\n};\n\nconst terminalRunStatuses = new Set<UseRealtimeRunStatus>([\n \"completed\",\n \"failed\",\n \"cancelled\",\n]);\n\nconst clampMessages = (\n prev: Realtime.Message[],\n next: Realtime.Message[],\n limit: number | null,\n) => {\n const merged = [...prev, ...next];\n if (limit === null) {\n return merged;\n }\n\n if (limit <= 0) {\n return [];\n }\n\n return merged.length > limit ? merged.slice(-limit) : merged;\n};\n\nconst getReconnectDelay = (attempt: number, minMs: number, maxMs: number) => {\n const jitter = Math.floor(Math.random() * minMs);\n return Math.min(maxMs, minMs * 2 ** attempt + jitter);\n};\n\nconst toError = (err: unknown) => {\n return err instanceof Error ? err : new Error(String(err));\n};\n\nconst isSubscriptionToken = (\n value: ClientSubscriptionToken | Realtime.Subscribe.Token,\n): value is Realtime.Subscribe.Token => {\n return \"channel\" in value && \"topics\" in value;\n};\n\nconst normalizeRunStatus = (\n value: unknown,\n): UseRealtimeRunStatus | undefined => {\n if (typeof value !== \"string\") {\n return;\n }\n\n switch (value.toLowerCase()) {\n case \"running\":\n case \"in_progress\":\n return \"running\";\n case \"completed\":\n case \"complete\":\n case \"succeeded\":\n case \"success\":\n return \"completed\";\n case \"failed\":\n case \"error\":\n return \"failed\";\n case \"cancelled\":\n case \"canceled\":\n return \"cancelled\";\n default:\n return;\n }\n};\n\nconst inferRunLifecycleUpdate = (\n message: Realtime.Message,\n): RunLifecycleUpdate => {\n if (message.kind !== \"run\") {\n return {};\n }\n\n const data = message.data;\n if (!data || typeof data !== \"object\") {\n return {};\n }\n\n const obj = data as Record<string, unknown>;\n const runStatus =\n normalizeRunStatus(obj.runStatus) ||\n normalizeRunStatus(obj.status) ||\n normalizeRunStatus(obj.state);\n\n if (\"result\" in obj) {\n return {\n runStatus,\n result: obj.result,\n };\n }\n\n if (runStatus === \"completed\" && \"output\" in obj) {\n return {\n runStatus,\n result: obj.output,\n };\n }\n\n return { runStatus };\n};\n\nconst hasDocument = () => typeof document !== \"undefined\";\n\nconst isDocumentVisible = () => {\n if (!hasDocument()) {\n return true;\n }\n\n return document.visibilityState !== \"hidden\";\n};\n\nconst sleep = (ms: number) =>\n new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n\nexport const useRealtime = <\n TChannel extends Realtime.ChannelInput = Realtime.ChannelInput,\n TTopics extends readonly string[] | undefined = readonly string[] | undefined,\n>({\n channel,\n topics,\n token: tokenInput,\n key,\n enabled = true,\n bufferInterval = 0,\n validate = true,\n apiBaseUrl,\n historyLimit = 100,\n reconnect = true,\n reconnectMinMs = 250,\n reconnectMaxMs = 5_000,\n pauseOnHidden = true,\n autoCloseOnTerminal = true,\n}: UseRealtimeOptions<TChannel, TTopics>): UseRealtimeResult<\n TChannel,\n TTopics\n> => {\n const channelKey =\n typeof channel === \"string\" ? channel : (channel?.name ?? undefined);\n const topicsKey = topics ? JSON.stringify([...topics]) : \"\";\n const [allMessages, setAllMessages] = useState<Realtime.Message[]>([]);\n const [messageDelta, setMessageDelta] = useState<Realtime.Message[]>([]);\n const [messagesByTopic, setMessagesByTopic] = useState<\n Record<string, Realtime.Message | undefined>\n >({});\n const [lastMessage, setLastMessage] = useState<Realtime.Message | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [connectionStatus, setConnectionStatus] =\n useState<UseRealtimeConnectionStatus>(\"idle\");\n const [pauseReason, setPauseReason] = useState<UseRealtimePauseReason>(null);\n const [runStatus, setRunStatus] = useState<UseRealtimeRunStatus>(\"unknown\");\n const [result, setResult] = useState<unknown>(undefined);\n const [isVisible, setIsVisible] = useState(() => isDocumentVisible());\n\n const subscriptionRef = useRef<Realtime.Subscribe.StreamSubscription | null>(\n null,\n );\n const readerRef =\n useRef<ReadableStreamDefaultReader<Realtime.Message> | null>(null);\n const messageBufferRef = useRef<Realtime.Message[]>([]);\n const bufferIntervalRef = useRef(bufferInterval);\n const messageLimitRef = useRef(historyLimit);\n const runStatusRef = useRef(runStatus);\n\n useEffect(() => {\n runStatusRef.current = runStatus;\n }, [runStatus]);\n\n useEffect(() => {\n bufferIntervalRef.current = bufferInterval;\n }, [bufferInterval]);\n\n useEffect(() => {\n messageLimitRef.current = historyLimit;\n }, [historyLimit]);\n\n useEffect(() => {\n messageBufferRef.current = [];\n setAllMessages([]);\n setMessageDelta([]);\n setMessagesByTopic({});\n setLastMessage(null);\n setResult(undefined);\n setError(null);\n runStatusRef.current = \"unknown\";\n setRunStatus(\"unknown\");\n }, [channelKey, topicsKey, key]);\n\n useEffect(() => {\n if (!pauseOnHidden || !hasDocument()) {\n return;\n }\n\n const onVisibilityChange = () => {\n setIsVisible(isDocumentVisible());\n };\n\n document.addEventListener(\"visibilitychange\", onVisibilityChange);\n return () => {\n document.removeEventListener(\"visibilitychange\", onVisibilityChange);\n };\n }, [pauseOnHidden]);\n\n const reset = () => {\n messageBufferRef.current = [];\n setAllMessages([]);\n setMessageDelta([]);\n setMessagesByTopic({});\n setLastMessage(null);\n setResult(undefined);\n setError(null);\n runStatusRef.current = \"unknown\";\n setRunStatus(\"unknown\");\n };\n\n const flushBufferedMessages = () => {\n if (messageBufferRef.current.length === 0) {\n return;\n }\n\n const buffered = [...messageBufferRef.current];\n messageBufferRef.current = [];\n setMessageDelta(buffered);\n setAllMessages((prev) =>\n clampMessages(prev, buffered, messageLimitRef.current),\n );\n setLastMessage(buffered[buffered.length - 1] ?? null);\n };\n\n useEffect(() => {\n let interval: ReturnType<typeof setInterval> | null = null;\n\n if (bufferInterval <= 0) {\n flushBufferedMessages();\n } else {\n interval = setInterval(() => {\n flushBufferedMessages();\n }, bufferInterval);\n }\n\n return () => {\n if (interval) {\n clearInterval(interval);\n }\n };\n }, [bufferInterval]);\n\n useEffect(() => {\n const shouldRun = enabled && (!pauseOnHidden || isVisible);\n if (!shouldRun) {\n const nextPauseReason = !enabled\n ? \"disabled\"\n : pauseOnHidden && !isVisible\n ? \"hidden\"\n : null;\n\n if (nextPauseReason) {\n setPauseReason(nextPauseReason);\n setConnectionStatus(\"paused\");\n } else {\n setPauseReason(null);\n setConnectionStatus(\"idle\");\n }\n return;\n }\n\n setPauseReason(null);\n\n let cancelled = false;\n\n const cleanupConnection = async (reason = \"useRealtime cleanup\") => {\n flushBufferedMessages();\n\n const reader = readerRef.current;\n const sub = subscriptionRef.current;\n\n readerRef.current = null;\n subscriptionRef.current = null;\n\n try {\n await reader?.cancel();\n } catch {\n // no-op\n }\n\n try {\n reader?.releaseLock();\n } catch {\n // no-op\n }\n\n try {\n sub?.unsubscribe(reason);\n } catch {\n // no-op\n }\n };\n\n const resolveToken = async (): Promise<Realtime.Subscribe.Token> => {\n if (tokenInput && typeof tokenInput !== \"function\") {\n return tokenInput;\n }\n\n if (typeof tokenInput === \"function\") {\n const next = await tokenInput();\n if (typeof next === \"string\") {\n if (!channel || !topics) {\n throw new Error(\n \"useRealtime token() returned a string but channel/topics were not provided\",\n );\n }\n\n return {\n channel: channel as Realtime.ChannelInput,\n topics: topics as string[],\n key: next,\n } as Realtime.Subscribe.Token;\n }\n\n //\n // Token factory returned an object. If it has channel/topics, it's\n // a full token; otherwise it's a { key, apiBaseUrl? } shorthand\n // from a server function.\n if (isSubscriptionToken(next)) {\n return next as Realtime.Subscribe.Token;\n }\n\n if (!channel || !topics) {\n throw new Error(\n \"useRealtime token() returned a key object but channel/topics were not provided\",\n );\n }\n\n return {\n channel: channel as Realtime.ChannelInput,\n topics: topics as string[],\n key: next.key,\n apiBaseUrl: next.apiBaseUrl,\n } as Realtime.Subscribe.Token;\n }\n\n throw new Error(\"No token provided and no token() handler.\");\n };\n\n const applyMessage = (message: Realtime.Message) => {\n if (message.kind === \"run\") {\n const lifecycle = inferRunLifecycleUpdate(message);\n\n if (lifecycle.runStatus) {\n runStatusRef.current = lifecycle.runStatus;\n setRunStatus(lifecycle.runStatus);\n }\n if (\"result\" in lifecycle) {\n setResult(lifecycle.result);\n }\n return;\n }\n\n if (runStatusRef.current === \"unknown\") {\n runStatusRef.current = \"running\";\n setRunStatus(\"running\");\n }\n\n if (message.topic) {\n setMessagesByTopic((prev) => ({\n ...prev,\n [message.topic as string]: message,\n }));\n }\n\n if (bufferIntervalRef.current === 0) {\n setMessageDelta([message]);\n setAllMessages((prev) =>\n clampMessages(prev, [message], messageLimitRef.current),\n );\n setLastMessage(message);\n return;\n }\n\n messageBufferRef.current.push(message);\n };\n\n const run = async () => {\n let reconnectAttempt = 0;\n\n while (!cancelled) {\n try {\n setError(null);\n setConnectionStatus(\"connecting\");\n\n const token = await resolveToken();\n if (cancelled) {\n break;\n }\n\n const stream = (await realtimeSubscribe({\n ...token,\n validate,\n apiBaseUrl: apiBaseUrl ?? token.apiBaseUrl,\n })) as Realtime.Subscribe.StreamSubscription;\n\n if (cancelled) {\n stream.unsubscribe(\"useRealtime cancelled before start\");\n break;\n }\n\n reconnectAttempt = 0;\n subscriptionRef.current = stream;\n setConnectionStatus(\"open\");\n\n if (runStatusRef.current === \"unknown\") {\n runStatusRef.current = \"running\";\n setRunStatus(\"running\");\n }\n\n const reader = stream.getReader();\n readerRef.current = reader;\n\n try {\n while (!cancelled) {\n const { done, value } = await reader.read();\n if (done || cancelled) {\n break;\n }\n\n applyMessage(value);\n\n if (\n autoCloseOnTerminal &&\n terminalRunStatuses.has(runStatusRef.current)\n ) {\n stream.unsubscribe(\"Run reached terminal status\");\n break;\n }\n }\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // no-op\n }\n if (readerRef.current === reader) {\n readerRef.current = null;\n }\n }\n\n if (cancelled) {\n break;\n }\n\n setConnectionStatus(\"closed\");\n\n if (\n autoCloseOnTerminal &&\n terminalRunStatuses.has(runStatusRef.current)\n ) {\n break;\n }\n\n if (!reconnect) {\n break;\n }\n } catch (err) {\n if (cancelled) {\n break;\n }\n\n setError(toError(err));\n setConnectionStatus(\"error\");\n\n if (!reconnect) {\n break;\n }\n } finally {\n await cleanupConnection(\"reconnect cycle cleanup\");\n }\n\n if (cancelled || !reconnect) {\n break;\n }\n\n const delay = getReconnectDelay(\n reconnectAttempt++,\n reconnectMinMs,\n reconnectMaxMs,\n );\n await sleep(delay);\n }\n };\n\n void run().catch((err) => {\n if (!cancelled) {\n setError(toError(err));\n setConnectionStatus(\"error\");\n }\n });\n\n return () => {\n cancelled = true;\n void cleanupConnection(\"useRealtime unmount\");\n setConnectionStatus((prev) => (prev === \"open\" ? \"closed\" : prev));\n };\n }, [\n apiBaseUrl,\n autoCloseOnTerminal,\n channelKey,\n enabled,\n isVisible,\n key,\n pauseOnHidden,\n reconnect,\n reconnectMaxMs,\n reconnectMinMs,\n tokenInput,\n topicsKey,\n validate,\n ]);\n const isPaused = connectionStatus === \"paused\";\n\n return {\n connectionStatus,\n runStatus,\n isPaused,\n pauseReason,\n\n messages: {\n byTopic: messagesByTopic as MessagesByTopicMap<TChannel, TTopics>,\n all: allMessages,\n last: lastMessage,\n delta: messageDelta,\n },\n\n result,\n error,\n reset,\n } as UseRealtimeResult<TChannel, TTopics>;\n};\n\nexport { getClientSubscriptionToken };\nexport type { Inngest };\n"],"mappings":"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"}