nuxt-og-image 3.0.0-beta.10 → 3.0.0-beta.14

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 (107) hide show
  1. package/dist/client/200.html +5 -5
  2. package/dist/client/404.html +5 -5
  3. package/dist/client/_nuxt/{IconCSS.389cad49.js → IconCSS.59f1542b.js} +1 -1
  4. package/dist/client/_nuxt/IconCSS.7e8f1f7b.css +1 -0
  5. package/dist/client/_nuxt/builds/latest.json +1 -1
  6. package/dist/client/_nuxt/builds/meta/4222eee5-f71e-4425-9403-92637db48893.json +1 -0
  7. package/dist/client/_nuxt/entry.03caefbf.js +137 -0
  8. package/dist/client/_nuxt/entry.3a009184.css +1 -0
  9. package/dist/client/_nuxt/{error-404.91508473.js → error-404.8bab7a15.js} +1 -1
  10. package/dist/client/_nuxt/{error-500.b66f3aae.js → error-500.b72200bc.js} +1 -1
  11. package/dist/client/index.html +5 -5
  12. package/dist/module.d.mts +40 -23
  13. package/dist/module.d.ts +40 -23
  14. package/dist/module.json +2 -2
  15. package/dist/module.mjs +68 -53
  16. package/dist/runtime/cache.d.ts +7 -10
  17. package/dist/runtime/cache.mjs +38 -26
  18. package/dist/runtime/components/OgImage/OgImage.d.ts +5 -0
  19. package/dist/runtime/components/OgImage/{index.mjs → OgImage.mjs} +1 -1
  20. package/dist/runtime/components/OgImage/Screenshot.d.ts +3 -4
  21. package/dist/runtime/components/OgImage/Screenshot.mjs +1 -1
  22. package/dist/runtime/components/Templates/Official/SimpleBlog.vue +1 -0
  23. package/dist/runtime/composables/defineOgImage.d.ts +2 -23
  24. package/dist/runtime/composables/defineOgImage.mjs +32 -115
  25. package/dist/runtime/composables/defineOgImageComponent.d.ts +3 -0
  26. package/dist/runtime/composables/defineOgImageComponent.mjs +8 -0
  27. package/dist/runtime/composables/defineOgImagePageScreenshot.d.ts +2 -0
  28. package/dist/runtime/composables/defineOgImagePageScreenshot.mjs +14 -0
  29. package/dist/runtime/core/bindings/css-inline/node.d.ts +2 -5
  30. package/dist/runtime/core/bindings/css-inline/node.mjs +2 -10
  31. package/dist/runtime/core/bindings/resvg/wasm.mjs +2 -5
  32. package/dist/runtime/core/bindings/satori/wasm.mjs +7 -0
  33. package/dist/runtime/core/cache/emojis.d.ts +1 -0
  34. package/dist/runtime/core/cache/emojis.mjs +5 -0
  35. package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
  36. package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
  37. package/dist/runtime/core/cache/prerender.d.ts +1 -1
  38. package/dist/runtime/core/font/fetch.d.ts +2 -3
  39. package/dist/runtime/core/font/fetch.mjs +10 -4
  40. package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
  41. package/dist/runtime/core/html/applyEmojis.mjs +37 -0
  42. package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
  43. package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
  44. package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
  45. package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +8 -31
  46. package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
  47. package/dist/runtime/core/html/fetchIsland.mjs +17 -0
  48. package/dist/runtime/core/options/fetch.d.ts +1 -1
  49. package/dist/runtime/core/options/fetch.mjs +10 -5
  50. package/dist/runtime/core/options/normalise.d.ts +2 -2
  51. package/dist/runtime/core/renderers/chromium/index.mjs +6 -7
  52. package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
  53. package/dist/runtime/core/renderers/chromium/screenshot.mjs +5 -4
  54. package/dist/runtime/core/renderers/satori/fonts.d.ts +2 -2
  55. package/dist/runtime/core/renderers/satori/fonts.mjs +2 -2
  56. package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
  57. package/dist/runtime/core/renderers/satori/index.mjs +21 -18
  58. package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
  59. package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
  60. package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
  61. package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +8 -4
  62. package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
  63. package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
  64. package/dist/runtime/core/renderers/satori/vnodes.mjs +14 -6
  65. package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
  66. package/dist/runtime/core/utils/resolveRendererContext.mjs +34 -21
  67. package/dist/runtime/core/utils/wasm.d.ts +1 -0
  68. package/dist/runtime/core/utils/wasm.mjs +6 -0
  69. package/dist/runtime/nitro/plugins/nuxt-content.mjs +2 -2
  70. package/dist/runtime/nitro/plugins/prerender.mjs +2 -2
  71. package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +1 -1
  72. package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +14 -47
  73. package/dist/runtime/nuxt/utils.d.ts +2 -0
  74. package/dist/runtime/nuxt/utils.mjs +55 -0
  75. package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +0 -2
  76. package/dist/runtime/server/routes/__og-image__/debug.json.mjs +2 -7
  77. package/dist/runtime/server/routes/__og-image__/image.mjs +86 -0
  78. package/dist/runtime/types.d.ts +57 -24
  79. package/dist/runtime/utils.d.ts +3 -0
  80. package/dist/runtime/utils.mjs +11 -0
  81. package/package.json +17 -32
  82. package/virtual.d.ts +49 -0
  83. package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
  84. package/dist/client/_nuxt/builds/meta/3185e4a0-6b15-4476-b2f3-85ef31d35fc6.json +0 -1
  85. package/dist/client/_nuxt/entry.434c2c45.css +0 -1
  86. package/dist/client/_nuxt/entry.e62f04d6.js +0 -137
  87. package/dist/client/grid.png +0 -0
  88. package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
  89. package/dist/runtime/components/OgImage/Cached.mjs +0 -10
  90. package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
  91. package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
  92. package/dist/runtime/components/OgImage/Static.d.ts +0 -8
  93. package/dist/runtime/components/OgImage/Static.mjs +0 -10
  94. package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
  95. package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
  96. package/dist/runtime/components/OgImage/index.d.ts +0 -5
  97. package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
  98. package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
  99. package/dist/runtime/core/bindings/satori/yoga-wasm.mjs +0 -7
  100. package/dist/runtime/core/bindings/sharp/wasm.d.ts +0 -2
  101. package/dist/runtime/core/bindings/sharp/wasm.mjs +0 -2
  102. package/dist/runtime/core/html/fetch.d.ts +0 -3
  103. package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
  104. package/dist/runtime/utilts.d.ts +0 -2
  105. package/dist/runtime/utilts.mjs +0 -8
  106. /package/dist/runtime/core/bindings/satori/{yoga-wasm.d.ts → wasm.d.ts} +0 -0
  107. /package/dist/runtime/server/routes/__og-image__/{image-[path]-og.[extension].d.ts → image.d.ts} +0 -0
