nuxt-og-image 3.0.0-beta.4 → 3.0.0-beta.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/README.md +4 -4
  2. package/dist/client/200.html +5 -5
  3. package/dist/client/404.html +5 -5
  4. package/dist/client/_nuxt/IconCSS.7e8f1f7b.css +1 -0
  5. package/dist/client/_nuxt/{IconCSS.6583687a.js → IconCSS.aa1d279a.js} +1 -1
  6. package/dist/client/_nuxt/builds/latest.json +1 -1
  7. package/dist/client/_nuxt/builds/meta/fa0d9e15-6d49-41d0-bdff-8eca0446edd7.json +1 -0
  8. package/dist/client/_nuxt/entry.16c420c7.js +137 -0
  9. package/dist/client/_nuxt/entry.47aab0b4.css +1 -0
  10. package/dist/client/_nuxt/{error-404.214d08e9.js → error-404.26fce296.js} +1 -1
  11. package/dist/client/_nuxt/{error-500.f9a9234a.js → error-500.89729d99.js} +1 -1
  12. package/dist/client/index.html +5 -5
  13. package/dist/module.d.mts +46 -27
  14. package/dist/module.d.ts +46 -27
  15. package/dist/module.json +2 -2
  16. package/dist/module.mjs +195 -103
  17. package/dist/runtime/cache.d.ts +7 -10
  18. package/dist/runtime/cache.mjs +40 -27
  19. package/dist/runtime/components/OgImage/OgImage.d.ts +5 -0
  20. package/dist/runtime/components/OgImage/{index.mjs → OgImage.mjs} +1 -1
  21. package/dist/runtime/components/OgImage/OgImageScreenshot.d.ts +5 -0
  22. package/dist/runtime/components/OgImage/{Screenshot.mjs → OgImageScreenshot.mjs} +1 -1
  23. package/dist/runtime/components/Templates/{Official → Community}/BrandedLogo.vue +3 -2
  24. package/dist/runtime/components/Templates/Community/Nuxt.vue +6 -5
  25. package/dist/runtime/components/Templates/Community/NuxtSeo.vue +137 -0
  26. package/dist/runtime/components/Templates/{Official → Community}/SimpleBlog.vue +7 -5
  27. package/dist/runtime/components/Templates/Community/UnJs.vue +108 -0
  28. package/dist/runtime/components/Templates/{Official → Community}/Wave.vue +3 -2
  29. package/dist/runtime/components/Templates/{Official → Community}/WithEmoji.vue +3 -2
  30. package/dist/runtime/composables/defineOgImage.d.ts +2 -23
  31. package/dist/runtime/composables/defineOgImage.mjs +33 -116
  32. package/dist/runtime/composables/defineOgImageComponent.d.ts +3 -0
  33. package/dist/runtime/composables/defineOgImageComponent.mjs +8 -0
  34. package/dist/runtime/composables/defineOgImageScreenshot.d.ts +2 -0
  35. package/dist/runtime/composables/defineOgImageScreenshot.mjs +14 -0
  36. package/dist/runtime/core/bindings/css-inline/node.d.ts +2 -5
  37. package/dist/runtime/core/bindings/css-inline/node.mjs +2 -10
  38. package/dist/runtime/core/bindings/resvg/stackblitz.d.ts +40 -0
  39. package/dist/runtime/core/bindings/resvg/stackblitz.mjs +6 -0
  40. package/dist/runtime/core/bindings/resvg/wasm.mjs +2 -3
  41. package/dist/runtime/core/bindings/satori/stackblitz.mjs +13 -0
  42. package/dist/runtime/core/bindings/satori/wasm.d.ts +6 -0
  43. package/dist/runtime/core/bindings/satori/wasm.mjs +14 -0
  44. package/dist/runtime/core/cache/emojis.d.ts +1 -0
  45. package/dist/runtime/core/cache/emojis.mjs +5 -0
  46. package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
  47. package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
  48. package/dist/runtime/core/cache/prerender.d.ts +1 -1
  49. package/dist/runtime/core/cache/prerender.mjs +1 -1
  50. package/dist/runtime/core/env/assets.d.ts +0 -1
  51. package/dist/runtime/core/env/assets.mjs +0 -4
  52. package/dist/runtime/core/font/fetch.d.ts +2 -3
  53. package/dist/runtime/core/font/fetch.mjs +32 -15
  54. package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
  55. package/dist/runtime/core/html/applyEmojis.mjs +37 -0
  56. package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
  57. package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
  58. package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
  59. package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +33 -42
  60. package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
  61. package/dist/runtime/core/html/fetchIsland.mjs +17 -0
  62. package/dist/runtime/core/options/fetch.d.ts +1 -1
  63. package/dist/runtime/core/options/fetch.mjs +10 -5
  64. package/dist/runtime/core/options/normalise.d.ts +2 -2
  65. package/dist/runtime/core/options/normalise.mjs +3 -2
  66. package/dist/runtime/core/renderers/chromium/index.mjs +6 -7
  67. package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
  68. package/dist/runtime/core/renderers/chromium/screenshot.mjs +8 -8
  69. package/dist/runtime/core/renderers/satori/fonts.d.ts +2 -2
  70. package/dist/runtime/core/renderers/satori/fonts.mjs +2 -2
  71. package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
  72. package/dist/runtime/core/renderers/satori/index.mjs +26 -22
  73. package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
  74. package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
  75. package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
  76. package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +23 -10
  77. package/dist/runtime/core/renderers/satori/plugins/unocss.d.ts +2 -0
  78. package/dist/runtime/core/renderers/satori/plugins/unocss.mjs +45 -0
  79. package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
  80. package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
  81. package/dist/runtime/core/renderers/satori/vnodes.mjs +16 -6
  82. package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
  83. package/dist/runtime/core/utils/resolveRendererContext.mjs +47 -29
  84. package/dist/runtime/core/utils/wasm.d.ts +3 -0
  85. package/dist/runtime/core/utils/wasm.mjs +16 -0
  86. package/dist/runtime/nitro/plugins/nuxt-content.mjs +3 -4
  87. package/dist/runtime/nitro/plugins/prerender.d.ts +1 -1
  88. package/dist/runtime/nitro/plugins/prerender.mjs +20 -12
  89. package/dist/runtime/nitro/utils.d.ts +2 -0
  90. package/dist/runtime/nitro/utils.mjs +17 -0
  91. package/dist/runtime/nuxt/plugins/og-image-canonical-urls.server.mjs +31 -0
  92. package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +16 -50
  93. package/dist/runtime/nuxt/utils.d.ts +2 -0
  94. package/dist/runtime/nuxt/utils.mjs +53 -0
  95. package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +1 -3
  96. package/dist/runtime/server/routes/__og-image__/debug.json.mjs +4 -8
  97. package/dist/runtime/server/routes/__og-image__/image.mjs +87 -0
  98. package/dist/runtime/types.d.ts +77 -25
  99. package/dist/runtime/utils.d.ts +4 -0
  100. package/dist/runtime/utils.mjs +11 -0
  101. package/dist/runtime/utils.pure.d.ts +5 -0
  102. package/dist/runtime/utils.pure.mjs +43 -0
  103. package/package.json +28 -30
  104. package/virtual.d.ts +49 -0
  105. package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
  106. package/dist/client/_nuxt/builds/meta/0ca67bfd-95de-4c16-8f0a-055751cdca51.json +0 -1
  107. package/dist/client/_nuxt/entry.089f6f0f.js +0 -137
  108. package/dist/client/_nuxt/entry.434c2c45.css +0 -1
  109. package/dist/client/grid.png +0 -0
  110. package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
  111. package/dist/runtime/components/OgImage/Cached.mjs +0 -10
  112. package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
  113. package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
  114. package/dist/runtime/components/OgImage/Screenshot.d.ts +0 -6
  115. package/dist/runtime/components/OgImage/Static.d.ts +0 -8
  116. package/dist/runtime/components/OgImage/Static.mjs +0 -10
  117. package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
  118. package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
  119. package/dist/runtime/components/OgImage/index.d.ts +0 -5
  120. package/dist/runtime/components/Templates/Official/Fallback.vue +0 -147
  121. package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
  122. package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
  123. package/dist/runtime/core/bindings/satori/yoga-wasm.mjs +0 -7
  124. package/dist/runtime/core/bindings/sharp/wasm.d.ts +0 -2
  125. package/dist/runtime/core/bindings/sharp/wasm.mjs +0 -2
  126. package/dist/runtime/core/html/fetch.d.ts +0 -3
  127. package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +0 -29
  128. package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
  129. package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
  130. package/dist/runtime/utilts.d.ts +0 -2
  131. package/dist/runtime/utilts.mjs +0 -8
  132. /package/dist/runtime/core/bindings/satori/{yoga-wasm.d.ts → stackblitz.d.ts} +0 -0
  133. /package/dist/runtime/nuxt/plugins/{nuxt-content-canonical-urls.d.ts → og-image-canonical-urls.server.d.ts} +0 -0
  134. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-400-normal.woff +0 -0
  135. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-700-normal.woff +0 -0
  136. /package/dist/runtime/server/routes/__og-image__/{image-[path]-og.[extension].d.ts → image.d.ts} +0 -0
