@nuxt/scripts 1.0.0-beta.30 → 1.0.0-beta.32
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/dist/client/200.html +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_nuxt/{CYlYSSNW.js → CxpRPAAJ.js} +1 -1
- package/dist/client/_nuxt/{D5FIkDae.js → D0d_xOOu.js} +1 -1
- package/dist/client/_nuxt/{AwAKM0sG.js → DxzaVa0B.js} +1 -1
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/d7ecb215-eee2-4720-b2bc-f3ad271b9c30.json +1 -0
- package/dist/client/_nuxt/entry.esAfLJmC.css +1 -0
- package/dist/client/_nuxt/ojT6Btul.js +162 -0
- package/dist/client/index.html +1 -1
- package/dist/module.d.mts +23 -45
- package/dist/module.d.ts +23 -45
- package/dist/module.json +1 -1
- package/dist/module.mjs +241 -227
- package/dist/registry.d.mts +6 -1
- package/dist/registry.d.ts +6 -1
- package/dist/registry.mjs +150 -11
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.d.vue.ts +5 -2
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue +11 -2
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue.d.ts +5 -2
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.d.vue.ts +14 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue +50 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue.d.ts +14 -0
- package/dist/runtime/registry/gravatar.d.ts +1 -1
- package/dist/runtime/server/proxy-handler.js +25 -36
- package/dist/runtime/server/utils/privacy.d.ts +0 -8
- package/dist/runtime/server/utils/privacy.js +7 -7
- package/dist/runtime/types.d.ts +71 -13
- package/dist/shared/scripts.T4Z99VT8.mjs +37 -0
- package/dist/stats.mjs +7 -15
- package/dist/types-source.mjs +16 -2
- package/dist/types.d.mts +1 -1
- package/package.json +2 -2
- package/dist/client/_nuxt/Bl23o3st.js +0 -162
- package/dist/client/_nuxt/builds/meta/f0b4dd20-8496-4003-b7a3-05cbae515923.json +0 -1
- package/dist/client/_nuxt/entry.C5SUNdim.css +0 -1
- package/dist/shared/scripts.ViOoYQXH.mjs +0 -381
package/dist/module.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { useNuxt, addDevServerHandler, extendRouteRules, tryUseNuxt, extendViteConfig, useLogger, addServerHandler, addPluginTemplate, logger as logger$1, addTypeTemplate, defineNuxtModule, createResolver, addImports, addComponentsDir, addTemplate, hasNuxtModule, addBuildPlugin } from '@nuxt/kit';
|
|
3
3
|
import { defu } from 'defu';
|
|
4
4
|
import { join, resolve, relative } from 'pathe';
|
|
5
5
|
import { resolvePackageJSON, readPackageJSON } from 'pkg-types';
|
|
@@ -19,48 +19,161 @@ import { colors } from 'consola/utils';
|
|
|
19
19
|
import MagicString from 'magic-string';
|
|
20
20
|
import { hash } from 'ohash';
|
|
21
21
|
import { registry } from './registry.mjs';
|
|
22
|
-
import {
|
|
22
|
+
import { b as buildProxyConfigsFromRegistry } from './shared/scripts.T4Z99VT8.mjs';
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
const renderedScript = /* @__PURE__ */ new Map();
|
|
25
|
+
const ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365;
|
|
26
|
+
function bundleStorage() {
|
|
27
|
+
const nuxt = tryUseNuxt();
|
|
28
|
+
return createStorage({
|
|
29
|
+
driver: fsDriver({
|
|
30
|
+
base: resolve(nuxt?.options.rootDir || "", "node_modules/.cache/nuxt/scripts")
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function setupPublicAssetStrategy(options = {}) {
|
|
35
|
+
const assetsBaseURL = options.prefix || "/_scripts/assets";
|
|
36
|
+
const nuxt = useNuxt();
|
|
37
|
+
const storage = bundleStorage();
|
|
38
|
+
addDevServerHandler({
|
|
39
|
+
route: assetsBaseURL,
|
|
40
|
+
handler: lazyEventHandler(async () => {
|
|
41
|
+
return eventHandler(async (event) => {
|
|
42
|
+
const cleanPath = (event.path || "").split("?")[0]?.slice(1) || "";
|
|
43
|
+
const filename = cleanPath;
|
|
44
|
+
const scriptDescriptor = renderedScript.get(join(assetsBaseURL, cleanPath));
|
|
45
|
+
if (!scriptDescriptor || scriptDescriptor instanceof Error)
|
|
46
|
+
throw createError({ statusCode: 404 });
|
|
47
|
+
if (scriptDescriptor.content) {
|
|
48
|
+
return scriptDescriptor.content;
|
|
49
|
+
}
|
|
50
|
+
const key = `bundle:${filename}`;
|
|
51
|
+
let res = await storage.getItemRaw(key);
|
|
52
|
+
if (!res) {
|
|
53
|
+
res = await fetch(scriptDescriptor.src).then((r) => r.arrayBuffer()).then((r) => Buffer.from(r));
|
|
54
|
+
await storage.setItemRaw(key, res);
|
|
55
|
+
}
|
|
56
|
+
return res;
|
|
57
|
+
});
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
if (nuxt.options.dev) {
|
|
61
|
+
extendRouteRules(joinURL(assetsBaseURL, "**"), {
|
|
62
|
+
cache: {
|
|
63
|
+
maxAge: ONE_YEAR_IN_SECONDS
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const cacheDir = join(nuxt.options.buildDir, "cache", "scripts");
|
|
68
|
+
nuxt.hook("nitro:config", (nitroConfig) => {
|
|
69
|
+
nitroConfig.publicAssets ||= [];
|
|
70
|
+
nitroConfig.publicAssets.push({
|
|
71
|
+
dir: cacheDir,
|
|
72
|
+
maxAge: ONE_YEAR_IN_SECONDS,
|
|
73
|
+
baseURL: assetsBaseURL
|
|
74
|
+
});
|
|
75
|
+
nitroConfig.prerender ||= {};
|
|
76
|
+
nitroConfig.prerender.ignore ||= [];
|
|
77
|
+
nitroConfig.prerender.ignore.push(assetsBaseURL);
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
renderedScript
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const DEVTOOLS_UI_ROUTE = "/__nuxt-scripts";
|
|
85
|
+
const DEVTOOLS_UI_LOCAL_PORT = 3300;
|
|
86
|
+
|
|
87
|
+
async function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
|
|
88
|
+
const clientPath = await resolve("./client");
|
|
89
|
+
const isProductionBuild = existsSync(clientPath);
|
|
90
|
+
if (isProductionBuild) {
|
|
91
|
+
nuxt.hook("vite:serverCreated", async (server) => {
|
|
92
|
+
const sirv = await import('sirv').then((r) => r.default || r);
|
|
93
|
+
server.middlewares.use(
|
|
94
|
+
DEVTOOLS_UI_ROUTE,
|
|
95
|
+
sirv(clientPath, { dev: true, single: true })
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
extendViteConfig((config) => {
|
|
100
|
+
config.server = config.server || {};
|
|
101
|
+
config.server.proxy = config.server.proxy || {};
|
|
102
|
+
config.server.proxy[DEVTOOLS_UI_ROUTE] = {
|
|
103
|
+
target: `http://localhost:${DEVTOOLS_UI_LOCAL_PORT}${DEVTOOLS_UI_ROUTE}`,
|
|
104
|
+
changeOrigin: true,
|
|
105
|
+
followRedirects: true,
|
|
106
|
+
rewrite: (path) => path.replace(DEVTOOLS_UI_ROUTE, "")
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
addCustomTab({
|
|
111
|
+
// unique identifier
|
|
112
|
+
name: "nuxt-scripts",
|
|
113
|
+
// title to display in the tab
|
|
114
|
+
title: "Scripts",
|
|
115
|
+
// any icon from Iconify, or a URL to an image
|
|
116
|
+
icon: "carbon:script",
|
|
117
|
+
// iframe view
|
|
118
|
+
view: {
|
|
119
|
+
type: "iframe",
|
|
120
|
+
src: DEVTOOLS_UI_ROUTE
|
|
35
121
|
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function generatePartytownResolveUrl(proxyPrefix) {
|
|
126
|
+
return `function(url, location, type) {
|
|
127
|
+
if (url.origin !== location.origin) {
|
|
128
|
+
return new URL(${JSON.stringify(proxyPrefix)} + '/' + url.host + url.pathname + url.search, location.origin);
|
|
36
129
|
}
|
|
37
130
|
}`;
|
|
38
131
|
}
|
|
39
132
|
|
|
40
133
|
const logger = useLogger("@nuxt/scripts");
|
|
41
134
|
|
|
42
|
-
function
|
|
43
|
-
const
|
|
135
|
+
function resolveCapabilities(script, scriptOptions) {
|
|
136
|
+
const defaults = script.defaultCapability ?? {};
|
|
137
|
+
const ceiling = script.capabilities ?? {};
|
|
138
|
+
const resolved = { ...defaults };
|
|
139
|
+
if (!scriptOptions)
|
|
140
|
+
return resolved;
|
|
141
|
+
const overrideKeys = ["reverseProxyIntercept", "bundle", "partytown"];
|
|
142
|
+
for (const key of overrideKeys) {
|
|
143
|
+
if (key in scriptOptions) {
|
|
144
|
+
const userValue = scriptOptions[key];
|
|
145
|
+
if (typeof userValue !== "boolean")
|
|
146
|
+
continue;
|
|
147
|
+
if (userValue && !ceiling[key]) {
|
|
148
|
+
if (import.meta.dev) {
|
|
149
|
+
logger.warn(
|
|
150
|
+
`[nuxt-scripts] Script "${script.registryKey}" does not support capability "${key}". This override will be ignored. Supported capabilities: ${JSON.stringify(ceiling)}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
resolved[key] = userValue;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return resolved;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function generateInterceptPluginContents(proxyPrefix) {
|
|
44
162
|
return `export default defineNuxtPlugin({
|
|
45
163
|
name: 'nuxt-scripts:intercept',
|
|
46
164
|
enforce: 'pre',
|
|
47
165
|
setup() {
|
|
48
|
-
const
|
|
166
|
+
const proxyPrefix = ${JSON.stringify(proxyPrefix)};
|
|
49
167
|
const origBeacon = typeof navigator !== 'undefined' && navigator.sendBeacon
|
|
50
168
|
? navigator.sendBeacon.bind(navigator)
|
|
51
169
|
: () => false;
|
|
52
170
|
const origFetch = globalThis.fetch.bind(globalThis);
|
|
53
171
|
|
|
54
|
-
function
|
|
172
|
+
function proxyUrl(url) {
|
|
55
173
|
try {
|
|
56
174
|
const parsed = new URL(url, location.origin);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (rule.pathPrefix && !parsed.pathname.startsWith(rule.pathPrefix)) continue;
|
|
60
|
-
const path = rule.pathPrefix ? parsed.pathname.slice(rule.pathPrefix.length) : parsed.pathname;
|
|
61
|
-
return location.origin + rule.target + (path.startsWith('/') ? '' : '/') + path + parsed.search;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
175
|
+
if (parsed.origin !== location.origin)
|
|
176
|
+
return location.origin + proxyPrefix + '/' + parsed.host + parsed.pathname + parsed.search;
|
|
64
177
|
} catch {}
|
|
65
178
|
return url;
|
|
66
179
|
}
|
|
@@ -70,7 +183,7 @@ function generateInterceptPluginContents(interceptRules) {
|
|
|
70
183
|
class ProxiedXHR extends OrigXHR {
|
|
71
184
|
open() {
|
|
72
185
|
const args = Array.from(arguments);
|
|
73
|
-
if (typeof args[1] === 'string') args[1] =
|
|
186
|
+
if (typeof args[1] === 'string') args[1] = proxyUrl(args[1]);
|
|
74
187
|
return super.open.apply(this, args);
|
|
75
188
|
}
|
|
76
189
|
}
|
|
@@ -83,7 +196,7 @@ function generateInterceptPluginContents(interceptRules) {
|
|
|
83
196
|
if (origSrcDesc && origSrcDesc.set) {
|
|
84
197
|
Object.defineProperty(img, 'src', {
|
|
85
198
|
get() { return origSrcDesc.get.call(this); },
|
|
86
|
-
set(v) { origSrcDesc.set.call(this, typeof v === 'string' ?
|
|
199
|
+
set(v) { origSrcDesc.set.call(this, typeof v === 'string' ? proxyUrl(v) : v); },
|
|
87
200
|
configurable: true,
|
|
88
201
|
});
|
|
89
202
|
}
|
|
@@ -91,8 +204,12 @@ function generateInterceptPluginContents(interceptRules) {
|
|
|
91
204
|
}
|
|
92
205
|
|
|
93
206
|
globalThis.__nuxtScripts = {
|
|
94
|
-
sendBeacon: (url, data) => origBeacon(
|
|
95
|
-
fetch: (url, opts) =>
|
|
207
|
+
sendBeacon: (url, data) => origBeacon(proxyUrl(url), data),
|
|
208
|
+
fetch: (url, opts) => {
|
|
209
|
+
if (typeof url === 'string') return origFetch(proxyUrl(url), opts);
|
|
210
|
+
if (url instanceof Request) return origFetch(new Request(proxyUrl(url.url), url), opts);
|
|
211
|
+
return origFetch(url, opts);
|
|
212
|
+
},
|
|
96
213
|
XMLHttpRequest: ProxiedXHR,
|
|
97
214
|
Image: ProxiedImage,
|
|
98
215
|
};
|
|
@@ -102,13 +219,12 @@ function generateInterceptPluginContents(interceptRules) {
|
|
|
102
219
|
}
|
|
103
220
|
|
|
104
221
|
async function setupFirstParty(config, resolvePath) {
|
|
105
|
-
const
|
|
106
|
-
const proxyPrefix = typeof config.
|
|
107
|
-
const privacy = typeof config.
|
|
222
|
+
const proxyDisabled = config.proxy === false;
|
|
223
|
+
const proxyPrefix = typeof config.proxy === "object" ? config.proxy.prefix || "/_scripts/p" : "/_scripts/p";
|
|
224
|
+
const privacy = typeof config.proxy === "object" ? config.proxy.privacy : void 0;
|
|
108
225
|
const assetsPrefix = config.assets?.prefix || "/_scripts/assets";
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
if (enabled) {
|
|
226
|
+
const firstParty = { enabled: !proxyDisabled, proxyPrefix, privacy, assetsPrefix, proxyConfigs: {} };
|
|
227
|
+
if (!proxyDisabled) {
|
|
112
228
|
const proxyHandlerPath = await resolvePath("./runtime/server/proxy-handler");
|
|
113
229
|
logger.debug("[nuxt-scripts] Registering proxy handler:", `${proxyPrefix}/**`, "->", proxyHandlerPath);
|
|
114
230
|
addServerHandler({
|
|
@@ -123,6 +239,9 @@ function applyAutoInject(registry, runtimeConfig, proxyPrefix, registryKey, auto
|
|
|
123
239
|
if (!entry)
|
|
124
240
|
return;
|
|
125
241
|
const input = entry[0];
|
|
242
|
+
const scriptOptions = entry[1];
|
|
243
|
+
if (input?.reverseProxyIntercept === false || scriptOptions?.reverseProxyIntercept === false)
|
|
244
|
+
return;
|
|
126
245
|
const rtScripts = runtimeConfig.public?.scripts;
|
|
127
246
|
const rtEntry = rtScripts?.[registryKey];
|
|
128
247
|
const config = rtEntry && typeof rtEntry === "object" ? rtEntry : input;
|
|
@@ -133,16 +252,6 @@ function applyAutoInject(registry, runtimeConfig, proxyPrefix, registryKey, auto
|
|
|
133
252
|
if (rtEntry && typeof rtEntry === "object" && rtEntry !== input)
|
|
134
253
|
rtEntry[autoInject.configField] = value;
|
|
135
254
|
}
|
|
136
|
-
const DOMAIN_RE = /^https?:\/\/([^/]+)/;
|
|
137
|
-
function extractDomains(routes) {
|
|
138
|
-
const domains = /* @__PURE__ */ new Set();
|
|
139
|
-
for (const { proxy } of Object.values(routes)) {
|
|
140
|
-
const match = proxy.match(DOMAIN_RE);
|
|
141
|
-
if (match?.[1])
|
|
142
|
-
domains.add(match[1]);
|
|
143
|
-
}
|
|
144
|
-
return [...domains].sort();
|
|
145
|
-
}
|
|
146
255
|
function computePrivacyLevel(privacy) {
|
|
147
256
|
const flags = Object.values(privacy);
|
|
148
257
|
if (flags.every(Boolean))
|
|
@@ -153,17 +262,19 @@ function computePrivacyLevel(privacy) {
|
|
|
153
262
|
}
|
|
154
263
|
function finalizeFirstParty(opts) {
|
|
155
264
|
const { firstParty, registryScripts, nuxtOptions } = opts;
|
|
156
|
-
const {
|
|
265
|
+
const { proxyPrefix } = firstParty;
|
|
266
|
+
const proxyConfigs = buildProxyConfigsFromRegistry(registryScripts);
|
|
267
|
+
firstParty.proxyConfigs = proxyConfigs;
|
|
157
268
|
const registryKeys = Object.keys(opts.registry || {});
|
|
158
269
|
const scriptByKey = /* @__PURE__ */ new Map();
|
|
159
270
|
for (const script of registryScripts) {
|
|
160
271
|
if (script.registryKey)
|
|
161
272
|
scriptByKey.set(script.registryKey, script);
|
|
162
273
|
}
|
|
163
|
-
const
|
|
164
|
-
const routePrivacyOverrides = {};
|
|
274
|
+
const domainPrivacy = {};
|
|
165
275
|
const unsupportedScripts = [];
|
|
166
276
|
const unmatchedScripts = [];
|
|
277
|
+
let totalDomains = 0;
|
|
167
278
|
const devtoolsScripts = [];
|
|
168
279
|
for (const key of registryKeys) {
|
|
169
280
|
const script = scriptByKey.get(key);
|
|
@@ -171,20 +282,22 @@ function finalizeFirstParty(opts) {
|
|
|
171
282
|
unmatchedScripts.push(key);
|
|
172
283
|
continue;
|
|
173
284
|
}
|
|
174
|
-
if (script.
|
|
285
|
+
if (!script.capabilities?.reverseProxyIntercept)
|
|
286
|
+
continue;
|
|
287
|
+
const registryEntry = opts.registry?.[key];
|
|
288
|
+
const entryScriptOptions = registryEntry?.[1];
|
|
289
|
+
const entryInput = registryEntry?.[0];
|
|
290
|
+
if (entryScriptOptions?.reverseProxyIntercept === false || entryInput?.reverseProxyIntercept === false)
|
|
175
291
|
continue;
|
|
176
|
-
const configKey = script.
|
|
292
|
+
const configKey = script.proxyConfig || key;
|
|
177
293
|
const proxyConfig = proxyConfigs[configKey];
|
|
178
294
|
if (!proxyConfig) {
|
|
179
|
-
|
|
180
|
-
unsupportedScripts.push(key);
|
|
295
|
+
unsupportedScripts.push(key);
|
|
181
296
|
continue;
|
|
182
297
|
}
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
for (const routePath of Object.keys(proxyConfig.routes))
|
|
187
|
-
routePrivacyOverrides[routePath] = proxyConfig.privacy;
|
|
298
|
+
for (const domain of proxyConfig.domains) {
|
|
299
|
+
domainPrivacy[domain] = proxyConfig.privacy;
|
|
300
|
+
totalDomains++;
|
|
188
301
|
}
|
|
189
302
|
if (proxyConfig.autoInject && opts.registry)
|
|
190
303
|
applyAutoInject(opts.registry, nuxtOptions.runtimeConfig, proxyPrefix, key, proxyConfig.autoInject);
|
|
@@ -200,7 +313,6 @@ function finalizeFirstParty(opts) {
|
|
|
200
313
|
};
|
|
201
314
|
const logo = script.logo;
|
|
202
315
|
const logoStr = typeof logo === "object" ? logo.dark || logo.light : logo || "";
|
|
203
|
-
const interceptRules2 = routesToInterceptRules(scriptRoutes);
|
|
204
316
|
devtoolsScripts.push({
|
|
205
317
|
registryKey: key,
|
|
206
318
|
label: script.label || key,
|
|
@@ -213,9 +325,7 @@ function finalizeFirstParty(opts) {
|
|
|
213
325
|
hasPostProcess: !!proxyConfig.postProcess,
|
|
214
326
|
privacy: normalizedPrivacy,
|
|
215
327
|
privacyLevel: computePrivacyLevel(normalizedPrivacy),
|
|
216
|
-
domains:
|
|
217
|
-
routes: Object.entries(scriptRoutes).map(([local, { proxy }]) => ({ local, target: proxy })),
|
|
218
|
-
interceptRules: interceptRules2
|
|
328
|
+
domains: [...proxyConfig.domains]
|
|
219
329
|
});
|
|
220
330
|
}
|
|
221
331
|
}
|
|
@@ -231,30 +341,21 @@ These scripts will not have proxy routes registered. Check that the registry key
|
|
|
231
341
|
They will load directly from third-party servers. Request support at https://github.com/nuxt/scripts/issues`
|
|
232
342
|
);
|
|
233
343
|
}
|
|
234
|
-
const interceptRules = routesToInterceptRules(neededRoutes);
|
|
235
344
|
addPluginTemplate({
|
|
236
345
|
filename: "nuxt-scripts-intercept.client.mjs",
|
|
237
346
|
getContents() {
|
|
238
|
-
return generateInterceptPluginContents(
|
|
347
|
+
return generateInterceptPluginContents(proxyPrefix);
|
|
239
348
|
}
|
|
240
349
|
});
|
|
241
|
-
const flatRoutes = {};
|
|
242
|
-
for (const [path, config] of Object.entries(neededRoutes))
|
|
243
|
-
flatRoutes[path] = config.proxy;
|
|
244
350
|
nuxtOptions.runtimeConfig["nuxt-scripts-proxy"] = {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
351
|
+
proxyPrefix,
|
|
352
|
+
domainPrivacy,
|
|
353
|
+
privacy: firstParty.privacy
|
|
248
354
|
};
|
|
249
355
|
const privacyLabel = firstParty.privacy === void 0 ? "per-script" : typeof firstParty.privacy === "boolean" ? firstParty.privacy ? "anonymize" : "passthrough" : "custom";
|
|
250
|
-
if (
|
|
251
|
-
const routeCount = Object.keys(neededRoutes).length;
|
|
356
|
+
if (totalDomains > 0 && nuxtOptions.dev) {
|
|
252
357
|
const scriptsCount = registryKeys.length;
|
|
253
|
-
logger.success(`First-party mode enabled for ${scriptsCount} script(s), ${
|
|
254
|
-
if (logger.level >= 4) {
|
|
255
|
-
for (const [path, config] of Object.entries(neededRoutes))
|
|
256
|
-
logger.debug(` ${path} \u2192 ${config.proxy}`);
|
|
257
|
-
}
|
|
358
|
+
logger.success(`First-party mode enabled for ${scriptsCount} script(s), ${totalDomains} domain(s) proxied (privacy: ${privacyLabel})`);
|
|
258
359
|
}
|
|
259
360
|
const staticPresets = ["static", "github-pages", "cloudflare-pages-static", "netlify-static", "azure-static", "firebase-static"];
|
|
260
361
|
const preset = process.env.NITRO_PRESET || "";
|
|
@@ -266,7 +367,7 @@ Scripts will be bundled, but collection requests will not be proxied.
|
|
|
266
367
|
Options:
|
|
267
368
|
1. Configure platform rewrites (Vercel, Netlify, Cloudflare)
|
|
268
369
|
2. Switch to server-rendered mode (ssr: true)
|
|
269
|
-
3. Disable with
|
|
370
|
+
3. Disable with proxy: false
|
|
270
371
|
|
|
271
372
|
See: https://scripts.nuxt.com/docs/guides/first-party#static-hosting`
|
|
272
373
|
);
|
|
@@ -283,112 +384,10 @@ See: https://scripts.nuxt.com/docs/guides/first-party#static-hosting`
|
|
|
283
384
|
proxyPrefix,
|
|
284
385
|
privacyMode: privacyLabel,
|
|
285
386
|
scripts: devtoolsScripts,
|
|
286
|
-
totalRoutes: Object.keys(neededRoutes).length,
|
|
287
387
|
totalDomains: allDomains.size
|
|
288
388
|
};
|
|
289
389
|
}
|
|
290
|
-
return {
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const renderedScript = /* @__PURE__ */ new Map();
|
|
294
|
-
const ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365;
|
|
295
|
-
function bundleStorage() {
|
|
296
|
-
const nuxt = tryUseNuxt();
|
|
297
|
-
return createStorage({
|
|
298
|
-
driver: fsDriver({
|
|
299
|
-
base: resolve(nuxt?.options.rootDir || "", "node_modules/.cache/nuxt/scripts")
|
|
300
|
-
})
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
function setupPublicAssetStrategy(options = {}) {
|
|
304
|
-
const assetsBaseURL = options.prefix || "/_scripts/assets";
|
|
305
|
-
const nuxt = useNuxt();
|
|
306
|
-
const storage = bundleStorage();
|
|
307
|
-
addDevServerHandler({
|
|
308
|
-
route: assetsBaseURL,
|
|
309
|
-
handler: lazyEventHandler(async () => {
|
|
310
|
-
return eventHandler(async (event) => {
|
|
311
|
-
const cleanPath = (event.path || "").split("?")[0]?.slice(1) || "";
|
|
312
|
-
const filename = cleanPath;
|
|
313
|
-
const scriptDescriptor = renderedScript.get(join(assetsBaseURL, cleanPath));
|
|
314
|
-
if (!scriptDescriptor || scriptDescriptor instanceof Error)
|
|
315
|
-
throw createError({ statusCode: 404 });
|
|
316
|
-
if (scriptDescriptor.content) {
|
|
317
|
-
return scriptDescriptor.content;
|
|
318
|
-
}
|
|
319
|
-
const key = `bundle:${filename}`;
|
|
320
|
-
let res = await storage.getItemRaw(key);
|
|
321
|
-
if (!res) {
|
|
322
|
-
res = await fetch(scriptDescriptor.src).then((r) => r.arrayBuffer()).then((r) => Buffer.from(r));
|
|
323
|
-
await storage.setItemRaw(key, res);
|
|
324
|
-
}
|
|
325
|
-
return res;
|
|
326
|
-
});
|
|
327
|
-
})
|
|
328
|
-
});
|
|
329
|
-
if (nuxt.options.dev) {
|
|
330
|
-
extendRouteRules(joinURL(assetsBaseURL, "**"), {
|
|
331
|
-
cache: {
|
|
332
|
-
maxAge: ONE_YEAR_IN_SECONDS
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
const cacheDir = join(nuxt.options.buildDir, "cache", "scripts");
|
|
337
|
-
nuxt.hook("nitro:config", (nitroConfig) => {
|
|
338
|
-
nitroConfig.publicAssets ||= [];
|
|
339
|
-
nitroConfig.publicAssets.push({
|
|
340
|
-
dir: cacheDir,
|
|
341
|
-
maxAge: ONE_YEAR_IN_SECONDS,
|
|
342
|
-
baseURL: assetsBaseURL
|
|
343
|
-
});
|
|
344
|
-
nitroConfig.prerender ||= {};
|
|
345
|
-
nitroConfig.prerender.ignore ||= [];
|
|
346
|
-
nitroConfig.prerender.ignore.push(assetsBaseURL);
|
|
347
|
-
});
|
|
348
|
-
return {
|
|
349
|
-
renderedScript
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const DEVTOOLS_UI_ROUTE = "/__nuxt-scripts";
|
|
354
|
-
const DEVTOOLS_UI_LOCAL_PORT = 3300;
|
|
355
|
-
|
|
356
|
-
async function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
|
|
357
|
-
const clientPath = await resolve("./client");
|
|
358
|
-
const isProductionBuild = existsSync(clientPath);
|
|
359
|
-
if (isProductionBuild) {
|
|
360
|
-
nuxt.hook("vite:serverCreated", async (server) => {
|
|
361
|
-
const sirv = await import('sirv').then((r) => r.default || r);
|
|
362
|
-
server.middlewares.use(
|
|
363
|
-
DEVTOOLS_UI_ROUTE,
|
|
364
|
-
sirv(clientPath, { dev: true, single: true })
|
|
365
|
-
);
|
|
366
|
-
});
|
|
367
|
-
} else {
|
|
368
|
-
extendViteConfig((config) => {
|
|
369
|
-
config.server = config.server || {};
|
|
370
|
-
config.server.proxy = config.server.proxy || {};
|
|
371
|
-
config.server.proxy[DEVTOOLS_UI_ROUTE] = {
|
|
372
|
-
target: `http://localhost:${DEVTOOLS_UI_LOCAL_PORT}${DEVTOOLS_UI_ROUTE}`,
|
|
373
|
-
changeOrigin: true,
|
|
374
|
-
followRedirects: true,
|
|
375
|
-
rewrite: (path) => path.replace(DEVTOOLS_UI_ROUTE, "")
|
|
376
|
-
};
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
addCustomTab({
|
|
380
|
-
// unique identifier
|
|
381
|
-
name: "nuxt-scripts",
|
|
382
|
-
// title to display in the tab
|
|
383
|
-
title: "Scripts",
|
|
384
|
-
// any icon from Iconify, or a URL to an image
|
|
385
|
-
icon: "carbon:script",
|
|
386
|
-
// iframe view
|
|
387
|
-
view: {
|
|
388
|
-
type: "iframe",
|
|
389
|
-
src: DEVTOOLS_UI_ROUTE
|
|
390
|
-
}
|
|
391
|
-
});
|
|
390
|
+
return { proxyPrefix, devtools };
|
|
392
391
|
}
|
|
393
392
|
|
|
394
393
|
const isStackblitz = provider === "stackblitz";
|
|
@@ -710,7 +709,8 @@ function rewriteScriptUrlsAST(content, filename, rewrites, postProcess, options)
|
|
|
710
709
|
}
|
|
711
710
|
if (node.type === "CallExpression" && !options?.skipApiRewrites) {
|
|
712
711
|
const callee = node.callee;
|
|
713
|
-
const
|
|
712
|
+
const shouldNeutralizeCanvas = options?.neutralizeCanvas !== false;
|
|
713
|
+
const canvasPropName = shouldNeutralizeCanvas && callee?.type === "MemberExpression" ? callee.computed ? callee.property?.type === "Literal" && typeof callee.property.value === "string" ? callee.property.value : null : callee.property?.name : null;
|
|
714
714
|
if (canvasPropName === "toDataURL" && callee.object) {
|
|
715
715
|
const blankCanvas = `"${BLANK_CANVAS_DATA_URL}"`;
|
|
716
716
|
if (callee.object.type === "Identifier") {
|
|
@@ -817,7 +817,7 @@ function normalizeScriptData(src, assetsBaseURL = "/_scripts/assets") {
|
|
|
817
817
|
return { url: src };
|
|
818
818
|
}
|
|
819
819
|
async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
|
|
820
|
-
const { src, url, filename, forceDownload, integrity, proxyRewrites, postProcess, skipApiRewrites } = opts;
|
|
820
|
+
const { src, url, filename, forceDownload, integrity, proxyRewrites, postProcess, skipApiRewrites, neutralizeCanvas } = opts;
|
|
821
821
|
if (src === url || !filename) {
|
|
822
822
|
return;
|
|
823
823
|
}
|
|
@@ -855,7 +855,7 @@ async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
|
|
|
855
855
|
await storage.setItemRaw(`bundle:${filename}`, res);
|
|
856
856
|
if (proxyRewrites?.length && res) {
|
|
857
857
|
const content = res.toString("utf-8");
|
|
858
|
-
const rewritten = rewriteScriptUrlsAST(content, filename || "script.js", proxyRewrites, postProcess, { skipApiRewrites });
|
|
858
|
+
const rewritten = rewriteScriptUrlsAST(content, filename || "script.js", proxyRewrites, postProcess, { skipApiRewrites, neutralizeCanvas });
|
|
859
859
|
res = Buffer.from(rewritten, "utf-8");
|
|
860
860
|
logger.debug(`Rewrote ${proxyRewrites.length} URL patterns in ${filename}`);
|
|
861
861
|
}
|
|
@@ -1035,34 +1035,39 @@ function NuxtScriptBundleTransformer(options = {
|
|
|
1035
1035
|
canBundle = bundleValue === true || bundleValue === "force" || String(bundleValue) === "true";
|
|
1036
1036
|
forceDownload = bundleValue === "force";
|
|
1037
1037
|
}
|
|
1038
|
-
const
|
|
1039
|
-
return prop.type === "Property" && prop.key?.name === "
|
|
1038
|
+
const rpiOption = scriptOptions?.value.properties?.find((prop) => {
|
|
1039
|
+
return prop.type === "Property" && prop.key?.name === "reverseProxyIntercept" && prop.value.type === "Literal";
|
|
1040
1040
|
});
|
|
1041
|
-
let firstPartyOptOut =
|
|
1041
|
+
let firstPartyOptOut = rpiOption?.value.value === false;
|
|
1042
1042
|
if (!firstPartyOptOut && node.arguments[1]?.type === "ObjectExpression") {
|
|
1043
|
-
const
|
|
1044
|
-
(p) => p.type === "Property" && p.key?.name === "
|
|
1043
|
+
const secondArgProp = node.arguments[1].properties.find(
|
|
1044
|
+
(p) => p.type === "Property" && p.key?.name === "reverseProxyIntercept" && p.value.type === "Literal"
|
|
1045
1045
|
);
|
|
1046
|
-
firstPartyOptOut =
|
|
1046
|
+
firstPartyOptOut = secondArgProp?.value.value === false;
|
|
1047
1047
|
}
|
|
1048
1048
|
if (!firstPartyOptOut && node.arguments[0]?.type === "ObjectExpression") {
|
|
1049
|
-
const
|
|
1050
|
-
(p) => p.type === "Property" && p.key?.name === "
|
|
1049
|
+
const firstArgProp = node.arguments[0].properties.find(
|
|
1050
|
+
(p) => p.type === "Property" && p.key?.name === "reverseProxyIntercept" && p.value.type === "Literal"
|
|
1051
1051
|
);
|
|
1052
|
-
firstPartyOptOut =
|
|
1052
|
+
firstPartyOptOut = firstArgProp?.value.value === false;
|
|
1053
1053
|
}
|
|
1054
1054
|
if (canBundle) {
|
|
1055
1055
|
const { url: _url, filename } = normalizeScriptData(src, options.assetsBaseURL);
|
|
1056
1056
|
const script = options.scripts?.find((s2) => s2.import.name === fnName);
|
|
1057
|
-
const
|
|
1057
|
+
const hasReverseProxy = script?.capabilities?.reverseProxyIntercept;
|
|
1058
|
+
const proxyConfigKey = hasReverseProxy ? script?.proxyConfig || registryKey : void 0;
|
|
1058
1059
|
const proxyConfig = !firstPartyOptOut && proxyConfigKey ? options.proxyConfigs?.[proxyConfigKey] : void 0;
|
|
1059
|
-
const proxyRewrites = proxyConfig?.
|
|
1060
|
+
const proxyRewrites = proxyConfig?.domains?.map((domain) => ({
|
|
1061
|
+
from: domain,
|
|
1062
|
+
to: `${options.proxyPrefix}/${domain}`
|
|
1063
|
+
}));
|
|
1060
1064
|
const postProcess = proxyConfig?.postProcess;
|
|
1061
1065
|
const skipApiRewrites = !!(registryKey && options.partytownScripts?.has(registryKey));
|
|
1066
|
+
const neutralizeCanvas = proxyConfig?.privacy !== void 0 && typeof proxyConfig.privacy === "object" ? proxyConfig.privacy.hardware ?? true : true;
|
|
1062
1067
|
deferredOps.push(async () => {
|
|
1063
1068
|
let url = _url;
|
|
1064
1069
|
try {
|
|
1065
|
-
await downloadScript({ src, url, filename, forceDownload, proxyRewrites, postProcess, integrity: options.integrity, skipApiRewrites }, renderedScript, options.fetchOptions, options.cacheMaxAge);
|
|
1070
|
+
await downloadScript({ src, url, filename, forceDownload, proxyRewrites, postProcess, integrity: options.integrity, skipApiRewrites, neutralizeCanvas }, renderedScript, options.fetchOptions, options.cacheMaxAge);
|
|
1066
1071
|
} catch (e) {
|
|
1067
1072
|
if (options.fallbackOnSrcOnBundleFail) {
|
|
1068
1073
|
logger.warn(`[Nuxt Scripts: Bundle Transformer] Failed to bundle ${src}. Fallback to remote loading.`);
|
|
@@ -1436,7 +1441,6 @@ const module$1 = defineNuxtModule({
|
|
|
1436
1441
|
}
|
|
1437
1442
|
},
|
|
1438
1443
|
defaults: {
|
|
1439
|
-
firstParty: true,
|
|
1440
1444
|
defaultScriptOptions: {
|
|
1441
1445
|
trigger: "onNuxtReady"
|
|
1442
1446
|
},
|
|
@@ -1513,37 +1517,11 @@ const module$1 = defineNuxtModule({
|
|
|
1513
1517
|
};
|
|
1514
1518
|
if (config.defaultScriptOptions?.bundle !== void 0) {
|
|
1515
1519
|
logger.warn(
|
|
1516
|
-
"`scripts.defaultScriptOptions.bundle` is deprecated.
|
|
1520
|
+
"`scripts.defaultScriptOptions.bundle` is deprecated. Bundling is now auto-enabled per-script via capabilities. Set `bundle: false` per-script to disable."
|
|
1517
1521
|
);
|
|
1518
1522
|
}
|
|
1519
1523
|
const firstParty = await setupFirstParty(config, resolvePath);
|
|
1520
1524
|
const assetsPrefix = firstParty.assetsPrefix;
|
|
1521
|
-
if (config.partytown?.length) {
|
|
1522
|
-
config.registry = config.registry || {};
|
|
1523
|
-
const requiredForwards = [];
|
|
1524
|
-
for (const scriptKey of config.partytown) {
|
|
1525
|
-
const forwards = PARTYTOWN_FORWARDS[scriptKey];
|
|
1526
|
-
if (forwards) {
|
|
1527
|
-
requiredForwards.push(...forwards);
|
|
1528
|
-
} else if (import.meta.dev) {
|
|
1529
|
-
logger.warn(`[partytown] "${scriptKey}" has no known Partytown forwards configured. It may not work correctly or may require manual forward configuration.`);
|
|
1530
|
-
}
|
|
1531
|
-
const reg = config.registry;
|
|
1532
|
-
const existing = reg[scriptKey];
|
|
1533
|
-
if (existing) {
|
|
1534
|
-
existing[1] = { ...existing[1], partytown: true };
|
|
1535
|
-
} else {
|
|
1536
|
-
reg[scriptKey] = [{}, { partytown: true }];
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
if (requiredForwards.length && hasNuxtModule("@nuxtjs/partytown")) {
|
|
1540
|
-
const partytownConfig = nuxt.options.partytown || {};
|
|
1541
|
-
const existingForwards = partytownConfig.forward || [];
|
|
1542
|
-
const newForwards = [.../* @__PURE__ */ new Set([...existingForwards, ...requiredForwards])];
|
|
1543
|
-
nuxt.options.partytown = { ...partytownConfig, forward: newForwards };
|
|
1544
|
-
logger.info(`[partytown] Auto-configured forwards: ${requiredForwards.join(", ")}`);
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
1525
|
const composables = [
|
|
1548
1526
|
"useScript",
|
|
1549
1527
|
"useScriptEventPage",
|
|
@@ -1600,8 +1578,43 @@ const module$1 = defineNuxtModule({
|
|
|
1600
1578
|
});
|
|
1601
1579
|
}
|
|
1602
1580
|
const { renderedScript } = setupPublicAssetStrategy(config.assets);
|
|
1581
|
+
const partytownScripts = /* @__PURE__ */ new Set();
|
|
1582
|
+
const scriptByKey = /* @__PURE__ */ new Map();
|
|
1583
|
+
for (const script of registryScripts) {
|
|
1584
|
+
if (script.registryKey)
|
|
1585
|
+
scriptByKey.set(script.registryKey, script);
|
|
1586
|
+
}
|
|
1587
|
+
let anyNeedsProxy = false;
|
|
1588
|
+
const registryKeys = Object.keys(config.registry || {});
|
|
1589
|
+
for (const key of registryKeys) {
|
|
1590
|
+
const script = scriptByKey.get(key);
|
|
1591
|
+
if (!script)
|
|
1592
|
+
continue;
|
|
1593
|
+
const entry = config.registry?.[key];
|
|
1594
|
+
const scriptOptions = entry?.[1] || {};
|
|
1595
|
+
const inputOptions = entry?.[0] || {};
|
|
1596
|
+
const mergedOverrides = { ...inputOptions, ...scriptOptions };
|
|
1597
|
+
const resolved = resolveCapabilities(script, mergedOverrides);
|
|
1598
|
+
if (resolved.reverseProxyIntercept)
|
|
1599
|
+
anyNeedsProxy = true;
|
|
1600
|
+
if (resolved.partytown) {
|
|
1601
|
+
partytownScripts.add(key);
|
|
1602
|
+
const forwards = PARTYTOWN_FORWARDS[key];
|
|
1603
|
+
if (forwards?.length && hasNuxtModule("@nuxtjs/partytown")) {
|
|
1604
|
+
const partytownConfig = nuxt.options.partytown || {};
|
|
1605
|
+
const existingForwards = partytownConfig.forward || [];
|
|
1606
|
+
const newForwards = [.../* @__PURE__ */ new Set([...existingForwards, ...forwards])];
|
|
1607
|
+
nuxt.options.partytown = { ...partytownConfig, forward: newForwards };
|
|
1608
|
+
} else if (!forwards && import.meta.dev) {
|
|
1609
|
+
logger.warn(`[partytown] "${key}" has no known Partytown forwards configured. It may not work correctly or may require manual forward configuration.`);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
if (firstParty.enabled && !anyNeedsProxy) {
|
|
1614
|
+
firstParty.enabled = false;
|
|
1615
|
+
}
|
|
1603
1616
|
if (firstParty.enabled) {
|
|
1604
|
-
const {
|
|
1617
|
+
const { proxyPrefix, devtools: devtoolsData } = finalizeFirstParty({
|
|
1605
1618
|
firstParty,
|
|
1606
1619
|
registry: config.registry,
|
|
1607
1620
|
registryScripts,
|
|
@@ -1610,14 +1623,14 @@ const module$1 = defineNuxtModule({
|
|
|
1610
1623
|
if (devtoolsData) {
|
|
1611
1624
|
nuxt.options.runtimeConfig.public["nuxt-scripts-devtools"] = devtoolsData;
|
|
1612
1625
|
}
|
|
1613
|
-
if (
|
|
1626
|
+
if (partytownScripts.size && hasNuxtModule("@nuxtjs/partytown")) {
|
|
1614
1627
|
const partytownConfig = nuxt.options.partytown || {};
|
|
1615
1628
|
if (!partytownConfig.resolveUrl) {
|
|
1616
|
-
partytownConfig.resolveUrl = generatePartytownResolveUrl(
|
|
1629
|
+
partytownConfig.resolveUrl = generatePartytownResolveUrl(proxyPrefix);
|
|
1617
1630
|
nuxt.options.partytown = partytownConfig;
|
|
1618
1631
|
logger.info("[partytown] Auto-configured resolveUrl for first-party proxy");
|
|
1619
1632
|
} else {
|
|
1620
|
-
logger.warn("[partytown] Custom resolveUrl already set
|
|
1633
|
+
logger.warn("[partytown] Custom resolveUrl already set. Add first-party proxy rules to your resolveUrl manually.");
|
|
1621
1634
|
}
|
|
1622
1635
|
}
|
|
1623
1636
|
}
|
|
@@ -1630,7 +1643,8 @@ const module$1 = defineNuxtModule({
|
|
|
1630
1643
|
registryConfig: nuxt.options.runtimeConfig.public.scripts,
|
|
1631
1644
|
defaultBundle: firstParty.enabled || config.defaultScriptOptions?.bundle,
|
|
1632
1645
|
proxyConfigs: firstParty.proxyConfigs,
|
|
1633
|
-
|
|
1646
|
+
proxyPrefix: firstParty.proxyPrefix,
|
|
1647
|
+
partytownScripts,
|
|
1634
1648
|
moduleDetected(module) {
|
|
1635
1649
|
if (nuxt.options.dev && module !== "@nuxt/scripts" && !moduleInstallPromises.has(module) && !hasNuxtModule(module))
|
|
1636
1650
|
moduleInstallPromises.set(module, () => installNuxtModule(module));
|