package/dist/module.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as fs from 'node:fs';
2
2
  import { existsSync } from 'node:fs';
3
- import { useNuxt, createResolver, addTemplate, defineNuxtModule, useLogger, hasNuxtModule, addServerPlugin, addPlugin, addServerHandler, addImports, addComponentsDir, addComponent } from '@nuxt/kit';
3
+ import { useNuxt, createResolver, addTemplate, resolvePath, defineNuxtModule, useLogger, hasNuxtModule, addServerPlugin, addPlugin, addServerHandler, addImports, addComponentsDir, addComponent } from '@nuxt/kit';
4
4
  import { installNuxtSiteConfig } from 'nuxt-site-config-kit';
5
5
  import { provider, env } from 'std-env';
6
6
  import { hash } from 'ohash';
@@ -8,8 +8,10 @@ import { relative } from 'pathe';
8
8
  import 'nypm';
9
9
  import { defu } from 'defu';
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.10";
14
+ const version = "3.0.0-beta.14";
13
15
 
14
16
  const autodetectableProviders = {
15
17
  azure_static: "azure",
@@ -32,8 +34,7 @@ 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: {
@@ -42,8 +43,8 @@ const cloudflare = {
42
43
  "resvg": "wasm",
43
44
  "satori": "node",
44
45
  "sharp": false
45
- },
46
- wasmStrategy: "import"
46
+ }
47
+ // nitro configures wasm
47
48
  };
