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.

235 lines • 10.3 kB
"use strict"; /** * An adapter for Next.js to serve and register any declared functions with * Inngest, making them available to be triggered by events. * * Supports Next.js 12+, both serverless and edge. * * @example Next.js <=12 or the pages router can export the handler directly * ```ts * export default serve({ client: inngest, functions: [fn1, fn2] }); * ``` * * @example Next.js >=13 with the `app` dir must export individual methods * ```ts * export const { GET, POST, PUT } = serve({ * client: inngest, * functions: [fn1, fn2], * }); * ``` * * @module */ Object.defineProperty(exports, "__esModule", { value: true }); exports.serve = exports.frameworkName = void 0; const InngestCommHandler_js_1 = require("./components/InngestCommHandler.js"); const env_js_1 = require("./helpers/env.js"); /** * The name of the framework, used to identify the framework in Inngest * dashboards and during testing. */ exports.frameworkName = "nextjs"; const isRecord = (val) => { return typeof val === "object" && val !== null; }; const isFunction = (val) => { return typeof val === "function"; }; const isNext12ApiResponse = (val) => { return (isRecord(val) && isFunction(val.setHeader) && isFunction(val.status) && isFunction(val.send)); }; /** * In Next.js, serve and register any declared functions with Inngest, making * them available to be triggered by events. * * Supports Next.js 12+, both serverless and edge. * * @example Next.js <=12 or the pages router can export the handler directly * ```ts * export default serve({ client: inngest, functions: [fn1, fn2] }); * ``` * * @example Next.js >=13 with the `app` dir must export individual methods * ```ts * export const { GET, POST, PUT } = serve({ * client: inngest, * functions: [fn1, fn2], * }); * ``` * * @public */ // Has explicit return type to avoid JSR-defined "slow types" const serve = (options) => { const handler = new InngestCommHandler_js_1.InngestCommHandler(Object.assign(Object.assign({ frameworkName: exports.frameworkName }, options), { handler: (reqMethod, ...args) => { const [expectedReq, res] = args; const req = expectedReq; const getHeader = (key) => { const header = typeof req.headers.get === "function" ? req.headers.get(key) : req.headers[key]; return Array.isArray(header) ? header[0] : header; }; return { // eslint-disable-next-line @typescript-eslint/no-unsafe-return body: () => (typeof req.json === "function" ? req.json() : req.body), headers: getHeader, method: () => { /** * `req.method`, though types say otherwise, is not available in Next.js * 13 {@link https://beta.nextjs.org/docs/routing/route-handlers Route Handlers}. * * Therefore, we must try to set the method ourselves where we know it. */ const method = reqMethod || req.method || ""; return method; }, isProduction: () => { /** * Vercel Edge Functions do not allow dynamic access to environment * variables, so we'll manage production checks directly here. * * We try/catch to avoid situations where Next.js is being used in * environments where `process.env` is not accessible or polyfilled. */ try { // eslint-disable-next-line @inngest/internal/process-warn const isProd = process.env.NODE_ENV === "production"; return isProd; } catch (err) { // no-op } }, queryString: (key, url) => { var _a; const qs = ((_a = req.query) === null || _a === void 0 ? void 0 : _a[key]) || url.searchParams.get(key); return Array.isArray(qs) ? qs[0] : qs; }, url: () => { let absoluteUrl; try { absoluteUrl = new URL(req.url); } catch (_a) { // no-op } if (absoluteUrl) { /** * `req.url` here should may be the full URL, including query string. * There are some caveats, however, where Next.js will obfuscate * the host. For example, in the case of `host.docker.internal`, * Next.js will instead set the host here to `localhost`. * * To avoid this, we'll try to parse the URL from `req.url`, but * also use the `host` header if it's available. */ const host = options.serveHost || getHeader("host"); if (host) { const hostWithProtocol = new URL(host.includes("://") ? host : `${absoluteUrl.protocol}//${host}`); absoluteUrl.protocol = hostWithProtocol.protocol; absoluteUrl.host = hostWithProtocol.host; absoluteUrl.port = hostWithProtocol.port; absoluteUrl.username = hostWithProtocol.username; absoluteUrl.password = hostWithProtocol.password; } return absoluteUrl; } let scheme = "https"; const host = options.serveHost || getHeader("host") || ""; try { // eslint-disable-next-line @inngest/internal/process-warn if (process.env.NODE_ENV === "development") { scheme = "http"; } } catch (err) { // no-op } const url = new URL(req.url, `${scheme}://${host}`); return url; }, transformResponse: ({ body, headers, status }) => { /** * Carefully attempt to set headers and data on the response object * for Next.js 12 support. * * This also assumes that we're not using Next.js 15, where the `res` * object is repopulated as a `RouteContext` object. We expect these * methods to NOT be defined in Next.js 15. * * We could likely use `instanceof ServerResponse` to better check the * type of this, though Next.js 12 had issues with this due to not * instantiating the response correctly. */ if (isNext12ApiResponse(res)) { for (const [key, value] of Object.entries(headers)) { res.setHeader(key, value); } res.status(status); res.send(body); /** * If we're here, we're in a serverless endpoint (not edge), so * we've correctly sent the response and can return `undefined`. * * Next.js 13 edge requires that the return value is typed as * `Response`, so we still enforce that as we cannot dynamically * adjust typing based on the environment. */ return undefined; } /** * If we're here, we're in an edge environment and need to return a * `Response` object. * * We also don't know if the current environment has a native * `Response` object, so we'll grab that first. */ const Res = (0, env_js_1.getResponse)(); return new Res(body, { status, headers }); }, transformStreamingResponse: ({ body, headers, status }) => { return new Response(body, { status, headers }); }, }; } })); /** * Next.js 13 uses * {@link https://beta.nextjs.org/docs/routing/route-handlers Route Handlers} * to declare API routes instead of a generic catch-all method that was * available using the `pages/api` directory. * * This means that users must now export a function for each method supported * by the endpoint. For us, this means requiring a user explicitly exports * `GET`, `POST`, and `PUT` functions. * * Because of this, we'll add circular references to those property names of * the returned handler, meaning we can write some succinct code to export * them. Thanks, @goodoldneon. * * @example * ```ts * export const { GET, POST, PUT } = serve(...); * ``` * * See {@link https://beta.nextjs.org/docs/routing/route-handlers} */ const baseFn = handler.createHandler(); const fn = baseFn.bind(null, undefined); /** * Ensure we have a non-variadic length to avoid issues with forced type * checking. */ Object.defineProperty(fn, "length", { value: 1 }); const handlerFn = Object.defineProperties(fn, { GET: { value: baseFn.bind(null, "GET") }, POST: { value: baseFn.bind(null, "POST") }, PUT: { value: baseFn.bind(null, "PUT") }, }); return handlerFn; }; exports.serve = serve; //# sourceMappingURL=next.js.map