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.

208 lines (206 loc) • 6.49 kB
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs'); const require_types = require('../../helpers/types.cjs'); const require_utils = require('../middleware/utils.cjs'); let zod_v3 = require("zod/v3"); //#region src/components/execution/streaming.ts const sseMetadataSchema = zod_v3.z.object({ type: zod_v3.z.literal("inngest.metadata"), runId: zod_v3.z.string() }); const sseStreamSchema = zod_v3.z.object({ type: zod_v3.z.literal("inngest.stream"), data: zod_v3.z.unknown(), hashedStepId: zod_v3.z.string().optional() }); const sseCommitSchema = zod_v3.z.object({ type: zod_v3.z.literal("inngest.commit"), hashedStepId: zod_v3.z.string().nullable() }); const sseRollbackSchema = zod_v3.z.object({ type: zod_v3.z.literal("inngest.rollback"), hashedStepId: zod_v3.z.string().nullable() }); const sseResultSchema = zod_v3.z.object({ type: zod_v3.z.literal("inngest.response"), status: zod_v3.z.union([zod_v3.z.literal("succeeded"), zod_v3.z.literal("failed")]), response: zod_v3.z.object({ body: zod_v3.z.string(), headers: zod_v3.z.record(zod_v3.z.string()), statusCode: zod_v3.z.number() }) }); const sseRedirectSchema = zod_v3.z.object({ type: zod_v3.z.literal("inngest.redirect_info"), runId: zod_v3.z.string(), url: zod_v3.z.string() }); /** * Builds a single SSE event with the given event name and JSON-serialized data. * * `undefined` is normalized to `null` so that the `data:` field is always valid * JSON (since `JSON.stringify(undefined)` returns the JS primitive `undefined`, * not the string `"null"`). */ function buildSseEvent(event, data) { return `event: ${event}\ndata: ${JSON.stringify(data ?? null)}\n\n`; } /** * Builds an SSE metadata event string for a streaming response. * * The event follows the Server-Sent Events format and provides run context * (run ID) to consumers of the stream. */ function buildSseMetadataEvent(runId) { return buildSseEvent("inngest.metadata", { runId }); } /** * Builds an SSE stream event string for user-pushed data. * * Used by `stream.push()` and `stream.pipe()` to send arbitrary data to * clients as part of a streaming response. */ function buildSseStreamEvent(data, hashedStepId) { const payload = { data }; if (hashedStepId) payload.hashedStepId = hashedStepId; return buildSseEvent("inngest.stream", payload); } /** * Builds an `inngest.response` SSE event with status `succeeded`. */ function buildSseSucceededEvent(response) { return buildSseEvent("inngest.response", { status: "succeeded", response }); } /** * Builds an `inngest.response` SSE event with status `failed`. */ function buildSseFailedEvent(error) { return buildSseEvent("inngest.response", { status: "failed", response: { body: JSON.stringify(error), statusCode: 500, headers: { "content-type": "application/json" } } }); } /** * Builds an SSE redirect event telling the client that execution has switched * to async mode and it should reconnect elsewhere to get remaining output. * * The `url` already contains the realtime JWT as a query parameter, so no * separate token field is needed. */ function buildSseRedirectEvent(data) { return buildSseEvent("inngest.redirect_info", data); } /** * Returns a new `ReadableStream` that emits `prefix` first, then pipes * through all chunks from the original `stream`. */ function prependToStream(prefix, stream) { return new ReadableStream({ async start(controller) { controller.enqueue(prefix); const reader = stream.getReader(); try { while (true) { const { done, value } = await reader.read(); if (done) break; controller.enqueue(value); } controller.close(); } catch (err) { controller.error(err); } finally { reader.releaseLock(); } } }); } /** * Builds an `inngest.commit` SSE event indicating a step's data is committed. */ function buildSseCommitEvent(hashedStepId) { return buildSseEvent("inngest.commit", { hashedStepId }); } /** * Builds an `inngest.rollback` SSE event indicating a step's data should be * rolled back (e.g. step errored and will retry, or disconnect mid-step). */ function buildSseRollbackEvent(hashedStepId) { return buildSseEvent("inngest.rollback", { hashedStepId }); } /** * Parses a `ReadableStream<Uint8Array>` as an SSE byte stream, yielding * `RawSseEvent` objects for each complete event. */ async function* iterSse(body) { const reader = body.getReader(); const decoder = new TextDecoder(); let buffer = ""; try { while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const parts = buffer.split("\n\n"); buffer = parts.pop() ?? ""; for (const part of parts) { if (!part.trim()) continue; let event = "message"; const dataLines = []; for (const line of part.split("\n")) if (line.startsWith("event: ")) event = line.slice(7); else if (line.startsWith("data: ")) dataLines.push(line.slice(6)); const data = dataLines.join("\n"); yield { event, data }; } } } finally { reader.releaseLock(); } } const sseSchemasByEvent = { "inngest.metadata": sseMetadataSchema, "inngest.stream": sseStreamSchema, "inngest.response": sseResultSchema, "inngest.commit": sseCommitSchema, "inngest.rollback": sseRollbackSchema, "inngest.redirect_info": sseRedirectSchema }; /** * Converts a `RawSseEvent` into a typed `SseEvent`, or returns `undefined` * if the event type is unrecognised or fails validation. */ function parseSseEvent(raw) { const schema = sseSchemasByEvent[raw.event]; if (!schema) return; let parsed; try { parsed = JSON.parse(raw.data); } catch { throw new require_utils.UnreachableError("SSE data is not a valid JSON string"); } if (!require_types.isRecord(parsed)) return; const result = schema.safeParse({ ...parsed, type: raw.event }); if (!result.success) throw new Error("Unknown SSE event", { cause: result.error }); return result.data; } //#endregion exports.buildSseCommitEvent = buildSseCommitEvent; exports.buildSseFailedEvent = buildSseFailedEvent; exports.buildSseMetadataEvent = buildSseMetadataEvent; exports.buildSseRedirectEvent = buildSseRedirectEvent; exports.buildSseRollbackEvent = buildSseRollbackEvent; exports.buildSseStreamEvent = buildSseStreamEvent; exports.buildSseSucceededEvent = buildSseSucceededEvent; exports.iterSse = iterSse; exports.parseSseEvent = parseSseEvent; exports.prependToStream = prependToStream; //# sourceMappingURL=streaming.cjs.map