nuxt-og-image 6.10.3 → 7.0.0

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 (103) hide show
  1. package/README.md +10 -14
  2. package/dist/chunks/tw4.mjs +6 -6
  3. package/dist/chunks/uno.mjs +7 -7
  4. package/dist/cli.mjs +4 -4
  5. package/dist/devtools/components/og-image/RendererSelectModal.vue +1 -1
  6. package/dist/devtools/lib/og-image/fonts.ts +38 -0
  7. package/dist/devtools/lib/og-image/types.ts +7 -0
  8. package/dist/devtools/pages/og-image/index.vue +19 -14
  9. package/dist/module.d.mts +14 -10
  10. package/dist/module.d.ts +14 -10
  11. package/dist/module.json +2 -2
  12. package/dist/module.mjs +6 -6
  13. package/dist/runtime/app/client-utils.js +7 -4
  14. package/dist/runtime/app/components/Templates/Community/SaaS.satori.vue +1 -1
  15. package/dist/runtime/app/components/Templates/Community/SimpleBlog.satori.vue +1 -1
  16. package/dist/runtime/app/disabled/components.d.ts +1 -0
  17. package/dist/runtime/app/disabled/components.js +0 -0
  18. package/dist/runtime/app/disabled/composables/defineOgImage.d.ts +1 -0
  19. package/dist/runtime/app/disabled/composables/defineOgImage.js +1 -0
  20. package/dist/runtime/app/disabled/composables/defineOgImageComponent.d.ts +1 -0
  21. package/dist/runtime/app/disabled/composables/defineOgImageComponent.js +1 -0
  22. package/dist/runtime/app/disabled/composables/defineOgImageScreenshot.d.ts +1 -0
  23. package/dist/runtime/app/disabled/composables/defineOgImageScreenshot.js +1 -0
  24. package/dist/runtime/app/disabled/composables/mock.d.ts +1 -0
  25. package/dist/runtime/app/disabled/composables/mock.js +1 -0
  26. package/dist/runtime/app/disabled/index.d.ts +3 -0
  27. package/dist/runtime/app/disabled/index.js +3 -0
  28. package/dist/runtime/app/index.d.ts +4 -0
  29. package/dist/runtime/app/index.js +4 -0
  30. package/dist/runtime/app/utils/plugins.js +1 -1
  31. package/dist/runtime/app/utils.js +2 -2
  32. package/dist/runtime/server/index.d.ts +1 -0
  33. package/dist/runtime/server/index.js +1 -0
  34. package/dist/runtime/server/middleware/signing.d.ts +2 -0
  35. package/dist/runtime/server/middleware/signing.js +19 -0
  36. package/dist/runtime/server/nitro.d.ts +3 -3
  37. package/dist/runtime/server/nitro.js +4 -4
  38. package/dist/runtime/server/og-image/bindings/font-assets/dev-prerender.js +8 -49
  39. package/dist/runtime/server/og-image/bindings/font-assets/node.js +3 -2
  40. package/dist/runtime/server/og-image/bindings/satori/node.d.ts +1 -2
  41. package/dist/runtime/server/og-image/bindings/satori/wasm-fs.d.ts +1 -2
  42. package/dist/runtime/server/og-image/bindings/satori/wasm-fs.js +1 -1
  43. package/dist/runtime/server/og-image/bindings/satori/wasm.d.ts +1 -2
  44. package/dist/runtime/server/og-image/bindings/satori/wasm.js +1 -1
  45. package/dist/runtime/server/og-image/browser/screenshot.js +5 -3
  46. package/dist/runtime/server/og-image/cache/publish.d.ts +43 -0
  47. package/dist/runtime/server/og-image/cache/publish.js +91 -0
  48. package/dist/runtime/server/og-image/cache/published.d.ts +17 -0
  49. package/dist/runtime/server/og-image/cache/published.js +49 -0
  50. package/dist/runtime/server/og-image/context.js +1 -1
  51. package/dist/runtime/server/og-image/core/plugins/imageSrc.js +2 -5
  52. package/dist/runtime/server/og-image/core/transforms/emojis/index.d.ts +3 -2
  53. package/dist/runtime/server/og-image/core/vnodes.js +19 -1
  54. package/dist/runtime/server/og-image/font-source.d.ts +1 -0
  55. package/dist/runtime/server/og-image/font-source.js +1 -0
  56. package/dist/runtime/server/og-image/fonts.d.ts +1 -1
  57. package/dist/runtime/server/og-image/fonts.js +1 -1
  58. package/dist/runtime/server/og-image/satori/filters.d.ts +1 -0
  59. package/dist/runtime/server/og-image/satori/filters.js +14 -0
  60. package/dist/runtime/server/og-image/satori/instances.d.ts +1 -2
  61. package/dist/runtime/server/og-image/satori/plugins/classes.js +0 -7
  62. package/dist/runtime/server/og-image/satori/renderer.js +2 -1
  63. package/dist/runtime/server/og-image/satori/vnodes.js +1 -4
  64. package/dist/runtime/server/og-image/takumi/renderer.js +11 -47
  65. package/dist/runtime/server/og-image/utils/css.d.ts +0 -5
  66. package/dist/runtime/server/og-image/utils/css.js +0 -5
  67. package/dist/runtime/server/plugins/auto-eject-nitro3.d.ts +2 -0
  68. package/dist/runtime/server/plugins/auto-eject-nitro3.js +9 -0
  69. package/dist/runtime/server/plugins/auto-eject.js +3 -31
  70. package/dist/runtime/server/plugins/prerender.js +68 -2
  71. package/dist/runtime/server/plugins/publish.d.ts +2 -0
  72. package/dist/runtime/server/plugins/publish.js +44 -0
  73. package/dist/runtime/server/routes/debug.json.d.ts +10 -1
  74. package/dist/runtime/server/routes/debug.json.js +4 -4
  75. package/dist/runtime/server/routes/static-font.d.ts +2 -0
  76. package/dist/runtime/server/routes/static-font.js +22 -0
  77. package/dist/runtime/server/signing-secret.d.ts +8 -0
  78. package/dist/runtime/server/signing-secret.js +75 -0
  79. package/dist/runtime/server/util/auto-eject-lifecycle.d.ts +13 -0
  80. package/dist/runtime/server/util/auto-eject-lifecycle.js +31 -0
  81. package/dist/runtime/server/util/cache.d.ts +1 -0
  82. package/dist/runtime/server/util/cache.js +12 -6
  83. package/dist/runtime/server/util/cloudflare.d.ts +2 -2
  84. package/dist/runtime/server/util/eventHandlers.js +69 -3
  85. package/dist/runtime/server/util/fetchLocalAsset.js +2 -2
  86. package/dist/runtime/server/util/origin.d.ts +3 -0
  87. package/dist/runtime/server/util/origin.js +4 -0
  88. package/dist/runtime/server/util/publishWarnings.d.ts +6 -0
  89. package/dist/runtime/server/util/publishWarnings.js +6 -0
  90. package/dist/runtime/server/utils.d.ts +3 -3
  91. package/dist/runtime/server/utils.js +5 -10
  92. package/dist/runtime/shared/publish.d.ts +13 -0
  93. package/dist/runtime/shared/publish.js +17 -0
  94. package/dist/runtime/shared/urlEncoding.js +9 -4
  95. package/dist/runtime/types.d.ts +11 -16
  96. package/dist/shared/{nuxt-og-image.Bcegsloy.mjs → nuxt-og-image.DR_SxdDv.mjs} +1224 -1109
  97. package/package.json +60 -62
  98. package/skills/nuxt-og-image/SKILL.md +31 -14
  99. package/types/virtual.d.ts +8 -0
  100. package/dist/runtime/server/og-image/satori/plugins/emojis.d.ts +0 -2
  101. package/dist/runtime/server/og-image/satori/plugins/emojis.js +0 -112
  102. package/dist/runtime/server/og-image/satori/plugins/flex.d.ts +0 -2
  103. package/dist/runtime/server/og-image/satori/plugins/flex.js +0 -48