package/dist/module.mjs CHANGED
@@ -1,15 +1,17 @@
1
1
  import * as fs from 'node:fs';
2
2
  import { existsSync } from 'node:fs';
3
- import { useNuxt, createResolver, addTemplate, addServerPlugin, defineNuxtModule, useLogger, hasNuxtModule, addPlugin, addServerHandler, addImports, addComponentsDir, addComponent } from '@nuxt/kit';
4
- import { installNuxtSiteConfig } from 'nuxt-site-config-kit';
5
- import { provider, env } from 'std-env';
3
+ import { loadNuxtModuleInstance, useNuxt, createResolver, addTemplate, resolvePath, defineNuxtModule, useLogger, hasNuxtModule, addServerPlugin, addServerHandler, addImports, addComponentsDir, addComponent, addPlugin } from '@nuxt/kit';
4
+ import { assertSiteConfig, installNuxtSiteConfig } from 'nuxt-site-config-kit';
5
+ import { provider, env, isDevelopment } from 'std-env';
6
6
  import { hash } from 'ohash';
7
- import { relative } from 'pathe';
8
- import 'nypm';
7
+ import { relative, dirname } from 'pathe';
9
8
  import { defu } from 'defu';
9
+ import 'nypm';
10
10
  import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
11
+ import { readFile, writeFile } from 'node:fs/promises';
12
+ import { createHash } from 'node:crypto';
11
13
 
