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 6.26 kB
{"version":3,"file":"express.cjs","names":["frameworkName: SupportedFrameworkName","InngestCommHandler"],"sources":["../src/express.ts"],"sourcesContent":["/**\n * An adapter for Express to serve and register any declared functions with\n * Inngest, making them available to be triggered by events.\n *\n * @example\n * ```ts\n * import { serve } from \"inngest/express\";\n * import { inngest } from \"./src/inngest/client\";\n * import fnA from \"./src/inngest/fnA\"; // Your own function\n *\n * // Important: ensure you add JSON middleware to process incoming JSON POST payloads.\n * app.use(express.json());\n * app.use(\n * // Expose the middleware on our recommended path at `/api/inngest`.\n * \"/api/inngest\",\n * serve({ client: inngest, functions: [fnA] })\n * );\n * ```\n *\n * @module\n */\n\nimport type { VercelRequest, VercelResponse } from \"@vercel/node\";\nimport type { Request, Response } from \"express\";\nimport {\n InngestCommHandler,\n type ServeHandlerOptions,\n} from \"./components/InngestCommHandler.ts\";\nimport type { Either } from \"./helpers/types.ts\";\nimport type { SupportedFrameworkName } from \"./types.ts\";\n\n/**\n * The name of the framework, used to identify the framework in Inngest\n * dashboards and during testing.\n */\nexport const frameworkName: SupportedFrameworkName = \"express\";\n\n/**\n * Serve and register any declared functions with Inngest, making them available\n * to be triggered by events.\n *\n * The return type is currently `any` to ensure there's no required type matches\n * between the `express` and `vercel` packages. This may change in the future to\n * appropriately infer.\n *\n * @example\n * ```ts\n * import { serve } from \"inngest/express\";\n * import { inngest } from \"./src/inngest/client\";\n * import fnA from \"./src/inngest/fnA\"; // Your own function\n *\n * // Important: ensure you add JSON middleware to process incoming JSON POST payloads.\n * app.use(express.json());\n * app.use(\n * // Expose the middleware on our recommended path at `/api/inngest`.\n * \"/api/inngest\",\n * serve({ client: inngest, functions: [fnA] })\n * );\n * ```\n *\n * @public\n */\n// Has explicit return type to avoid JSR-defined \"slow types\"\n// biome-ignore lint/suspicious/noExplicitAny: intentional\nexport const serve = (options: ServeHandlerOptions): any => {\n const handler = new InngestCommHandler({\n frameworkName,\n ...options,\n handler: (\n req: Either<VercelRequest, Request>,\n res: Either<Response, VercelResponse>,\n ) => {\n return {\n body: () => req.body,\n headers: (key) => {\n const header = req.headers[key];\n return Array.isArray(header) ? header[0] : header;\n },\n method: () => req.method || \"GET\",\n url: () => {\n // `req.hostname` can filter out port numbers; beware!\n const hostname = req.headers[\"host\"] || options?.serveOrigin;\n\n const protocol = hostname?.includes(\"://\")\n ? \"\"\n : `${req.protocol || \"https\"}://`;\n\n const url = new URL(\n req.originalUrl || req.url || \"\",\n `${protocol}${hostname || \"\"}`,\n );\n\n return url;\n },\n queryString: (key) => {\n const qs = req.query[key];\n return Array.isArray(qs) ? qs[0] : qs;\n },\n transformResponse: ({ body, headers, status }) => {\n for (const [name, value] of Object.entries(headers)) {\n res.setHeader(name, value);\n }\n\n return res.status(status).send(body);\n },\n\n /**\n * Express doesn't support a Web API `ReadableStream` being written as\n * the response body (only `node:stream` `ReadableStream`s), so we\n * manually read the stream we're given and call `res.write()` for each\n * chunk.\n *\n * See {@link https://github.com/expressjs/discussions/issues/288}.\n *\n * Alternatively, we could pipe this through a transform and create a\n * Node stream, but the feels more dangerous than just writing directly\n * to the response.\n */\n transformStreamingResponse: async ({ body, headers, status }) => {\n for (const [name, value] of Object.entries(headers)) {\n res.setHeader(name, value);\n }\n\n res.status(status);\n\n const reader = body.getReader();\n try {\n // Keep writing from the stream until it's done\n let done = false;\n while (!done) {\n const result = await reader.read();\n done = result.done;\n if (!done) {\n res.write(result.value);\n }\n }\n res.end();\n } catch (error) {\n if (error instanceof Error) {\n res.destroy(error);\n } else {\n res.destroy(new Error(String(error)));\n }\n }\n },\n };\n },\n });\n\n return handler.createHandler();\n};\n"],"mappings":";;;;;;;AAmCA,MAAaA,gBAAwC;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BrD,MAAa,SAAS,YAAsC;AAqF1D,QApFgB,IAAIC,8CAAmB;EACrC;EACA,GAAG;EACH,UACE,KACA,QACG;AACH,UAAO;IACL,YAAY,IAAI;IAChB,UAAU,QAAQ;KAChB,MAAM,SAAS,IAAI,QAAQ;AAC3B,YAAO,MAAM,QAAQ,OAAO,GAAG,OAAO,KAAK;;IAE7C,cAAc,IAAI,UAAU;IAC5B,WAAW;KAET,MAAM,WAAW,IAAI,QAAQ,WAAW,SAAS;KAEjD,MAAM,WAAW,UAAU,SAAS,MAAM,GACtC,KACA,GAAG,IAAI,YAAY,QAAQ;AAO/B,YALY,IAAI,IACd,IAAI,eAAe,IAAI,OAAO,IAC9B,GAAG,WAAW,YAAY,KAC3B;;IAIH,cAAc,QAAQ;KACpB,MAAM,KAAK,IAAI,MAAM;AACrB,YAAO,MAAM,QAAQ,GAAG,GAAG,GAAG,KAAK;;IAErC,oBAAoB,EAAE,MAAM,SAAS,aAAa;AAChD,UAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,QAAQ,CACjD,KAAI,UAAU,MAAM,MAAM;AAG5B,YAAO,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK;;IAetC,4BAA4B,OAAO,EAAE,MAAM,SAAS,aAAa;AAC/D,UAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,QAAQ,CACjD,KAAI,UAAU,MAAM,MAAM;AAG5B,SAAI,OAAO,OAAO;KAElB,MAAM,SAAS,KAAK,WAAW;AAC/B,SAAI;MAEF,IAAI,OAAO;AACX,aAAO,CAAC,MAAM;OACZ,MAAM,SAAS,MAAM,OAAO,MAAM;AAClC,cAAO,OAAO;AACd,WAAI,CAAC,KACH,KAAI,MAAM,OAAO,MAAM;;AAG3B,UAAI,KAAK;cACF,OAAO;AACd,UAAI,iBAAiB,MACnB,KAAI,QAAQ,MAAM;UAElB,KAAI,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;;;IAI5C;;EAEJ,CAAC,CAEa,eAAe"}