@nuxt/scripts 1.0.0-beta.1 → 1.0.0-beta.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +6 -0
  2. package/dist/client/200.html +1 -1
  3. package/dist/client/404.html +1 -1
  4. package/dist/client/_nuxt/48AF9EJD.js +1 -0
  5. package/dist/client/_nuxt/Bk6ed9rg.js +1 -0
  6. package/dist/client/_nuxt/C4Cj8gBr.js +162 -0
  7. package/dist/client/_nuxt/{DTDyDxvR.js → DP0kj6Xn.js} +1 -1
  8. package/dist/client/_nuxt/builds/latest.json +1 -1
  9. package/dist/client/_nuxt/builds/meta/0e95b1cc-8751-4000-8cb4-a6ef270b636f.json +1 -0
  10. package/dist/client/_nuxt/entry.D45OuV0w.css +1 -0
  11. package/dist/client/_nuxt/error-404.B57D-jUQ.css +1 -0
  12. package/dist/client/_nuxt/error-500.DTHUW7BI.css +1 -0
  13. package/dist/client/index.html +1 -1
  14. package/dist/module.d.mts +87 -2
  15. package/dist/module.d.ts +176 -0
  16. package/dist/module.json +1 -1
  17. package/dist/module.mjs +710 -273
  18. package/dist/registry.d.ts +6 -0
  19. package/dist/registry.mjs +42 -19
  20. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.d.vue.ts +1 -1
  21. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +6 -6
  22. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue.d.ts +1 -1
  23. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue +6 -6
  24. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsCircle.vue +7 -7
  25. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.vue +6 -6
  26. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue +12 -12
  27. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue +6 -6
  28. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.d.vue.ts +1 -1
  29. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue +6 -6
  30. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue.d.ts +1 -1
  31. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPinElement.vue +5 -5
  32. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.vue +7 -7
  33. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.vue +7 -7
  34. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.vue +7 -7
  35. package/dist/runtime/components/ScriptCrisp.vue +1 -1
  36. package/dist/runtime/components/ScriptGoogleAdsense.vue +1 -1
  37. package/dist/runtime/components/ScriptInstagramEmbed.d.vue.ts +53 -0
  38. package/dist/runtime/components/ScriptInstagramEmbed.vue +38 -0
  39. package/dist/runtime/components/ScriptInstagramEmbed.vue.d.ts +53 -0
  40. package/dist/runtime/components/ScriptIntercom.vue +4 -3
  41. package/dist/runtime/components/ScriptLoadingIndicator.d.vue.ts +1 -1
  42. package/dist/runtime/components/ScriptLoadingIndicator.vue.d.ts +1 -1
  43. package/dist/runtime/components/ScriptPayPalButtons.d.vue.ts +2 -2
  44. package/dist/runtime/components/ScriptPayPalButtons.vue +13 -11
  45. package/dist/runtime/components/ScriptPayPalButtons.vue.d.ts +2 -2
  46. package/dist/runtime/components/ScriptPayPalMarks.d.vue.ts +2 -2
  47. package/dist/runtime/components/ScriptPayPalMarks.vue +10 -8
  48. package/dist/runtime/components/ScriptPayPalMarks.vue.d.ts +2 -2
  49. package/dist/runtime/components/ScriptPayPalMessages.d.vue.ts +2 -2
  50. package/dist/runtime/components/ScriptPayPalMessages.vue +11 -9
  51. package/dist/runtime/components/ScriptPayPalMessages.vue.d.ts +2 -2
  52. package/dist/runtime/components/ScriptStripePricingTable.vue +2 -2
  53. package/dist/runtime/components/ScriptVimeoPlayer.vue +1 -1
  54. package/dist/runtime/components/ScriptXEmbed.d.vue.ts +82 -0
  55. package/dist/runtime/components/ScriptXEmbed.vue +76 -0
  56. package/dist/runtime/components/ScriptXEmbed.vue.d.ts +82 -0
  57. package/dist/runtime/components/ScriptYouTubePlayer.vue +7 -4
  58. package/dist/runtime/composables/useScript.js +32 -6
  59. package/dist/runtime/composables/useScriptEventPage.js +2 -2
  60. package/dist/runtime/composables/useScriptTriggerConsent.js +1 -1
  61. package/dist/runtime/composables/useScriptTriggerElement.js +1 -1
  62. package/dist/runtime/composables/useScriptTriggerIdleTimeout.js +1 -1
  63. package/dist/runtime/composables/useScriptTriggerServiceWorker.d.ts +7 -0
  64. package/dist/runtime/composables/useScriptTriggerServiceWorker.js +39 -0
  65. package/dist/runtime/registry/clarity.js +21 -25
  66. package/dist/runtime/registry/cloudflare-web-analytics.js +1 -1
  67. package/dist/runtime/registry/crisp.js +1 -1
  68. package/dist/runtime/registry/databuddy-analytics.js +1 -1
  69. package/dist/runtime/registry/fathom-analytics.js +1 -1
  70. package/dist/runtime/registry/google-adsense.js +1 -1
  71. package/dist/runtime/registry/google-analytics.js +2 -2
  72. package/dist/runtime/registry/google-maps.d.ts +1 -1
  73. package/dist/runtime/registry/google-maps.js +1 -1
  74. package/dist/runtime/registry/google-recaptcha.js +2 -2
  75. package/dist/runtime/registry/google-sign-in.js +1 -1
  76. package/dist/runtime/registry/google-tag-manager.d.ts +1 -1
  77. package/dist/runtime/registry/google-tag-manager.js +2 -2
  78. package/dist/runtime/registry/hotjar.js +1 -1
  79. package/dist/runtime/registry/instagram-embed.d.ts +23 -0
  80. package/dist/runtime/registry/instagram-embed.js +22 -0
  81. package/dist/runtime/registry/intercom.js +1 -1
  82. package/dist/runtime/registry/lemon-squeezy.d.ts +0 -1
  83. package/dist/runtime/registry/matomo-analytics.js +2 -2
  84. package/dist/runtime/registry/meta-pixel.js +1 -1
  85. package/dist/runtime/registry/npm.js +1 -1
  86. package/dist/runtime/registry/paypal.d.ts +1 -1
  87. package/dist/runtime/registry/paypal.js +2 -2
  88. package/dist/runtime/registry/plausible-analytics.js +15 -9
  89. package/dist/runtime/registry/posthog.d.ts +3 -2
  90. package/dist/runtime/registry/posthog.js +8 -12
  91. package/dist/runtime/registry/reddit-pixel.js +1 -1
  92. package/dist/runtime/registry/rybbit-analytics.js +5 -3
  93. package/dist/runtime/registry/segment.js +1 -1
  94. package/dist/runtime/registry/snapchat-pixel.js +1 -1
  95. package/dist/runtime/registry/stripe.d.ts +1 -1
  96. package/dist/runtime/registry/stripe.js +1 -1
  97. package/dist/runtime/registry/tiktok-pixel.d.ts +1 -0
  98. package/dist/runtime/registry/tiktok-pixel.js +2 -1
  99. package/dist/runtime/registry/umami-analytics.js +1 -1
  100. package/dist/runtime/registry/vimeo-player.d.ts +2 -2
  101. package/dist/runtime/registry/vimeo-player.js +1 -1
  102. package/dist/runtime/registry/x-embed.d.ts +77 -0
  103. package/dist/runtime/registry/x-embed.js +41 -0
  104. package/dist/runtime/registry/x-pixel.js +1 -1
  105. package/dist/runtime/registry/youtube-player.d.ts +7 -7
  106. package/dist/runtime/registry/youtube-player.js +1 -1
  107. package/dist/runtime/server/google-static-maps-proxy.js +1 -1
  108. package/dist/runtime/server/instagram-embed-asset.d.ts +2 -0
  109. package/dist/runtime/server/instagram-embed-asset.js +42 -0
  110. package/dist/runtime/server/instagram-embed-image.d.ts +2 -0
  111. package/dist/runtime/server/instagram-embed-image.js +54 -0
  112. package/dist/runtime/server/instagram-embed.d.ts +2 -0
  113. package/dist/runtime/server/instagram-embed.js +91 -0
  114. package/dist/runtime/server/proxy-handler.d.ts +6 -0
  115. package/dist/runtime/server/proxy-handler.js +264 -0
  116. package/dist/runtime/server/utils/privacy.d.ts +141 -0
  117. package/dist/runtime/server/utils/privacy.js +324 -0
  118. package/dist/runtime/server/x-embed-image.d.ts +2 -0
  119. package/dist/runtime/server/x-embed-image.js +53 -0
  120. package/dist/runtime/server/x-embed.d.ts +49 -0
  121. package/dist/runtime/server/x-embed.js +31 -0
  122. package/dist/runtime/types.d.ts +51 -22
  123. package/dist/runtime/utils/pure.d.ts +9 -0
  124. package/dist/runtime/utils/pure.js +0 -0
  125. package/dist/runtime/utils.d.ts +3 -3
  126. package/dist/runtime/utils.js +3 -2
  127. package/dist/shared/scripts.DLRgvHQg.mjs +288 -0
  128. package/dist/stats.d.mts +39 -0
  129. package/dist/stats.d.ts +39 -0
  130. package/dist/stats.mjs +711 -0
  131. package/dist/types.d.mts +1 -1
  132. package/package.json +48 -41
  133. package/dist/client/_nuxt/Bdf7Qtwg.js +0 -1
  134. package/dist/client/_nuxt/CoyZWCgl.js +0 -162
  135. package/dist/client/_nuxt/Ds1k3yKJ.js +0 -1
  136. package/dist/client/_nuxt/builds/meta/62574f80-71d4-4f9e-8b96-145c85230d99.json +0 -1
  137. package/dist/client/_nuxt/entry.BjfcJo5q.css +0 -1
  138. package/dist/client/_nuxt/error-404.D45Vtjcx.css +0 -1
  139. package/dist/client/_nuxt/error-500.BOm1rWQf.css +0 -1