12
- const version = "3.0.0-beta.4";
14
+ const version = "3.0.0-beta.41";
13
15
 
14
16
  const autodetectableProviders = {
15
17
  azure_static: "azure",
@@ -32,18 +34,19 @@ const NodeRuntime = {
32
34
  "resvg": "node",
33
35
  "satori": "node",
34
36
  "sharp": "node"
35
- },
36
- wasmStrategy: "import"
37
+ }
37
38
  };
38
39
  const cloudflare = {
39
40
  bindings: {
40
41
  "chromium": false,
41
- "css-inline": "node",
42
+ "css-inline": false,
42
43
  "resvg": "wasm",
43
44
  "satori": "node",
44
45
  "sharp": false
45
46
  },
46
- wasmStrategy: "import"
47
+ wasm: {
48
+ esmImport: true
49
+ }
47
50
  };
48
51
  const awsLambda = {
49
52
  bindings: {
@@ -52,8 +55,7 @@ const awsLambda = {
52
55
  "resvg": "node",
53
56
  "satori": "node",
54
57
  "sharp": "node"
55
- },
56
- wasmStrategy: "inline"
58
+ }
57
59
  };
58
60
  const RuntimeCompatibility = {
59
61
  "nitro-dev": NodeRuntime,
@@ -62,45 +64,43 @@ const RuntimeCompatibility = {
62
64
  "stackblitz": {
63
65
  bindings: {
64
66
  "chromium": false,
65
- "css-inline": "node",
66
- "resvg": "wasm",
67
- "satori": "node",
68
- "sharp": "node"
69
- },
70
- wasmStrategy: "inline"
67
+ "css-inline": false,
68
+ "resvg": "stackblitz",
69
+ "satori": "stackblitz",
70
+ "sharp": false
71
+ }
71
72
  },
72
73
  "aws-lambda": awsLambda,
73
74
  "netlify": awsLambda,
74
75
  "netlify-edge": {
75
76
  bindings: {
76
77
  "chromium": false,
77
- "css-inline": "node",
78
- "resvg": "node",
79
- "satori": "node",
80
- "sharp": false
81
- },
82
- wasmStrategy: "inline"
83
- },
84
- "vercel": {
85
- bindings: {
86
- "chromium": false,
87
- "css-inline": "node",
78
+ "css-inline": false,
88
79
  "resvg": "wasm",
89
80
  "satori": "node",
90
- "sharp": "node"
81
+ "sharp": false
91
82
  },
92
- wasmStrategy: "inline"
83
+ wasm: {
84
+ rollup: {
85
+ targetEnv: "auto-inline",
86
+ sync: ["@resvg/resvg-wasm/index_bg.wasm"]
87
+ }
88
+ }
93
89
  },
90
+ "firebase": awsLambda,
91
+ "vercel": awsLambda,
94
92
  "vercel-edge": {
95
93
  bindings: {
96
94
  "chromium": false,
97
- "css-inline": "node",
95
+ "css-inline": false,
98
96
  "resvg": "wasm",
99
97
  "satori": "node",
100
- "sharp": "node"
98
+ "sharp": false
101
99
  },
102
- wasmStrategy: "inline",
103
- wasmImportQuery: "?module"
100
+ wasm: {
101
+ // lowers workers kb size
102
+ esmImport: true
103
+ }
104
104
  },
105
105
  "cloudflare-pages": cloudflare,
106
106
  "cloudflare": cloudflare
@@ -141,15 +141,37 @@ function applyNitroPresetCompatibility(nitroConfig, options) {
141
141
  applyBinding("satori"),
142
142
  applyBinding("resvg"),
143
143
  applyBinding("sharp"),
144
+ applyBinding("css-inline"),
144
145
  nitroConfig.alias || {}
145
146
  );
146
- if (target.includes("cloudflare")) {
147
- nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
148
- nitroConfig.rollupConfig.output.inlineDynamicImports = true;
147
+ if (Object.values(compatibility.bindings).includes("wasm")) {
148
+ nitroConfig.experimental = nitroConfig.experimental || {};
149
+ nitroConfig.experimental.wasm = true;
149
150
  }
151
+ nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
152
+ nitroConfig.wasm = defu(compatibility.wasm, nitroConfig.wasm);
150
153
  return compatibility;
151
154
  }
152
155
 
156
+ async function getNuxtModuleOptions(module, nuxt = useNuxt()) {
157
+ const moduleMeta = (typeof module === "string" ? { name: module } : await module.getMeta?.()) || {};
158
+ const { nuxtModule } = await loadNuxtModuleInstance(module, nuxt);
159
+ let moduleEntry;
160
+ for (const m of nuxt.options.modules) {
161
+ if (Array.isArray(m) && m.length >= 2) {
162
+ const _module = m[0];
163
+ const _moduleEntryName = typeof _module === "string" ? _module : (await _module.getMeta?.())?.name || "";
164
+ if (_moduleEntryName === moduleMeta.name)
165
+ moduleEntry = m;
166
+ }
167
+ }
168
+ let inlineOptions = {};
169
+ if (moduleEntry)
170
+ inlineOptions = moduleEntry[1];
171
+ if (nuxtModule.getOptions)
172
+ return nuxtModule.getOptions(inlineOptions, nuxt);
173
+ return inlineOptions;
174
+ }
153
175
  function extendTypes(module, template) {
154
176
  const nuxt = useNuxt();
155
177
  const { resolve } = createResolver(import.meta.url);
@@ -201,9 +223,15 @@ function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
201
223
  rpc.broadcast.refreshRouteData(path).catch(() => {
202
224
  });
203
225
  }
204
- if (options.componentDirs.some((dir) => path.includes(dir)))
205
- rpc.broadcast.refreshGlobalData().catch(() => {
206
- });
226
+ if (options.componentDirs.some((dir) => path.includes(dir))) {
227
+ if (e === "change") {
228
+ rpc.broadcast.refresh().catch(() => {
229
+ });
230
+ } else {
231
+ rpc.broadcast.refreshGlobalData().catch(() => {
232
+ });
233
+ }
234
+ }
207
235
  });