48
49
  const awsLambda = {
49
50
  bindings: {
@@ -52,8 +53,7 @@ const awsLambda = {
52
53
  "resvg": "node",
53
54
  "satori": "node",
54
55
  "sharp": "node"
55
- },
56
- wasmStrategy: "inline"
56
+ }
57
57
  };
58
58
  const RuntimeCompatibility = {
59
59
  "nitro-dev": NodeRuntime,
@@ -66,8 +66,7 @@ const RuntimeCompatibility = {
66
66
  "resvg": "wasm",
67
67
  "satori": "node",
68
68
  "sharp": "node"
69
- },
70
- wasmStrategy: "inline"
69
+ }
71
70
  },
72
71
  "aws-lambda": awsLambda,
73
72
  "netlify": awsLambda,
@@ -79,19 +78,25 @@ const RuntimeCompatibility = {
79
78
  "satori": "node",
80
79
  "sharp": false
81
80
  },
82
- wasmStrategy: "inline"
81
+ wasm: {
82
+ rollup: {
83
+ targetEnv: "auto-inline"
84
+ }
85
+ }
83
86
  },
84
87
  "vercel": awsLambda,
85
88
  "vercel-edge": {
86
89
  bindings: {
87
90
  "chromium": false,
88
- "css-inline": "node",
91
+ "css-inline": false,
89
92
  "resvg": "wasm",
90
93
  "satori": "node",
91
- "sharp": "node"
94
+ "sharp": false
92
95
  },
93
- wasmStrategy: "inline",
94
- wasmImportQuery: "?module"
96
+ wasm: {
97
+ // lowers workers kb size
98
+ esmImport: true
99
+ }
95
100
  },
96
101
  "cloudflare-pages": cloudflare,
97
102
  "cloudflare": cloudflare
@@ -132,18 +137,15 @@ function applyNitroPresetCompatibility(nitroConfig, options) {
132
137
  applyBinding("satori"),
133
138
  applyBinding("resvg"),
134
139
  applyBinding("sharp"),
140
+ applyBinding("css-inline"),
135
141
  nitroConfig.alias || {}
136
142
  );
137
- nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
138
- if (target === "netlify-edge") {
139
- nitroConfig.wasm = nitroConfig.wasm || {};
140
- nitroConfig.wasm.rollup = nitroConfig.wasm.rollup || {};
141
- nitroConfig.wasm.rollup.targetEnv = "auto-inline";
142
- }
143
- if (target.includes("edge") || target.includes("cloudflare")) {
143
+ if (Object.values(compatibility.bindings).includes("wasm")) {
144
144
  nitroConfig.experimental = nitroConfig.experimental || {};
145
145
  nitroConfig.experimental.wasm = true;
146
146
  }
147
+ nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
148
+ nitroConfig.wasm = defu(compatibility.wasm, nitroConfig.wasm);
147
149
  return compatibility;
148
150
  }
149
151
 
@@ -272,13 +274,27 @@ async function setupBuildHandler(config, resolve, nuxt = useNuxt()) {
272
274
  nitroConfig.alias["utf-8-validate"] = "unenv/runtime/mock/proxy-cjs";
273
275
  nitroConfig.alias.queue = "unenv/runtime/mock/proxy-cjs";
274
276
  });
277
+ nuxt.hooks.hook("nitro:init", async (nitro) => {
278
+ nitro.hooks.hook("compiled", async (_nitro) => {
279
+ const configuredEntry = nitro.options.rollupConfig?.output.entryFileNames;
280
+ const serverEntry = resolve(_nitro.options.output.serverDir, typeof configuredEntry === "string" ? configuredEntry : "index.mjs");
281
+ const contents = await readFile(serverEntry, "utf-8");
282
+ const wasmSource = await readFile(await resolvePath("@resvg/resvg-wasm/index_bg.wasm"));
283
+ const wasmHash = sha1(wasmSource);
284
+ const postfix = _nitro.options.preset === "vercel-edge" ? "?module" : "";
285
+ await writeFile(serverEntry, contents.replaceAll('"@resvg/resvg-wasm/index_bg.wasm"', `"./wasm/index_bg-${wasmHash}.wasm${postfix}"`), { encoding: "utf-8" });
286
+ });
287
+ });
288
+ }
289
+ function sha1(source) {
290
+ return createHash("sha1").update(source).digest("hex").slice(0, 16);
275
291
  }