package/dist/module.mjs CHANGED
@@ -1,79 +1,36 @@
1
- import { useNuxt, extendViteConfig, useLogger, addDevServerHandler, tryUseNuxt, logger as logger$1, addTypeTemplate, defineNuxtModule, createResolver, addImports, addComponentsDir, addTemplate, addPluginTemplate, addBuildPlugin, addServerHandler, hasNuxtModule } from '@nuxt/kit';
1
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
+ import { useNuxt, addDevServerHandler, extendRouteRules, tryUseNuxt, extendViteConfig, logger as logger$1, useLogger, addTypeTemplate, defineNuxtModule, createResolver, hasNuxtModule, addImports, addComponentsDir, addTemplate, addPluginTemplate, addServerHandler, addBuildPlugin } from '@nuxt/kit';
2
3
  import { defu } from 'defu';
3
- import { resolvePackageJSON, readPackageJSON } from 'pkg-types';
4
- import { existsSync } from 'node:fs';
5
- import { createHash } from 'node:crypto';
6
- import fsp from 'node:fs/promises';
7
- import { createUnplugin } from 'unplugin';
8
- import MagicString from 'magic-string';
9
- import { asyncWalk, walk } from 'estree-walker';
10
- import { joinURL, parseURL, parseQuery, hasProtocol } from 'ufo';
11
- import { hash } from 'ohash';
12
4
  import { join, resolve, relative } from 'pathe';
13
- import { colors } from 'consola/utils';
14
- import { fetch, $fetch } from 'ofetch';
5
+ import { resolvePackageJSON, readPackageJSON } from 'pkg-types';
15
6
  import { lazyEventHandler, eventHandler, createError } from 'h3';
7
+ import { fetch, $fetch } from 'ofetch';
8
+ import { joinURL, parseURL, parseQuery, hasProtocol } from 'ufo';
16
9
  import { createStorage } from 'unstorage';
17
10
  import fsDriver from 'unstorage/drivers/fs-lite';
18
- import { pathToFileURL } from 'node:url';
11
+ import { addCustomTab } from '@nuxt/devtools-kit';
19
12
  import { isCI, provider } from 'std-env';
13
+ import { parseAndWalk } from 'oxc-walker';
14
+ import { createUnplugin } from 'unplugin';
15
+ import { pathToFileURL } from 'node:url';
16
+ import { createHash } from 'node:crypto';
17
+ import fsp from 'node:fs/promises';
18
+ import { colors } from 'consola/utils';
19
+ import MagicString from 'magic-string';
20
+ import { hash } from 'ohash';
21
+ import { a as getProxyConfig, g as getAllProxyConfigs, r as routesToInterceptRules } from './shared/scripts.DLRgvHQg.mjs';
20
22
  import { registry } from './registry.mjs';
21
23
 
22
- const DEVTOOLS_UI_ROUTE = "/__nuxt-scripts";
23
- const DEVTOOLS_UI_LOCAL_PORT = 3300;
24
-
25
- async function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
26
- const clientPath = await resolve("./client");
27
- const isProductionBuild = existsSync(clientPath);
28
- if (isProductionBuild) {
29
- nuxt.hook("vite:serverCreated", async (server) => {
30
- const sirv = await import('sirv').then((r) => r.default || r);
31
- server.middlewares.use(
32
- DEVTOOLS_UI_ROUTE,
33
- sirv(clientPath, { dev: true, single: true })
34
- );
35
- });
36
- } else {
37
- extendViteConfig((config) => {
38
- config.server = config.server || {};
39
- config.server.proxy = config.server.proxy || {};
40
- config.server.proxy[DEVTOOLS_UI_ROUTE] = {
41
- target: `http://localhost:${DEVTOOLS_UI_LOCAL_PORT}${DEVTOOLS_UI_ROUTE}`,
42
- changeOrigin: true,
43
- followRedirects: true,
44
- rewrite: (path) => path.replace(DEVTOOLS_UI_ROUTE, "")
45
- };
46
- });
47
- }
48
- nuxt.hook("devtools:customTabs", (tabs) => {
49
- tabs.push({
50
- // unique identifier
51
- name: "nuxt-scripts",
52
- // title to display in the tab
53
- title: "Scripts",
54
- // any icon from Iconify, or a URL to an image
55
- icon: "carbon:script",
56
- // iframe view
57
- view: {
58
- type: "iframe",
59
- src: DEVTOOLS_UI_ROUTE
60
- }
61
- });
62
- });
63
- }
64
-
65
- const logger = useLogger("@nuxt/scripts");
66
-
67
24
  const renderedScript = /* @__PURE__ */ new Map();
68
25
  const ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365;
69
- const bundleStorage = () => {
26
+ function bundleStorage() {
70
27
  const nuxt = tryUseNuxt();
71
28
  return createStorage({
72
29
  driver: fsDriver({
73
30
  base: resolve(nuxt?.options.rootDir || "", "node_modules/.cache/nuxt/scripts")
74
31
  })
75
32
  });
76
- };
33
+ }
77
34
  function setupPublicAssetStrategy(options = {}) {
78
35
  const assetsBaseURL = options.prefix || "/_scripts";
79
36
  const nuxt = useNuxt();
@@ -86,6 +43,9 @@ function setupPublicAssetStrategy(options = {}) {
86
43
  const scriptDescriptor = renderedScript.get(join(assetsBaseURL, event.path.slice(1)));
87
44
  if (!scriptDescriptor || scriptDescriptor instanceof Error)
88
45
  throw createError({ statusCode: 404 });
46
+ if (scriptDescriptor.content) {
47
+ return scriptDescriptor.content;
48
+ }
89
49
  const key = `bundle:${filename}`;
90
50
  let res = await storage.getItemRaw(key);
91
51
  if (!res) {
@@ -97,31 +57,112 @@ function setupPublicAssetStrategy(options = {}) {
97
57
  })
98
58
  });
99
59
  if (nuxt.options.dev) {
100
- nuxt.options.routeRules ||= {};
101
- nuxt.options.routeRules[joinURL(assetsBaseURL, "**")] = {
60
+ extendRouteRules(joinURL(assetsBaseURL, "**"), {
102
61
  cache: {
103
62
  maxAge: ONE_YEAR_IN_SECONDS
104
63
  }
105
- };
64
+ });
106
65
  }
107
- nuxt.options.nitro.publicAssets ||= [];
108
66
  const cacheDir = join(nuxt.options.buildDir, "cache", "scripts");
