nuxt-og-image 6.6.0 → 6.7.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.
- package/README.md +2 -0
- package/dist/chunks/tw4.cjs +7 -7
- package/dist/chunks/tw4.mjs +7 -7
- package/dist/chunks/uno.cjs +6 -6
- package/dist/chunks/uno.mjs +6 -6
- package/dist/cli.cjs +12 -5
- package/dist/cli.mjs +10 -3
- package/dist/module.cjs +5 -5
- package/dist/module.d.cts +5 -3
- package/dist/module.d.mts +5 -3
- package/dist/module.d.ts +5 -3
- package/dist/module.json +1 -1
- package/dist/module.mjs +5 -5
- package/dist/runtime/server/og-image/bindings/font-assets/cloudflare.d.ts +1 -1
- package/dist/runtime/server/og-image/bindings/font-assets/cloudflare.js +6 -1
- package/dist/runtime/server/og-image/bindings/font-assets/dev-prerender.js +13 -6
- package/dist/runtime/server/og-image/bindings/font-assets/external-url.d.ts +36 -0
- package/dist/runtime/server/og-image/bindings/font-assets/external-url.js +47 -0
- package/dist/runtime/server/og-image/bindings/font-assets/node.d.ts +1 -1
- package/dist/runtime/server/og-image/bindings/font-assets/node.js +14 -7
- package/dist/runtime/server/og-image/bindings/takumi/node-dev.js +7 -1
- package/dist/runtime/server/og-image/fonts.d.ts +4 -0
- package/dist/runtime/server/og-image/fonts.js +21 -5
- package/dist/runtime/server/og-image/satori/instances.d.ts +1 -2
- package/dist/runtime/server/og-image/takumi/renderer.js +61 -19
- package/dist/runtime/server/util/ssrf.d.ts +10 -0
- package/dist/runtime/server/util/ssrf.js +9 -1
- package/dist/runtime/types.d.ts +13 -0
- package/dist/shared/{nuxt-og-image.DdbTs-xp.mjs → nuxt-og-image.CPSxZhVO.mjs} +122 -496
- package/dist/shared/nuxt-og-image.DM30kcDz.mjs +660 -0
- package/dist/shared/nuxt-og-image.RI9DgjgV.cjs +689 -0
- package/dist/shared/{nuxt-og-image.CfTPCtaS.cjs → nuxt-og-image.yDJBWXBt.cjs} +181 -555
- package/package.json +43 -39
- package/dist/shared/nuxt-og-image.CJa2KCie.mjs +0 -189
- package/dist/shared/nuxt-og-image.CMYbz66P.cjs +0 -193
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const node_crypto = require('node:crypto');
|
|
3
4
|
const fs = require('node:fs');
|
|
4
5
|
const promises = require('node:fs/promises');
|
|
5
6
|
const node_url = require('node:url');
|
|
6
7
|
const kit = require('@nuxt/kit');
|
|
7
8
|
const defu = require('defu');
|
|
8
|
-
const kit$
|
|
9
|
+
const kit$1 = require('nuxt-site-config/kit');
|
|
9
10
|
const ohash = require('ohash');
|
|
10
11
|
const pathe = require('pathe');
|
|
11
12
|
const pkgTypes = require('pkg-types');
|
|
12
13
|
const stdEnv = require('std-env');
|
|
13
|
-
const node_crypto = require('node:crypto');
|
|
14
14
|
const oxcWalker = require('oxc-walker');
|
|
15
|
-
const
|
|
16
|
-
const logger_js = require('../../dist/runtime/logger.js');
|
|
17
|
-
const chromeLauncher = require('chrome-launcher');
|
|
18
|
-
const nypm = require('nypm');
|
|
15
|
+
const dependencies = require('./nuxt-og-image.RI9DgjgV.cjs');
|
|
19
16
|
const devtools = require('nuxtseo-shared/devtools');
|
|
20
17
|
const unstorage = require('unstorage');
|
|
21
18
|
const fsDriver = require('unstorage/drivers/fs-lite');
|
|
19
|
+
const logger_js = require('../../dist/runtime/logger.js');
|
|
22
20
|
const css_js = require('../../dist/runtime/server/og-image/utils/css.js');
|
|
23
21
|
const MagicString = require('magic-string');
|
|
24
22
|
const stripLiteral = require('strip-literal');
|
|
@@ -29,7 +27,7 @@ const ofetch = require('ofetch');
|
|
|
29
27
|
const ultrahtml = require('ultrahtml');
|
|
30
28
|
const emojiUtils_js = require('../../dist/runtime/server/og-image/core/transforms/emojis/emoji-utils.js');
|
|
31
29
|
const exsolve = require('exsolve');
|
|
32
|
-
const
|
|
30
|
+
const kit$2 = require('nuxtseo-shared/kit');
|
|
33
31
|
|
|
34
32
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
35
33
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
@@ -50,279 +48,9 @@ const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
|
|
|
50
48
|
const fsDriver__default = /*#__PURE__*/_interopDefaultCompat(fsDriver);
|
|
51
49
|
const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
|
|
52
50
|
|
|
53
|
-
const isUndefinedOrTruthy = (v) => typeof v === "undefined" || v !== false;
|
|
54
|
-
function checkLocalChrome() {
|
|
55
|
-
if (stdEnv.isCI)
|
|
56
|
-
return false;
|
|
57
|
-
let hasChromeLocally = false;
|
|
58
|
-
try {
|
|
59
|
-
hasChromeLocally = !!chromeLauncher.Launcher.getFirstInstallation();
|
|
60
|
-
} catch {
|
|
61
|
-
}
|
|
62
|
-
return hasChromeLocally;
|
|
63
|
-
}
|
|
64
|
-
async function hasResolvableDependency(dep) {
|
|
65
|
-
return await kit.resolvePath(dep, { fallbackToOriginal: true }).catch(() => null).then((r) => r && r !== dep);
|
|
66
|
-
}
|
|
67
|
-
const VALID_RENDERER_SUFFIXES = ["satori", "browser", "takumi"];
|
|
68
|
-
const RE_RENDERER_SUFFIX_CI = /\.?(satori|browser|takumi)$/i;
|
|
69
|
-
const RE_RENDERER_SUFFIX = /(Satori|Browser|Takumi)$/;
|
|
70
|
-
const RE_LEGACY_SUFFIX = /-legacy$/;
|
|
71
|
-
const RE_WHITESPACE = /\s+/;
|
|
72
|
-
function getRendererFromFilename(filepath) {
|
|
73
|
-
const filename = pathe.basename(filepath).replace(".vue", "");
|
|
74
|
-
for (const suffix of VALID_RENDERER_SUFFIXES) {
|
|
75
|
-
if (filename.endsWith(`.${suffix}`))
|
|
76
|
-
return suffix;
|
|
77
|
-
}
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
const OGIMAGE_PREFIXES = [
|
|
81
|
-
{ prefix: "OgImageCommunity", overlapWord: "Community" },
|
|
82
|
-
{ prefix: "OgImageTemplate", overlapWord: "Template" },
|
|
83
|
-
{ prefix: "OgImage", overlapWord: "Image" }
|
|
84
|
-
];
|
|
85
|
-
function getRegisteredBaseNames(registeredPascalName) {
|
|
86
|
-
const stripped = registeredPascalName.replace(RE_RENDERER_SUFFIX_CI, "").replace(RE_RENDERER_SUFFIX, "");
|
|
87
|
-
const names = [];
|
|
88
|
-
for (const { prefix, overlapWord } of OGIMAGE_PREFIXES) {
|
|
89
|
-
if (!stripped.startsWith(prefix))
|
|
90
|
-
continue;
|
|
91
|
-
const withoutPrefix = stripped.slice(prefix.length);
|
|
92
|
-
if (withoutPrefix) {
|
|
93
|
-
names.push(withoutPrefix);
|
|
94
|
-
if (withoutPrefix !== overlapWord)
|
|
95
|
-
names.push(overlapWord + withoutPrefix);
|
|
96
|
-
} else {
|
|
97
|
-
names.push(overlapWord);
|
|
98
|
-
}
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
101
|
-
if (names.length === 0)
|
|
102
|
-
names.push(stripped);
|
|
103
|
-
return names;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const NodeRuntime = {
|
|
107
|
-
// node-server runtime
|
|
108
|
-
browser: "on-demand",
|
|
109
|
-
// this gets changed build start
|
|
110
|
-
resvg: "node",
|
|
111
|
-
satori: "node",
|
|
112
|
-
takumi: "node",
|
|
113
|
-
sharp: "node",
|
|
114
|
-
// will be disabled if they're missing the dependency
|
|
115
|
-
emoji: "local"
|
|
116
|
-
// can bundle icons, no size constraints
|
|
117
|
-
};
|
|
118
|
-
const NodeDevRuntime = {
|
|
119
|
-
...NodeRuntime,
|
|
120
|
-
resvg: "node-dev",
|
|
121
|
-
// use worker to prevent crashes from killing process
|
|
122
|
-
takumi: "node-dev"
|
|
123
|
-
// use worker to prevent crashes from killing process
|
|
124
|
-
};
|
|
125
|
-
const NodePrerenderRuntime = {
|
|
126
|
-
...NodeRuntime,
|
|
127
|
-
resvg: "node-dev",
|
|
128
|
-
// use worker to prevent crashes from killing prerender process
|
|
129
|
-
takumi: "node-dev"
|
|
130
|
-
// use worker to prevent crashes from killing prerender process
|
|
131
|
-
};
|
|
132
|
-
const cloudflare = {
|
|
133
|
-
browser: "cloudflare",
|
|
134
|
-
resvg: "wasm",
|
|
135
|
-
satori: "wasm",
|
|
136
|
-
takumi: "wasm",
|
|
137
|
-
sharp: false,
|
|
138
|
-
emoji: "fetch",
|
|
139
|
-
// edge size limits - use API instead of bundling 24MB icons
|
|
140
|
-
wasm: {
|
|
141
|
-
esmImport: true
|
|
142
|
-
// Do NOT set lazy here — Nitro's cloudflare preset uses lazy: false because
|
|
143
|
-
// CF Workers require WASM modules to be imported eagerly via top-level await
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
const awsLambda = {
|
|
147
|
-
browser: false,
|
|
148
|
-
resvg: "node",
|
|
149
|
-
satori: "node",
|
|
150
|
-
takumi: "node",
|
|
151
|
-
sharp: false,
|
|
152
|
-
// 0.33.x has issues
|
|
153
|
-
emoji: "local"
|
|
154
|
-
// serverless has larger size limits
|
|
155
|
-
};
|
|
156
|
-
const WebContainer = {
|
|
157
|
-
browser: false,
|
|
158
|
-
resvg: "wasm-fs",
|
|
159
|
-
satori: "wasm-fs",
|
|
160
|
-
takumi: "wasm",
|
|
161
|
-
sharp: false,
|
|
162
|
-
emoji: "fetch"
|
|
163
|
-
// webcontainer has size constraints
|
|
164
|
-
};
|
|
165
|
-
const RuntimeCompatibility = {
|
|
166
|
-
"nitro-dev": NodeDevRuntime,
|
|
167
|
-
"nitro-prerender": NodePrerenderRuntime,
|
|
168
|
-
"node-server": NodeRuntime,
|
|
169
|
-
"node-cluster": NodeRuntime,
|
|
170
|
-
"node-listener": NodeRuntime,
|
|
171
|
-
"bun": NodeRuntime,
|
|
172
|
-
"deno-server": NodeRuntime,
|
|
173
|
-
"deno-deploy": NodeRuntime,
|
|
174
|
-
// node-server extending presets
|
|
175
|
-
"alwaysdata": NodeRuntime,
|
|
176
|
-
"cleavr": NodeRuntime,
|
|
177
|
-
"digital-ocean": NodeRuntime,
|
|
178
|
-
"edgio": NodeRuntime,
|
|
179
|
-
"flight-control": NodeRuntime,
|
|
180
|
-
"heroku": NodeRuntime,
|
|
181
|
-
"iis-handler": NodeRuntime,
|
|
182
|
-
"iis-node": NodeRuntime,
|
|
183
|
-
"koyeb": NodeRuntime,
|
|
184
|
-
"platform-sh": NodeRuntime,
|
|
185
|
-
"render-com": NodeRuntime,
|
|
186
|
-
"zeabur": NodeRuntime,
|
|
187
|
-
"zerops": NodeRuntime,
|
|
188
|
-
"stackblitz": WebContainer,
|
|
189
|
-
"codesandbox": WebContainer,
|
|
190
|
-
"aws-amplify": awsLambda,
|
|
191
|
-
"aws-lambda": awsLambda,
|
|
192
|
-
"azure": awsLambda,
|
|
193
|
-
"azure-functions": awsLambda,
|
|
194
|
-
"azure-swa": awsLambda,
|
|
195
|
-
"netlify": awsLambda,
|
|
196
|
-
"netlify-edge": {
|
|
197
|
-
browser: false,
|
|
198
|
-
resvg: "wasm",
|
|
199
|
-
satori: "node",
|
|
200
|
-
takumi: "wasm",
|
|
201
|
-
sharp: false,
|
|
202
|
-
emoji: "fetch",
|
|
203
|
-
// edge size limits
|
|
204
|
-
wasm: {
|
|
205
|
-
rollup: {
|
|
206
|
-
targetEnv: "auto-inline",
|
|
207
|
-
sync: ["@resvg/resvg-wasm/index_bg.wasm"]
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
},
|
|
211
|
-
"firebase": awsLambda,
|
|
212
|
-
"firebase-app-hosting": awsLambda,
|
|
213
|
-
"genezio": awsLambda,
|
|
214
|
-
"stormkit": awsLambda,
|
|
215
|
-
"vercel": awsLambda,
|
|
216
|
-
"vercel-edge": {
|
|
217
|
-
browser: false,
|
|
218
|
-
resvg: "wasm",
|
|
219
|
-
satori: "wasm",
|
|
220
|
-
takumi: "wasm",
|
|
221
|
-
sharp: false,
|
|
222
|
-
emoji: "fetch",
|
|
223
|
-
// edge size limits - bundling 24MB icons not viable
|
|
224
|
-
wasm: {
|
|
225
|
-
// lowers workers kb size
|
|
226
|
-
esmImport: true,
|
|
227
|
-
lazy: true
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
"cloudflare-pages": cloudflare,
|
|
231
|
-
"cloudflare-pages-static": cloudflare,
|
|
232
|
-
"cloudflare": cloudflare,
|
|
233
|
-
"cloudflare-module": cloudflare,
|
|
234
|
-
"cloudflare-durable": cloudflare
|
|
235
|
-
};
|
|
236
|
-
function resolveOgImagePreset(nitroConfig) {
|
|
237
|
-
const nuxt = kit.useNuxt();
|
|
238
|
-
if (nuxt.options.dev)
|
|
239
|
-
return "nitro-dev";
|
|
240
|
-
if (nuxt.options.nitro.static)
|
|
241
|
-
return "nitro-prerender";
|
|
242
|
-
return kit$1.resolveNitroPreset(nitroConfig);
|
|
243
|
-
}
|
|
244
|
-
function getPresetNitroPresetCompatibility(target) {
|
|
245
|
-
const normalizedTarget = target.replace(RE_LEGACY_SUFFIX, "");
|
|
246
|
-
let compatibility = RuntimeCompatibility[normalizedTarget];
|
|
247
|
-
if (!compatibility) {
|
|
248
|
-
logger_js.logger.warn(`Unknown Nitro preset "${target}" \u2014 falling back to node-server compatibility. Set ogImage.compatibility.runtime to override.`);
|
|
249
|
-
compatibility = NodeRuntime;
|
|
250
|
-
}
|
|
251
|
-
return compatibility;
|
|
252
|
-
}
|
|
253
|
-
async function applyNitroPresetCompatibility(nitroConfig, options) {
|
|
254
|
-
const target = resolveOgImagePreset(nitroConfig);
|
|
255
|
-
const compatibility = getPresetNitroPresetCompatibility(target);
|
|
256
|
-
const { resolve, detectedRenderers } = options;
|
|
257
|
-
const satoriEnabled = detectedRenderers.has("satori");
|
|
258
|
-
const browserEnabled = detectedRenderers.has("browser");
|
|
259
|
-
const takumiEnabled = detectedRenderers.has("takumi");
|
|
260
|
-
for (const renderer of detectedRenderers) {
|
|
261
|
-
if (!compatibility[renderer]) {
|
|
262
|
-
logger_js.logger.warn(`Renderer "${renderer}" detected but not supported on "${target}" preset. OG images using .${renderer}.vue components may fail.`);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
const emptyMock = await resolve.resolvePath("./runtime/mock/empty");
|
|
266
|
-
nitroConfig.alias["#og-image/renderers/satori"] = satoriEnabled ? await resolve.resolvePath("./runtime/server/og-image/satori/renderer") : emptyMock;
|
|
267
|
-
nitroConfig.alias["#og-image/renderers/browser"] = browserEnabled ? await resolve.resolvePath("./runtime/server/og-image/browser/renderer") : emptyMock;
|
|
268
|
-
nitroConfig.alias["#og-image/renderers/takumi"] = takumiEnabled ? await resolve.resolvePath("./runtime/server/og-image/takumi/renderer") : emptyMock;
|
|
269
|
-
const resolvedCompatibility = {};
|
|
270
|
-
async function applyBinding(key) {
|
|
271
|
-
let binding = options.compatibility?.[key];
|
|
272
|
-
if (typeof binding === "undefined")
|
|
273
|
-
binding = compatibility[key];
|
|
274
|
-
const isRendererBinding = key === "browser" || key === "satori" || key === "takumi";
|
|
275
|
-
if (isRendererBinding && !detectedRenderers.has(key)) {
|
|
276
|
-
binding = false;
|
|
277
|
-
}
|
|
278
|
-
resolvedCompatibility[key] = binding;
|
|
279
|
-
if (!binding && isRendererBinding) {
|
|
280
|
-
nitroConfig.alias[`#og-image/renderers/${key}`] = emptyMock;
|
|
281
|
-
}
|
|
282
|
-
return {
|
|
283
|
-
[`#og-image/bindings/${key}`]: !binding ? emptyMock : await resolve.resolvePath(`./runtime/server/og-image/bindings/${key}/${binding}`)
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
const satoriPkgDir = await resolve.resolvePath("satori/package.json").then((p) => p.replace("/package.json", ""));
|
|
287
|
-
const yogaWasmPath = `${satoriPkgDir}/yoga.wasm`;
|
|
288
|
-
nitroConfig.alias = defu.defu(
|
|
289
|
-
{ "#og-image/yoga-wasm": `${yogaWasmPath}?module` },
|
|
290
|
-
await applyBinding("browser"),
|
|
291
|
-
await applyBinding("satori"),
|
|
292
|
-
await applyBinding("takumi"),
|
|
293
|
-
await applyBinding("resvg"),
|
|
294
|
-
await applyBinding("sharp"),
|
|
295
|
-
nitroConfig.alias || {}
|
|
296
|
-
);
|
|
297
|
-
if (Object.values(resolvedCompatibility).includes("wasm")) {
|
|
298
|
-
nitroConfig.experimental = nitroConfig.experimental || {};
|
|
299
|
-
nitroConfig.experimental.wasm = true;
|
|
300
|
-
}
|
|
301
|
-
nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
|
|
302
|
-
nitroConfig.wasm = defu.defu(compatibility.wasm, nitroConfig.wasm);
|
|
303
|
-
nitroConfig.virtual["#og-image/compatibility"] = () => `export default ${JSON.stringify(resolvedCompatibility)}`;
|
|
304
|
-
kit.addTemplate({
|
|
305
|
-
filename: "nuxt-og-image/compatibility.mjs",
|
|
306
|
-
getContents() {
|
|
307
|
-
return `export default ${JSON.stringify(resolvedCompatibility)}`;
|
|
308
|
-
},
|
|
309
|
-
options: { mode: "server" }
|
|
310
|
-
});
|
|
311
|
-
return resolvedCompatibility;
|
|
312
|
-
}
|
|
313
|
-
async function ensureDependencies(dep, nuxt = kit.useNuxt()) {
|
|
314
|
-
const { ensureDependencyInstalled } = await import('nypm');
|
|
315
|
-
return Promise.all(dep.map((d) => {
|
|
316
|
-
return ensureDependencyInstalled(d, {
|
|
317
|
-
cwd: nuxt.options.rootDir,
|
|
318
|
-
dev: true
|
|
319
|
-
});
|
|
320
|
-
}));
|
|
321
|
-
}
|
|
322
|
-
|
|
323
51
|
const RE_REFLECT_HAS_MINIFIED = /Reflect\.has\(([\w$]+),([\w$]+)\)\?Reflect\.get\(\1,\2,([\w$]+)\):Reflect\.get\(([\w$]+),\2,\3\)/g;
|
|
324
52
|
const RE_WASM_IMPORT = /import\("(\.\/wasm\/[^"]+\.wasm)"\)/g;
|
|
325
|
-
async function setupBuildHandler(config, resolve, getDetectedRenderers, nuxt = kit.useNuxt()) {
|
|
53
|
+
async function setupBuildHandler(config, resolve, getDetectedRenderers, getCompatibilityMeta = () => ({}), nuxt = kit.useNuxt()) {
|
|
326
54
|
nuxt.options.nitro.storage = nuxt.options.nitro.storage || {};
|
|
327
55
|
if (typeof config.runtimeCacheStorage === "object")
|
|
328
56
|
nuxt.options.nitro.storage["nuxt-og-image"] = config.runtimeCacheStorage;
|
|
@@ -342,9 +70,9 @@ async function setupBuildHandler(config, resolve, getDetectedRenderers, nuxt = k
|
|
|
342
70
|
});
|
|
343
71
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
344
72
|
const renderers = getDetectedRenderers();
|
|
345
|
-
await applyNitroPresetCompatibility(nitro.options, { compatibility: config.compatibility?.runtime, resolve, detectedRenderers: renderers });
|
|
346
|
-
const target = resolveOgImagePreset(nitro.options);
|
|
347
|
-
const normalizedTarget = target.replace(RE_LEGACY_SUFFIX, "");
|
|
73
|
+
await dependencies.applyNitroPresetCompatibility(nitro.options, { compatibility: config.compatibility?.runtime, resolve, detectedRenderers: renderers, metadata: getCompatibilityMeta() });
|
|
74
|
+
const target = dependencies.resolveOgImagePreset(nitro.options);
|
|
75
|
+
const normalizedTarget = target.replace(dependencies.RE_LEGACY_SUFFIX, "");
|
|
348
76
|
const isEdgePreset = ["cloudflare", "cloudflare-pages", "cloudflare-pages-static", "cloudflare-module", "cloudflare-durable", "vercel-edge", "netlify-edge"].includes(normalizedTarget);
|
|
349
77
|
const isCloudflarePreset = normalizedTarget.startsWith("cloudflare");
|
|
350
78
|
const isCloudflarePagesOrModule = ["cloudflare-pages", "cloudflare-pages-static", "cloudflare-module", "cloudflare-durable"].includes(normalizedTarget);
|
|
@@ -356,7 +84,7 @@ async function setupBuildHandler(config, resolve, getDetectedRenderers, nuxt = k
|
|
|
356
84
|
nitro.options.cloudflare.pages.routes.exclude.push("/_og/s/*");
|
|
357
85
|
}
|
|
358
86
|
nitro.hooks.hook("compiled", async (_nitro) => {
|
|
359
|
-
const compatibility = getPresetNitroPresetCompatibility(target);
|
|
87
|
+
const compatibility = dependencies.getPresetNitroPresetCompatibility(target);
|
|
360
88
|
if (!isEdgePreset)
|
|
361
89
|
return;
|
|
362
90
|
const configuredEntry = nitro.options.rollupConfig?.output.entryFileNames;
|
|
@@ -475,194 +203,19 @@ function patchWebAssemblyInstantiate(code) {
|
|
|
475
203
|
return code;
|
|
476
204
|
}
|
|
477
205
|
|
|
478
|
-
|
|
479
|
-
{
|
|
480
|
-
name: "satori",
|
|
481
|
-
description: "SVG-based renderer using Satori",
|
|
482
|
-
bindings: {
|
|
483
|
-
"node": [
|
|
484
|
-
{ name: "satori", description: "HTML to SVG renderer" },
|
|
485
|
-
{ name: "@resvg/resvg-js", description: "SVG to PNG converter (native)" }
|
|
486
|
-
],
|
|
487
|
-
"wasm": [
|
|
488
|
-
{ name: "satori", description: "HTML to SVG renderer" },
|
|
489
|
-
{ name: "@resvg/resvg-wasm", description: "SVG to PNG converter (WASM)" }
|
|
490
|
-
],
|
|
491
|
-
"wasm-fs": [
|
|
492
|
-
{ name: "satori", description: "HTML to SVG renderer" },
|
|
493
|
-
{ name: "@resvg/resvg-wasm", description: "SVG to PNG converter (WASM)" }
|
|
494
|
-
]
|
|
495
|
-
}
|
|
496
|
-
},
|
|
497
|
-
{
|
|
498
|
-
name: "takumi",
|
|
499
|
-
description: "Rust-based high-performance renderer (recommended)",
|
|
500
|
-
bindings: {
|
|
501
|
-
"node": [
|
|
502
|
-
{ name: "@takumi-rs/core", description: "Native Takumi renderer" }
|
|
503
|
-
],
|
|
504
|
-
"wasm": [
|
|
505
|
-
{ name: "@takumi-rs/wasm", description: "WASM Takumi renderer" }
|
|
506
|
-
],
|
|
507
|
-
"wasm-fs": [
|
|
508
|
-
{ name: "@takumi-rs/wasm", description: "WASM Takumi renderer" }
|
|
509
|
-
]
|
|
510
|
-
}
|
|
511
|
-
},
|
|
512
|
-
{
|
|
513
|
-
name: "browser",
|
|
514
|
-
description: "Browser-based screenshot renderer",
|
|
515
|
-
bindings: {
|
|
516
|
-
node: [
|
|
517
|
-
{ name: "playwright-core", description: "Headless browser automation" }
|
|
518
|
-
]
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
];
|
|
522
|
-
async function getInstalledProviders() {
|
|
523
|
-
const installed = [];
|
|
524
|
-
for (const provider of PROVIDER_DEPENDENCIES) {
|
|
525
|
-
if (provider.bindings.node) {
|
|
526
|
-
const allNodeInstalled = await Promise.all(
|
|
527
|
-
provider.bindings.node.map((dep) => hasResolvableDependency(dep.name))
|
|
528
|
-
);
|
|
529
|
-
if (allNodeInstalled.every(Boolean)) {
|
|
530
|
-
installed.push({ provider: provider.name, binding: "node" });
|
|
531
|
-
continue;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
if (provider.bindings.wasm) {
|
|
535
|
-
const allWasmInstalled = await Promise.all(
|
|
536
|
-
provider.bindings.wasm.map((dep) => hasResolvableDependency(dep.name))
|
|
537
|
-
);
|
|
538
|
-
if (allWasmInstalled.every(Boolean)) {
|
|
539
|
-
installed.push({ provider: provider.name, binding: "wasm" });
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
return installed;
|
|
544
|
-
}
|
|
545
|
-
async function getMissingDependencies(provider, binding = "node") {
|
|
546
|
-
const providerDef = PROVIDER_DEPENDENCIES.find((p) => p.name === provider);
|
|
547
|
-
if (!providerDef)
|
|
548
|
-
return [];
|
|
549
|
-
const deps = providerDef.bindings[binding] || providerDef.bindings.node || [];
|
|
550
|
-
const missing = [];
|
|
551
|
-
for (const dep of deps) {
|
|
552
|
-
if (!await hasResolvableDependency(dep.name))
|
|
553
|
-
missing.push(dep.name);
|
|
554
|
-
}
|
|
555
|
-
return missing;
|
|
556
|
-
}
|
|
557
|
-
function getProviderDependencies(provider, binding = "node") {
|
|
558
|
-
const providerDef = PROVIDER_DEPENDENCIES.find((p) => p.name === provider);
|
|
559
|
-
if (!providerDef)
|
|
560
|
-
return [];
|
|
561
|
-
const deps = providerDef.bindings[binding] || providerDef.bindings.node || [];
|
|
562
|
-
return deps.map((d) => d.name);
|
|
563
|
-
}
|
|
564
|
-
function getRecommendedBindingFromPreset(provider) {
|
|
565
|
-
const preset = resolveOgImagePreset();
|
|
566
|
-
const compatibility = getPresetNitroPresetCompatibility(preset);
|
|
567
|
-
return getRecommendedBinding(provider, compatibility);
|
|
568
|
-
}
|
|
569
|
-
function getRecommendedBinding(provider, compatibility) {
|
|
570
|
-
if (provider === "satori") {
|
|
571
|
-
const resvgBinding = compatibility.resvg;
|
|
572
|
-
if (resvgBinding === "wasm-fs")
|
|
573
|
-
return "wasm-fs";
|
|
574
|
-
if (resvgBinding === "wasm")
|
|
575
|
-
return "wasm";
|
|
576
|
-
return "node";
|
|
577
|
-
}
|
|
578
|
-
if (provider === "takumi") {
|
|
579
|
-
const takumiBinding = compatibility.takumi;
|
|
580
|
-
if (takumiBinding === "wasm")
|
|
581
|
-
return "wasm";
|
|
582
|
-
return "node";
|
|
583
|
-
}
|
|
584
|
-
if (provider === "browser") {
|
|
585
|
-
return "node";
|
|
586
|
-
}
|
|
587
|
-
return "node";
|
|
588
|
-
}
|
|
589
|
-
async function ensureProviderDependencies(provider, binding, nuxt) {
|
|
590
|
-
const missing = await getMissingDependencies(provider, binding);
|
|
591
|
-
if (missing.length === 0)
|
|
592
|
-
return { success: true, installed: [] };
|
|
593
|
-
const pm = await nypm.detectPackageManager(nuxt.options.rootDir);
|
|
594
|
-
const pmName = pm?.name || "npm";
|
|
595
|
-
logger_js.logger.info(`Installing ${provider} dependencies: ${missing.join(", ")}`);
|
|
596
|
-
const installed = [];
|
|
597
|
-
for (const pkg of missing) {
|
|
598
|
-
const success = await nypm.addDependency(pkg, {
|
|
599
|
-
cwd: nuxt.options.rootDir,
|
|
600
|
-
dev: false
|
|
601
|
-
}).then(() => {
|
|
602
|
-
installed.push(pkg);
|
|
603
|
-
return true;
|
|
604
|
-
}).catch(() => {
|
|
605
|
-
logger_js.logger.error(`Failed to install ${pkg}. Run manually: ${pmName} add ${pkg}`);
|
|
606
|
-
return false;
|
|
607
|
-
});
|
|
608
|
-
if (!success)
|
|
609
|
-
return { success: false, installed };
|
|
610
|
-
}
|
|
611
|
-
return { success: true, installed };
|
|
612
|
-
}
|
|
613
|
-
function canPromptInteractively(env = {
|
|
614
|
-
hasTTY: stdEnv.hasTTY,
|
|
615
|
-
hasStdinTTY: Boolean(process.stdin?.isTTY),
|
|
616
|
-
isAgent: stdEnv.isAgent,
|
|
617
|
-
isCI: stdEnv.isCI
|
|
618
|
-
}) {
|
|
619
|
-
return env.hasTTY && env.hasStdinTTY && !env.isAgent && !env.isCI;
|
|
620
|
-
}
|
|
621
|
-
async function promptForRendererSelection() {
|
|
622
|
-
logger_js.logger.info("Welcome to Nuxt OG Image! No renderer dependencies detected.");
|
|
623
|
-
const renderer = await logger_js.logger.prompt("Which renderer would you like to use?", {
|
|
624
|
-
type: "select",
|
|
625
|
-
options: PROVIDER_DEPENDENCIES.map((p) => p.name),
|
|
626
|
-
initial: "takumi"
|
|
627
|
-
});
|
|
628
|
-
return renderer || "takumi";
|
|
629
|
-
}
|
|
630
|
-
async function validateProviderSetup(renderer, compatibility) {
|
|
631
|
-
const issues = [];
|
|
632
|
-
const binding = getRecommendedBinding(renderer, compatibility);
|
|
633
|
-
const missing = await getMissingDependencies(renderer, binding);
|
|
634
|
-
if (missing.length > 0) {
|
|
635
|
-
issues.push(`Missing ${renderer} dependencies: ${missing.join(", ")}`);
|
|
636
|
-
}
|
|
637
|
-
if (renderer === "satori") {
|
|
638
|
-
const hasResvgNode = await hasResolvableDependency("@resvg/resvg-js");
|
|
639
|
-
const hasResvgWasm = await hasResolvableDependency("@resvg/resvg-wasm");
|
|
640
|
-
if (!hasResvgNode && !hasResvgWasm) {
|
|
641
|
-
issues.push("Satori requires either @resvg/resvg-js (node) or @resvg/resvg-wasm to render PNGs");
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
if (renderer === "browser") {
|
|
645
|
-
const hasPlaywright = await hasResolvableDependency("playwright-core");
|
|
646
|
-
if (!hasPlaywright && binding === "node") {
|
|
647
|
-
issues.push("Browser renderer requires playwright-core");
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
return { valid: issues.length === 0, issues };
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
function setupDevHandler(options, resolve, getDetectedRenderers, nuxt = kit.useNuxt()) {
|
|
206
|
+
function setupDevHandler(options, resolve, getDetectedRenderers, getCompatibilityMeta = () => ({}), nuxt = kit.useNuxt()) {
|
|
654
207
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
655
208
|
const detectedRenderers = new Set(getDetectedRenderers());
|
|
656
|
-
const targetCompatibility = getPresetNitroPresetCompatibility(resolveOgImagePreset(nitro.options));
|
|
209
|
+
const targetCompatibility = dependencies.getPresetNitroPresetCompatibility(dependencies.resolveOgImagePreset(nitro.options));
|
|
657
210
|
for (const renderer of ["satori", "takumi", "browser"]) {
|
|
658
211
|
if (!detectedRenderers.has(renderer)) {
|
|
659
|
-
const binding = getRecommendedBinding(renderer, targetCompatibility);
|
|
660
|
-
const missing = await getMissingDependencies(renderer, binding);
|
|
212
|
+
const binding = dependencies.getRecommendedBinding(renderer, targetCompatibility);
|
|
213
|
+
const missing = await dependencies.getMissingDependencies(renderer, binding);
|
|
661
214
|
if (missing.length === 0)
|
|
662
215
|
detectedRenderers.add(renderer);
|
|
663
216
|
}
|
|
664
217
|
}
|
|
665
|
-
await applyNitroPresetCompatibility(nitro.options, { compatibility: options.compatibility?.dev, resolve, detectedRenderers });
|
|
218
|
+
await dependencies.applyNitroPresetCompatibility(nitro.options, { compatibility: options.compatibility?.dev, resolve, detectedRenderers, metadata: getCompatibilityMeta() });
|
|
666
219
|
});
|
|
667
220
|
}
|
|
668
221
|
|
|
@@ -788,9 +341,9 @@ ${content}`, "utf-8");
|
|
|
788
341
|
if (nameWithoutExt.includes(".")) {
|
|
789
342
|
dotNotationName = `${nameWithoutExt}.vue`;
|
|
790
343
|
} else {
|
|
791
|
-
const rendererMatch = nameWithoutExt.match(RE_RENDERER_SUFFIX);
|
|
344
|
+
const rendererMatch = nameWithoutExt.match(dependencies.RE_RENDERER_SUFFIX);
|
|
792
345
|
const renderer = rendererMatch?.[1]?.toLowerCase() || "satori";
|
|
793
|
-
const baseName = nameWithoutExt.replace(RE_RENDERER_SUFFIX, "");
|
|
346
|
+
const baseName = nameWithoutExt.replace(dependencies.RE_RENDERER_SUFFIX, "");
|
|
794
347
|
dotNotationName = `${baseName}.${renderer}.vue`;
|
|
795
348
|
}
|
|
796
349
|
const dir = pathe.join(nuxt.options.srcDir, "components", dirName || "");
|
|
@@ -1471,7 +1024,7 @@ async function downlevelColor(prop, value) {
|
|
|
1471
1024
|
function convertIndividualTransforms(styles) {
|
|
1472
1025
|
const parts = [];
|
|
1473
1026
|
if (styles.translate) {
|
|
1474
|
-
const vals = styles.translate.trim().split(RE_WHITESPACE);
|
|
1027
|
+
const vals = styles.translate.trim().split(dependencies.RE_WHITESPACE);
|
|
1475
1028
|
parts.push(vals.length === 2 ? `translate(${vals[0]}, ${vals[1]})` : `translateX(${vals[0]})`);
|
|
1476
1029
|
delete styles.translate;
|
|
1477
1030
|
}
|
|
@@ -1480,7 +1033,7 @@ function convertIndividualTransforms(styles) {
|
|
|
1480
1033
|
delete styles.rotate;
|
|
1481
1034
|
}
|
|
1482
1035
|
if (styles.scale) {
|
|
1483
|
-
const vals = styles.scale.trim().split(RE_WHITESPACE).filter(Boolean);
|
|
1036
|
+
const vals = styles.scale.trim().split(dependencies.RE_WHITESPACE).filter(Boolean);
|
|
1484
1037
|
parts.push(`scale(${vals.join(", ")})`);
|
|
1485
1038
|
delete styles.scale;
|
|
1486
1039
|
}
|
|
@@ -2113,7 +1666,7 @@ function resolveWeightsFromFontEntry(fontWeight, requestedWeights) {
|
|
|
2113
1666
|
min = Number(fontWeight[0]);
|
|
2114
1667
|
max = Number(fontWeight[1]);
|
|
2115
1668
|
} else if (typeof fontWeight === "string") {
|
|
2116
|
-
const parts = fontWeight.split(RE_WHITESPACE).map(Number);
|
|
1669
|
+
const parts = fontWeight.split(dependencies.RE_WHITESPACE).map(Number);
|
|
2117
1670
|
if (parts.length >= 2 && !Number.isNaN(parts[0]) && !Number.isNaN(parts[1])) {
|
|
2118
1671
|
min = parts[0];
|
|
2119
1672
|
max = parts[1];
|
|
@@ -2452,7 +2005,7 @@ ${familyBreakdown}`);
|
|
|
2452
2005
|
|
|
2453
2006
|
function setupGenerateHandler(_options, resolve, _getDetectedRenderers, nuxt = kit.useNuxt()) {
|
|
2454
2007
|
nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
|
|
2455
|
-
await applyNitroPresetCompatibility(nitroConfig, {
|
|
2008
|
+
await dependencies.applyNitroPresetCompatibility(nitroConfig, {
|
|
2456
2009
|
compatibility: {
|
|
2457
2010
|
browser: false,
|
|
2458
2011
|
satori: false,
|
|
@@ -2466,10 +2019,10 @@ function setupGenerateHandler(_options, resolve, _getDetectedRenderers, nuxt = k
|
|
|
2466
2019
|
}
|
|
2467
2020
|
|
|
2468
2021
|
const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2469
|
-
function setupPrerenderHandler(options, resolve, getDetectedRenderers, nuxt = kit.useNuxt()) {
|
|
2022
|
+
function setupPrerenderHandler(options, resolve, getDetectedRenderers, getCompatibilityMeta = () => ({}), nuxt = kit.useNuxt()) {
|
|
2470
2023
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
2471
2024
|
nitro.hooks.hook("prerender:config", async (nitroConfig) => {
|
|
2472
|
-
await applyNitroPresetCompatibility(nitroConfig, { compatibility: options.compatibility?.prerender, resolve, detectedRenderers: getDetectedRenderers() });
|
|
2025
|
+
await dependencies.applyNitroPresetCompatibility(nitroConfig, { compatibility: options.compatibility?.prerender, resolve, detectedRenderers: getDetectedRenderers(), metadata: getCompatibilityMeta() });
|
|
2473
2026
|
nitroConfig.wasm = nitroConfig.wasm || {};
|
|
2474
2027
|
nitroConfig.wasm.esmImport = false;
|
|
2475
2028
|
nitroConfig.prerender = nitroConfig.prerender || {};
|
|
@@ -2557,6 +2110,15 @@ function extractPropNamesFromVue(code) {
|
|
|
2557
2110
|
}
|
|
2558
2111
|
}
|
|
2559
2112
|
|
|
2113
|
+
function resolveSigningSecret(configSecret, envSecret, generate) {
|
|
2114
|
+
if (configSecret === false)
|
|
2115
|
+
return { secret: "", hasExplicit: false, optOut: true, generated: false };
|
|
2116
|
+
const explicit = configSecret || "" || (envSecret || "");
|
|
2117
|
+
if (explicit)
|
|
2118
|
+
return { secret: explicit, hasExplicit: true, optOut: false, generated: false };
|
|
2119
|
+
return { secret: generate(), hasExplicit: false, optOut: false, generated: true };
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2560
2122
|
function isVue(id, opts = {}) {
|
|
2561
2123
|
const { search } = ufo.parseURL(decodeURIComponent(node_url.pathToFileURL(id).href));
|
|
2562
2124
|
if (id.endsWith(".vue") && !search) {
|
|
@@ -2671,7 +2233,7 @@ async function extractFontRequirementsFromVue(code) {
|
|
|
2671
2233
|
const el = node;
|
|
2672
2234
|
for (const prop of el.props) {
|
|
2673
2235
|
if (prop.type === ATTRIBUTE_NODE$1 && prop.name === "class" && prop.value) {
|
|
2674
|
-
for (const cls of prop.value.content.split(RE_WHITESPACE)) {
|
|
2236
|
+
for (const cls of prop.value.content.split(dependencies.RE_WHITESPACE)) {
|
|
2675
2237
|
extractFontWeightFromClass(cls, weights, styles);
|
|
2676
2238
|
extractFontFamilyFromClass(cls, familyClasses, familyNames);
|
|
2677
2239
|
}
|
|
@@ -2998,7 +2560,7 @@ async function transformVueTemplate(code, options) {
|
|
|
2998
2560
|
};
|
|
2999
2561
|
for (const prop of el.props) {
|
|
3000
2562
|
if (prop.type === ATTRIBUTE_NODE && prop.name === "class" && prop.value) {
|
|
3001
|
-
collector.classes = prop.value.content.split(RE_WHITESPACE).filter(Boolean);
|
|
2563
|
+
collector.classes = prop.value.content.split(dependencies.RE_WHITESPACE).filter(Boolean);
|
|
3002
2564
|
collector.classLoc = {
|
|
3003
2565
|
start: prop.loc.start.offset,
|
|
3004
2566
|
end: prop.loc.end.offset
|
|
@@ -3491,7 +3053,7 @@ const AssetTransformPlugin = unplugin.createUnplugin((options) => {
|
|
|
3491
3053
|
const [fullMatch, , attrsStr, classValue] = elMatch;
|
|
3492
3054
|
if (!classValue)
|
|
3493
3055
|
continue;
|
|
3494
|
-
const classes = classValue.split(RE_WHITESPACE).filter(Boolean);
|
|
3056
|
+
const classes = classValue.split(dependencies.RE_WHITESPACE).filter(Boolean);
|
|
3495
3057
|
let iconPrefix;
|
|
3496
3058
|
let iconName;
|
|
3497
3059
|
for (const cls of classes) {
|
|
@@ -3710,7 +3272,7 @@ const AssetTransformPlugin = unplugin.createUnplugin((options) => {
|
|
|
3710
3272
|
const classAttr = el.attributes?.class;
|
|
3711
3273
|
if (!classAttr)
|
|
3712
3274
|
return;
|
|
3713
|
-
const elClasses = classAttr.split(RE_WHITESPACE).filter(Boolean);
|
|
3275
|
+
const elClasses = classAttr.split(dependencies.RE_WHITESPACE).filter(Boolean);
|
|
3714
3276
|
const matchedStyles = {};
|
|
3715
3277
|
const consumedClasses = /* @__PURE__ */ new Set();
|
|
3716
3278
|
for (const cls of elClasses) {
|
|
@@ -4214,15 +3776,19 @@ async function onInstall(nuxt) {
|
|
|
4214
3776
|
if (nuxt.options._prepare)
|
|
4215
3777
|
return;
|
|
4216
3778
|
if (stdEnv.isCI) {
|
|
4217
|
-
const installedProviders2 = await getInstalledProviders();
|
|
3779
|
+
const installedProviders2 = await dependencies.getInstalledProviders();
|
|
4218
3780
|
if (installedProviders2.length === 0) {
|
|
4219
3781
|
throw new Error(
|
|
4220
|
-
|
|
3782
|
+
`[nuxt-og-image] No OG image provider dependencies found. Install a provider before running in CI:
|
|
3783
|
+
npm add ${dependencies.TAKUMI_CORE_INSTALL_SPEC} # for takumi
|
|
3784
|
+
npm add @resvg/resvg-js satori yoga-wasm-web # for satori
|
|
3785
|
+
npm add playwright-core # for browser
|
|
3786
|
+
See: https://nuxtseo.com/og-image/getting-started`
|
|
4221
3787
|
);
|
|
4222
3788
|
}
|
|
4223
3789
|
return;
|
|
4224
3790
|
}
|
|
4225
|
-
if (!canPromptInteractively()) {
|
|
3791
|
+
if (!dependencies.canPromptInteractively()) {
|
|
4226
3792
|
logger_js.logger.info("Skipping interactive onboarding (non-interactive environment). Defaulting to the takumi renderer.");
|
|
4227
3793
|
return;
|
|
4228
3794
|
}
|
|
@@ -4232,7 +3798,7 @@ async function onInstall(nuxt) {
|
|
|
4232
3798
|
logger_js.logger.info("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
4233
3799
|
logger_js.logger.info("");
|
|
4234
3800
|
const state = {};
|
|
4235
|
-
const installedProviders = await getInstalledProviders();
|
|
3801
|
+
const installedProviders = await dependencies.getInstalledProviders();
|
|
4236
3802
|
if (installedProviders.length > 0) {
|
|
4237
3803
|
logger_js.logger.info("Detected installed providers:");
|
|
4238
3804
|
for (const { provider, binding } of installedProviders) {
|
|
@@ -4250,7 +3816,7 @@ async function onInstall(nuxt) {
|
|
|
4250
3816
|
if (!state.selectedRenderer) {
|
|
4251
3817
|
const rendererChoice = await logger_js.logger.prompt("Select a renderer:", {
|
|
4252
3818
|
type: "select",
|
|
4253
|
-
options: PROVIDER_DEPENDENCIES.map((p) => ({
|
|
3819
|
+
options: dependencies.PROVIDER_DEPENDENCIES.map((p) => ({
|
|
4254
3820
|
label: p.name,
|
|
4255
3821
|
value: p.name,
|
|
4256
3822
|
hint: p.description
|
|
@@ -4263,8 +3829,8 @@ async function onInstall(nuxt) {
|
|
|
4263
3829
|
state.selectedRenderer = rendererChoice;
|
|
4264
3830
|
}
|
|
4265
3831
|
if (!state.selectedBinding) {
|
|
4266
|
-
const recommendedBinding = getRecommendedBindingFromPreset(state.selectedRenderer);
|
|
4267
|
-
const providerDef = PROVIDER_DEPENDENCIES.find((p) => p.name === state.selectedRenderer);
|
|
3832
|
+
const recommendedBinding = dependencies.getRecommendedBindingFromPreset(state.selectedRenderer);
|
|
3833
|
+
const providerDef = dependencies.PROVIDER_DEPENDENCIES.find((p) => p.name === state.selectedRenderer);
|
|
4268
3834
|
const hasNodeBinding = !!providerDef?.bindings.node;
|
|
4269
3835
|
const hasWasmBinding = !!providerDef?.bindings.wasm || !!providerDef?.bindings["wasm-fs"];
|
|
4270
3836
|
if (hasNodeBinding && hasWasmBinding) {
|
|
@@ -4289,10 +3855,10 @@ async function onInstall(nuxt) {
|
|
|
4289
3855
|
state.selectedBinding = hasNodeBinding ? "node" : "wasm";
|
|
4290
3856
|
}
|
|
4291
3857
|
}
|
|
4292
|
-
const
|
|
4293
|
-
if (
|
|
3858
|
+
const missingInstallSpecs = await dependencies.getMissingDependencyInstallSpecs(state.selectedRenderer, state.selectedBinding);
|
|
3859
|
+
if (missingInstallSpecs.length > 0) {
|
|
4294
3860
|
logger_js.logger.info(`Required dependencies for ${state.selectedRenderer} (${state.selectedBinding}):`);
|
|
4295
|
-
for (const pkg of
|
|
3861
|
+
for (const pkg of missingInstallSpecs) {
|
|
4296
3862
|
logger_js.logger.info(` - ${pkg}`);
|
|
4297
3863
|
}
|
|
4298
3864
|
const installDeps = await logger_js.logger.prompt("Install missing dependencies?", {
|
|
@@ -4300,7 +3866,7 @@ async function onInstall(nuxt) {
|
|
|
4300
3866
|
initial: true
|
|
4301
3867
|
});
|
|
4302
3868
|
if (installDeps) {
|
|
4303
|
-
const result = await ensureProviderDependencies(
|
|
3869
|
+
const result = await dependencies.ensureProviderDependencies(
|
|
4304
3870
|
state.selectedRenderer,
|
|
4305
3871
|
state.selectedBinding,
|
|
4306
3872
|
nuxt
|
|
@@ -4309,11 +3875,11 @@ async function onInstall(nuxt) {
|
|
|
4309
3875
|
logger_js.logger.success(`Installed: ${result.installed.join(", ")}`);
|
|
4310
3876
|
} else {
|
|
4311
3877
|
logger_js.logger.error("Failed to install some dependencies. Install manually:");
|
|
4312
|
-
const allDeps =
|
|
3878
|
+
const allDeps = dependencies.getProviderDependencyInstallSpecs(state.selectedRenderer, state.selectedBinding);
|
|
4313
3879
|
logger_js.logger.info(` npm add ${allDeps.join(" ")}`);
|
|
4314
3880
|
}
|
|
4315
3881
|
} else {
|
|
4316
|
-
const allDeps =
|
|
3882
|
+
const allDeps = dependencies.getProviderDependencyInstallSpecs(state.selectedRenderer, state.selectedBinding);
|
|
4317
3883
|
logger_js.logger.warn("Dependencies required. Install manually:");
|
|
4318
3884
|
logger_js.logger.info(` npm add ${allDeps.join(" ")}`);
|
|
4319
3885
|
}
|
|
@@ -4327,14 +3893,14 @@ async function onInstall(nuxt) {
|
|
|
4327
3893
|
if (createComponent) {
|
|
4328
3894
|
await createStarterComponent(nuxt);
|
|
4329
3895
|
}
|
|
4330
|
-
const hasSharp = await hasResolvableDependency("sharp");
|
|
3896
|
+
const hasSharp = await dependencies.hasResolvableDependency("sharp");
|
|
4331
3897
|
if (!hasSharp && state.selectedRenderer === "satori") {
|
|
4332
3898
|
const wantJpeg = await logger_js.logger.prompt("Install sharp for JPEG output support?", {
|
|
4333
3899
|
type: "confirm",
|
|
4334
3900
|
initial: false
|
|
4335
3901
|
});
|
|
4336
3902
|
if (wantJpeg) {
|
|
4337
|
-
await ensureProviderDependencies("satori", "node", nuxt).catch(() => logger_js.logger.warn("Failed to install sharp, JPEG output unavailable"));
|
|
3903
|
+
await dependencies.ensureProviderDependencies("satori", "node", nuxt).catch(() => logger_js.logger.warn("Failed to install sharp, JPEG output unavailable"));
|
|
4338
3904
|
}
|
|
4339
3905
|
}
|
|
4340
3906
|
logger_js.logger.info("");
|
|
@@ -4369,7 +3935,7 @@ async function onUpgrade(nuxt, _options, previousVersion) {
|
|
|
4369
3935
|
issues.push(`Config \`defaults.component\` is deprecated: Removed \u2014 rename component to OgImage/Default.{renderer}.vue`);
|
|
4370
3936
|
}
|
|
4371
3937
|
if ("fonts" in ogImageConfig && !nuxt.options._prepare && !stdEnv.isCI) {
|
|
4372
|
-
await
|
|
3938
|
+
await dependencies.promptFontsMigration(nuxt.options.rootDir);
|
|
4373
3939
|
}
|
|
4374
3940
|
}
|
|
4375
3941
|
if (issues.length > 0) {
|
|
@@ -4386,17 +3952,17 @@ async function onUpgrade(nuxt, _options, previousVersion) {
|
|
|
4386
3952
|
const ogComponentDir = pathe.join(nuxt.options.srcDir, "components", "OgImage");
|
|
4387
3953
|
if (fs.existsSync(ogComponentDir)) {
|
|
4388
3954
|
for (const file of fs.readdirSync(ogComponentDir).filter((f) => f.endsWith(".vue"))) {
|
|
4389
|
-
const renderer = getRendererFromFilename(file);
|
|
3955
|
+
const renderer = dependencies.getRendererFromFilename(file);
|
|
4390
3956
|
if (renderer)
|
|
4391
3957
|
detectedRenderers.add(renderer);
|
|
4392
3958
|
}
|
|
4393
3959
|
}
|
|
4394
3960
|
if (detectedRenderers.size === 0)
|
|
4395
3961
|
detectedRenderers.add("satori");
|
|
4396
|
-
const preset = resolveOgImagePreset();
|
|
4397
|
-
const compatibility = getPresetNitroPresetCompatibility(preset);
|
|
3962
|
+
const preset = dependencies.resolveOgImagePreset();
|
|
3963
|
+
const compatibility = dependencies.getPresetNitroPresetCompatibility(preset);
|
|
4398
3964
|
for (const renderer of detectedRenderers) {
|
|
4399
|
-
const validation = await validateProviderSetup(renderer, compatibility);
|
|
3965
|
+
const validation = await dependencies.validateProviderSetup(renderer, compatibility);
|
|
4400
3966
|
if (!validation.valid) {
|
|
4401
3967
|
logger_js.logger.warn(`Provider setup issues for ${renderer}:`);
|
|
4402
3968
|
for (const issue of validation.issues) {
|
|
@@ -4455,7 +4021,7 @@ function registerTypeTemplates(ctx) {
|
|
|
4455
4021
|
const sortedDirs = config.componentDirs.sort((a, b) => b.length - a.length);
|
|
4456
4022
|
const baseNameRenderers = /* @__PURE__ */ new Map();
|
|
4457
4023
|
for (const component of componentCtx.components) {
|
|
4458
|
-
for (const baseName of getRegisteredBaseNames(component.pascalName)) {
|
|
4024
|
+
for (const baseName of dependencies.getRegisteredBaseNames(component.pascalName)) {
|
|
4459
4025
|
const renderers = baseNameRenderers.get(baseName) || [];
|
|
4460
4026
|
renderers.push(component.renderer);
|
|
4461
4027
|
baseNameRenderers.set(baseName, renderers);
|
|
@@ -4466,7 +4032,7 @@ function registerTypeTemplates(ctx) {
|
|
|
4466
4032
|
const importType = getComponentTypeExpression(component, nuxt);
|
|
4467
4033
|
const strippedName = sortedDirs.reduce((n, dir) => n.replace(new RegExp(`^${dir}`), ""), component.pascalName);
|
|
4468
4034
|
const renderer = component.renderer;
|
|
4469
|
-
const baseNames = getRegisteredBaseNames(component.pascalName);
|
|
4035
|
+
const baseNames = dependencies.getRegisteredBaseNames(component.pascalName);
|
|
4470
4036
|
lines.push(` '${strippedName}': ${importType}`);
|
|
4471
4037
|
const seen = /* @__PURE__ */ new Set([strippedName]);
|
|
4472
4038
|
for (const baseName of baseNames) {
|
|
@@ -4548,8 +4114,8 @@ declare module '#og-image-virtual/build-dir.mjs' {
|
|
|
4548
4114
|
}
|
|
4549
4115
|
|
|
4550
4116
|
declare module '#og-image/compatibility' {
|
|
4551
|
-
import type {
|
|
4552
|
-
const compatibility:
|
|
4117
|
+
import type { RuntimeCompatibilityPayload } from '${typesPath}'
|
|
4118
|
+
const compatibility: RuntimeCompatibilityPayload
|
|
4553
4119
|
export default compatibility
|
|
4554
4120
|
}
|
|
4555
4121
|
declare module '#og-image-virtual/tw4-theme.mjs' {
|
|
@@ -4665,6 +4231,44 @@ const RE_INLINE_CONFIG = /const\s+inlineConfig\s*=\s*(\{[\s\S]*?\n\})/;
|
|
|
4665
4231
|
const RE_PASCAL_TO_KEBAB = /([a-z])([A-Z])/g;
|
|
4666
4232
|
const RE_TILDE_PREFIX = /^~\//;
|
|
4667
4233
|
const IS_MODULE_DEVELOPMENT = undefined.endsWith(".ts");
|
|
4234
|
+
async function findPackageVersionFromEntry(pkg, resolver) {
|
|
4235
|
+
const entry = await resolver.resolvePath(pkg, { fallbackToOriginal: false }).catch(() => null);
|
|
4236
|
+
if (!entry || entry === pkg)
|
|
4237
|
+
return;
|
|
4238
|
+
let dir = pathe.dirname(entry);
|
|
4239
|
+
while (dir && dir !== pathe.dirname(dir)) {
|
|
4240
|
+
const pkgPath = pathe.join(dir, "package.json");
|
|
4241
|
+
if (fs.existsSync(pkgPath)) {
|
|
4242
|
+
const pkgJson = await pkgTypes.readPackageJSON(pkgPath).catch(() => null);
|
|
4243
|
+
if (pkgJson?.name === pkg)
|
|
4244
|
+
return pkgJson.version;
|
|
4245
|
+
}
|
|
4246
|
+
dir = pathe.dirname(dir);
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
4249
|
+
function normalizeTakumiVersion(version) {
|
|
4250
|
+
const major = version ? Number.parseInt(version.split(".")[0], 10) : Number.NaN;
|
|
4251
|
+
if (major >= 2)
|
|
4252
|
+
return 2;
|
|
4253
|
+
if (major === 1)
|
|
4254
|
+
return 1;
|
|
4255
|
+
}
|
|
4256
|
+
async function detectTakumiVersion(resolver, binding) {
|
|
4257
|
+
const packages = binding === "wasm" ? ["@takumi-rs/wasm", "@takumi-rs/core"] : ["@takumi-rs/core", "@takumi-rs/wasm"];
|
|
4258
|
+
const versions = (await Promise.all(packages.map(async (pkg) => {
|
|
4259
|
+
const version = await findPackageVersionFromEntry(pkg, resolver);
|
|
4260
|
+
const major = normalizeTakumiVersion(version);
|
|
4261
|
+
return version && major ? { pkg, version, major } : void 0;
|
|
4262
|
+
}))).filter(Boolean);
|
|
4263
|
+
const detectedMajors = new Set(versions.map(({ major }) => major));
|
|
4264
|
+
if (detectedMajors.size > 1) {
|
|
4265
|
+
const preferred = versions[0];
|
|
4266
|
+
logger_js.logger.warn(
|
|
4267
|
+
`Mismatched @takumi-rs package major versions detected (${versions.map(({ pkg, version }) => `${pkg}@${version}`).join(", ")}). Using ${preferred.pkg}@${preferred.version} for Takumi v${preferred.major} compatibility.`
|
|
4268
|
+
);
|
|
4269
|
+
}
|
|
4270
|
+
return versions[0]?.major;
|
|
4271
|
+
}
|
|
4668
4272
|
function isProviderEnabledForEnv(provider, nuxt, config) {
|
|
4669
4273
|
return nuxt.options.dev && config.compatibility?.dev?.[provider] !== false || !nuxt.options.dev && (config.compatibility?.runtime?.[provider] !== false || config.compatibility?.prerender?.[provider] !== false);
|
|
4670
4274
|
}
|
|
@@ -4713,7 +4317,7 @@ const module$1 = kit.defineNuxtModule({
|
|
|
4713
4317
|
await onUpgrade(nuxt, options, previousVersion);
|
|
4714
4318
|
},
|
|
4715
4319
|
async setup(config, nuxt) {
|
|
4716
|
-
const _resolver = kit.createResolver((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/nuxt-og-image.
|
|
4320
|
+
const _resolver = kit.createResolver((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/nuxt-og-image.yDJBWXBt.cjs', document.baseURI).href)));
|
|
4717
4321
|
const fixSharedPath = (p) => {
|
|
4718
4322
|
return p.replace(/\/shared\/runtime(\/|$)/, "/runtime$1").replace(/\/shared\/client(\/|$)/, "/client$1").replace(/\/shared\/devtools(\/|$)/, "/devtools$1");
|
|
4719
4323
|
};
|
|
@@ -4744,23 +4348,30 @@ const module$1 = kit.defineNuxtModule({
|
|
|
4744
4348
|
if (config.debug && !nuxt.options.dev) {
|
|
4745
4349
|
logger_js.logger.warn("`ogImage.debug` is enabled in production. This exposes the `/_og/debug.json` endpoint and should not be enabled in production. Disable it before deploying.");
|
|
4746
4350
|
}
|
|
4747
|
-
const
|
|
4748
|
-
|
|
4351
|
+
const signing = resolveSigningSecret(
|
|
4352
|
+
config.security?.secret,
|
|
4353
|
+
process.env.NUXT_OG_IMAGE_SECRET,
|
|
4354
|
+
() => node_crypto.randomBytes(32).toString("base64url")
|
|
4355
|
+
);
|
|
4356
|
+
const resolvedSecret = signing.secret;
|
|
4357
|
+
if (config.security?.strict && !signing.hasExplicit) {
|
|
4749
4358
|
throw new Error("[nuxt-og-image] `security.strict` requires a signing secret. Generate one with: npx nuxt-og-image generate-secret");
|
|
4750
4359
|
}
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
"
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4360
|
+
nuxt.hook("nitro:init", (nitro) => {
|
|
4361
|
+
const hasServerRuntime = !nitro.options.static && !nuxt.options._generate;
|
|
4362
|
+
if (!nuxt.options.dev || config.zeroRuntime || !hasServerRuntime)
|
|
4363
|
+
return;
|
|
4364
|
+
if (signing.optOut) {
|
|
4365
|
+
logger_js.logger.warn("OG image URL signing is disabled (`security.secret: false`). Anyone can craft arbitrary image generation requests.");
|
|
4366
|
+
} else if (signing.generated) {
|
|
4367
|
+
logger_js.logger.warn([
|
|
4368
|
+
"OG image URLs are signed with an auto-generated secret that changes every build.",
|
|
4369
|
+
"This is fine for single-instance deploys; for rolling or multi-instance deploys set a stable secret:",
|
|
4370
|
+
" NUXT_OG_IMAGE_SECRET=<secret>",
|
|
4371
|
+
" Generate one with: npx nuxt-og-image generate-secret"
|
|
4372
|
+
].join("\n"));
|
|
4373
|
+
}
|
|
4374
|
+
});
|
|
4764
4375
|
const ogImageConfig = config;
|
|
4765
4376
|
for (const key of Object.keys(REMOVED_CONFIG)) {
|
|
4766
4377
|
if (key !== "chromium-node" && key !== "browser-node" && key in ogImageConfig && ogImageConfig[key] !== void 0) {
|
|
@@ -4798,9 +4409,10 @@ Or pin to a specific version in package.json:
|
|
|
4798
4409
|
}
|
|
4799
4410
|
nuxt.options.alias["#og-image"] = resolve("./runtime");
|
|
4800
4411
|
nuxt.options.alias["#og-image-cache"] = resolve("./runtime/server/og-image/cache/lru");
|
|
4801
|
-
const preset = resolveOgImagePreset(nuxt.options.nitro);
|
|
4802
|
-
const targetCompatibility = getPresetNitroPresetCompatibility(preset);
|
|
4803
|
-
const
|
|
4412
|
+
const preset = dependencies.resolveOgImagePreset(nuxt.options.nitro);
|
|
4413
|
+
const targetCompatibility = dependencies.getPresetNitroPresetCompatibility(preset);
|
|
4414
|
+
const runtimeCompatibilityMeta = {};
|
|
4415
|
+
const normalizedPreset = preset.replace(dependencies.RE_LEGACY_SUFFIX, "");
|
|
4804
4416
|
const isCloudflareWorkers = ["cloudflare", "cloudflare-module", "cloudflare-durable"].includes(normalizedPreset);
|
|
4805
4417
|
if (isCloudflareWorkers) {
|
|
4806
4418
|
nuxt.hooks.hook("nitro:init", (nitro) => {
|
|
@@ -5071,7 +4683,7 @@ ${familyInfo}`);
|
|
|
5071
4683
|
}
|
|
5072
4684
|
} else if (hasConfiguredJpegs) {
|
|
5073
4685
|
logger_js.logger.warn("You have enabled `JPEG` images. These require the `sharp` dependency which is missing, installing it for you.");
|
|
5074
|
-
await ensureDependencies(["sharp"]);
|
|
4686
|
+
await dependencies.ensureDependencies(["sharp"]);
|
|
5075
4687
|
logger_js.logger.warn("Support for `sharp` is limited so check the compatibility guide.");
|
|
5076
4688
|
attemptSharpUsage = true;
|
|
5077
4689
|
}
|
|
@@ -5085,8 +4697,8 @@ ${familyInfo}`);
|
|
|
5085
4697
|
}
|
|
5086
4698
|
}
|
|
5087
4699
|
if (isProviderEnabledForEnv("browser", nuxt, config)) {
|
|
5088
|
-
const hasChromeLocally = checkLocalChrome();
|
|
5089
|
-
const hasPlaywrightDependency = await hasResolvableDependency("playwright");
|
|
4700
|
+
const hasChromeLocally = dependencies.checkLocalChrome();
|
|
4701
|
+
const hasPlaywrightDependency = await dependencies.hasResolvableDependency("playwright");
|
|
5090
4702
|
const browserCompatibilityFlags = {
|
|
5091
4703
|
prerender: config.compatibility?.prerender?.browser,
|
|
5092
4704
|
dev: config.compatibility?.dev?.browser,
|
|
@@ -5103,7 +4715,7 @@ ${familyInfo}`);
|
|
|
5103
4715
|
if (!browserConfig.binding) {
|
|
5104
4716
|
throw new Error("[nuxt-og-image] `ogImage.browser.binding` is required when provider is cloudflare");
|
|
5105
4717
|
}
|
|
5106
|
-
const hasCloudfarePuppeteer = await hasResolvableDependency("@cloudflare/puppeteer");
|
|
4718
|
+
const hasCloudfarePuppeteer = await dependencies.hasResolvableDependency("@cloudflare/puppeteer");
|
|
5107
4719
|
if (!hasCloudfarePuppeteer) {
|
|
5108
4720
|
throw new Error(
|
|
5109
4721
|
"[nuxt-og-image] Missing @cloudflare/puppeteer dependency. Install it with: pnpm add @cloudflare/puppeteer"
|
|
@@ -5113,12 +4725,12 @@ ${familyInfo}`);
|
|
|
5113
4725
|
browserBinding.prerender = hasPlaywrightDependency ? "playwright" : hasChromeLocally ? "chrome-launcher" : "on-demand";
|
|
5114
4726
|
browserBinding.runtime = "cloudflare";
|
|
5115
4727
|
} else if (nuxt.options.dev) {
|
|
5116
|
-
if (isUndefinedOrTruthy(browserCompatibilityFlags.dev))
|
|
4728
|
+
if (dependencies.isUndefinedOrTruthy(browserCompatibilityFlags.dev))
|
|
5117
4729
|
browserBinding.dev = hasChromeLocally ? "chrome-launcher" : hasPlaywrightDependency ? "playwright" : "on-demand";
|
|
5118
4730
|
} else {
|
|
5119
|
-
if (isUndefinedOrTruthy(browserCompatibilityFlags.prerender))
|
|
4731
|
+
if (dependencies.isUndefinedOrTruthy(browserCompatibilityFlags.prerender))
|
|
5120
4732
|
browserBinding.prerender = hasChromeLocally ? "chrome-launcher" : hasPlaywrightDependency ? "playwright" : "on-demand";
|
|
5121
|
-
if (isUndefinedOrTruthy(browserCompatibilityFlags.runtime))
|
|
4733
|
+
if (dependencies.isUndefinedOrTruthy(browserCompatibilityFlags.runtime))
|
|
5122
4734
|
browserBinding.runtime = hasPlaywrightDependency ? "playwright" : null;
|
|
5123
4735
|
}
|
|
5124
4736
|
config.compatibility = defu.defu(config.compatibility, {
|
|
@@ -5127,7 +4739,7 @@ ${familyInfo}`);
|
|
|
5127
4739
|
prerender: { browser: browserBinding.prerender }
|
|
5128
4740
|
});
|
|
5129
4741
|
}
|
|
5130
|
-
await kit$
|
|
4742
|
+
await kit$1.installNuxtSiteConfig();
|
|
5131
4743
|
nuxt.options.experimental.componentIslands ||= true;
|
|
5132
4744
|
if (config.debug || nuxt.options.dev) {
|
|
5133
4745
|
kit.addServerHandler({
|
|
@@ -5240,7 +4852,7 @@ ${familyInfo}`);
|
|
|
5240
4852
|
if (isUserDir && fs__namespace.existsSync(resolvedPath)) {
|
|
5241
4853
|
const files = fs__namespace.readdirSync(resolvedPath).filter((f) => f.endsWith(".vue"));
|
|
5242
4854
|
for (const file of files) {
|
|
5243
|
-
const renderer = getRendererFromFilename(file);
|
|
4855
|
+
const renderer = dependencies.getRendererFromFilename(file);
|
|
5244
4856
|
if (renderer) {
|
|
5245
4857
|
ogImageComponentCtx.detectedRenderers.add(renderer);
|
|
5246
4858
|
hasUserComponents = true;
|
|
@@ -5249,42 +4861,45 @@ ${familyInfo}`);
|
|
|
5249
4861
|
}
|
|
5250
4862
|
}
|
|
5251
4863
|
if (!nuxt.options._prepare && !hasUserComponents) {
|
|
5252
|
-
const installedProviders = await getInstalledProviders();
|
|
4864
|
+
const installedProviders = await dependencies.getInstalledProviders();
|
|
5253
4865
|
const preferred = installedProviders.find((p) => p.provider === "takumi") || installedProviders[0];
|
|
5254
4866
|
if (preferred) {
|
|
5255
4867
|
ogImageComponentCtx.detectedRenderers.add(preferred.provider);
|
|
5256
4868
|
logger_js.logger.debug(`Using ${preferred.provider} renderer`);
|
|
5257
|
-
} else if (nuxt.options.dev && !nuxt.options._prepare && canPromptInteractively()) {
|
|
5258
|
-
const renderer = await promptForRendererSelection();
|
|
4869
|
+
} else if (nuxt.options.dev && !nuxt.options._prepare && dependencies.canPromptInteractively()) {
|
|
4870
|
+
const renderer = await dependencies.promptForRendererSelection();
|
|
5259
4871
|
ogImageComponentCtx.detectedRenderers.add(renderer);
|
|
5260
4872
|
logger_js.logger.debug(`Using ${renderer} renderer`);
|
|
5261
4873
|
} else {
|
|
5262
4874
|
ogImageComponentCtx.detectedRenderers.add("takumi");
|
|
5263
|
-
logger_js.logger.warn(
|
|
4875
|
+
logger_js.logger.warn(`No OG image renderer dependency detected. Defaulting to \`takumi\` (non-interactive environment). Install \`${dependencies.TAKUMI_CORE_INSTALL_SPEC}\`, or add a renderer component (e.g. components/OgImage/Default.satori.vue) to choose explicitly.`);
|
|
5264
4876
|
}
|
|
5265
4877
|
}
|
|
5266
4878
|
const availableRenderers = /* @__PURE__ */ new Set();
|
|
5267
4879
|
if (!nuxt.options._prepare) {
|
|
5268
4880
|
if (!config.zeroRuntime) {
|
|
5269
4881
|
for (const renderer of ogImageComponentCtx.detectedRenderers) {
|
|
5270
|
-
const binding = getRecommendedBinding(renderer, targetCompatibility);
|
|
5271
|
-
const missing = await getMissingDependencies(renderer, binding);
|
|
4882
|
+
const binding = dependencies.getRecommendedBinding(renderer, targetCompatibility);
|
|
4883
|
+
const missing = await dependencies.getMissingDependencies(renderer, binding);
|
|
5272
4884
|
if (missing.length === 0) {
|
|
5273
4885
|
availableRenderers.add(renderer);
|
|
5274
4886
|
} else if (nuxt.options.dev && !nuxt.options._prepare) {
|
|
5275
|
-
|
|
5276
|
-
|
|
4887
|
+
const installSpecs = await dependencies.getMissingDependencyInstallSpecs(renderer, binding);
|
|
4888
|
+
logger_js.logger.warn(`${renderer} renderer requires: ${installSpecs.join(", ")}`);
|
|
4889
|
+
const { success } = await dependencies.ensureProviderDependencies(renderer, binding, nuxt);
|
|
5277
4890
|
if (success) {
|
|
5278
4891
|
availableRenderers.add(renderer);
|
|
5279
4892
|
} else if (stdEnv.isAgent) {
|
|
5280
|
-
throw new Error(`[nuxt-og-image] Failed to install ${renderer} dependencies: ${missing.join(", ")}. Install manually: npx nypm add ${
|
|
4893
|
+
throw new Error(`[nuxt-og-image] Failed to install ${renderer} dependencies: ${missing.join(", ")}. Install manually: npx nypm add ${installSpecs.join(" ")}`);
|
|
5281
4894
|
} else {
|
|
5282
4895
|
logger_js.logger.error(`Failed to install ${renderer} dependencies. Templates using this renderer won't work.`);
|
|
5283
4896
|
}
|
|
5284
4897
|
} else if (stdEnv.isAgent) {
|
|
5285
|
-
|
|
4898
|
+
const installSpecs = await dependencies.getMissingDependencyInstallSpecs(renderer, binding);
|
|
4899
|
+
throw new Error(`[nuxt-og-image] ${renderer} renderer missing dependencies: ${missing.join(", ")}. Install with: npx nypm add ${installSpecs.join(" ")}`);
|
|
5286
4900
|
} else {
|
|
5287
|
-
|
|
4901
|
+
const installSpecs = await dependencies.getMissingDependencyInstallSpecs(renderer, binding);
|
|
4902
|
+
logger_js.logger.error(`${renderer} renderer missing dependencies: ${missing.join(", ")}. Install with: npx nypm add ${installSpecs.join(" ")}`);
|
|
5288
4903
|
}
|
|
5289
4904
|
if (renderer === "satori" && availableRenderers.has(renderer) && binding !== "node") {
|
|
5290
4905
|
logger_js.logger.warn("ReSVG native binding not available. Falling back to WASM version, this may slow down PNG rendering.");
|
|
@@ -5304,11 +4919,19 @@ ${familyInfo}`);
|
|
|
5304
4919
|
availableRenderers.add(renderer);
|
|
5305
4920
|
}
|
|
5306
4921
|
}
|
|
4922
|
+
runtimeCompatibilityMeta.takumiVersion = await detectTakumiVersion(
|
|
4923
|
+
resolver,
|
|
4924
|
+
dependencies.getRecommendedBinding("takumi", targetCompatibility)
|
|
4925
|
+
);
|
|
4926
|
+
if (ogImageComponentCtx.detectedRenderers.has("takumi") && !runtimeCompatibilityMeta.takumiVersion) {
|
|
4927
|
+
logger_js.logger.warn("Unable to detect @takumi-rs version. Falling back to Takumi v1 renderer compatibility.");
|
|
4928
|
+
runtimeCompatibilityMeta.takumiVersion = 1;
|
|
4929
|
+
}
|
|
5307
4930
|
if (nuxt.options.dev) {
|
|
5308
4931
|
const communityRenderers = /* @__PURE__ */ new Set();
|
|
5309
4932
|
for (const renderer of ["satori", "takumi", "browser"]) {
|
|
5310
|
-
const binding = getRecommendedBinding(renderer, targetCompatibility);
|
|
5311
|
-
const missing = await getMissingDependencies(renderer, binding);
|
|
4933
|
+
const binding = dependencies.getRecommendedBinding(renderer, targetCompatibility);
|
|
4934
|
+
const missing = await dependencies.getMissingDependencies(renderer, binding);
|
|
5312
4935
|
if (missing.length === 0)
|
|
5313
4936
|
communityRenderers.add(renderer);
|
|
5314
4937
|
}
|
|
@@ -5339,7 +4962,7 @@ ${familyInfo}`);
|
|
|
5339
4962
|
if (valid && fs__namespace.existsSync(component.filePath)) {
|
|
5340
4963
|
if (!component.filePath.endsWith(".vue"))
|
|
5341
4964
|
return;
|
|
5342
|
-
const renderer = getRendererFromFilename(component.filePath);
|
|
4965
|
+
const renderer = dependencies.getRendererFromFilename(component.filePath);
|
|
5343
4966
|
if (!renderer) {
|
|
5344
4967
|
invalidComponents.push(component.filePath);
|
|
5345
4968
|
return;
|
|
@@ -5370,18 +4993,18 @@ ${familyInfo}`);
|
|
|
5370
4993
|
const communityDir = resolve("./runtime/app/components/Templates/Community");
|
|
5371
4994
|
if (fs__namespace.existsSync(communityDir)) {
|
|
5372
4995
|
fs__namespace.readdirSync(communityDir).filter((f) => f.endsWith(".vue")).forEach((file) => {
|
|
5373
|
-
const renderer = getRendererFromFilename(file);
|
|
4996
|
+
const renderer = dependencies.getRendererFromFilename(file);
|
|
5374
4997
|
if (!renderer)
|
|
5375
4998
|
return;
|
|
5376
4999
|
const pascalName = file.replace(".vue", "").split(".").map((s, i) => i === 0 ? s : s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
5377
5000
|
const filePath = resolve(communityDir);
|
|
5378
|
-
const communityBaseNames = getRegisteredBaseNames(pascalName);
|
|
5001
|
+
const communityBaseNames = dependencies.getRegisteredBaseNames(pascalName);
|
|
5379
5002
|
if (ogImageComponentCtx.components.some((c) => {
|
|
5380
5003
|
if (c.pascalName === pascalName)
|
|
5381
5004
|
return true;
|
|
5382
5005
|
if (c.renderer !== renderer)
|
|
5383
5006
|
return false;
|
|
5384
|
-
const existingBaseNames = getRegisteredBaseNames(c.pascalName);
|
|
5007
|
+
const existingBaseNames = dependencies.getRegisteredBaseNames(c.pascalName);
|
|
5385
5008
|
return communityBaseNames.some((cb) => existingBaseNames.includes(cb));
|
|
5386
5009
|
})) {
|
|
5387
5010
|
return;
|
|
@@ -5402,10 +5025,12 @@ ${familyInfo}`);
|
|
|
5402
5025
|
if (nuxt.options.dev) {
|
|
5403
5026
|
for (const renderer of ogImageComponentCtx.detectedRenderers) {
|
|
5404
5027
|
if (!availableRenderers.has(renderer)) {
|
|
5405
|
-
const binding = getRecommendedBinding(renderer, targetCompatibility);
|
|
5406
|
-
getMissingDependencies(renderer, binding).then((missing) => {
|
|
5407
|
-
if (missing.length > 0)
|
|
5408
|
-
|
|
5028
|
+
const binding = dependencies.getRecommendedBinding(renderer, targetCompatibility);
|
|
5029
|
+
dependencies.getMissingDependencies(renderer, binding).then(async (missing) => {
|
|
5030
|
+
if (missing.length > 0) {
|
|
5031
|
+
const installSpecs = await dependencies.getMissingDependencyInstallSpecs(renderer, binding);
|
|
5032
|
+
logger_js.logger.warn(`New ${renderer} component detected but dependencies missing: ${missing.join(", ")}. Install with: npx nypm add ${installSpecs.join(" ")}`);
|
|
5033
|
+
}
|
|
5409
5034
|
});
|
|
5410
5035
|
}
|
|
5411
5036
|
}
|
|
@@ -5451,7 +5076,7 @@ Run: npx nuxt-og-image migrate v6`;
|
|
|
5451
5076
|
maxAge: 60 * 60 * 24 * 365
|
|
5452
5077
|
});
|
|
5453
5078
|
nuxt.options.nitro.virtual["#og-image-virtual/public-assets.mjs"] = async () => {
|
|
5454
|
-
const normalizedPreset2 = preset.replace(RE_LEGACY_SUFFIX, "");
|
|
5079
|
+
const normalizedPreset2 = preset.replace(dependencies.RE_LEGACY_SUFFIX, "");
|
|
5455
5080
|
const isCloudflare = normalizedPreset2 === "cloudflare" || normalizedPreset2.startsWith("cloudflare-");
|
|
5456
5081
|
if (isCloudflare) {
|
|
5457
5082
|
const devBinding2 = resolver.resolve("./runtime/server/og-image/bindings/font-assets/dev-prerender");
|
|
@@ -5607,7 +5232,7 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`;
|
|
|
5607
5232
|
const buildCacheDir = config.buildCache ? pathe.join(nuxt.options.rootDir, buildCachePath) : void 0;
|
|
5608
5233
|
nuxt.hooks.hook("modules:done", async () => {
|
|
5609
5234
|
const hasColorModeModule = kit.hasNuxtModule("@nuxtjs/color-mode");
|
|
5610
|
-
const colorModeOptions = hasColorModeModule ? await kit$
|
|
5235
|
+
const colorModeOptions = hasColorModeModule ? await kit$2.getNuxtModuleOptions("@nuxtjs/color-mode") : {};
|
|
5611
5236
|
let colorPreference = colorModeOptions.preference;
|
|
5612
5237
|
if (!colorPreference || colorPreference === "system")
|
|
5613
5238
|
colorPreference = colorModeOptions.fallback;
|
|
@@ -5643,7 +5268,7 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`;
|
|
|
5643
5268
|
imageFetchTimeout: config.security?.imageFetchTimeout ?? 3e3,
|
|
5644
5269
|
maxQueryParamSize: config.security?.maxQueryParamSize ?? (config.security?.strict ? 2048 : null),
|
|
5645
5270
|
restrictRuntimeImagesToOrigin: config.security?.restrictRuntimeImagesToOrigin === true || config.security?.strict && config.security?.restrictRuntimeImagesToOrigin == null ? [] : config.security?.restrictRuntimeImagesToOrigin || false,
|
|
5646
|
-
secret:
|
|
5271
|
+
secret: resolvedSecret
|
|
5647
5272
|
}
|
|
5648
5273
|
};
|
|
5649
5274
|
if (nuxt.options.dev) {
|
|
@@ -5657,7 +5282,7 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`;
|
|
|
5657
5282
|
const existingOgImageCfg = nuxt.options.runtimeConfig.ogImage;
|
|
5658
5283
|
nuxt.options.runtimeConfig.ogImage = {
|
|
5659
5284
|
...existingOgImageCfg && typeof existingOgImageCfg === "object" ? existingOgImageCfg : {},
|
|
5660
|
-
secret: existingOgImageCfg?.secret ||
|
|
5285
|
+
secret: existingOgImageCfg?.secret || (signing.hasExplicit ? signing.secret : "")
|
|
5661
5286
|
};
|
|
5662
5287
|
nuxt.options.runtimeConfig.public = {
|
|
5663
5288
|
...nuxt.options.runtimeConfig.public,
|
|
@@ -5678,8 +5303,9 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`;
|
|
|
5678
5303
|
};
|
|
5679
5304
|
});
|
|
5680
5305
|
const getDetectedRenderers = () => ogImageComponentCtx.detectedRenderers;
|
|
5306
|
+
const getCompatibilityMeta = () => runtimeCompatibilityMeta;
|
|
5681
5307
|
if (nuxt.options.dev) {
|
|
5682
|
-
setupDevHandler(config, resolver, getDetectedRenderers);
|
|
5308
|
+
setupDevHandler(config, resolver, getDetectedRenderers, getCompatibilityMeta);
|
|
5683
5309
|
setupDevToolsUI(config, resolve, nuxt, cssFramework || "none");
|
|
5684
5310
|
const useNitro = new Promise((resolveNitro) => {
|
|
5685
5311
|
nuxt.hooks.hook("nitro:init", resolveNitro);
|
|
@@ -5710,14 +5336,14 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`;
|
|
|
5710
5336
|
await nitro.hooks.callHook("rollup:reload");
|
|
5711
5337
|
}
|
|
5712
5338
|
});
|
|
5713
|
-
} else if (kit$
|
|
5339
|
+
} else if (kit$2.isNuxtGenerate()) {
|
|
5714
5340
|
setupGenerateHandler(config, resolver);
|
|
5715
5341
|
} else if (nuxt.options.build) {
|
|
5716
|
-
await setupBuildHandler(config, resolver, getDetectedRenderers);
|
|
5342
|
+
await setupBuildHandler(config, resolver, getDetectedRenderers, getCompatibilityMeta);
|
|
5717
5343
|
}
|
|
5718
5344
|
if (nuxt.options.build)
|
|
5719
5345
|
kit.addServerPlugin(resolve("./runtime/server/plugins/prerender"));
|
|
5720
|
-
setupPrerenderHandler(config, resolver, getDetectedRenderers);
|
|
5346
|
+
setupPrerenderHandler(config, resolver, getDetectedRenderers, getCompatibilityMeta);
|
|
5721
5347
|
if (nuxt.options.dev && hasWarnings()) {
|
|
5722
5348
|
nuxt.hook("ready", () => {
|
|
5723
5349
|
emitWarnings();
|