276
292
 
277
293
  const module = defineNuxtModule({
278
294
  meta: {
279
295
  name: "nuxt-og-image",
280
296
  compatibility: {
281
- nuxt: "^3.7.0",
297
+ nuxt: "^3.8.2",
282
298
  bridge: false
283
299
  },
284
300
  configKey: "ogImage"
@@ -287,13 +303,13 @@ const module = defineNuxtModule({
287
303
  return {
288
304
  enabled: true,
289
305
  defaults: {
306
+ emojis: "noto",
290
307
  renderer: "satori",
291
308
  component: "Fallback",
292
309
  width: 1200,
293
310
  height: 600,
294
- cache: true,
295
311
  // default is to cache the image for 1 day (24 hours)
296
- cacheTtl: 24 * 60 * 60 * 1e3
312
+ cacheMaxAgeSeconds: 60 * 60 * 24 * 3
297
313
  },
298
314
  componentDirs: ["OgImage", "OgImageTemplate"],
299
315
  runtimeSatori: true,
@@ -318,9 +334,17 @@ const module = defineNuxtModule({
318
334
  const { resolve } = createResolver(import.meta.url);
319
335
  const preset = resolveNitroPreset(nuxt.options.nitro);
320
336
  const compatibility = getPresetNitroPresetCompatibility(preset);
321
- config.defaults.extension = "jpg";
322
- if (!compatibility.bindings.sharp)
337
+ const userConfiguredExtension = config.defaults.extension;
338
+ config.defaults.extension = userConfiguredExtension || "jpg";
339
+ if (!compatibility.bindings.sharp && config.defaults.renderer !== "chromium") {
340
+ if (userConfiguredExtension && ["jpeg", "jpg"].includes(userConfiguredExtension))
341
+ logger.warn("The sharp runtime is not available for this target, disabling sharp and using png instead.");
323
342
  config.defaults.extension = "png";
343
+ }
344
+ if (config.runtimeBrowser && !compatibility.bindings.chromium) {
345
+ logger.warn("The Chromium runtime is not available for this target, disabling runtimeBrowser.");
346
+ config.runtimeBrowser = false;
347
+ }
324
348
  await installNuxtSiteConfig();
325
349
  if (hasNuxtModule("@nuxt/content")) {
326
350
  addServerPlugin(resolve("./runtime/nitro/plugins/nuxt-content"));
@@ -344,24 +368,13 @@ const module = defineNuxtModule({
344
368
  addServerHandler({
345
369
  lazy: true,
346
370
  route: "/__og-image__/image/**",
347
- handler: resolve("./runtime/server/routes/__og-image__/image-[path]-og.[extension]")
371
+ handler: resolve("./runtime/server/routes/__og-image__/image")
348
372
  });
349
373
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"] = [];
350
- [
351
- // deprecated
352
- "Dynamic",
353
- "Static",
354
- // new
355
- "index",
356
- "Cached",
357
- "Component",
358
- "WithoutCache",
359
- "Screenshot"
360
- ].forEach((name) => {
361
- name = name === "index" ? "defineOgImage" : `defineOgImage${name}`;
374
+ ["defineOgImage", "defineOgImageComponent", "defineOgImageScreenshot"].forEach((name) => {
362
375
  addImports({
363
376
  name,
364
- from: resolve("./runtime/composables/defineOgImage")
377
+ from: resolve(`./runtime/composables/${name}`)
365
378
  });
366
379
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"].push(name);
367
380
  });
@@ -374,18 +387,12 @@ const module = defineNuxtModule({
374
387
  island: true
375
388
  });
376
389
  [
377
- // deprecated
378
- "Static",
379
- "Dynamic",
380
390
  // new
381
- "index",
382
- "Cached",
383
- "WithoutCache",
384
- "Screenshot"
391
+ "OgImage",
392
+ "OgImageScreenshot"
385
393
  ].forEach((name) => {
386
394
  addComponent({
387
- global: hasNuxtModule("@nuxt/content"),
388
- name: name === "index" ? "OgImage" : `OgImage${name}`,
395
+ name,
389
396
  filePath: resolve(`./runtime/components/OgImage/${name}`)
390
397
  });
391
398
  });
@@ -443,12 +450,13 @@ const module = defineNuxtModule({
443
450
  return `
444
451
  declare module 'nitropack' {
445
452
  interface NitroRouteRules {
446
- ogImage?: false | import('${typesPath}').OgImageOptions
453
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
447
454
  }
448
455
  interface NitroRouteConfig {
449
- ogImage?: false | import('${typesPath}').OgImageOptions
456
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
450
457
  }
451
458
  }
459
+
452
460
  declare module '#nuxt-og-image/components' {
453
461
  export interface OgImageComponents {
454
462
  ${componentImports}
@@ -456,6 +464,11 @@ ${componentImports}
456
464
  }
457
465
  `;
458
466
  });
467
+ const cacheEnabled = typeof config.runtimeCacheStorage !== "undefined" && config.runtimeCacheStorage !== false;
468
+ const runtimeCacheStorage = typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver;
469
+ let baseCacheKey = runtimeCacheStorage === "default" ? `/cache/nuxt-og-image@${version}` : `/nuxt-og-image@${version}`;
470
+ if (!cacheEnabled)
471
+ baseCacheKey = false;
459
472
  nuxt.hooks.hook("modules:done", async () => {
460
473
  nuxt.hooks.callHook("og-image:config", config);
461
474
  const normalisedFonts = config.fonts.map((f) => {
@@ -486,8 +499,10 @@ ${componentImports}
486
499
  runtimeBrowser: config.runtimeBrowser,
487
500
  // @ts-expect-error runtime type
488
501
  defaults: config.defaults,
502
+ debug: config.debug,
489
503
  // avoid adding credentials
490
- runtimeCacheStorage: typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver,
504
+ // @ts-expect-error runtime type
505
+ baseCacheKey,
491
506
  // convert the fonts to uniform type to fix ts issue
492
507
  fonts: normalisedFonts,
493
508
  hasNuxtIcon: hasNuxtModule("nuxt-icon")
@@ -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 { H3EventOgImageRender } from './core/utils/resolveRendererContext';
2
+ export declare function useOgImageBufferCache(ctx: H3EventOgImageRender, 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,57 @@
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 = maxAge > 0;
9
+ const cache = prefixStorage(useStorage(), withTrailingSlash(options.baseCacheKey || "/"));
10
+ const key = ctx.key;
11
+ const purge = typeof getQuery(ctx.e).purge !== "undefined";
15
12
  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() }));
13
+ if (enabled && await cache.hasItem(key).catch(() => false)) {
14
+ const { value, expiresAt, headers } = await cache.getItem(key).catch(() => ({ value: null, expiresAt: Date.now() }));
18
15
  if (purge) {
19
- xCacheHeader = "PURGE";
20
- xCacheExpires = newExpires;
21
16
  await cache.removeItem(key).catch(() => {
22
17
  });
23
18
  } else if (expiresAt > Date.now()) {
24
- xCacheHeader = "HIT";
25
- xCacheExpires = newExpires;
26
- cachedItem = value;
19
+ cachedItem = Buffer.from(value, "base64");
20
+ if (handleCacheHeaders(ctx.e, {
21
+ modifiedTime: new Date(headers["last-modified"]),
22
+ etag: headers.etag,
23
+ maxAge
24
+ }))
25
+ return;
26
+ setHeaders(ctx.e, headers);
27
27
  } else {
28
- xCacheHeader = "MISS";
29
- xCacheExpires = expiresAt;
30
28
  await cache.removeItem(key).catch(() => {
31
29
  });
32
30
  }
33
31
  }
34
- if (options.headers) {
35
- setHeader(e, `x-${module}-cache`, xCacheHeader);
36
- setHeader(e, `x-${module}-expires`, xCacheExpires.toString());
32
+ if (!enabled) {
33
+ setHeader(ctx.e, "Cache-Control", "no-cache, no-store, must-revalidate");
34
+ setHeader(ctx.e, "Pragma", "no-cache");
35
+ setHeader(ctx.e, "Expires", "0");
37
36
  }
38
37
  return {
39
38
  enabled,
40
39
  cachedItem,
41
40
  async update(item) {
42
- enabled && await cache.setItem(key, { value: item, expiresAt: Date.now() + (options.cacheTtl || 0) });
41
+ const value = Buffer.from(item).toString("base64");
42
+ const headers = {
43
+ // avoid multi-tenancy cache issues
44
+ "Vary": "accept-encoding, host",
45
+ "etag": `W/"${hash(value)}"`,
46
+ "last-modified": (/* @__PURE__ */ new Date()).toUTCString(),
47
+ "cache-control": `public, s-maxage=${maxAge}, stale-while-revalidate`
48
+ };
49
+ setHeaders(ctx.e, headers);
50
+ enabled && await cache.setItem(key, {
51
+ value,
52
+ headers,
53
+ expiresAt: Date.now() + maxAge * 1e3
54
+ });
43
55
  }
44
56
  };
45
57
  }
@@ -0,0 +1,5 @@
1
+ import type { OgImageOptions } from '../../types';
2
+ declare const _default: import("vue").DefineComponent<OgImageOptions<"Fallback">, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<OgImageOptions<"Fallback">>, {
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
  });
@@ -1,6 +1,5 @@
1
- import type { OgImageScreenshotOptions } from '../../types';
2
- declare const _default: import("vue").DefineComponent<OgImageScreenshotOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageScreenshotOptions>>, {
3
- [x: string]: any;
4
- [x: number]: any;
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;
5
4
  }, {}>;
6
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
  });
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { parseURL } from 'ufo'
3
+ import { computed, useSiteConfig } from '#imports'
3
4
 
4
5
  // inherited attrs can mess up the satori parser
5
6
  defineOptions({ inheritAttrs: false })
@@ -1,23 +1,2 @@
1
- import type { AllowedComponentProps, Component, ComponentCustomProps, VNodeProps } from '@vue/runtime-core';
2
- import type { OgImageOptions, OgImageScreenshotOptions } from '../types';
3
- import type { OgImageComponents } from '#nuxt-og-image/components';
4
- export declare function defineOgImageScreenshot(options?: OgImageScreenshotOptions): void;
5
- /**
6
- * @param options
7
- * @deprecated Use `defineOgImage` or `defineOgImageCached` instead
8
- */
9
- export declare function defineOgImageStatic(options?: OgImageOptions): void;
10
- export declare function defineOgImageCached(options?: OgImageOptions): void;
11
- export declare function defineOgImageWithoutCache(options?: OgImageOptions): void;
12
- /**
13
- * @param options
14
- * @deprecated Use `defineOgImageWithoutCache` instead
15
- */
16
- export declare function defineOgImageDynamic(options?: OgImageOptions): void;
17
- type OgImagePrebuilt = {
18
- url: string;
19
- } & Pick<OgImageOptions, 'width' | 'height' | 'alt'>;
20
- type ExtractComponentProps<T extends Component> = T extends new (...args: any) => any ? Omit<InstanceType<T>['$props'], keyof ComponentCustomProps | keyof VNodeProps | keyof AllowedComponentProps> : never;
21
- export declare function defineOgImageComponent<T extends keyof OgImageComponents>(component: T, props: ExtractComponentProps<OgImageComponents[T]>, options?: OgImageOptions): void;
22
- export declare function defineOgImage(_options?: OgImagePrebuilt | OgImageOptions): void;
23
- export {};
1
+ import type { DefineOgImageInput } from '../types';
2
+ export declare function defineOgImage(_options?: DefineOgImageInput): void;
@@ -1,124 +1,41 @@
1
1
  import { defu } from "defu";
2
2
  import { appendHeader } from "h3";
3
- import { getOgImagePath } from "../utilts.mjs";
3
+ import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
4
+ import { withoutBase } from "ufo";
5
+ import { getOgImagePath } from "../utils.mjs";
4
6
  import { normaliseOptions } from "../core/options/normalise.mjs";
5
- import { useRouter, useRuntimeConfig, useServerHead, withSiteUrl } from "#imports";
6
- export function defineOgImageScreenshot(options = {}) {
7
- const router = useRouter();
8
- const route = router.currentRoute.value?.path || "";
9
- return defineOgImage({
10
- alt: `Web page screenshot${route ? ` of ${route}` : ""}.`,
11
- renderer: "chromium",
12
- extension: "jpeg",
13
- component: "PageScreenshot",
14
- // this is an alias
15
- cache: true,
16
- ...options
7
+ import { createOgImageMeta } from "../nuxt/utils.mjs";
8
+ import { useNuxtApp, useRequestEvent, useRouter, useRuntimeConfig } from "#imports";
9
+ export function defineOgImage(_options = {}) {
10
+ if (!import.meta.server)
11
+ return;
12
+ const nuxtApp = useNuxtApp();
13
+ const ogImageInstances = nuxtApp.ssrContext._ogImageInstances || [];
14
+ const basePath = useRouter().currentRoute.value?.path;
15
+ const _routeRulesMatcher = toRouteMatcher(
16
+ createRadixRouter({ routes: useRuntimeConfig().nitro?.routeRules })
17
+ );
18
+ const routeRules = defu({}, ..._routeRulesMatcher.matchAll(
19
+ withoutBase(basePath.split("?")[0], useRuntimeConfig().app.baseURL)
20
+ ).reverse()).ogImage;
21
+ if (!_options || nuxtApp.ssrContext?.event.context._nitro?.routeRules?.ogImage === false || typeof routeRules !== "undefined" && routeRules === false) {
22
+ ogImageInstances.forEach((e) => {
23
+ e.dispose();
24
+ });
25
+ nuxtApp.ssrContext._ogImageInstances = void 0;
26
+ return;
27
+ }
28
+ const options = normaliseOptions({
29
+ ..._options
17
30
  });
18
- }
19
- export function defineOgImageStatic(options = {}) {
20
- return defineOgImageCached(options);
21
- }
22
- export function defineOgImageCached(options = {}) {
23
31
  const { defaults } = useRuntimeConfig()["nuxt-og-image"];
24
- if (!defaults.cacheTtl && !options.cacheTtl)
25
- options.cacheTtl = 60 * 60 * 24 * 1e3 * 7;
26
- return defineOgImage({
27
- cache: true,
28
- ...options
29
- });
30
- }
31
- export function defineOgImageWithoutCache(options = {}) {
32
- return defineOgImage({
33
- ...options,
34
- cache: false,
35
- cacheTtl: 0
36
- });
37
- }
38
- export function defineOgImageDynamic(options = {}) {
39
- return defineOgImageWithoutCache(options);
40
- }
41
- export function defineOgImageComponent(component, props, options = {}) {
42
- defineOgImage({
43
- component,
44
- ...props,
45
- ...options
46
- });
47
- }
48
- export function defineOgImage(_options = {}) {
49
- if (import.meta.server) {
50
- if (_options.url) {
51
- const type = _options.url.endsWith(".png") ? "image/png" : "image/jpeg";
52
- const meta2 = [
53
- { property: "og:image", content: _options.url },
54
- { property: "og:image:type", content: type },
55
- { name: "twitter:card", content: "summary_large_image" },
56
- { name: "twitter:image:src", content: _options.url }
57
- ];
58
- if (_options.width) {
59
- meta2.push({ property: "og:image:width", content: _options.width });
60
- meta2.push({ name: "twitter:image:width", content: _options.width });
61
- }
62
- if (_options.height) {
63
- meta2.push({ property: "og:image:height", content: _options.height });
64
- meta2.push({ name: "twitter:image:height", content: _options.height });
65
- }
66
- if (_options.alt) {
67
- meta2.push({ property: "og:image:alt", content: _options.alt });
68
- meta2.push({ name: "twitter:image:alt", content: _options.alt });
69
- }
70
- useServerHead({ meta: meta2 }, {
71
- // after async scripts when capo.js is enabled
72
- tagPriority: 35
73
- });
74
- return;
75
- }
76
- const { defaults } = useRuntimeConfig()["nuxt-og-image"];
77
- const options = normaliseOptions(_options);
78
- const optionsWithDefault = defu(options, defaults);
79
- const path = getOgImagePath(useRouter().currentRoute.value?.path, optionsWithDefault.extension);
80
- const src = withSiteUrl(path);
32
+ const resolvedOptions = normaliseOptions(defu(options, routeRules, defaults));
33
+ if (_options.url) {
34
+ createOgImageMeta(null, options, resolvedOptions, nuxtApp.ssrContext);
35
+ } else {
36
+ const path = getOgImagePath(basePath, resolvedOptions);
81
37
  if (import.meta.prerender)
82
38
  appendHeader(useRequestEvent(), "x-nitro-prerender", path);
83
- const meta = [
84
- { property: "og:image", content: src },
85
- { property: "og:image:width", content: optionsWithDefault.width },
86
- { property: "og:image:height", content: optionsWithDefault.height },
87
- { property: "og:image:type", content: `image/${optionsWithDefault.extension}` }
88
- ];
89
- if (optionsWithDefault.alt)
90
- meta.push({ property: "og:image:alt", content: optionsWithDefault.alt });
91
- meta.push(...[
92
- { name: "twitter:card", content: "summary_large_image" },
93
- { name: "twitter:image:src", content: src },
94
- { name: "twitter:image:width", content: optionsWithDefault.width },
95
- { name: "twitter:image:height", content: optionsWithDefault.height }
96
- ]);
97
- if (optionsWithDefault.alt)
98
- meta.push({ name: "twitter:image:alt", content: optionsWithDefault.alt });
99
- useServerHead({
100
- meta,
101
- script: [
102
- {
103
- id: "nuxt-og-image-options",
104
- type: "application/json",
105
- processTemplateParams: true,
106
- innerHTML: () => {
107
- const payload = {
108
- title: "%s"
109
- };
110
- Object.entries(options).forEach(([key, val]) => {
111
- payload[key.replace(/-([a-z])/g, (g) => g[1].toUpperCase())] = val;
112
- });
113
- return payload;
114
- },
115
- // we want this to be last in our head
116
- tagPosition: "bodyClose"
117
- }
118
- ]
119
- }, {
120
- // after async scripts when capo.js is enabled
121
- tagPriority: 35
122
- });
39
+ createOgImageMeta(path, options, resolvedOptions, nuxtApp.ssrContext);
123
40
  }
124
41
  }
@@ -0,0 +1,3 @@
1
+ import type { ExtractComponentProps, OgImageOptions } from '../types';
2
+ import type { OgImageComponents } from '#nuxt-og-image/components';
3
+ export declare function defineOgImageComponent<T extends keyof OgImageComponents>(component: T, props: ExtractComponentProps<OgImageComponents[T]>, options?: OgImageOptions): void;
@@ -0,0 +1,8 @@
1
+ import { defineOgImage } from "./defineOgImage.mjs";
2
+ export function defineOgImageComponent(component, props, options = {}) {
3
+ return defineOgImage({
4
+ component,
5
+ props,
6
+ ...options
7
+ });
8
+ }
@@ -0,0 +1,2 @@
1
+ import type { OgImagePageScreenshotOptions } from '../types';
2
+ export declare function defineOgImageScreenshot(options?: OgImagePageScreenshotOptions): any;
@@ -0,0 +1,14 @@
1
+ import { defineOgImage, useRouter } from "#imports";
2
+ export function defineOgImageScreenshot(options = {}) {
3
+ const router = useRouter();
4
+ const route = router.currentRoute.value?.path || "";
5
+ return defineOgImage({
6
+ alt: `Web page screenshot${route ? ` of ${route}` : ""}.`,
7
+ renderer: "chromium",
8
+ extension: "jpeg",
9
+ component: "PageScreenshot",
10
+ // this is an alias
11
+ cache: true,
12
+ ...options
13
+ });
14
+ }
@@ -1,5 +1,2 @@
1
- declare function nodeFn(html: string, options: any): string;
2
- declare namespace nodeFn {
3
- var __mock: boolean;
4
- }
5
- export default nodeFn;
1
+ import cssInline from 'css-inline';
2
+ export default cssInline;
@@ -1,10 +1,2 @@
1
- import { inline } from "css-inline";
2
- function nodeFn(html, options) {
3
- return inline(html, {
4
- ...options,
5
- load_remote_stylesheets: false,
6
- keep_style_tags: false
7
- });
8
- }
9
- nodeFn.__mock = false;
10
- export default nodeFn;
1
+ import cssInline from "css-inline";
2
+ export default cssInline;