208
236
  });
209
237
  nuxt.hook("devtools:customTabs", (tabs) => {
@@ -226,8 +254,8 @@ function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
226
254
  function setupDevHandler(options, resolve, nuxt = useNuxt()) {
227
255
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
228
256
  nitroConfig.alias["#nuxt-og-image/renderers/satori"] = options.runtimeSatori ? resolve("./runtime/core/renderers/satori") : "unenv/runtime/mock/empty";
229
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = options.runtimeBrowser ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
230
- applyNitroPresetCompatibility(nitroConfig, { resolve });
257
+ nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = options.runtimeChromium ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
258
+ applyNitroPresetCompatibility(nitroConfig, { resolve, compatibility: options.runtimeCompatibility });
231
259
  });
232
260
  }
233
261
 
@@ -247,16 +275,28 @@ function setupGenerateHandler(options, resolve, nuxt = useNuxt()) {
247
275
  },
248
276
  resolve
249
277
  });
278
+ assertSiteConfig("nuxt-og-image", {
279
+ url: "OG Image tags are required to be absolute URLs."
280
+ }, {
281
+ throwError: true
282
+ });
250
283
  });
251
284
  }
252
285
 
253
286
  function setupPrerenderHandler(options, resolve, nuxt = useNuxt()) {
254
- addServerPlugin(resolve("./runtime/nitro/plugins/prerender.ts"));
255
287
  nuxt.hooks.hook("nitro:init", async (nitro) => {
256
288
  nitro.hooks.hook("prerender:config", async (nitroConfig) => {
257
289
  nitroConfig.alias["#nuxt-og-image/renderers/satori"] = resolve("./runtime/core/renderers/satori");
258
290
  nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = resolve("./runtime/core/renderers/chromium");
259
291
  applyNitroPresetCompatibility(nitroConfig, { resolve });
292
+ nitroConfig.wasm = nitroConfig.wasm || {};
293
+ nitroConfig.wasm.esmImport = false;
294
+ const prerenderingPages = (nuxt.options.nitro.prerender?.routes || []).some((r) => r && (!r.includes(".") || r.includes("*")));
295
+ prerenderingPages && assertSiteConfig("nuxt-og-image", {
296
+ url: "OG Image tags are required to be absolute URLs."
297
+ }, {
298
+ throwError: false
299
+ });
260
300
  });
261
301
  });
262
302
  }
@@ -267,20 +307,41 @@ async function setupBuildHandler(config, resolve, nuxt = useNuxt()) {
267
307
  nuxt.options.nitro.storage["og-image"] = config.runtimeCacheStorage;
268
308
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
269
309
  nitroConfig.alias["#nuxt-og-image/renderers/satori"] = config.runtimeSatori ? resolve("./runtime/core/renderers/satori") : "unenv/runtime/mock/empty";
270
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = config.runtimeBrowser ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
310
+ nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = config.runtimeChromium ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
271
311
  applyNitroPresetCompatibility(nitroConfig, { resolve, compatibility: config.runtimeCompatibility });
272
312
  nitroConfig.alias.electron = "unenv/runtime/mock/proxy-cjs";
273
313
  nitroConfig.alias.bufferutil = "unenv/runtime/mock/proxy-cjs";
274
314
  nitroConfig.alias["utf-8-validate"] = "unenv/runtime/mock/proxy-cjs";
275
315
  nitroConfig.alias.queue = "unenv/runtime/mock/proxy-cjs";
276
316
  });
317
+ nuxt.hooks.hook("nitro:init", async (nitro) => {
318
+ nitro.hooks.hook("compiled", async (_nitro) => {
319
+ const target = resolveNitroPreset(_nitro.options);
320
+ const compatibility = getPresetNitroPresetCompatibility(target);
321
+ if (compatibility.wasm?.esmImport !== true)
322
+ return;
323
+ const configuredEntry = nitro.options.rollupConfig?.output.entryFileNames;
324
+ let serverEntry = resolve(_nitro.options.output.serverDir, typeof configuredEntry === "string" ? configuredEntry : "index.mjs");
325
+ if (target === "cloudflare-pages")
326
+ serverEntry = resolve(dirname(serverEntry), "./chunks/wasm.mjs");
327
+ const contents = await readFile(serverEntry, "utf-8");
328
+ const resvgHash = sha1(await readFile(await resolvePath("@resvg/resvg-wasm/index_bg.wasm")));
329
+ const yogaHash = sha1(await readFile(await resolvePath("yoga-wasm-web/dist/yoga.wasm")));
330
+ const postfix = target === "vercel-edge" ? "?module" : "";
331
+ const path = target === "cloudflare-pages" ? `../wasm/` : `./wasm/`;
332
+ await writeFile(serverEntry, contents.replaceAll('"@resvg/resvg-wasm/index_bg.wasm"', `"${path}index_bg-${resvgHash}.wasm${postfix}"`).replaceAll('"yoga-wasm-web/dist/yoga.wasm"', `"${path}yoga-${yogaHash}.wasm${postfix}"`), { encoding: "utf-8" });
333
+ });
334
+ });
335
+ }
336
+ function sha1(source) {
337
+ return createHash("sha1").update(source).digest("hex").slice(0, 16);
277
338
  }
