{"version":3,"file":"plugins-B2SMtsK6.cjs","names":["requestHeaders: FastifyRequest[\"headers\"]","request: FastifyRequest<RouteGenericInterface, Server>","url","reply: FastifyReply<RouteGenericInterface, Server>","createReadableStreamFromReadable:\n    | typeof RemixCreateReadableStreamFromReadable\n    | typeof RRCreateReadableStreamFromReadable","controller: AbortController | null","init: RequestInit","nodeResponse: Response","response: Response","Readable","fastify: FastifyInstance","virtualModule:\n    | \"virtual:remix/server-build\"\n    | \"virtual:react-router/server-build\"","createRequestHandler:\n    | RemixCreateRequestHandlerFunction\n    | RRCreateRequestHandlerFunction","vite: ViteDevServer | undefined","fastifyStatic"],"sources":["../src/shared.ts","../src/plugins/index.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type * as http2 from \"node:http2\";\nimport type * as https from \"node:https\";\nimport { Readable } from \"node:stream\";\n\nimport type { createReadableStreamFromReadable as RRCreateReadableStreamFromReadable } from \"@react-router/node\";\nimport type { createReadableStreamFromReadable as RemixCreateReadableStreamFromReadable } from \"@remix-run/node\";\nimport type {\n  FastifyReply,\n  FastifyRequest,\n  RawReplyDefaultExpression,\n  RawRequestDefaultExpression,\n  RouteGenericInterface,\n} from \"fastify\";\n\nexport type HttpServer =\n  | http.Server\n  | https.Server\n  | http2.Http2Server\n  | http2.Http2SecureServer;\n\nexport type HttpRequest = RawRequestDefaultExpression<HttpServer>;\nexport type HttpResponse = RawReplyDefaultExpression<HttpServer>;\n\nexport type RequestHandler<Server extends HttpServer> = (\n  request: FastifyRequest<RouteGenericInterface, Server>,\n  reply: FastifyReply<RouteGenericInterface, Server>,\n) => Promise<void>;\n\n/**\n * A function that returns the value to use as `context` in route `loader` and\n * `action` functions.\n *\n * You can think of this as an escape hatch that allows you to pass\n * environment/platform-specific values through to your loader/action.\n */\nexport type GetLoadContextFunction<\n  Server extends HttpServer,\n  AppLoadContext,\n> = (\n  request: FastifyRequest<RouteGenericInterface, Server>,\n  reply: FastifyReply<RouteGenericInterface, Server>,\n) => Promise<AppLoadContext> | AppLoadContext;\n\nexport function createHeaders(\n  requestHeaders: FastifyRequest[\"headers\"],\n): Headers {\n  let headers = new Headers();\n\n  for (let [key, values] of Object.entries(requestHeaders)) {\n    if (values) {\n      if (Array.isArray(values)) {\n        for (let value of values) {\n          headers.append(key, value);\n        }\n      } else {\n        headers.set(key, values);\n      }\n    }\n  }\n\n  return headers;\n}\n\nexport function getUrl<Server extends HttpServer>(\n  request: FastifyRequest<RouteGenericInterface, Server>,\n): string {\n  let origin = `${request.protocol}://${request.host}`;\n  // Use `request.originalUrl` so Remix and React Router are aware of the full path\n  let url = `${origin}${request.originalUrl}`;\n  return url;\n}\n\nexport function createRequest<Server extends HttpServer>(\n  request: FastifyRequest<RouteGenericInterface, Server>,\n  reply: FastifyReply<RouteGenericInterface, Server>,\n  createReadableStreamFromReadable:\n    | typeof RemixCreateReadableStreamFromReadable\n    | typeof RRCreateReadableStreamFromReadable,\n): Request {\n  let url = getUrl(request);\n\n  let controller: AbortController | null = new AbortController();\n\n  let init: RequestInit = {\n    method: request.method,\n    headers: createHeaders(request.headers),\n    signal: controller.signal,\n  };\n\n  // Abort action/loaders once we can no longer write a response if we have\n  // not yet sent a response (i.e., `close` without `finish`)\n  // `finish` -> done rendering the response\n  // `close` -> response can no longer be written to\n  reply.raw.on(\"finish\", () => (controller = null));\n  reply.raw.on(\"close\", () => controller?.abort());\n\n  if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n    init.body = createReadableStreamFromReadable(request.raw);\n    init.duplex = \"half\";\n  }\n\n  return new Request(url, init);\n}\n\nexport async function sendResponse<Server extends HttpServer>(\n  reply: FastifyReply<RouteGenericInterface, Server>,\n  nodeResponse: Response,\n): Promise<void> {\n  reply.status(nodeResponse.status);\n\n  for (let [key, values] of nodeResponse.headers.entries()) {\n    reply.headers({ [key]: values });\n  }\n\n  if (nodeResponse.body) {\n    let stream = responseToReadable(nodeResponse);\n    return reply.send(stream);\n  }\n\n  return reply.send(await nodeResponse.text());\n}\n\nfunction responseToReadable(response: Response): Readable | null {\n  if (!response.body) return null;\n\n  let reader = response.body.getReader();\n  let readable = new Readable();\n  readable._read = async () => {\n    try {\n      let result = await reader.read();\n      if (!result.done) {\n        readable.push(Buffer.from(result.value));\n      } else {\n        readable.push(null);\n      }\n    } catch (error) {\n      readable.destroy(error as Error);\n      throw error;\n    }\n  };\n\n  return readable;\n}\n","import path from \"node:path\";\nimport url from \"node:url\";\n\nimport type { FastifyStaticOptions } from \"@fastify/static\";\nimport fastifyStatic from \"@fastify/static\";\nimport type { FastifyInstance, RouteShorthandOptions } from \"fastify\";\nimport { cacheHeader } from \"pretty-cache-header\";\nimport type { InlineConfig, ViteDevServer } from \"vite\";\n\nimport type { CreateRequestHandlerFunction as RRCreateRequestHandlerFunction } from \"../servers/react-router\";\nimport type { CreateRequestHandlerFunction as RemixCreateRequestHandlerFunction } from \"../servers/remix\";\nimport type { GetLoadContextFunction, HttpServer } from \"../shared\";\n\nexport type PluginOptions<\n  Server extends HttpServer = HttpServer,\n  AppLoadContext = unknown,\n  ServerBuild = unknown,\n> = {\n  /**\n   * The base path for the Remix app.\n   * match the `basename` in your Vite config.\n   * @default \"/\"\n   */\n  basename?: string;\n  /**\n   * The directory where the Remix app is built.\n   * This should match the `buildDirectory` directory in your Remix config.\n   * @default \"build\"\n   */\n  buildDirectory?: string;\n  /**\n   * The Remix server output filename\n   * This should match the `serverBuildFile` filename in your Remix config.\n   * @default \"index.js\"\n   */\n  serverBuildFile?: string;\n  /**\n   * A function that returns the value to use as `context` in route `loader` and\n   * `action` functions.\n   *\n   * You can think of this as an escape hatch that allows you to pass\n   * environment/platform-specific values through to your loader/action.\n   */\n  getLoadContext?: GetLoadContextFunction<Server, AppLoadContext>;\n  mode?: string;\n  /**\n   * Options to pass to the Vite server in development.\n   */\n  viteOptions?: InlineConfig;\n  /**\n   * Options to pass to the `@fastify/static` plugin for serving compiled assets in production.\n   */\n  fastifyStaticOptions?: FastifyStaticOptions;\n  /**\n   * The cache control options to use for build assets in production.\n   * uses `pretty-cache-header` under the hood.\n   * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control\n   * @default { public: true, maxAge: '1 year', immutable: true }\n   */\n  assetCacheControl?: Parameters<typeof cacheHeader>[0];\n  /**\n   * The cache control options to use for other assets in production.\n   * uses `pretty-cache-header` under the hood.\n   * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control\n   * @default { public: true, maxAge: '1 hour' }\n   */\n  defaultCacheControl?: Parameters<typeof cacheHeader>[0];\n  /**\n   * The Remix server build to use in production. Use this only if the default approach doesn't work for you.\n   *\n   * If not provided, it will be loaded using `import()` with the server build path provided in the options.\n   */\n  productionServerBuild?:\n    | ServerBuild\n    | (() => ServerBuild | Promise<ServerBuild>);\n\n  childServerOptions?: RouteShorthandOptions<Server>;\n};\n\nexport function createPlugin(\n  fastify: FastifyInstance,\n  {\n    basename = \"/\",\n    buildDirectory = \"build\",\n    serverBuildFile = \"index.js\",\n    getLoadContext,\n    mode = process.env.NODE_ENV,\n    viteOptions,\n    fastifyStaticOptions,\n    assetCacheControl = { public: true, maxAge: \"1 year\", immutable: true },\n    defaultCacheControl = { public: true, maxAge: \"1 hour\" },\n    productionServerBuild,\n    childServerOptions,\n  }: PluginOptions,\n  virtualModule:\n    | \"virtual:remix/server-build\"\n    | \"virtual:react-router/server-build\",\n  // TODO: look if importing the function as a type requires the peer dependency\n  createRequestHandler:\n    | RemixCreateRequestHandlerFunction\n    | RRCreateRequestHandlerFunction,\n) {\n  return async () => {\n    let cwd = process.env.REMIX_ROOT ?? process.cwd();\n\n    let vite: ViteDevServer | undefined;\n\n    if (mode !== \"production\") {\n      vite = await import(\"vite\").then((mod) => {\n        return mod.createServer({\n          ...viteOptions,\n          server: {\n            ...viteOptions?.server,\n            middlewareMode: true,\n          },\n        });\n      });\n    }\n\n    let resolvedBuildDirectory = path.resolve(cwd, buildDirectory);\n    let SERVER_BUILD = path.join(\n      resolvedBuildDirectory,\n      \"server\",\n      serverBuildFile,\n    );\n    let SERVER_BUILD_URL = url.pathToFileURL(SERVER_BUILD).href;\n\n    let handler = createRequestHandler<HttpServer>({\n      mode,\n      // @ts-expect-error - fix this\n      getLoadContext,\n      build: vite\n        ? () => vite.ssrLoadModule(virtualModule)\n        : (productionServerBuild ?? (await import(SERVER_BUILD_URL))),\n    });\n\n    // handle asset requests\n    if (vite) {\n      let middie = await import(\"@fastify/middie\").then((mod) => mod.default);\n      await fastify.register(middie);\n      fastify.use(vite.middlewares);\n    } else {\n      let BUILD_DIR = path.join(resolvedBuildDirectory, \"client\");\n      let ASSET_DIR = path.join(BUILD_DIR, \"assets\");\n      await fastify.register(fastifyStatic, {\n        root: BUILD_DIR,\n        prefix: basename,\n        wildcard: false,\n        cacheControl: false, // required because we are setting custom cache-control headers in setHeaders\n        dotfiles: \"allow\",\n        etag: true,\n        serveDotFiles: true,\n        lastModified: true,\n        setHeaders(res, filepath) {\n          let isAsset = filepath.startsWith(ASSET_DIR);\n          res.setHeader(\n            \"cache-control\",\n            isAsset\n              ? cacheHeader(assetCacheControl)\n              : cacheHeader(defaultCacheControl),\n          );\n        },\n        ...fastifyStaticOptions,\n      });\n    }\n\n    fastify.register(\n      async function createRemixRequestHandler(childServer) {\n        // remove the default content type parsers\n        childServer.removeAllContentTypeParsers();\n        // allow all content types\n        childServer.addContentTypeParser(\"*\", (_request, payload, done) => {\n          done(null, payload);\n        });\n\n        if (childServerOptions) {\n          childServer.all(\"*\", childServerOptions, handler);\n        } else {\n          childServer.all(\"*\", handler);\n        }\n      },\n      { prefix: basename },\n    );\n  };\n}\n"],"mappings":"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"}