109
- nuxt.options.nitro.publicAssets.push();
110
- nuxt.options.nitro = defu(nuxt.options.nitro, {
111
- publicAssets: [{
67
+ nuxt.hook("nitro:config", (nitroConfig) => {
68
+ nitroConfig.publicAssets ||= [];
69
+ nitroConfig.publicAssets.push({
112
70
  dir: cacheDir,
113
71
  maxAge: ONE_YEAR_IN_SECONDS,
114
72
  baseURL: assetsBaseURL
115
- }],
116
- prerender: {
117
- ignore: [assetsBaseURL]
118
- }
73
+ });
74
+ nitroConfig.prerender ||= {};
75
+ nitroConfig.prerender.ignore ||= [];
76
+ nitroConfig.prerender.ignore.push(assetsBaseURL);
119
77
  });
120
78
  return {
121
79
  renderedScript
122
80
  };
123
81
  }
124
82
 
83
+ const DEVTOOLS_UI_ROUTE = "/__nuxt-scripts";
84
+ const DEVTOOLS_UI_LOCAL_PORT = 3300;
85
+
86
+ async function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
87
+ const clientPath = await resolve("./client");
88
+ const isProductionBuild = existsSync(clientPath);
89
+ if (isProductionBuild) {
90
+ nuxt.hook("vite:serverCreated", async (server) => {
91
+ const sirv = await import('sirv').then((r) => r.default || r);
92
+ server.middlewares.use(
93
+ DEVTOOLS_UI_ROUTE,
94
+ sirv(clientPath, { dev: true, single: true })
95
+ );
96
+ });
97
+ } else {
98
+ extendViteConfig((config) => {
99
+ config.server = config.server || {};
100
+ config.server.proxy = config.server.proxy || {};
101
+ config.server.proxy[DEVTOOLS_UI_ROUTE] = {
102
+ target: `http://localhost:${DEVTOOLS_UI_LOCAL_PORT}${DEVTOOLS_UI_ROUTE}`,
103
+ changeOrigin: true,
104
+ followRedirects: true,
105
+ rewrite: (path) => path.replace(DEVTOOLS_UI_ROUTE, "")
106
+ };
107
+ });
108
+ }
109
+ addCustomTab({
110
+ // unique identifier
111
+ name: "nuxt-scripts",
112
+ // title to display in the tab
113
+ title: "Scripts",
114
+ // any icon from Iconify, or a URL to an image
115
+ icon: "carbon:script",
116
+ // iframe view
117
+ view: {
118
+ type: "iframe",
119
+ src: DEVTOOLS_UI_ROUTE
120
+ }
121
+ });
122
+ }
123
+
124
+ const isStackblitz = provider === "stackblitz";
125
+ async function promptToInstall(name, installCommand, options) {
126
+ if (await resolvePackageJSON(name).catch(() => null))
127
+ return true;
128
+ logger$1.info(`Package ${name} is missing`);
129
+ if (isCI)
130
+ return false;
131
+ if (options.prompt === true || options.prompt !== false && !isStackblitz) {
132
+ const confirm = await logger$1.prompt(`Do you want to install ${name} package?`, {
133
+ type: "confirm",
134
+ name: "confirm",
135
+ initial: true
136
+ });
137
+ if (!confirm)
138
+ return false;
139
+ }
140
+ logger$1.info(`Installing ${name}...`);
141
+ try {
142
+ await installCommand();
143
+ logger$1.success(`Installed ${name}`);
144
+ return true;
145
+ } catch (err) {
146
+ logger$1.error(err);
147
+ return false;
148
+ }
149
+ }
150
+ const installPrompts = /* @__PURE__ */ new Set();
151
+ function installNuxtModule(name, options) {
152
+ if (installPrompts.has(name))
153
+ return;
154
+ installPrompts.add(name);
155
+ const nuxt = tryUseNuxt();
156
+ if (!nuxt)
157
+ return;
158
+ return promptToInstall(name, async () => {
159
+ const { runCommand } = await import(String("nuxi"));
160
+ await runCommand("module", ["add", name, "--cwd", nuxt.options.rootDir]);
161
+ }, { rootDir: nuxt.options.rootDir, searchPaths: nuxt.options.modulesDir, ...options });
162
+ }
163
+
164
+ const logger = useLogger("@nuxt/scripts");
165
+
125
166
  function isVue(id, opts = {}) {
126
167
  const { search } = parseURL(decodeURIComponent(pathToFileURL(id).href));
127
168
  if (id.endsWith(".vue") && !search) {
@@ -149,6 +190,173 @@ function isJS(id) {
149
190
  return JS_RE.test(pathname);
150
191
  }
151
192
 
193
+ function NuxtScriptsCheckScripts() {
194
+ return createUnplugin(() => {
195
+ return {
196
+ name: "nuxt-scripts:check-scripts",
197
+ transform: {
198
+ filter: {
199
+ id: /\.vue/
200
+ },
201
+ handler(code, id) {
202
+ if (!isVue(id, { type: ["script"] }))
203
+ return;
204
+ if (!code.includes("useScript"))
205
+ return;
206
+ let nameNode;
207
+ let errorNode;
208
+ parseAndWalk(code, id, (_node) => {
209
+ if (_node.type === "VariableDeclaration" && _node.declarations?.[0]?.id?.type === "ObjectPattern") {
210
+ const objPattern = _node.declarations[0]?.id;
211
+ for (const property of objPattern.properties) {
212
+ if (property.type === "Property" && property.key.type === "Identifier" && property.key.name === "$script" && property.value.type === "Identifier") {
213
+ nameNode = _node;
214
+ }
215
+ }
216
+ }
217
+ if (nameNode) {
218
+ let sequence = _node.type === "SequenceExpression" ? _node : null;
219
+ let assignmentExpression;
220
+ if (_node.type === "VariableDeclaration") {
221
+ if (_node.declarations[0]?.init?.type === "SequenceExpression") {
222
+ sequence = _node.declarations[0]?.init;
223
+ assignmentExpression = _node.declarations[0]?.init?.expressions?.[0];
224
+ }
225
+ }
226
+ if (sequence && !assignmentExpression) {
227
+ assignmentExpression = sequence.expressions[0]?.type === "AssignmentExpression" ? sequence.expressions[0] : null;
228
+ }
229
+ if (assignmentExpression) {
230
+ const right = assignmentExpression?.right;
231
+ if (right.callee?.name === "_withAsyncContext") {
232
+ if (right.arguments[0]?.body?.name === "$script" || right.arguments[0]?.body?.callee?.object?.name === "$script") {
233
+ errorNode = nameNode;
234
+ }
235
+ }
236
+ }
237
+ }
238
+ });
239
+ if (errorNode) {
240
+ return this.error(new Error("You can't use a top-level await on $script as it will never resolve."));
241
+ }
242
+ }
243
+ }
244
+ };
245
+ });
246
+ }
247
+
248
+ function isPropertyKeyAST(parent, ctx) {
249
+ return parent?.type === "Property" && ctx.key === "key" || parent?.type === "SwitchCase" && ctx.key === "test";
250
+ }
251
+ function matchAndRewrite(value, rewrites) {
252
+ for (const { from, to } of rewrites) {
253
+ const isSuffixMatch = from.startsWith(".");
254
+ const fromSlashIdx = from.indexOf("/");
255
+ const fromHost = fromSlashIdx > 0 ? from.slice(0, fromSlashIdx) : from;
256
+ const fromPath = fromSlashIdx > 0 ? from.slice(fromSlashIdx) : "";
257
+ if (!value.includes(fromHost))
258
+ continue;
259
+ const url = parseURL(value);
260
+ let shouldRewrite = false;
261
+ let rewriteSuffix = "";
262
+ if (url.host) {
263
+ const hostMatches = isSuffixMatch ? url.host.endsWith(fromHost) : url.host === fromHost;
264
+ if (hostMatches) {
265
+ const fullPath = url.pathname + (url.search || "") + (url.hash || "");
266
+ if (fromPath && fullPath.startsWith(fromPath)) {
267
+ shouldRewrite = true;
268
+ rewriteSuffix = fullPath.slice(fromPath.length);
269
+ } else if (!fromPath) {
270
+ shouldRewrite = true;
271
+ rewriteSuffix = fullPath;
272
+ }
273
+ }
274
+ } else if (value.startsWith("//")) {
275
+ const hostPart = value.slice(2).split("/")[0];
276
+ const hostMatches = isSuffixMatch ? hostPart?.endsWith(fromHost) ?? false : hostPart === fromHost;
277
+ if (hostMatches) {
278
+ const remainder = value.slice(2 + (hostPart?.length ?? 0));
279
+ if (fromPath && remainder.startsWith(fromPath)) {
280
+ shouldRewrite = true;
281
+ rewriteSuffix = remainder.slice(fromPath.length);
282
+ } else if (!fromPath) {
283
+ shouldRewrite = true;
284
+ rewriteSuffix = remainder;
285
+ }
286
+ }
287
+ } else if (fromPath && (value.startsWith(from) || isSuffixMatch && value.includes(from))) {
288
+ const domainEnd = value.indexOf(from) + from.length;
289
+ const nextChar = value[domainEnd];
290
+ if (!nextChar || nextChar === "/" || nextChar === "?" || nextChar === "#") {
291
+ shouldRewrite = true;
292
+ rewriteSuffix = value.slice(domainEnd);
293
+ }
294
+ }
295
+ if (shouldRewrite) {
296
+ return rewriteSuffix === "/" || rewriteSuffix.startsWith("?") || rewriteSuffix.startsWith("#") ? to + rewriteSuffix : joinURL(to, rewriteSuffix);
297
+ }
298
+ }
299
+ return null;
300
+ }
301
+ function rewriteScriptUrlsAST(content, filename, rewrites) {
302
+ const s = new MagicString(content);
303
+ parseAndWalk(content, filename, (node, parent, ctx) => {
304
+ if (node.type === "Literal" && typeof node.value === "string") {
305
+ const value = node.value;
306
+ const rewritten = matchAndRewrite(value, rewrites);
307
+ if (rewritten === null)
308
+ return;
309
+ const quote = content[node.start];
310
+ if (isPropertyKeyAST(parent, ctx)) {
311
+ s.overwrite(node.start, node.end, quote + rewritten + quote);
312
+ } else {
313
+ s.overwrite(node.start, node.end, `self.location.origin+${quote}${rewritten}${quote}`);
314
+ }
315
+ }
316
+ if (node.type === "TemplateLiteral" && node.expressions?.length === 0) {
317
+ const quasis = node.quasis;
318
+ if (quasis?.length === 1) {
319
+ const value = quasis[0].value?.cooked ?? quasis[0].value?.raw;
320
+ if (typeof value !== "string")
321
+ return;
322
+ const rewritten = matchAndRewrite(value, rewrites);
323
+ if (rewritten === null)
324
+ return;
325
+ if (isPropertyKeyAST(parent, ctx)) {
326
+ s.overwrite(node.start, node.end, `\`${rewritten}\``);
327
+ } else {
328
+ s.overwrite(node.start, node.end, `self.location.origin+\`${rewritten}\``);
329
+ }
330
+ }
331
+ }
332
+ if (node.type === "CallExpression") {
333
+ const callee = node.callee;
334
+ if (callee?.type === "MemberExpression" && !callee.computed && callee.object?.type === "Identifier" && callee.object.name === "navigator" && callee.property?.name === "sendBeacon") {
335
+ s.overwrite(callee.start, callee.end, "__nuxtScripts.sendBeacon");
336
+ }
337
+ if (callee?.type === "Identifier" && callee.name === "fetch") {
338
+ s.overwrite(callee.start, callee.end, "__nuxtScripts.fetch");
339
+ }
340
+ if (callee?.type === "MemberExpression" && !callee.computed && callee.object?.type === "Identifier" && (callee.object.name === "window" || callee.object.name === "self" || callee.object.name === "globalThis") && callee.property?.name === "fetch") {
341
+ s.overwrite(callee.start, callee.end, "__nuxtScripts.fetch");
342
+ }
343
+ }
344
+ });
345
+ let output = s.toString();
346
+ const gaRewrite = rewrites.find((r) => r.from.includes("google-analytics.com/g/collect"));
347
+ if (gaRewrite) {
348
+ output = output.replace(
349
+ /"https:\/\/"\+\(.*?\)\+"\.google-analytics\.com\/g\/collect"/g,
350
+ `self.location.origin+"${gaRewrite.to}"`
351
+ );
352
+ output = output.replace(
353
+ /"https:\/\/"\+\(.*?\)\+"\.analytics\.google\.com\/g\/collect"/g,
354
+ `self.location.origin+"${gaRewrite.to}"`
355
+ );
356
+ }
357
+ return output;
358
+ }
359
+
152
360
  const SEVEN_DAYS_IN_MS = 7 * 24 * 60 * 60 * 1e3;
153
361
  function calculateIntegrity(content, algorithm = "sha384") {
154
362
  const hash = createHash(algorithm).update(content).digest("base64");
@@ -166,10 +374,8 @@ function normalizeScriptData(src, assetsBaseURL = "/_scripts") {
166
374
  if (hasProtocol(src, { acceptRelative: true })) {
167
375
  src = src.replace(/^\/\//, "https://");
168
376
  const url = parseURL(src);
169
- const file = [
170
- `${hash(url)}.js`
171
- // force an extension
172
- ].filter(Boolean).join("-");
377
+ const h = hash(url);
378
+ const file = `${h.startsWith("-") ? `_${h.slice(1)}` : h}.js`;
173
379
  const nuxt = tryUseNuxt();
174
380
  const cdnURL = nuxt?.options.runtimeConfig?.app?.cdnURL || nuxt?.options.app?.cdnURL || "";
175
381
  const baseURL = cdnURL || nuxt?.options.app.baseURL || "";
@@ -178,7 +384,7 @@ function normalizeScriptData(src, assetsBaseURL = "/_scripts") {
178
384
  return { url: src };
179
385
  }
180
386
  async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
181
- const { src, url, filename, forceDownload, integrity } = opts;
387
+ const { src, url, filename, forceDownload, integrity, proxyRewrites } = opts;
182
388
  if (src === url || !filename) {
183
389
  return;
184
390
  }
@@ -186,7 +392,8 @@ async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
186
392
  const scriptContent = renderedScript.get(src);
187
393
  let res = scriptContent instanceof Error ? void 0 : scriptContent?.content;
188
394
  if (!res) {
189
- const cacheKey = `bundle:${filename}`;
395
+ const proxyRewritesHash = proxyRewrites?.length ? `-${hash(proxyRewrites)}` : "";
396
+ const cacheKey = proxyRewrites?.length ? `bundle-proxy:${filename.replace(".js", `${proxyRewritesHash}.js`)}` : `bundle:${filename}`;
190
397
  const shouldUseCache = !forceDownload && await storage.hasItem(cacheKey) && !await isCacheExpired(storage, filename, cacheMaxAge);
191
398
  if (shouldUseCache) {
192
399
  const cachedContent = await storage.getItemRaw(cacheKey);
@@ -212,8 +419,15 @@ async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
212
419
  size = contentLength ? Number(contentLength) / 1024 : 0;
213
420
  return Buffer.from(r._data || await r.arrayBuffer());
214
421
  });
215
- const integrityHash = integrity && res ? calculateIntegrity(res, integrity === true ? "sha384" : integrity) : void 0;
216
422
  await storage.setItemRaw(`bundle:${filename}`, res);
423
+ if (proxyRewrites?.length && res) {
424
+ const content = res.toString("utf-8");
425
+ const rewritten = rewriteScriptUrlsAST(content, filename || "script.js", proxyRewrites);
426
+ res = Buffer.from(rewritten, "utf-8");
427
+ logger.debug(`Rewrote ${proxyRewrites.length} URL patterns in ${filename}`);
428
+ }
429
+ const integrityHash = integrity && res ? calculateIntegrity(res, integrity === true ? "sha384" : integrity) : void 0;
430
+ await storage.setItemRaw(cacheKey, res);
217
431
  await storage.setItem(`bundle-meta:${filename}`, {
218
432
  timestamp: Date.now(),
219
433
  src,
@@ -262,16 +476,21 @@ function NuxtScriptBundleTransformer(options = {
262
476
  return createUnplugin(() => {
263
477
  return {
264
478
  name: "nuxt:scripts:bundler-transformer",
265
- transformInclude(id) {
266
- return isVue(id, { type: ["template", "script"] }) || isJS(id);
267
- },
268
- async transform(code, id) {
269
- if (!code.includes("useScript"))
270
- return;
271
- const ast = this.parse(code);
272
- const s = new MagicString(code);
273
- await asyncWalk(ast, {
274
- async enter(_node) {
479
+ transform: {
480
+ filter: {
481
+ id: {
482
+ include: [/\.vue/, /\.[cm]?[jt]sx?$/],
483
+ exclude: [/\.(?:test|spec)\./]
484
+ }
485
+ },
486
+ async handler(code, id) {
487
+ if (!isVue(id, { type: ["template", "script"] }) && !isJS(id))
488
+ return;
489
+ if (!code.includes("useScript"))
490
+ return;
491
+ const s = new MagicString(code);
492
+ const deferredOps = [];
493
+ parseAndWalk(code, id, (_node) => {
275
494
  const calleeName = _node.callee?.name;
276
495
  if (!calleeName)
277
496
  return;
@@ -281,6 +500,11 @@ function NuxtScriptBundleTransformer(options = {
281
500
  const node = _node;
282
501
  let scriptSrcNode;
283
502
  let src;
503
+ let registryKey;
504
+ if (fnName !== "useScript") {
505
+ const baseName = fnName.replace(/^useScript/, "");
506
+ registryKey = baseName.length > 0 ? baseName.charAt(0).toLowerCase() + baseName.slice(1) : void 0;
507
+ }
284
508
  if (fnName === "useScript") {
285
509
  if (node.arguments[0]?.type === "Literal") {
286
510
  scriptSrcNode = node.arguments[0];
@@ -297,9 +521,7 @@ function NuxtScriptBundleTransformer(options = {
297
521
  }
298
522
  if (!registryNode.scriptBundling && !registryNode.src)
299
523
  return;
300
- const baseName = fnName.replace(/^useScript/, "");
301
- const registryKey = baseName.length > 0 ? baseName.charAt(0).toLowerCase() + baseName.slice(1) : "";
302
- const registryConfig = options.registryConfig?.[registryKey] || {};
524
+ const registryConfig = options.registryConfig?.[registryKey || ""] || {};
303
525
  const fnArg0 = {};
304
526
  if (node.arguments[0]?.type === "ObjectExpression") {
305
527
  const optionsNode = node.arguments[0];
@@ -319,6 +541,8 @@ function NuxtScriptBundleTransformer(options = {
319
541
  src = registryNode.scriptBundling && registryNode.scriptBundling(mergedOptions);
320
542
  if (src === false)
321
543
  return;
544
+ if (!src && registryNode.src)
545
+ src = registryNode.src;
322
546
  }
323
547
  }
324
548
  if (!scriptSrcNode && !src) {
@@ -333,8 +557,7 @@ function NuxtScriptBundleTransformer(options = {
333
557
  if (bundleProperty && bundleProperty.value.type === "Literal") {
334
558
  const bundleValue = bundleProperty.value.value;
335
559
  if (bundleValue === true || bundleValue === "force" || String(bundleValue) === "true") {
336
- const valueNode = bundleProperty.value;
337
- s.overwrite(valueNode.start, valueNode.end, `'unsupported'`);
560
+ s.overwrite(bundleProperty.value.start, bundleProperty.value.end, `'unsupported'`);
338
561
  }
339
562
  }
340
563
  }
@@ -351,8 +574,7 @@ function NuxtScriptBundleTransformer(options = {
351
574
  (p) => (p.key?.name === "bundle" || p.key?.value === "bundle") && p.type === "Property"
352
575
  );
353
576
  if (bundleProperty && bundleProperty.value.type === "Literal") {
354
- const value = bundleProperty.value;
355
- const bundleValue = value.value;
577
+ const bundleValue = bundleProperty.value.value;
356
578
  if (bundleValue !== true && bundleValue !== "force" && String(bundleValue) !== "true") {
357
579
  canBundle = false;
358
580
  return;
@@ -380,175 +602,104 @@ function NuxtScriptBundleTransformer(options = {
380
602
  canBundle = bundleValue === true || bundleValue === "force" || String(bundleValue) === "true";
381
603
  forceDownload = bundleValue === "force";
382
604
  }
605
+ const firstPartyOption = scriptOptions?.value.properties?.find((prop) => {
606
+ return prop.type === "Property" && prop.key?.name === "firstParty" && prop.value.type === "Literal";
607
+ });
608
+ let firstPartyOptOut = firstPartyOption?.value.value === false;
609
+ if (!firstPartyOptOut && node.arguments[1]?.type === "ObjectExpression") {
610
+ const secondArgFirstPartyProp = node.arguments[1].properties.find(
611
+ (p) => p.type === "Property" && p.key?.name === "firstParty" && p.value.type === "Literal"
612
+ );
613
+ firstPartyOptOut = secondArgFirstPartyProp?.value.value === false;
614
+ }
615
+ if (!firstPartyOptOut && node.arguments[0]?.type === "ObjectExpression") {
616
+ const firstArgFirstPartyProp = node.arguments[0].properties.find(
617
+ (p) => p.type === "Property" && p.key?.name === "firstParty" && p.value.type === "Literal"
618
+ );
619
+ firstPartyOptOut = firstArgFirstPartyProp?.value.value === false;
620
+ }
383
621
  if (canBundle) {
384
622
  const { url: _url, filename } = normalizeScriptData(src, options.assetsBaseURL);
385
- let url = _url;
386
- try {
387
- await downloadScript({ src, url, filename, forceDownload, integrity: options.integrity }, renderedScript, options.fetchOptions, options.cacheMaxAge);
388
- } catch (e) {
389
- if (options.fallbackOnSrcOnBundleFail) {
390
- logger.warn(`[Nuxt Scripts: Bundle Transformer] Failed to bundle ${src}. Fallback to remote loading.`);
391
- url = src;
392
- } else {
393
- const errorMessage = e?.message || "Unknown error";
394
- if (errorMessage.includes("timeout") || errorMessage.includes("network") || errorMessage.includes("ENOTFOUND")) {
395
- logger.error(`[Nuxt Scripts: Bundle Transformer] Network issue while bundling ${src}: ${errorMessage}`);
396
- logger.error(`[Nuxt Scripts: Bundle Transformer] Tip: Set 'fallbackOnSrcOnBundleFail: true' in module options or disable bundling in Docker environments`);
623
+ const script = options.scripts?.find((s2) => s2.import.name === fnName);
624
+ const proxyConfigKey = script?.proxy !== false ? script?.proxy || registryKey : void 0;
625
+ const proxyRewrites = options.firstPartyEnabled && !firstPartyOptOut && proxyConfigKey && options.firstPartyCollectPrefix ? getProxyConfig(proxyConfigKey, options.firstPartyCollectPrefix)?.rewrite : void 0;
626
+ deferredOps.push(async () => {
627
+ let url = _url;
628
+ try {
629
+ await downloadScript({ src, url, filename, forceDownload, proxyRewrites, integrity: options.integrity }, renderedScript, options.fetchOptions, options.cacheMaxAge);
630
+ } catch (e) {
631
+ if (options.fallbackOnSrcOnBundleFail) {
632
+ logger.warn(`[Nuxt Scripts: Bundle Transformer] Failed to bundle ${src}. Fallback to remote loading.`);
633
+ url = src;
634
+ } else {
635
+ const errorMessage = e?.message || "Unknown error";
636
+ if (errorMessage.includes("timeout") || errorMessage.includes("network") || errorMessage.includes("ENOTFOUND") || errorMessage.includes("certificate")) {
637
+ logger.error(`[Nuxt Scripts: Bundle Transformer] Network issue while bundling ${src}: ${errorMessage}`);
638
+ logger.error(`[Nuxt Scripts: Bundle Transformer] Tip: Set 'fallbackOnSrcOnBundleFail: true' in module options or disable bundling in Docker environments`);
639
+ }
640
+ throw e;
397
641
  }
398
- throw e;
399
642
  }
400
- }
401
- if (src === url) {
402
- if (src && src.startsWith("/"))
403
- logger.warn(`[Nuxt Scripts: Bundle Transformer] Relative scripts are already bundled. Skipping bundling for \`${src}\`.`);
404
- else
405
- logger.warn(`[Nuxt Scripts: Bundle Transformer] Failed to bundle ${src}.`);
406
- }
407
- const scriptMeta = renderedScript.get(url);
408
- const integrityHash = scriptMeta instanceof Error ? void 0 : scriptMeta?.integrity;
409
- if (scriptSrcNode) {
410
- if (integrityHash && fnName === "useScript" && node.arguments[0]?.type === "Literal") {
411
- s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `{ src: '${url}', integrity: '${integrityHash}', crossorigin: 'anonymous' }`);
412
- } else if (integrityHash && fnName === "useScript" && node.arguments[0]?.type === "ObjectExpression") {
413
- s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `'${url}'`);
414
- const objArg = node.arguments[0];
415
- s.appendLeft(objArg.end - 1, `, integrity: '${integrityHash}', crossorigin: 'anonymous'`);
416
- } else {
417
- s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `'${url}'`);
643
+ if (src === url) {
644
+ if (src && src.startsWith("/"))
645
+ logger.warn(`[Nuxt Scripts: Bundle Transformer] Relative scripts are already bundled. Skipping bundling for \`${src}\`.`);
646
+ else
647
+ logger.warn(`[Nuxt Scripts: Bundle Transformer] Failed to bundle ${src}.`);
418
648
  }
419
- } else {
420
- const integrityProps = integrityHash ? `, integrity: '${integrityHash}', crossorigin: 'anonymous'` : "";
421
- if (node.arguments[0]) {
422
- const optionsNode = node.arguments[0];
423
- const scriptInputProperty = optionsNode.properties.find(
424
- (p) => p.key?.name === "scriptInput" || p.key?.value === "scriptInput"
425
- );
426
- if (scriptInputProperty) {
427
- const scriptInput = scriptInputProperty.value;
428
- if (scriptInput.type === "ObjectExpression") {
429
- const srcProperty = scriptInput.properties.find(
430
- (p) => p.key?.name === "src" || p.key?.value === "src"
431
- );
432
- if (srcProperty) {
433
- s.overwrite(srcProperty.value.start, srcProperty.value.end, `'${url}'`);
434
- if (integrityHash)
435
- s.appendLeft(scriptInput.end - 1, integrityProps);
436
- } else {
437
- s.appendRight(scriptInput.end - 1, `, src: '${url}'${integrityProps}`);
649
+ const scriptMeta = renderedScript.get(url);
650
+ const integrityHash = scriptMeta instanceof Error ? void 0 : scriptMeta?.integrity;
651
+ if (scriptSrcNode) {
652
+ if (integrityHash && fnName === "useScript" && node.arguments[0]?.type === "Literal") {
653
+ s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `{ src: '${url}', integrity: '${integrityHash}', crossorigin: 'anonymous' }`);
654
+ } else if (integrityHash && fnName === "useScript" && node.arguments[0]?.type === "ObjectExpression") {
655
+ s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `'${url}'`);
656
+ s.appendLeft(node.arguments[0].end - 1, `, integrity: '${integrityHash}', crossorigin: 'anonymous'`);
657
+ } else {
658
+ s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `'${url}'`);
659
+ }
660
+ } else {
661
+ const integrityProps = integrityHash ? `, integrity: '${integrityHash}', crossorigin: 'anonymous'` : "";
662
+ if (node.arguments[0]) {
663
+ const optionsNode = node.arguments[0];
664
+ const scriptInputProperty = optionsNode.properties.find(
665
+ (p) => p.key?.name === "scriptInput" || p.key?.value === "scriptInput"
666
+ );
667
+ if (scriptInputProperty) {
668
+ const scriptInput = scriptInputProperty.value;
669
+ if (scriptInput.type === "ObjectExpression") {
670
+ const srcProperty = scriptInput.properties.find(
671
+ (p) => p.key?.name === "src" || p.key?.value === "src"
672
+ );
673
+ if (srcProperty) {
674
+ s.overwrite(srcProperty.value.start, srcProperty.value.end, `'${url}'`);
675
+ if (integrityHash)
676
+ s.appendLeft(scriptInput.end - 1, integrityProps);
677
+ } else {
678
+ s.appendRight(scriptInput.end - 1, `, src: '${url}'${integrityProps}`);
679
+ }
438
680
  }
681
+ } else {
682
+ s.appendRight(node.arguments[0].start + 1, ` scriptInput: { src: '${url}'${integrityProps} }, `);
439
683
  }
440
684
  } else {
441
- s.appendRight(node.arguments[0].start + 1, ` scriptInput: { src: '${url}'${integrityProps} }, `);
685
+ s.overwrite(node.callee.end, node.end, `({ scriptInput: { src: '${url}'${integrityProps} } })`);
442
686
  }
443
- } else {
444
- s.appendRight(node.callee.end, `({ scriptInput: { src: '${url}'${integrityProps} } })`);
445
687
  }
446
- }
688
+ });
447
689
  }
448
690
  }
449
691
  }
450
692
  }
693
+ });
694
+ for (const op of deferredOps) {
695
+ await op();
451
696
  }
452
- });
453
- if (s.hasChanged()) {
454
- return {
455
- code: s.toString(),
456
- map: s.generateMap({ includeContent: true, source: id })
457
- };
458
- }
459
- }
460
- };
461
- });
462
- }
463
-
464
- const isStackblitz = provider === "stackblitz";
465
- async function promptToInstall(name, installCommand, options) {
466
- if (await resolvePackageJSON(name).catch(() => null))
467
- return true;
468
- logger$1.info(`Package ${name} is missing`);
469
- if (isCI)
470
- return false;
471
- if (options.prompt === true || options.prompt !== false && !isStackblitz) {
472
- const confirm = await logger$1.prompt(`Do you want to install ${name} package?`, {
473
- type: "confirm",
474
- name: "confirm",
475
- initial: true
476
- });
477
- if (!confirm)
478
- return false;
479
- }
480
- logger$1.info(`Installing ${name}...`);
481
- try {
482
- await installCommand();
483
- logger$1.success(`Installed ${name}`);
484
- return true;
485
- } catch (err) {
486
- logger$1.error(err);
487
- return false;
488
- }
489
- }
490
- const installPrompts = /* @__PURE__ */ new Set();
491
- function installNuxtModule(name, options) {
492
- if (installPrompts.has(name))
493
- return;
494
- installPrompts.add(name);
495
- const nuxt = tryUseNuxt();
496
- if (!nuxt)
497
- return;
498
- return promptToInstall(name, async () => {
499
- const { runCommand } = await import(String("nuxi"));
500
- await runCommand("module", ["add", name, "--cwd", nuxt.options.rootDir]);
501
- }, { rootDir: nuxt.options.rootDir, searchPaths: nuxt.options.modulesDir, ...options });
502
- }
503
-
504
- function NuxtScriptsCheckScripts() {
505
- return createUnplugin(() => {
506
- return {
507
- name: "nuxt-scripts:check-scripts",
508
- transformInclude(id) {
509
- return isVue(id, { type: ["script"] });
510
- },
511
- async transform(code) {
512
- if (!code.includes("useScript"))
513
- return;
514
- const ast = this.parse(code);
515
- let nameNode;
516
- let errorNode;
517
- walk(ast, {
518
- enter(_node) {
519
- if (_node.type === "VariableDeclaration" && _node.declarations?.[0]?.id?.type === "ObjectPattern") {
520
- const objPattern = _node.declarations[0]?.id;
521
- for (const property of objPattern.properties) {
522
- if (property.type === "Property" && property.key.type === "Identifier" && property.key.name === "$script" && property.value.type === "Identifier") {
523
- nameNode = _node;
524
- }
525
- }
526
- }
527
- if (nameNode) {
528
- let sequence = _node.type === "SequenceExpression" ? _node : null;
529
- let assignmentExpression;
530
- if (_node.type === "VariableDeclaration") {
531
- if (_node.declarations[0]?.init?.type === "SequenceExpression") {
532
- sequence = _node.declarations[0]?.init;
533
- assignmentExpression = _node.declarations[0]?.init?.expressions?.[0];
534
- }
535
- }
536
- if (sequence && !assignmentExpression) {
537
- assignmentExpression = sequence.expressions[0]?.type === "AssignmentExpression" ? sequence.expressions[0] : null;
538
- }
539
- if (assignmentExpression) {
540
- const right = assignmentExpression?.right;
541
- if (right.callee?.name === "_withAsyncContext") {
542
- if (right.arguments[0]?.body?.name === "$script" || right.arguments[0]?.body?.callee?.object?.name === "$script") {
543
- errorNode = nameNode;
544
- }
545
- }
546
- }
547
- }
697
+ if (s.hasChanged()) {
698
+ return {
699
+ code: s.toString(),
700
+ map: s.generateMap({ includeContent: true, source: id })
701
+ };
548
702
  }
549
- });
550
- if (errorNode) {
551
- return this.error(new Error("You can't use a top-level await on $script as it will never resolve."));
552
703
  }
553
704
  }
554
705
  };
@@ -596,6 +747,7 @@ export {}`;
596
747
  function templateTriggerResolver(defaultScriptOptions) {
597
748
  const needsIdleTimeout = defaultScriptOptions?.trigger && typeof defaultScriptOptions.trigger === "object" && "idleTimeout" in defaultScriptOptions.trigger;
598
749
  const needsInteraction = defaultScriptOptions?.trigger && typeof defaultScriptOptions.trigger === "object" && "interaction" in defaultScriptOptions.trigger;
750
+ const needsServiceWorker = defaultScriptOptions?.trigger && typeof defaultScriptOptions.trigger === "object" && "serviceWorker" in defaultScriptOptions.trigger;
599
751
  const imports = [];
600
752
  if (needsIdleTimeout) {
601
753
  imports.push(`import { useScriptTriggerIdleTimeout } from '#nuxt-scripts/composables/useScriptTriggerIdleTimeout'`);
@@ -603,11 +755,15 @@ function templateTriggerResolver(defaultScriptOptions) {
603
755
  if (needsInteraction) {
604
756
  imports.push(`import { useScriptTriggerInteraction } from '#nuxt-scripts/composables/useScriptTriggerInteraction'`);
605
757
  }
758
+ if (needsServiceWorker) {
759
+ imports.push(`import { useScriptTriggerServiceWorker } from '#nuxt-scripts/composables/useScriptTriggerServiceWorker'`);
760
+ }
606
761
  return [
607
762
  ...imports,
608
763
  `export function resolveTrigger(trigger) {`,
609
764
  needsIdleTimeout ? ` if ('idleTimeout' in trigger) return useScriptTriggerIdleTimeout({ timeout: trigger.idleTimeout })` : "",
610
765
  needsInteraction ? ` if ('interaction' in trigger) return useScriptTriggerInteraction({ events: trigger.interaction })` : "",
766
+ needsServiceWorker ? ` if ('serviceWorker' in trigger) return useScriptTriggerServiceWorker()` : "",
611
767
  ` return null`,
612
768
  `}`
613
769
  ].filter(Boolean).join("\n");
@@ -624,6 +780,9 @@ function resolveTriggerForTemplate(trigger) {
624
780
  if ("interaction" in trigger) {
625
781
  return `useScriptTriggerInteraction({ events: ${JSON.stringify(trigger.interaction)} })`;
626
782
  }
783
+ if ("serviceWorker" in trigger) {
784
+ return `useScriptTriggerServiceWorker()`;
785
+ }
627
786
  }
628
787
  return null;
629
788
  }
@@ -634,27 +793,37 @@ function templatePlugin(config, registry) {
634
793
  }
635
794
  const imports = [];
636
795
  const inits = [];
796
+ const resolvedRegistryKeys = [];
637
797
  let needsIdleTimeoutImport = false;
638
798
  let needsInteractionImport = false;
799
+ let needsServiceWorkerImport = false;
639
800
  for (const [k, c] of Object.entries(config.registry || {})) {
640
- const importDefinition = registry.find((i) => i.import.name === `useScript${k.substring(0, 1).toUpperCase() + k.substring(1)}`);
801
+ const importDefinition = registry.find((i) => i.import.name.toLowerCase() === `usescript${k.toLowerCase()}`);
641
802
  if (importDefinition) {
803
+ resolvedRegistryKeys.push(k);
642
804
  imports.unshift(`import { ${importDefinition.import.name} } from '${importDefinition.import.from}'`);
643
- const args = (typeof c !== "object" ? {} : c) || {};
644
805
  if (c === "mock") {
645
- args.scriptOptions = { trigger: "manual", skipValidation: true };
646
- } else if (Array.isArray(c) && c.length === 2 && c[1]?.trigger) {
647
- const triggerResolved = resolveTriggerForTemplate(c[1].trigger);
806
+ inits.push(`const ${k} = ${importDefinition.import.name}({ scriptOptions: { trigger: 'manual', skipValidation: true } })`);
807
+ } else if (Array.isArray(c) && c.length === 2) {
808
+ const input = c[0] || {};
809
+ const scriptOptions = { ...c[1] };
810
+ const triggerResolved = resolveTriggerForTemplate(scriptOptions?.trigger);
648
811
  if (triggerResolved) {
649
- args.scriptOptions = { ...c[1] };
650
- if (args.scriptOptions) {
651
- args.scriptOptions.trigger = `__TRIGGER_${triggerResolved}__`;
652
- }
653
- if (triggerResolved.includes("useScriptTriggerIdleTimeout")) needsIdleTimeoutImport = true;
654
- if (triggerResolved.includes("useScriptTriggerInteraction")) needsInteractionImport = true;
812
+ scriptOptions.trigger = "__TRIGGER_PLACEHOLDER__";
813
+ if (triggerResolved.includes("useScriptTriggerIdleTimeout"))
814
+ needsIdleTimeoutImport = true;
815
+ if (triggerResolved.includes("useScriptTriggerInteraction"))
816
+ needsInteractionImport = true;
817
+ if (triggerResolved.includes("useScriptTriggerServiceWorker"))
818
+ needsServiceWorkerImport = true;
655
819
  }
820
+ const args = { ...input, scriptOptions };
821
+ const argsJson = triggerResolved ? JSON.stringify(args).replace(/"__TRIGGER_PLACEHOLDER__"/g, triggerResolved) : JSON.stringify(args);
822
+ inits.push(`const ${k} = ${importDefinition.import.name}(${argsJson})`);
823
+ } else {
824
+ const args = (typeof c !== "object" ? {} : c) || {};
825
+ inits.push(`const ${k} = ${importDefinition.import.name}(${JSON.stringify(args)})`);
656
826
  }
657
- inits.push(`const ${k} = ${importDefinition.import.name}(${JSON.stringify(args).replace(/"__TRIGGER_(.*?)__"/g, "$1")})`);
658
827
  }
659
828
  }
660
829
  for (const [k, c] of Object.entries(config.globals || {})) {
@@ -664,20 +833,30 @@ function templatePlugin(config, registry) {
664
833
  const options = c[1];
665
834
  const triggerResolved = resolveTriggerForTemplate(options?.trigger);
666
835
  if (triggerResolved) {
667
- if (triggerResolved.includes("useScriptTriggerIdleTimeout")) needsIdleTimeoutImport = true;
668
- if (triggerResolved.includes("useScriptTriggerInteraction")) needsInteractionImport = true;
669
- const resolvedOptions = { ...options, trigger: `__TRIGGER_${triggerResolved}__` };
670
- inits.push(`const ${k} = useScript(${JSON.stringify({ key: k, ...typeof c[0] === "string" ? { src: c[0] } : c[0] })}, { ...${JSON.stringify(resolvedOptions).replace(/"__TRIGGER_(.*?)__"/g, "$1")}, use: () => ({ ${k}: window.${k} }) })`);
836
+ if (triggerResolved.includes("useScriptTriggerIdleTimeout"))
837
+ needsIdleTimeoutImport = true;
838
+ if (triggerResolved.includes("useScriptTriggerInteraction"))
839
+ needsInteractionImport = true;
840
+ if (triggerResolved.includes("useScriptTriggerServiceWorker"))
841
+ needsServiceWorkerImport = true;
842
+ const resolvedOptions = { ...options, trigger: "__TRIGGER_PLACEHOLDER__" };
843
+ const optionsJson = JSON.stringify(resolvedOptions).replace(/"__TRIGGER_PLACEHOLDER__"/g, triggerResolved);
844
+ inits.push(`const ${k} = useScript(${JSON.stringify({ key: k, ...typeof c[0] === "string" ? { src: c[0] } : c[0] })}, { ...${optionsJson}, use: () => ({ ${k}: window.${k} }) })`);
671
845
  } else {
672
846
  inits.push(`const ${k} = useScript(${JSON.stringify({ key: k, ...typeof c[0] === "string" ? { src: c[0] } : c[0] })}, { ...${JSON.stringify(c[1])}, use: () => ({ ${k}: window.${k} }) })`);
673
847
  }
674
848
  } else if (typeof c === "object" && c !== null) {
675
849
  const triggerResolved = resolveTriggerForTemplate(c.trigger);
676
850
  if (triggerResolved) {
677
- if (triggerResolved.includes("useScriptTriggerIdleTimeout")) needsIdleTimeoutImport = true;
678
- if (triggerResolved.includes("useScriptTriggerInteraction")) needsInteractionImport = true;
679
- const resolvedOptions = { ...c, trigger: `__TRIGGER_${triggerResolved}__` };
680
- inits.push(`const ${k} = useScript(${JSON.stringify({ key: k, ...resolvedOptions }).replace(/"__TRIGGER_(.*?)__"/g, "$1")}, { use: () => ({ ${k}: window.${k} }) })`);
851
+ if (triggerResolved.includes("useScriptTriggerIdleTimeout"))
852
+ needsIdleTimeoutImport = true;
853
+ if (triggerResolved.includes("useScriptTriggerInteraction"))
854
+ needsInteractionImport = true;
855
+ if (triggerResolved.includes("useScriptTriggerServiceWorker"))
856
+ needsServiceWorkerImport = true;
857
+ const resolvedOptions = { ...c, trigger: "__TRIGGER_PLACEHOLDER__" };
858
+ const argsJson = JSON.stringify({ key: k, ...resolvedOptions }).replace(/"__TRIGGER_PLACEHOLDER__"/g, triggerResolved);
859
+ inits.push(`const ${k} = useScript(${argsJson}, { use: () => ({ ${k}: window.${k} }) })`);
681
860
  } else {
682
861
  inits.push(`const ${k} = useScript(${JSON.stringify({ key: k, ...c })}, { use: () => ({ ${k}: window.${k} }) })`);
683
862
  }
@@ -690,6 +869,9 @@ function templatePlugin(config, registry) {
690
869
  if (needsInteractionImport) {
691
870
  triggerImports.push(`import { useScriptTriggerInteraction } from '#nuxt-scripts/composables/useScriptTriggerInteraction'`);
692
871
  }
872
+ if (needsServiceWorkerImport) {
873
+ triggerImports.push(`import { useScriptTriggerServiceWorker } from '#nuxt-scripts/composables/useScriptTriggerServiceWorker'`);
874
+ }
693
875
  return [
694
876
  `import { useScript } from '#nuxt-scripts/composables/useScript'`,
695
877
  `import { defineNuxtPlugin } from 'nuxt/app'`,
@@ -702,12 +884,78 @@ function templatePlugin(config, registry) {
702
884
  ` parallel: true,`,
703
885
  ` setup() {`,
704
886
  ...inits.map((i) => ` ${i}`),
705
- ` return { provide: { $scripts: { ${[...Object.keys(config.globals || {}), ...Object.keys(config.registry || {})].join(", ")} } } }`,
887
+ ` return { provide: { scripts: { ${[...Object.keys(config.globals || {}), ...resolvedRegistryKeys].join(", ")} } } }`,
706
888
  ` }`,
707
889
  `})`
708
890
  ].join("\n");
709
891
  }
710
892
 
893
+ const SELF_CLOSING_SCRIPT_RE = /<((?:Script[A-Z]|script-)\w[\w-]*)\b([^>]*?)\/\s*>/g;
894
+ function fixSelfClosingScriptComponents(nuxt) {
895
+ function expandTags(content) {
896
+ SELF_CLOSING_SCRIPT_RE.lastIndex = 0;
897
+ if (!SELF_CLOSING_SCRIPT_RE.test(content))
898
+ return null;
899
+ SELF_CLOSING_SCRIPT_RE.lastIndex = 0;
900
+ return content.replace(SELF_CLOSING_SCRIPT_RE, (_, tag, attrs) => `<${tag}${attrs.trimEnd()}></${tag}>`);
901
+ }
902
+ function fixFile(filePath) {
903
+ if (!existsSync(filePath))
904
+ return;
905
+ const content = readFileSync(filePath, "utf-8");
906
+ const fixed = expandTags(content);
907
+ if (fixed)
908
+ nuxt.vfs[filePath] = fixed;
909
+ }
910
+ function scanDir(dir) {
911
+ if (!existsSync(dir))
912
+ return;
913
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
914
+ const fullPath = resolve(dir, entry.name);
915
+ if (entry.isDirectory())
916
+ scanDir(fullPath);
917
+ else if (entry.name.endsWith(".vue"))
918
+ fixFile(fullPath);
919
+ }
920
+ }
921
+ const pagesDirs = /* @__PURE__ */ new Set();
922
+ for (const layer of nuxt.options._layers) {
923
+ pagesDirs.add(resolve(
924
+ layer.config.srcDir,
925
+ layer.config.dir?.pages || "pages"
926
+ ));
927
+ }
928
+ for (const dir of pagesDirs) scanDir(dir);
929
+ if (nuxt.options.dev) {
930
+ nuxt.hook("builder:watch", (_event, relativePath) => {
931
+ if (!relativePath.endsWith(".vue"))
932
+ return;
933
+ for (const layer of nuxt.options._layers) {
934
+ const fullPath = resolve(layer.config.srcDir, relativePath);
935
+ for (const dir of pagesDirs) {
936
+ if (fullPath.startsWith(`${dir}/`)) {
937
+ fixFile(fullPath);
938
+ return;
939
+ }
940
+ }
941
+ }
942
+ });
943
+ }
944
+ }
945
+ const PARTYTOWN_FORWARDS = {
946
+ googleAnalytics: ["dataLayer.push", "gtag"],
947
+ plausible: ["plausible"],
948
+ fathom: ["fathom", "fathom.trackEvent", "fathom.trackPageview"],
949
+ umami: ["umami", "umami.track"],
950
+ matomo: ["_paq.push"],
951
+ segment: ["analytics", "analytics.track", "analytics.page", "analytics.identify"],
952
+ metaPixel: ["fbq"],
953
+ xPixel: ["twq"],
954
+ tiktokPixel: ["ttq.track", "ttq.page", "ttq.identify"],
955
+ snapchatPixel: ["snaptr"],
956
+ redditPixel: ["rdt"],
957
+ cloudflareWebAnalytics: ["__cfBeacon"]
958
+ };
711
959
  const module$1 = defineNuxtModule({
712
960
  meta: {
713
961
  name: "@nuxt/scripts",
@@ -717,6 +965,7 @@ const module$1 = defineNuxtModule({
717
965
  }
718
966
  },
719
967
  defaults: {
968
+ firstParty: true,
720
969
  defaultScriptOptions: {
721
970
  trigger: "onNuxtReady"
722
971
  },
@@ -772,13 +1021,57 @@ const module$1 = defineNuxtModule({
772
1021
  config.registry
773
1022
  );
774
1023
  }
1024
+ if (config.defaultScriptOptions?.bundle !== void 0) {
1025
+ logger.warn(
1026
+ "`scripts.defaultScriptOptions.bundle` is deprecated. Use `scripts.firstParty: true` instead. First-party mode is now enabled by default."
1027
+ );
1028
+ }
1029
+ const staticPresets = ["static", "github-pages", "cloudflare-pages-static"];
1030
+ const preset = process.env.NITRO_PRESET || "";
1031
+ const isStaticPreset = staticPresets.includes(preset);
1032
+ const firstPartyEnabled = !!config.firstParty;
1033
+ const firstPartyPrefix = typeof config.firstParty === "object" ? config.firstParty.prefix : void 0;
1034
+ const firstPartyCollectPrefix = typeof config.firstParty === "object" ? config.firstParty.collectPrefix || "/_proxy" : "/_proxy";
1035
+ const firstPartyPrivacy = typeof config.firstParty === "object" ? config.firstParty.privacy : void 0;
1036
+ const assetsPrefix = firstPartyPrefix || config.assets?.prefix || "/_scripts";
1037
+ if (config.partytown?.length) {
1038
+ config.registry = config.registry || {};
1039
+ const requiredForwards = [];
1040
+ for (const scriptKey of config.partytown) {
1041
+ const forwards = PARTYTOWN_FORWARDS[scriptKey];
1042
+ if (forwards) {
1043
+ requiredForwards.push(...forwards);
1044
+ } else if (import.meta.dev) {
1045
+ logger.warn(`[partytown] "${scriptKey}" has no known Partytown forwards configured. It may not work correctly or may require manual forward configuration.`);
1046
+ }
1047
+ const reg = config.registry;
1048
+ const existing = reg[scriptKey];
1049
+ if (Array.isArray(existing)) {
1050
+ existing[1] = { ...existing[1], partytown: true };
1051
+ } else if (existing && typeof existing === "object" && existing !== true && existing !== "mock") {
1052
+ reg[scriptKey] = [existing, { partytown: true }];
1053
+ } else if (existing === true || existing === "mock") {
1054
+ reg[scriptKey] = [{}, { partytown: true }];
1055
+ } else {
1056
+ reg[scriptKey] = [{}, { partytown: true }];
1057
+ }
1058
+ }
1059
+ if (requiredForwards.length && hasNuxtModule("@nuxtjs/partytown")) {
1060
+ const partytownConfig = nuxt.options.partytown || {};
1061
+ const existingForwards = partytownConfig.forward || [];
1062
+ const newForwards = [.../* @__PURE__ */ new Set([...existingForwards, ...requiredForwards])];
1063
+ nuxt.options.partytown = { ...partytownConfig, forward: newForwards };
1064
+ logger.info(`[partytown] Auto-configured forwards: ${requiredForwards.join(", ")}`);
1065
+ }
1066
+ }
775
1067
  const composables = [
776
1068
  "useScript",
777
1069
  "useScriptEventPage",
778
1070
  "useScriptTriggerConsent",
779
1071
  "useScriptTriggerElement",
780
1072
  "useScriptTriggerIdleTimeout",
781
- "useScriptTriggerInteraction"
1073
+ "useScriptTriggerInteraction",
1074
+ "useScriptTriggerServiceWorker"
782
1075
  ];
783
1076
  for (const composable of composables) {
784
1077
  addImports({
@@ -792,12 +1085,60 @@ const module$1 = defineNuxtModule({
792
1085
  path: await resolvePath("./runtime/components"),
793
1086
  pathPrefix: false
794
1087
  });
1088
+ fixSelfClosingScriptComponents(nuxt);
795
1089
  addTemplate({
796
1090
  filename: "nuxt-scripts-trigger-resolver.mjs",
797
1091
  getContents() {
798
1092
  return templateTriggerResolver(config.defaultScriptOptions);
799
1093
  }
800
1094
  });
1095
+ logger.debug("[nuxt-scripts] First-party config:", { firstPartyEnabled, firstPartyPrivacy, firstPartyCollectPrefix });
1096
+ let interceptRules = [];
1097
+ if (firstPartyEnabled) {
1098
+ addPluginTemplate({
1099
+ filename: "nuxt-scripts-intercept.client.mjs",
1100
+ getContents() {
1101
+ const rulesJson = JSON.stringify(interceptRules);
1102
+ return `export default defineNuxtPlugin({
1103
+ name: 'nuxt-scripts:intercept',
1104
+ enforce: 'pre',
1105
+ setup() {
1106
+ const rules = ${rulesJson};
1107
+ const origBeacon = typeof navigator !== 'undefined' && navigator.sendBeacon
1108
+ ? navigator.sendBeacon.bind(navigator)
1109
+ : () => false;
1110
+ const origFetch = globalThis.fetch.bind(globalThis);
1111
+
1112
+ function rewriteUrl(url) {
1113
+ try {
1114
+ const parsed = new URL(url, location.origin);
1115
+ for (const rule of rules) {
1116
+ if (parsed.hostname === rule.pattern || parsed.hostname.endsWith('.' + rule.pattern)) {
1117
+ if (rule.pathPrefix && !parsed.pathname.startsWith(rule.pathPrefix)) continue;
1118
+ const path = rule.pathPrefix ? parsed.pathname.slice(rule.pathPrefix.length) : parsed.pathname;
1119
+ return location.origin + rule.target + (path.startsWith('/') ? '' : '/') + path + parsed.search;
1120
+ }
1121
+ }
1122
+ } catch {}
1123
+ return url;
1124
+ }
1125
+
1126
+ globalThis.__nuxtScripts = {
1127
+ sendBeacon: (url, data) => origBeacon(rewriteUrl(url), data),
1128
+ fetch: (url, opts) => origFetch(typeof url === 'string' ? rewriteUrl(url) : url, opts),
1129
+ };
1130
+ },
1131
+ })
1132
+ `;
1133
+ }
1134
+ });
1135
+ const proxyHandlerPath = await resolvePath("./runtime/server/proxy-handler");
1136
+ logger.debug("[nuxt-scripts] Registering proxy handler:", `${firstPartyCollectPrefix}/**`, "->", proxyHandlerPath);
1137
+ addServerHandler({
1138
+ route: `${firstPartyCollectPrefix}/**`,
1139
+ handler: proxyHandlerPath
1140
+ });
1141
+ }
801
1142
  const scripts = await registry(resolvePath);
802
1143
  for (const script of scripts) {
803
1144
  if (script.import?.name) {
@@ -825,6 +1166,79 @@ const module$1 = defineNuxtModule({
825
1166
  });
826
1167
  }
827
1168
  const { renderedScript } = setupPublicAssetStrategy(config.assets);
1169
+ if (firstPartyEnabled) {
1170
+ const proxyConfigs = getAllProxyConfigs(firstPartyCollectPrefix);
1171
+ const registryKeys = Object.keys(config.registry || {});
1172
+ const neededRoutes = {};
1173
+ const routePrivacyOverrides = {};
1174
+ const unsupportedScripts = [];
1175
+ for (const key of registryKeys) {
1176
+ const script = registryScriptsWithImport.find((s) => s.import.name.toLowerCase() === `usescript${key.toLowerCase()}`);
1177
+ const proxyKey = script?.proxy || void 0;
1178
+ if (proxyKey) {
1179
+ const proxyConfig = proxyConfigs[proxyKey];
1180
+ if (proxyConfig?.routes) {
1181
+ Object.assign(neededRoutes, proxyConfig.routes);
1182
+ for (const routePath of Object.keys(proxyConfig.routes)) {
1183
+ routePrivacyOverrides[routePath] = proxyConfig.privacy;
1184
+ }
1185
+ } else {
1186
+ unsupportedScripts.push(key);
1187
+ }
1188
+ }
1189
+ }
1190
+ if (config.registry?.posthog && typeof config.registry.posthog === "object") {
1191
+ const phConfig = config.registry.posthog;
1192
+ if (!phConfig.apiHost) {
1193
+ const region = phConfig.region || "us";
1194
+ phConfig.apiHost = region === "eu" ? `${firstPartyCollectPrefix}/ph-eu` : `${firstPartyCollectPrefix}/ph`;
1195
+ }
1196
+ }
1197
+ if (unsupportedScripts.length && nuxt.options.dev) {
1198
+ logger.warn(
1199
+ `First-party mode is enabled but these scripts don't support it yet: ${unsupportedScripts.join(", ")}.
1200
+ They will load directly from third-party servers. Request support at https://github.com/nuxt/scripts/issues`
1201
+ );
1202
+ }
1203
+ interceptRules = routesToInterceptRules(neededRoutes);
1204
+ const flatRoutes = {};
1205
+ for (const [path, config2] of Object.entries(neededRoutes)) {
1206
+ flatRoutes[path] = config2.proxy;
1207
+ }
1208
+ nuxt.options.runtimeConfig["nuxt-scripts-proxy"] = {
1209
+ routes: flatRoutes,
1210
+ privacy: firstPartyPrivacy,
1211
+ // undefined = use per-script defaults, set = global override
1212
+ routePrivacy: routePrivacyOverrides
1213
+ // per-script privacy from registry
1214
+ };
1215
+ if (Object.keys(neededRoutes).length) {
1216
+ if (nuxt.options.dev) {
1217
+ const routeCount = Object.keys(neededRoutes).length;
1218
+ const scriptsCount = registryKeys.length;
1219
+ const privacyLabel = firstPartyPrivacy === void 0 ? "per-script" : typeof firstPartyPrivacy === "boolean" ? firstPartyPrivacy ? "anonymize" : "passthrough" : "custom";
1220
+ logger.success(`First-party mode enabled for ${scriptsCount} script(s), ${routeCount} proxy route(s) configured (privacy: ${privacyLabel})`);
1221
+ if (logger.level >= 4) {
1222
+ for (const [path, config2] of Object.entries(neededRoutes)) {
1223
+ logger.debug(` ${path} \u2192 ${config2.proxy}`);
1224
+ }
1225
+ }
1226
+ }
1227
+ }
1228
+ if (isStaticPreset) {
1229
+ logger.warn(
1230
+ `First-party collection endpoints require a server runtime (detected: ${preset || "static"}).
1231
+ Scripts will be bundled, but collection requests will not be proxied.
1232
+
1233
+ Options:
1234
+ 1. Configure platform rewrites (Vercel, Netlify, Cloudflare)
1235
+ 2. Switch to server-rendered mode (ssr: true)
1236
+ 3. Disable with firstParty: false
1237
+
1238
+ See: https://scripts.nuxt.com/docs/guides/first-party#static-hosting`
1239
+ );
1240
+ }
1241
+ }
828
1242
  const moduleInstallPromises = /* @__PURE__ */ new Map();
829
1243
  addBuildPlugin(NuxtScriptsCheckScripts(), {
830
1244
  dev: true
@@ -832,12 +1246,14 @@ const module$1 = defineNuxtModule({
832
1246
  addBuildPlugin(NuxtScriptBundleTransformer({
833
1247
  scripts: registryScriptsWithImport,
834
1248
  registryConfig: nuxt.options.runtimeConfig.public.scripts,
835
- defaultBundle: config.defaultScriptOptions?.bundle,
1249
+ defaultBundle: firstPartyEnabled || config.defaultScriptOptions?.bundle,
1250
+ firstPartyEnabled,
1251
+ firstPartyCollectPrefix,
836
1252
  moduleDetected(module) {
837
1253
  if (nuxt.options.dev && module !== "@nuxt/scripts" && !moduleInstallPromises.has(module) && !hasNuxtModule(module))
838
1254
  moduleInstallPromises.set(module, () => installNuxtModule(module));
839
1255
  },
840
- assetsBaseURL: config.assets?.prefix,
1256
+ assetsBaseURL: assetsPrefix,
841
1257
  fallbackOnSrcOnBundleFail: config.assets?.fallbackOnSrcOnBundleFail,
842
1258
  fetchOptions: config.assets?.fetchOptions,
843
1259
  cacheMaxAge: config.assets?.cacheMaxAge,
@@ -856,8 +1272,29 @@ const module$1 = defineNuxtModule({
856
1272
  handler: await resolvePath("./runtime/server/google-static-maps-proxy")
857
1273
  });
858
1274
  }
859
- if (nuxt.options.dev)
1275
+ addServerHandler({
1276
+ route: "/api/_scripts/x-embed",
1277
+ handler: await resolvePath("./runtime/server/x-embed")
1278
+ });
1279
+ addServerHandler({
1280
+ route: "/api/_scripts/x-embed-image",
1281
+ handler: await resolvePath("./runtime/server/x-embed-image")
1282
+ });
1283
+ addServerHandler({
1284
+ route: "/api/_scripts/instagram-embed",
1285
+ handler: await resolvePath("./runtime/server/instagram-embed")
1286
+ });
1287
+ addServerHandler({
1288
+ route: "/api/_scripts/instagram-embed-image",
1289
+ handler: await resolvePath("./runtime/server/instagram-embed-image")
1290
+ });
1291
+ addServerHandler({
1292
+ route: "/api/_scripts/instagram-embed-asset",
1293
+ handler: await resolvePath("./runtime/server/instagram-embed-asset")
1294
+ });
1295
+ if (nuxt.options.dev) {
860
1296
  setupDevToolsUI(config, resolvePath);
1297
+ }
861
1298
  }
862
1299
  });
863
1300