{"version":3,"file":"index.cjs","names":["ImageResponse","path"],"sources":["../src/og-image-generator.ts","../src/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { ImageResponse } from \"@vercel/og\";\nimport { createElement } from \"react\";\nimport { normalizePath, type ResolvedConfig } from \"vite\";\nimport type { OgImagePluginOptions } from \"./\";\n\nexport type ImageResponseOptions = Omit<\n  NonNullable<ConstructorParameters<typeof ImageResponse>[1]>,\n  keyof ResponseInit\n>;\n\nexport interface OgImageGeneratorOptions {\n  ogImagePluginOptions: OgImagePluginOptions;\n  resolvedConfig: ResolvedConfig;\n}\n\nexport class OgImageGenerator {\n  private readonly options: OgImageGeneratorOptions;\n  private readonly resolvedComponentPath: string;\n  constructor(options: OgImageGeneratorOptions) {\n    this.options = options;\n    this.resolvedComponentPath = this.resolveComponentPath(\n      options.ogImagePluginOptions.componentPath || \"./src/og-image\",\n      options.resolvedConfig.root,\n    );\n  }\n\n  async generateOgImage(\n    loadModule: (id: string) => Promise<Record<string, unknown>>,\n  ) {\n    try {\n      const module = await loadModule(this.resolvedComponentPath);\n      const element = createElement(module.default as React.ComponentType);\n      const imageRes = new ImageResponse(\n        element,\n        this.options.ogImagePluginOptions.imageResponseOptions,\n      );\n      const arrayBuffer = await imageRes.arrayBuffer();\n      return new Uint8Array(arrayBuffer);\n    } catch (error) {\n      console.error(\"Error generating OG image:\", error);\n      throw error;\n    }\n  }\n\n  async generateOgImageInProd(\n    loadModule: (id: string) => Promise<Record<string, unknown>>,\n  ) {\n    const arrayBuffer = await this.generateOgImage(loadModule);\n    const outputPath = `${path.basename(\n      this.resolvedComponentPath,\n      path.extname(this.resolvedComponentPath),\n    )}.png`;\n    return [outputPath, arrayBuffer] as const;\n  }\n\n  get imageSize() {\n    const opts = this.options.ogImagePluginOptions.imageResponseOptions;\n    return {\n      width: opts?.width ?? 1200,\n      height: opts?.height ?? 630,\n    };\n  }\n\n  get devComponentPath() {\n    const resolvedRelPath = path.relative(\n      this.options.resolvedConfig.root,\n      this.resolvedComponentPath,\n    );\n    const resolvedPath = normalizePath(\n      `${this.options.resolvedConfig.base}${resolvedRelPath}`,\n    );\n    return resolvedPath;\n  }\n\n  determineUrl(assetPath?: string) {\n    if (assetPath) {\n      // For production, use the built image path\n      return new URL(assetPath, this.options.ogImagePluginOptions.host);\n    }\n    return new URL(\n      this.devComponentPath,\n      this.options.ogImagePluginOptions.host,\n    );\n  }\n\n  private resolveComponentPath(componentPath: string, rootDir: string): string {\n    const fullPath = path.resolve(rootDir, componentPath);\n\n    // If the path already has an extension and exists, use it\n    if (path.extname(componentPath) && existsSync(fullPath)) {\n      return fullPath;\n    }\n\n    // If no extension or file doesn't exist, try extensions in order\n    const extensions = [\".tsx\", \".jsx\", \".ts\", \".js\"];\n    const basePath = path.extname(componentPath)\n      ? fullPath.slice(0, -path.extname(componentPath).length)\n      : fullPath;\n\n    for (const ext of extensions) {\n      const pathWithExt = basePath + ext;\n      if (existsSync(pathWithExt)) {\n        return pathWithExt;\n      }\n    }\n\n    // If nothing found, return the original path (will cause an error later)\n    return fullPath;\n  }\n}\n","import {\n  createServer,\n  type HtmlTagDescriptor,\n  type Plugin,\n  type ResolvedConfig,\n} from \"vite\";\nimport {\n  type ImageResponseOptions,\n  OgImageGenerator,\n} from \"./og-image-generator\";\n\nconst pluginName = \"vite-plugin-og-image\";\n\nexport interface OgImagePluginOptions {\n  componentPath?: string | undefined;\n  host: string;\n  alt?: string | undefined;\n  imageResponseOptions?: ImageResponseOptions | undefined;\n}\n\nexport default function ogImagePlugin(\n  ogImagePluginOptions: OgImagePluginOptions,\n): Plugin {\n  let resolvedConfig: ResolvedConfig;\n  let ogImageGenerator: OgImageGenerator;\n  let assetPath: string | undefined;\n  let referenceId: string;\n\n  return {\n    name: pluginName,\n    sharedDuringBuild: true,\n    configResolved(config) {\n      resolvedConfig = config;\n      ogImageGenerator = new OgImageGenerator({\n        ogImagePluginOptions,\n        resolvedConfig: resolvedConfig,\n      });\n    },\n    configureServer(server) {\n      server.middlewares.use(async (req, res, next) => {\n        const reqPath = req.url?.split(\"?\")[0];\n        const devPath = ogImageGenerator.devComponentPath;\n        if (reqPath === devPath) {\n          try {\n            const imageRes = await ogImageGenerator.generateOgImage((id) =>\n              server.ssrLoadModule(id),\n            );\n            res.setHeader(\"Content-Type\", \"image/png\");\n            res.setHeader(\"Cache-Control\", \"no-cache\");\n            res.end(imageRes);\n          } catch (error) {\n            console.error(\"Error generating OG image:\", error);\n            res.statusCode = 500;\n            res.end(\"Error generating OG image\");\n          }\n          return;\n        }\n        next();\n      });\n    },\n    async buildStart() {\n      if (resolvedConfig.command === \"build\") {\n        const server = await createServer();\n        try {\n          const [outputPath, arrayBuffer] =\n            await ogImageGenerator.generateOgImageInProd((id) =>\n              server.ssrLoadModule(id),\n            );\n          referenceId = this.emitFile({\n            type: \"asset\",\n            source: new Uint8Array(arrayBuffer),\n            name: outputPath,\n          });\n        } catch (error) {\n          console.error(\"Error generating OG image:\", error);\n        } finally {\n          await server.close();\n        }\n      }\n    },\n    generateBundle() {\n      assetPath = this.getFileName(referenceId);\n    },\n    transformIndexHtml() {\n      const url = ogImageGenerator.determineUrl(assetPath);\n      const { width, height } = ogImageGenerator.imageSize;\n      const commonTags: HtmlTagDescriptor[] = [\n        {\n          tag: \"meta\",\n          attrs: {\n            property: \"og:image\",\n            content: url.toString(),\n          },\n          injectTo: \"head\",\n        },\n        {\n          tag: \"meta\",\n          attrs: {\n            property: \"og:image:type\",\n            content: \"image/png\",\n          },\n          injectTo: \"head\",\n        },\n        {\n          tag: \"meta\",\n          attrs: {\n            property: \"og:image:width\",\n            content: String(width),\n          },\n          injectTo: \"head\",\n        },\n        {\n          tag: \"meta\",\n          attrs: {\n            property: \"og:image:height\",\n            content: String(height),\n          },\n          injectTo: \"head\",\n        },\n      ] as const;\n      if (ogImagePluginOptions.alt) {\n        return [\n          ...commonTags,\n          {\n            tag: \"meta\",\n            attrs: {\n              property: \"og:image:alt\",\n              content: ogImagePluginOptions.alt,\n            },\n            injectTo: \"head\",\n          },\n        ];\n      }\n      return commonTags;\n    },\n  };\n}\n"],"mappings":"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"}