278
339
 
279
340
  const module = defineNuxtModule({
280
341
  meta: {
281
342
  name: "nuxt-og-image",
282
343
  compatibility: {
283
- nuxt: "^3.7.0",
344
+ nuxt: "^3.8.2",
284
345
  bridge: false
285
346
  },
286
347
  configKey: "ogImage"
@@ -289,21 +350,20 @@ const module = defineNuxtModule({
289
350
  return {
290
351
  enabled: true,
291
352
  defaults: {
353
+ emojis: "noto",
292
354
  renderer: "satori",
293
- component: "Fallback",
355
+ component: "NuxtSeo",
294
356
  width: 1200,
295
357
  height: 600,
296
- cache: true,
297
- // default is to cache the image for 1 day (24 hours)
298
- cacheTtl: 24 * 60 * 60 * 1e3
358
+ // default is to cache the image for 3 day (72 hours)
359
+ cacheMaxAgeSeconds: 60 * 60 * 24 * 3
299
360
  },
300
361
  componentDirs: ["OgImage", "OgImageTemplate"],
301
- runtimeSatori: true,
302
- runtimeBrowser: nuxt.options.dev,
303
362
  fonts: [],
304
363
  runtimeCacheStorage: true,
305
- playground: env.NODE_ENV === "development" || nuxt.options.dev,
306
- debug: false
364
+ runtimeSatori: true,
365
+ runtimeChromium: nuxt.options.dev,
366
+ debug: isDevelopment
307
367
  };
308
368
  },
309
369
  async setup(config, nuxt) {
@@ -320,16 +380,44 @@ const module = defineNuxtModule({
320
380
  const { resolve } = createResolver(import.meta.url);
321
381
  const preset = resolveNitroPreset(nuxt.options.nitro);
322
382
  const compatibility = getPresetNitroPresetCompatibility(preset);
323
- config.defaults.extension = "jpg";
324
- if (!compatibility.bindings.sharp)
383
+ const userConfiguredExtension = config.defaults.extension;
384
+ config.defaults.extension = userConfiguredExtension || "jpg";
385
+ if (!compatibility.bindings.sharp && config.defaults.renderer !== "chromium") {
386
+ if (userConfiguredExtension && ["jpeg", "jpg"].includes(userConfiguredExtension))
387
+ logger.warn("The sharp runtime is not available for this target, disabling sharp and using png instead.");
325
388
  config.defaults.extension = "png";
389
+ }
390
+ if (config.runtimeChromium && !compatibility.bindings.chromium) {
391
+ logger.warn("The Chromium runtime is not available for this target, disabling runtimeChromium.");
392
+ config.runtimeChromium = false;
393
+ }
326
394
  await installNuxtSiteConfig();
327
- if (hasNuxtModule("@nuxt/content")) {
395
+ if (hasNuxtModule("@nuxt/content"))
328
396
  addServerPlugin(resolve("./runtime/nitro/plugins/nuxt-content"));
329
- addPlugin(resolve("./runtime/nuxt/plugins/nuxt-content-canonical-urls"));
330
- }
331
397
  if (!config.fonts.length)
332
398
  config.fonts = ["Inter:400", "Inter:700"];
399
+ if (preset === "stackblitz") {
400
+ config.fonts = config.fonts.map((f) => {
401
+ if (typeof f === "string" && f.startsWith("Inter:")) {
402
+ const [_, weight] = f.split(":");
403
+ return {
404
+ name: "Inter",
405
+ weight,
406
+ // nuxt server assets
407
+ key: `nuxt-og-image:fonts:inter-latin-ext-${weight}-normal.woff`
408
+ };
409
+ }
410
+ if (typeof f === "string" || !f.path && !f.key) {
411
+ logger.warn(`The ${typeof f === "string" ? f : `${f.name}:${f.weight}`} font was skipped because remote fonts are not available in StackBlitz, please use a local font.`);
412
+ return false;
413
+ }
414
+ return f;
415
+ }).filter(Boolean);
416
+ nuxt.hooks.hook("nitro:config", (nitroConfig) => {
417
+ nitroConfig.serverAssets = nitroConfig.serverAssets || [];
418
+ nitroConfig.serverAssets.push({ baseName: "nuxt-og-image:fonts", dir: resolve("./runtime/server/assets") });
419
+ });
420
+ }
333
421
  nuxt.options.experimental.componentIslands = true;
334
422
  addServerHandler({
335
423
  lazy: true,
@@ -346,52 +434,34 @@ const module = defineNuxtModule({
346
434
  addServerHandler({
347
435
  lazy: true,
348
436
  route: "/__og-image__/image/**",
349
- handler: resolve("./runtime/server/routes/__og-image__/image-[path]-og.[extension]")
437
+ handler: resolve("./runtime/server/routes/__og-image__/image")
350
438
  });
351
439
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"] = [];
352
- [
353
- // deprecated
354
- "Dynamic",
355
- "Static",
356
- // new
357
- "index",
358
- "Cached",
359
- "Component",
360
- "WithoutCache",
361
- "Screenshot"
362
- ].forEach((name) => {
363
- name = name === "index" ? "defineOgImage" : `defineOgImage${name}`;
440
+ ["defineOgImage", "defineOgImageComponent", "defineOgImageScreenshot"].forEach((name) => {
364
441
  addImports({
365
442
  name,
366
- from: resolve("./runtime/composables/defineOgImage")
443
+ from: resolve(`./runtime/composables/${name}`)
367
444
  });
368
445
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"].push(name);
369
446
  });
370
447
  await addComponentsDir({
371
448
  path: resolve("./runtime/components/Templates/Community"),
372
- island: true
373
- });
374
- await addComponentsDir({
375
- path: resolve("./runtime/components/Templates/Official"),
376
- island: true
449
+ island: true,
450
+ watch: true
377
451
  });
378
452
  [
379
- // deprecated
380
- "Static",
381
- "Dynamic",
382
453
  // new
383
- "index",
384
- "Cached",
385
- "WithoutCache",
386
- "Screenshot"
454
+ "OgImage",
455
+ "OgImageScreenshot"
387
456
  ].forEach((name) => {
388
457
  addComponent({
389
- global: hasNuxtModule("@nuxt/content"),
390
- name: name === "index" ? "OgImage" : `OgImage${name}`,
458
+ name,
459
+ global: true,
391
460
  filePath: resolve(`./runtime/components/OgImage/${name}`)
392
461
  });
393
462
  });
394
- addPlugin(resolve("./runtime/nuxt/plugins/route-rule-og-image.server"));
463
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/route-rule-og-image.server") });
464
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/og-image-canonical-urls.server") });
395
465
  const ogImageComponentCtx = { components: [] };
396
466
  nuxt.hook("components:extend", (components) => {
397
467
  ogImageComponentCtx.components = [];
@@ -409,8 +479,6 @@ const module = defineNuxtModule({
409
479
  let category = "app";
410
480
  if (component.filePath.includes(resolve("./runtime/components/Templates/Community")))
411
481
  category = "community";
412
- else if (component.filePath.includes(resolve("./runtime/components/Templates/Official")))
413
- category = "official";
414
482
  const componentFile = fs.readFileSync(component.filePath, "utf-8");
415
483
  const credits = componentFile.split("\n").find((line) => line.startsWith(" * @credits"))?.replace("* @credits", "").trim();
416
484
  ogImageComponentCtx.components.push({
@@ -437,6 +505,16 @@ const module = defineNuxtModule({
437
505
  nuxt.options.nitro.virtual["#nuxt-og-image/component-names.mjs"] = () => {
438
506
  return `export const componentNames = ${JSON.stringify(ogImageComponentCtx.components)}`;
439
507
  };
508
+ let unoCssConfig = { theme: {} };
509
+ nuxt.hook("tailwindcss:config", (tailwindConfig) => {
510
+ unoCssConfig = defu(tailwindConfig.theme.extend, { ...tailwindConfig.theme || {}, extend: void 0 });
511
+ });
512
+ nuxt.hook("unocss:config", (_unoCssConfig) => {
513
+ unoCssConfig = { ..._unoCssConfig.theme };
514
+ });
515
+ nuxt.options.nitro.virtual["#nuxt-og-image/unocss-config.mjs"] = () => {
516
+ return `export const theme = ${JSON.stringify(unoCssConfig)}`;
517
+ };
440
518
  extendTypes("nuxt-og-image", ({ typesPath }) => {
441
519
  const componentImports = ogImageComponentCtx.components.map((component) => {
442
520
  const relativeComponentPath = relative(resolve(nuxt.options.rootDir, nuxt.options.buildDir, "module"), component.path);
@@ -445,12 +523,17 @@ const module = defineNuxtModule({
445
523
  return `
446
524
  declare module 'nitropack' {
447
525
  interface NitroRouteRules {
448
- ogImage?: false | import('${typesPath}').OgImageOptions
526
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
449
527
  }
450
528
  interface NitroRouteConfig {
451
- ogImage?: false | import('${typesPath}').OgImageOptions
529
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
530
+ }
531
+ interface NitroRuntimeHooks {
532
+ 'nuxt-og-image:context': (ctx: import('${typesPath}').OgImageRenderEventContext) => void | Promise<void>
533
+ 'nuxt-og-image:satori:vnodes': (vnodes: import('${typesPath}').VNode) => void | Promise<void>
452
534
  }
453
535
  }
536
+
454
537
  declare module '#nuxt-og-image/components' {
455
538
  export interface OgImageComponents {
456
539
  ${componentImports}
@@ -458,8 +541,12 @@ ${componentImports}
458
541
  }
459
542
  `;
460
543
  });
544
+ const cacheEnabled = typeof config.runtimeCacheStorage !== "undefined" && config.runtimeCacheStorage !== false;
545
+ const runtimeCacheStorage = typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver;
546
+ let baseCacheKey = runtimeCacheStorage === "default" ? `/cache/nuxt-og-image@${version}` : `/nuxt-og-image@${version}`;
547
+ if (!cacheEnabled)
548
+ baseCacheKey = false;
461
549
  nuxt.hooks.hook("modules:done", async () => {
462
- nuxt.hooks.callHook("og-image:config", config);
463
550
  const normalisedFonts = config.fonts.map((f) => {
464
551
  if (typeof f === "string") {
465
552
  const [name, weight] = f.split(":");
@@ -474,29 +561,33 @@ ${componentImports}
474
561
  if (!nuxt.options._generate && nuxt.options.build) {
475
562
  nuxt.options.nitro.prerender = nuxt.options.nitro.prerender || {};
476
563
  nuxt.options.nitro.prerender.routes = nuxt.options.nitro.prerender.routes || [];
477
- normalisedFonts.filter((f) => !f.path).forEach(({ name, weight }) => {
564
+ normalisedFonts.filter((f) => !f.path && !f.key).forEach(({ name, weight }) => {
478
565
  nuxt.options.nitro.prerender.routes.push(`/__og-image__/font/${name}/${weight}.ttf`);
479
566
  });
480
567
  }
481
- nuxt.options.runtimeConfig["nuxt-og-image"] = {
568
+ let colorPreference = hasNuxtModule("@nuxtjs/color-mode") ? (await getNuxtModuleOptions("@nuxtjs/color-mode")).preference : "light";
569
+ if (!colorPreference || !["dark", "light"].includes(colorPreference))
570
+ colorPreference = "light";
571
+ const runtimeConfig = {
482
572
  version,
483
573
  // binding options
484
574
  satoriOptions: config.satoriOptions || {},
485
575
  resvgOptions: config.resvgOptions || {},
486
576
  sharpOptions: config.sharpOptions || {},
487
577
  runtimeSatori: config.runtimeSatori,
488
- runtimeBrowser: config.runtimeBrowser,
489
- // @ts-expect-error runtime type
578
+ runtimeChromium: config.runtimeChromium,
490
579
  defaults: config.defaults,
580
+ debug: config.debug,
491
581
  // avoid adding credentials
492
- runtimeCacheStorage: typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver,
582
+ baseCacheKey,
493
583
  // convert the fonts to uniform type to fix ts issue
494
584
  fonts: normalisedFonts,
495
- hasNuxtIcon: hasNuxtModule("nuxt-icon")
585
+ hasNuxtIcon: hasNuxtModule("nuxt-icon"),
586
+ colorPreference
496
587
  };
588
+ nuxt.hooks.callHook("nuxt-og-image:runtime-config", runtimeConfig);
589
+ nuxt.options.runtimeConfig["nuxt-og-image"] = runtimeConfig;
497
590
  });
498
- nuxt.options.nitro.experimental = nuxt.options.nitro.experimental || {};
499
- nuxt.options.nitro.experimental.wasm = true;
500
591
  if (nuxt.options.dev) {
501
592
  setupDevHandler(config, resolve);
502
593
  setupDevToolsUI(config, resolve);
@@ -505,8 +596,9 @@ ${componentImports}
505
596
  } else if (nuxt.options.build) {
506
597
  await setupBuildHandler(config, resolve);
507
598
  }
508
- if (nuxt.options.nitro.prerender?.routes || nuxt.options._generate)
509
- setupPrerenderHandler(config, resolve);
599
+ if (nuxt.options.build)
600
+ addServerPlugin(resolve("./runtime/nitro/plugins/prerender"));
601
+ setupPrerenderHandler(config, resolve);
510
602
  }
511
603
  });
512
604
 
@@ -1,12 +1,9 @@
1
- import type { H3Event } from 'h3';
2
- export declare function useNitroCache<T>(e: H3Event, options: {
3
- key: string;
4
- cacheTtl: number;
5
- cache: boolean;
6
- headers: boolean;
7
- skipRestore?: boolean;
8
- }): Promise<{
9
- cachedItem: false | T;
1
+ import type { OgImageRenderEventContext } from './types';
2
+ export declare function useOgImageBufferCache(ctx: OgImageRenderEventContext, options: {
3
+ baseCacheKey: string | false;
4
+ cacheMaxAgeSeconds?: number;
5
+ }): Promise<void | {
6
+ cachedItem: false | BufferSource;
10
7
  enabled: boolean;
11
- update: (item: T) => Promise<void>;
8
+ update: (image: BufferSource) => Promise<void>;
12
9
  }>;
@@ -1,45 +1,58 @@
1
1
  import { prefixStorage } from "unstorage";
2
- import { getQuery, setHeader } from "h3";
3
- import { useRuntimeConfig, useStorage } from "#imports";
4
- export async function useNitroCache(e, options) {
5
- const module = "nuxt-og-image";
6
- const { runtimeCacheStorage, version } = useRuntimeConfig()[module];
7
- const enabled = options.cache && runtimeCacheStorage && options.cacheTtl && options.cacheTtl > 0;
8
- const baseCacheKey = runtimeCacheStorage === "default" ? `/cache/${module}@${version}` : `/${module}@${version}`;
9
- const cache = prefixStorage(useStorage(), `${baseCacheKey}/`);
10
- const key = options.key;
11
- let xCacheHeader = "DISABLED";
12
- let xCacheExpires = 0;
13
- const newExpires = Date.now() + (options.cacheTtl || 0);
14
- const purge = typeof getQuery(e).purge !== "undefined";
2
+ import { getQuery, handleCacheHeaders, setHeader, setHeaders } from "h3";
3
+ import { withTrailingSlash } from "ufo";
4
+ import { hash } from "ohash";
5
+ import { useStorage } from "#imports";
6
+ export async function useOgImageBufferCache(ctx, options) {
7
+ const maxAge = Number(options.cacheMaxAgeSeconds);
8
+ const enabled = !import.meta.dev && import.meta.env.MODE !== "test" && maxAge > 0;
9
+ const cache = prefixStorage(useStorage(), withTrailingSlash(options.baseCacheKey || "/"));
10
+ const key = ctx.key;
15
11
  let cachedItem = false;
16
- if (!options.skipRestore && enabled && await cache.hasItem(key).catch(() => false)) {
17
- const { value, expiresAt } = await cache.getItem(key).catch(() => ({ value: null, expiresAt: Date.now() }));
18
- if (purge) {
19
- xCacheHeader = "PURGE";
20
- xCacheExpires = newExpires;
12
+ if (enabled && await cache.hasItem(key).catch(() => false)) {
13
+ const { value, expiresAt, headers } = await cache.getItem(key).catch(() => ({ value: null, expiresAt: Date.now() }));
14
+ if (typeof getQuery(ctx.e).purge !== "undefined") {
21
15
  await cache.removeItem(key).catch(() => {
22
16
  });
23
17
  } else if (expiresAt > Date.now()) {
24
- xCacheHeader = "HIT";
25
- xCacheExpires = newExpires;
26
- cachedItem = value;
18
+ cachedItem = Buffer.from(value, "base64");
19
+ if (handleCacheHeaders(ctx.e, {
20
+ modifiedTime: new Date(headers["last-modified"]),
21
+ etag: headers.etag,
22
+ maxAge
23
+ }))
24
+ return;
25
+ setHeaders(ctx.e, headers);
27
26
  } else {
28
- xCacheHeader = "MISS";
29
- xCacheExpires = expiresAt;
30
27
  await cache.removeItem(key).catch(() => {
31
28
  });
32
29
  }
33
30
  }
34
- if (options.headers) {
35
- setHeader(e, `x-${module}-cache`, xCacheHeader);
36
- setHeader(e, `x-${module}-expires`, xCacheExpires.toString());
31
+ if (!enabled) {
32
+ setHeader(ctx.e, "Cache-Control", "no-cache, no-store, must-revalidate");
33
+ setHeader(ctx.e, "Pragma", "no-cache");
34
+ setHeader(ctx.e, "Expires", "0");
37
35
  }
38
36
  return {
39
37
  enabled,
40
38
  cachedItem,
41
39
  async update(item) {
42
- enabled && await cache.setItem(key, { value: item, expiresAt: Date.now() + (options.cacheTtl || 0) });
40
+ if (!enabled)
41
+ return;
42
+ const value = Buffer.from(item).toString("base64");
43
+ const headers = {
44
+ // avoid multi-tenancy cache issues
45
+ "Vary": "accept-encoding, host",
46
+ "etag": `W/"${hash(value)}"`,
47
+ "last-modified": (/* @__PURE__ */ new Date()).toUTCString(),
48
+ "cache-control": `public, s-maxage=${maxAge}, stale-while-revalidate`
49
+ };
50
+ setHeaders(ctx.e, headers);
51
+ await cache.setItem(key, {
52
+ value,
53
+ headers,
54
+ expiresAt: Date.now() + maxAge * 1e3
55
+ });
43
56
  }
44
57
  };
45
58
  }
@@ -0,0 +1,5 @@
1
+ import type { OgImageOptions } from '../../types';
2
+ declare const _default: import("vue").DefineComponent<OgImageOptions<"NuxtSeo">, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<OgImageOptions<"NuxtSeo">>, {
3
+ props?: any;
4
+ }, {}>;
5
+ export default _default;
@@ -4,7 +4,7 @@ export default defineComponent({
4
4
  name: "OgImage",
5
5
  async setup(_, { attrs }) {
6
6
  if (import.meta.server)
7
- await defineOgImage(attrs);
7
+ defineOgImage(attrs);
8
8
  return () => null;
9
9
  }
10
10
  });
@@ -0,0 +1,5 @@
1
+ import type { OgImagePageScreenshotOptions } from '../../types';
2
+ declare const _default: import("vue").DefineComponent<OgImagePageScreenshotOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<OgImagePageScreenshotOptions>, {
3
+ props?: any;
4
+ }, {}>;
5
+ export default _default;
@@ -4,7 +4,7 @@ export default defineComponent({
4
4
  name: "OgImageScreenshot",
5
5
  async setup(_, { attrs }) {
6
6
  if (import.meta.server)
7
- await defineOgImageScreenshot(attrs);
7
+ defineOgImageScreenshot(attrs);
8
8
  return () => null;
9
9
  }
10
10
  });