@@ -1,12 +1,17 @@
1
- import { appendResponseHeader, createError, getRequestHost, H3Error, setHeader } from "#nuxtseo/h3";
1
+ import { appendResponseHeader, createError, getRequestHost, H3Error, sendRedirect, setHeader } from "#nuxtseo/h3";
2
+ import { useStorage } from "#nuxtseo/nitro";
2
3
  import { getSiteConfig } from "#site-config/server/composables/getSiteConfig";
3
4
  import { logger } from "../../logger.js";
4
5
  import { getBuildCachedImage, setBuildCachedImage } from "../og-image/cache/buildCache.js";
6
+ import { getPublishedImage, getPublishKey, publishImage } from "../og-image/cache/publish.js";
7
+ import { getPublishedImageCache, getPublishedImageCacheKey } from "../og-image/cache/published.js";
5
8
  import { resolveContext } from "../og-image/context.js";
6
9
  import { fetchPathHtmlAndExtractOptions } from "../og-image/devtools.js";
7
10
  import { html } from "../og-image/templates/html.js";
8
11
  import { useOgImageRuntimeConfig } from "../utils.js";
9
12
  import { useOgImageBufferCache } from "./cache.js";
13
+ import { warnPublishUnavailable } from "./publishWarnings.js";
14
+ import { getEventQuery } from "./query.js";
10
15
  export async function imageEventHandler(e) {
11
16
  const reqStart = performance.now();
12
17
  const ctx = await resolveContext(e).catch((err) => {
@@ -29,7 +34,8 @@ export async function imageEventHandler(e) {
29
34
  async function renderOgImage(e, ctx) {
30
35
  const timings = ctx.timings;
31
36
  const { isDevToolsContextRequest, extension, renderer } = ctx;
32
- const { debug, baseCacheKey, security } = useOgImageRuntimeConfig(e);
37
+ const config = useOgImageRuntimeConfig(e);
38
+ const { debug, baseCacheKey, security, publish } = config;
33
39
  if (!import.meta.prerender && !import.meta.dev && security?.restrictRuntimeImagesToOrigin) {
34
40
  const requestHost = getRequestHost(e, { xForwardedHost: true });
35
41
  let requestHostname;
@@ -116,11 +122,43 @@ async function renderOgImage(e, ctx) {
116
122
  timings.record("cache-hit", 0);
117
123
  return buildCachedImage;
118
124
  }
125
+ const purge = typeof getEventQuery(e).purge !== "undefined";
126
+ let publication = publish && !import.meta.dev && !import.meta.prerender ? (() => {
127
+ const key = getPublishKey(new URL(e.path, getSiteConfig(e).url).href, config.defaults, publish.cacheVersion);
128
+ return {
129
+ cache: getPublishedImageCache(ctx._nitro),
130
+ cacheKey: getPublishedImageCacheKey(publish, key, extension),
131
+ input: {
132
+ storage: useStorage(),
133
+ mount: publish.storage,
134
+ baseURL: publish.baseURL,
135
+ key,
136
+ extension,
137
+ maxAgeSeconds: Number(ctx.options.cacheMaxAgeSeconds),
138
+ timeoutMs: security.renderTimeout,
139
+ now: Date.now
140
+ }
141
+ };
142
+ })() : void 0;
143
+ if (publication && !purge && !publication.cache.isPublishing(publication.cacheKey, Date.now())) {
144
+ const result = await getPublishedImage(publication.input);
145
+ if (result._tag === "Published" && result.expiresAt > Date.now()) {
146
+ publication.cache.remember(publication.cacheKey, result, Date.now());
147
+ const remainingAge = Math.max(0, Math.floor((result.expiresAt - Date.now()) / 1e3));
148
+ setHeader(e, "Cache-Control", `public, max-age=${remainingAge}, s-maxage=${remainingAge}`);
149
+ return sendRedirect(e, result.url, 302);
150
+ }
151
+ publication.cache.forget(publication.cacheKey);
152
+ if (result._tag === "Unavailable") {
153
+ warnPublishUnavailable(ctx._nitro, result.reason, logger);
154
+ publication = void 0;
155
+ }
156
+ }
119
157
  const endCacheLookup = timings.start("cache-lookup");
120
158
  const cacheApi = await useOgImageBufferCache(ctx, {
121
159
  cacheMaxAgeSeconds: ctx.options.cacheMaxAgeSeconds,
122
160
  baseCacheKey,
123
- secret: security?.secret
161
+ secret: security?.secret || void 0
124
162
  }).finally(endCacheLookup);
125
163
  if (typeof cacheApi === "undefined") {
126
164
  return;
@@ -128,6 +166,8 @@ async function renderOgImage(e, ctx) {
128
166
  if (cacheApi instanceof H3Error) {
129
167
  return cacheApi;
130
168
  }
169
+ if (publication && purge)
170
+ publication.cache.forget(publication.cacheKey);
131
171
  let image = cacheApi.cachedItem;
132
172
  if (image) {
133
173
  timings.record("cache-hit", 0);
@@ -166,5 +206,31 @@ async function renderOgImage(e, ctx) {
166
206
  setBuildCachedImage(ctx.options, extension, image, ctx.options.cacheMaxAgeSeconds);
167
207
  }
168
208
  }
209
+ if (publication) {
210
+ const maxAge = Number(ctx.options.cacheMaxAgeSeconds);
211
+ const expiresAt = cacheApi.expiresAt || Date.now() + (Number.isFinite(maxAge) ? Math.max(0, maxAge) : 0) * 1e3;
212
+ const remainingAge = Math.max(0, (expiresAt - Date.now()) / 1e3);
213
+ const { cache, cacheKey, input } = publication;
214
+ const token = cache.begin(cacheKey, Date.now(), input.timeoutMs);
215
+ if (token) {
216
+ const bytes = new Uint8Array(image);
217
+ const app = ctx._nitro;
218
+ const task = publishImage({
219
+ ...input,
220
+ maxAgeSeconds: remainingAge,
221
+ expiresAt,
222
+ force: true,
223
+ render: async () => bytes
224
+ }).then((result) => {
225
+ cache.complete(cacheKey, token, result, Date.now());
226
+ if (result._tag === "Unavailable")
227
+ warnPublishUnavailable(app, result.reason, logger);
228
+ }).catch((reason) => {
229
+ cache.complete(cacheKey, token, { _tag: "Unavailable" }, Date.now());
230
+ warnPublishUnavailable(app, reason, logger);
231
+ });
232
+ e.waitUntil(task);
233
+ }
234
+ }
169
235
  return image;
170
236
  }
@@ -1,7 +1,7 @@
1
1
  import { $fetch } from "ofetch";
2
2
  import { fetchWithEvent } from "#nuxtseo/nitro";
3
- import { getNitroOrigin } from "#site-config/server/composables";
4
3
  import { tryCloudflareAssetsFetch } from "./cloudflareAssets.js";
4
+ import { getOgImageOrigin } from "./origin.js";
5
5
  export async function fetchLocalAsset(event, path, options) {
6
6
  const { fetchTimeout, headers, includeExternalFallback = false, onStepFailure } = options;
7
7
  const deadline = AbortSignal.timeout(fetchTimeout);
@@ -30,7 +30,7 @@ export async function fetchLocalAsset(event, path, options) {
30
30
  }));
31
31
  if (result || expired || !includeExternalFallback)
32
32
  return result;
33
- const absolute = `${getNitroOrigin(event)}${path}`;
33
+ const absolute = `${getOgImageOrigin(event)}${path}`;
34
34
  return await race($fetch(absolute, {
35
35
  responseType: "arrayBuffer",
36
36
  signal: deadline,
@@ -0,0 +1,3 @@
1
+ import type { RequestEvent } from 'nuxt/server';
2
+ /** Site Config captures the request origin before renderer and cache hooks run. */
3
+ export declare function getOgImageOrigin(event: Pick<RequestEvent, 'context'>): string;
@@ -0,0 +1,4 @@
1
+ import { getNitroOrigin } from "#site-config/server/composables";
2
+ export function getOgImageOrigin(event) {
3
+ return getNitroOrigin({ context: event.context });
4
+ }
@@ -0,0 +1,6 @@
1
+ import type { OgImageRenderEventContext } from '../../types.js';
2
+ export declare function warnPublishUnavailable(app: OgImageRenderEventContext['_nitro'] & {
3
+ _ogImagePublishWarned?: boolean;
4
+ }, reason: unknown, logger: {
5
+ warn: (message: string, reason: unknown) => void;
6
+ }): void;
@@ -0,0 +1,6 @@
1
+ export function warnPublishUnavailable(app, reason, logger) {
2
+ if (app._ogImagePublishWarned)
3
+ return;
4
+ app._ogImagePublishWarned = true;
5
+ logger.warn("[Nuxt OG Image] Publish storage is unavailable. Keeping app image URLs. Check the storage driver and credentials.", reason);
6
+ }
@@ -1,8 +1,8 @@
1
- import type { H3Event } from '#nuxtseo/h3';
1
+ import type { RequestEvent } from 'nuxt/server';
2
2
  import type { OgImageOptionsInternal, OgImageRuntimeConfig } from '../types.js';
3
3
  export interface GetOgImagePathResult {
4
4
  path: string;
5
5
  hash?: string;
6
6
  }
7
- export declare function getOgImagePath(event: H3Event, _pagePath: string, _options?: Partial<OgImageOptionsInternal>): GetOgImagePathResult;
8
- export declare function useOgImageRuntimeConfig(e?: H3Event): OgImageRuntimeConfig;
7
+ export declare function getOgImagePath(event: Pick<RequestEvent, 'context'>, _pagePath: string, _options?: Partial<OgImageOptionsInternal>): GetOgImagePathResult;
8
+ export declare function useOgImageRuntimeConfig(e?: Pick<RequestEvent, 'context'>): OgImageRuntimeConfig;
@@ -1,10 +1,9 @@
1
+ import { useRuntimeConfig } from "nuxt/server";
1
2
  import { joinURL } from "ufo";
2
- import { useRuntimeConfig } from "#nuxtseo/nitro";
3
3
  import { componentNames } from "#og-image-virtual/component-names.mjs";
4
4
  import { buildOgImageUrl } from "../shared.js";
5
- import { getCloudflareEnv } from "./util/cloudflare.js";
6
5
  export function getOgImagePath(event, _pagePath, _options) {
7
- const baseURL = useRuntimeConfig(event).app.baseURL;
6
+ const baseURL = useRuntimeConfig().app.baseURL;
8
7
  const { defaults, security } = useOgImageRuntimeConfig(event);
9
8
  const extension = _options?.extension || defaults.extension;
10
9
  const isStatic = import.meta.prerender && !(security?.secret && security?.strict);
@@ -20,15 +19,11 @@ export function getOgImagePath(event, _pagePath, _options) {
20
19
  };
21
20
  }
22
21
  export function useOgImageRuntimeConfig(e) {
23
- const c = useRuntimeConfig(e);
22
+ const c = useRuntimeConfig();
24
23
  const moduleCfg = c["nuxt-og-image"];
25
- const cloudflareEnv = getCloudflareEnv(e);
26
- const runtimeSecret = c.ogImage?.secret;
27
- const cloudflareSecret = cloudflareEnv?.NUXT_OG_IMAGE_SECRET;
28
- const overrideSecret = typeof runtimeSecret === "string" && runtimeSecret ? runtimeSecret : typeof cloudflareSecret === "string" ? cloudflareSecret : void 0;
29
- const security = overrideSecret ? { ...moduleCfg.security || {}, secret: overrideSecret } : moduleCfg.security;
24
+ const secret = e?.context._ogImageSigningSecret;
25
+ const security = secret ? { ...moduleCfg.security, secret } : moduleCfg.security;
30
26
  return {
31
- defaults: {},
32
27
  ...moduleCfg,
33
28
  security,
34
29
  app: {
@@ -0,0 +1,13 @@
1
+ interface PublishConfig {
2
+ storage: string;
3
+ baseURL: string;
4
+ }
5
+ export declare function parsePublishConfig(input: unknown): {
6
+ _tag: 'Ok';
7
+ value: PublishConfig;
8
+ } | {
9
+ _tag: 'Err';
10
+ reason: string;
11
+ };
12
+ export declare function hasPublishMount(mount: string, storage: Record<string, unknown>): boolean;
13
+ export {};
@@ -0,0 +1,17 @@
1
+ import { normalizeKey } from "unstorage";
2
+ export function parsePublishConfig(input) {
3
+ if (!input || typeof input !== "object")
4
+ return { _tag: "Err", reason: "Set publish.storage and publish.baseURL." };
5
+ const config = input;
6
+ if (typeof config.storage !== "string" || !config.storage.trim() || !normalizeKey(config.storage))
7
+ return { _tag: "Err", reason: "Set publish.storage to a Nitro storage mount name." };
8
+ if (typeof config.baseURL !== "string" || !URL.canParse(config.baseURL))
9
+ return { _tag: "Err", reason: "Set publish.baseURL to the public HTTP URL for uploaded images." };
10
+ const url = new URL(config.baseURL);
11
+ if (!["https:", "http:"].includes(url.protocol) || url.username || url.password || url.href.includes("?") || url.href.includes("#"))
12
+ return { _tag: "Err", reason: "Set publish.baseURL to an HTTP URL without credentials, query, or fragment." };
13
+ return { _tag: "Ok", value: { storage: normalizeKey(config.storage), baseURL: url.href.replace(/\/+$/, "") } };
14
+ }
15
+ export function hasPublishMount(mount, storage) {
16
+ return Object.keys(storage).some((key) => normalizeKey(key) === normalizeKey(mount));
17
+ }
@@ -9,6 +9,8 @@ const RE_UNDERSCORE = /_/g;
9
9
  const RE_DOUBLE_UNDERSCORE = /__/g;
10
10
  const RE_PERCENT20 = /%20/g;
11
11
  const RE_PLUS = /\+/g;
12
+ const RE_ENCODED_COMMA = /%2c/gi;
13
+ const RE_ENCODED_PLUS = /%2b/gi;
12
14
  const RE_SINGLE_UNDERSCORE = /(?<!_)_(?!_)/;
13
15
  const RE_OG_PATH_PREFIX = /^\/_og\/[ds]\//;
14
16
  const RE_OG_ROUTE_PREFIX = /\/_og\/[ds]\//;
@@ -260,9 +262,12 @@ export function buildOgImageUrl(options, extension = "png", isStatic = false, de
260
262
  const segment = encoded || "default";
261
263
  const signed = secret && !isStatic ? `${segment},s_${signEncodedParams(segment, secret)}` : segment;
262
264
  return {
263
- url: `${prefix}/${signed}.${extension}`
265
+ url: `${prefix}/${signed.replace(/,/g, "%2C").replace(RE_PLUS, "%2B")}.${extension}`
264
266
  };
265
267
  }
268
+ function normalizeUrlSegment(segment) {
269
+ return segment.replace(RE_ENCODED_COMMA, ",").replace(RE_ENCODED_PLUS, "+");
270
+ }
266
271
  export function signEncodedParams(encoded, secret) {
267
272
  return digest(`${secret}:${encoded}`).slice(0, 16);
268
273
  }
@@ -280,7 +285,7 @@ export function parseOgImageUrl(url) {
280
285
  const path = url.replace(RE_OG_PATH_PREFIX, "");
281
286
  const extMatch = path.match(RE_FILE_EXTENSION_WITH_CAPTURE);
282
287
  const extension = extMatch?.[1] || "png";
283
- const encoded = path.replace(RE_FILE_EXTENSION, "");
288
+ const encoded = normalizeUrlSegment(path.replace(RE_FILE_EXTENSION, ""));
284
289
  const hashMatch = encoded.match(RE_HASH_SEGMENT);
285
290
  if (hashMatch) {
286
291
  return {
@@ -300,7 +305,7 @@ export function parseOgImageUrl(url) {
300
305
  export function extractEncodedSegment(path, extension) {
301
306
  const match = path.match(RE_OG_ROUTE_PREFIX);
302
307
  if (match?.index != null) {
303
- return path.slice(match.index + match[0].length).replace(new RegExp(`\\.${extension}$`), "");
308
+ return normalizeUrlSegment(path.slice(match.index + match[0].length).replace(new RegExp(`\\.${extension}$`), ""));
304
309
  }
305
- return path.split("/").pop().replace(new RegExp(`\\.${extension}$`), "");
310
+ return normalizeUrlSegment(path.split("/").pop().replace(new RegExp(`\\.${extension}$`), ""));
306
311
  }
@@ -41,16 +41,21 @@ export interface OgImageRuntimeConfig {
41
41
  debug: boolean;
42
42
  /** Whether twitter:* meta tags are emitted alongside og:image tags */
43
43
  includeTwitter: boolean;
44
- baseCacheKey: string;
44
+ baseCacheKey: string | false;
45
45
  hasNuxtIcon: boolean;
46
46
  hasNuxtContent?: boolean;
47
47
  colorPreference: 'light' | 'dark';
48
- isNuxtContentDocumentDriven: boolean;
49
48
  zeroRuntime: boolean;
50
49
  cssFramework: 'tailwind' | 'unocss' | 'none';
51
50
  componentDirs?: string[];
52
51
  /** Directory for persistent build cache (CI caching) */
53
52
  buildCacheDir?: string;
53
+ /** Publish rendered images to a public storage mount. */
54
+ publish?: {
55
+ storage: string;
56
+ baseURL: string;
57
+ cacheVersion: string;
58
+ };
54
59
  /** Source directory for auto-eject (dev only) */
55
60
  srcDir?: string;
56
61
  /** Root directory for relative path display (dev only) */
@@ -69,7 +74,7 @@ export interface OgImageRuntimeConfig {
69
74
  imageFetchTimeout: number;
70
75
  maxQueryParamSize: number | null;
71
76
  restrictRuntimeImagesToOrigin: false | string[];
72
- secret: string;
77
+ secret: string | false;
73
78
  strict: boolean;
74
79
  };
75
80
  app: {
@@ -164,15 +169,6 @@ export interface OgImageOptions {
164
169
  src: string;
165
170
  data: ArrayBuffer | Uint8Array;
166
171
  }>;
167
- fetchedResources?: Array<{
168
- src: string;
169
- data: ArrayBuffer | Uint8Array;
170
- }>;
171
- /** @deprecated Use `images` instead. */
172
- persistentImages?: Array<{
173
- src: string;
174
- data: ArrayBuffer;
175
- }>;
176
172
  devicePixelRatio?: number;
177
173
  };
178
174
  /** @deprecated Legacy font override — no longer used at runtime */
@@ -208,6 +204,8 @@ export interface OgImageOptions {
208
204
  * Extends OgImageOptions with fields set by defineOgImage() and the module internals.
209
205
  */
210
206
  export interface OgImageOptionsInternal extends OgImageOptions {
207
+ /** Completed page content supplied during prerender publishing. */
208
+ _prerenderHtml?: string;
211
209
  /** Set by defineOgImage() — the resolved component PascalName */
212
210
  component?: string;
213
211
  /** Determined by component filename suffix (.satori.vue, .takumi.vue, .browser.vue) */
@@ -246,10 +244,7 @@ export interface RuntimeCompatibilitySchema {
246
244
  fetch?: 'node' | 'web';
247
245
  wasm?: any;
248
246
  }
249
- export interface RuntimeCompatibilityMeta {
250
- takumiVersion?: 1 | 2;
251
- }
252
- export type RuntimeCompatibilityPayload = Partial<Omit<RuntimeCompatibilitySchema, 'wasm'>> & RuntimeCompatibilityMeta;
247
+ export type RuntimeCompatibilityPayload = Partial<Omit<RuntimeCompatibilitySchema, 'wasm'>>;
253
248
  export type CompatibilityFlags = Partial<Omit<RuntimeCompatibilitySchema, 'wasm'>>;
254
249
  export interface CompatibilityFlagEnvOverrides {
255
250
  dev?: CompatibilityFlags;