@nuxt/scripts 1.3.3 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/devtools-client/200.html +1 -1
  2. package/dist/devtools-client/404.html +1 -1
  3. package/dist/devtools-client/_nuxt/{DAubxma0.js → 8ltZ0o6d.js} +1 -1
  4. package/dist/devtools-client/_nuxt/{CBuBrHyL.js → B8_EBdhg.js} +1 -1
  5. package/dist/devtools-client/_nuxt/Bf2Kt1P0.js +28 -0
  6. package/dist/devtools-client/_nuxt/CC0GKROJ.js +1 -0
  7. package/dist/devtools-client/_nuxt/{DvC3yV2P.js → CMXzQxJZ.js} +1 -1
  8. package/dist/devtools-client/_nuxt/{xAZ2vgo3.js → CP7c-Js6.js} +4 -4
  9. package/dist/devtools-client/_nuxt/{DzbSCA_w.js → DTP8MRtW.js} +1 -1
  10. package/dist/devtools-client/_nuxt/{DgAtAWdT.js → Dkc7iTdR.js} +1 -1
  11. package/dist/devtools-client/_nuxt/{WOtyQdps.js → KxC4Q3ev.js} +1 -1
  12. package/dist/devtools-client/_nuxt/builds/latest.json +1 -1
  13. package/dist/devtools-client/_nuxt/builds/meta/173480db-0944-415b-962d-d619682f0042.json +1 -0
  14. package/dist/devtools-client/_nuxt/{entry.9HJPJ6Hp.css → entry.CYUdJFoE.css} +1 -1
  15. package/dist/devtools-client/_nuxt/error-404.Bq2JQbJs.css +1 -0
  16. package/dist/devtools-client/_nuxt/error-500.5E_FOzlc.css +1 -0
  17. package/dist/devtools-client/_nuxt/{pages.BF1VnccH.css → pages.aU4WirOM.css} +1 -1
  18. package/dist/devtools-client/docs/index.html +1 -1
  19. package/dist/devtools-client/first-party/index.html +1 -1
  20. package/dist/devtools-client/index.html +1 -1
  21. package/dist/devtools-client/registry/index.html +1 -1
  22. package/dist/module.d.mts +1 -1
  23. package/dist/module.d.ts +1 -1
  24. package/dist/module.json +1 -1
  25. package/dist/module.mjs +270 -47
  26. package/dist/registry.mjs +2 -2
  27. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +71 -21
  28. package/dist/runtime/components/GoogleMaps/useGoogleMapsResource.d.ts +2 -1
  29. package/dist/runtime/components/GoogleMaps/useGoogleMapsResource.js +39 -25
  30. package/dist/runtime/components/ScriptCarbonAds.vue +11 -3
  31. package/dist/runtime/components/ScriptCrisp.vue +4 -1
  32. package/dist/runtime/components/ScriptIntercom.vue +4 -1
  33. package/dist/runtime/components/ScriptLemonSqueezy.d.vue.ts +13 -13
  34. package/dist/runtime/components/ScriptLemonSqueezy.vue +30 -6
  35. package/dist/runtime/components/ScriptLemonSqueezy.vue.d.ts +13 -13
  36. package/dist/runtime/components/ScriptPayPalButtons.vue +8 -1
  37. package/dist/runtime/components/ScriptPayPalMessages.vue +6 -0
  38. package/dist/runtime/components/ScriptStripePricingTable.vue +2 -0
  39. package/dist/runtime/components/ScriptVimeoPlayer.vue +8 -1
  40. package/dist/runtime/composables/useScript.js +121 -44
  41. package/dist/runtime/composables/useScriptEventPage.js +36 -20
  42. package/dist/runtime/composables/useScriptTriggerIdleTimeout.js +19 -5
  43. package/dist/runtime/composables/useScriptTriggerInteraction.js +23 -10
  44. package/dist/runtime/composables/useScriptTriggerServiceWorker.js +21 -18
  45. package/dist/runtime/devtools-standalone-bridge.client.js +28 -3
  46. package/dist/runtime/npm-script-proxy.d.ts +7 -0
  47. package/dist/runtime/npm-script-proxy.js +46 -0
  48. package/dist/runtime/npm-script-stub.js +4 -5
  49. package/dist/runtime/registry/posthog.js +11 -3
  50. package/dist/runtime/registry/speedcurve.js +33 -4
  51. package/dist/runtime/registry/usercentrics.js +4 -21
  52. package/dist/runtime/registry/youtube-player.js +16 -5
  53. package/dist/runtime/server/bluesky-embed.js +15 -6
  54. package/dist/runtime/server/google-maps-geocode-proxy.js +10 -5
  55. package/dist/runtime/server/google-static-maps-proxy.js +20 -13
  56. package/dist/runtime/server/gravatar-proxy.js +48 -11
  57. package/dist/runtime/server/instagram-embed-asset.js +1 -1
  58. package/dist/runtime/server/instagram-embed.js +44 -94
  59. package/dist/runtime/server/proxy-handler.d.ts +2 -1
  60. package/dist/runtime/server/proxy-handler.js +183 -23
  61. package/dist/runtime/server/utils/cache-config.d.ts +14 -0
  62. package/dist/runtime/server/utils/cache-config.js +13 -0
  63. package/dist/runtime/server/utils/cached-upstream.d.ts +23 -2
  64. package/dist/runtime/server/utils/cached-upstream.js +212 -15
  65. package/dist/runtime/server/utils/image-proxy.d.ts +3 -2
  66. package/dist/runtime/server/utils/image-proxy.js +26 -16
  67. package/dist/runtime/server/utils/instagram-embed.d.ts +8 -0
  68. package/dist/runtime/server/utils/instagram-embed.js +155 -0
  69. package/dist/runtime/server/utils/network-dispatcher.node.d.ts +2 -0
  70. package/dist/runtime/server/utils/network-dispatcher.node.js +21 -0
  71. package/dist/runtime/server/utils/network-dispatcher.platform.d.ts +2 -0
  72. package/dist/runtime/server/utils/network-dispatcher.platform.js +5 -0
  73. package/dist/runtime/server/utils/network-host.d.ts +20 -0
  74. package/dist/runtime/server/utils/network-host.js +51 -0
  75. package/dist/runtime/server/utils/network-hostname.d.ts +2 -0
  76. package/dist/runtime/server/utils/network-hostname.js +41 -0
  77. package/dist/runtime/server/utils/privacy.js +55 -19
  78. package/dist/runtime/server/utils/proxy-query.d.ts +2 -0
  79. package/dist/runtime/server/utils/proxy-query.js +10 -0
  80. package/dist/runtime/server/utils/sign.d.ts +1 -1
  81. package/dist/runtime/server/utils/sign.js +1 -1
  82. package/dist/runtime/server/utils/withSigning.d.ts +1 -1
  83. package/dist/runtime/server/utils/withSigning.js +3 -3
  84. package/dist/runtime/server/vercel-insights-sink.js +1 -1
  85. package/dist/runtime/server/x-embed.js +8 -4
  86. package/dist/runtime/unhead-features.d.ts +1 -0
  87. package/dist/runtime/unhead-features.js +3 -0
  88. package/dist/runtime/utils/abortable-promise.d.ts +8 -0
  89. package/dist/runtime/utils/abortable-promise.js +63 -0
  90. package/dist/runtime/utils/after-next-paint.d.ts +1 -1
  91. package/dist/runtime/utils/after-next-paint.js +16 -1
  92. package/dist/runtime/utils/usercentrics-consent.d.ts +10 -0
  93. package/dist/runtime/utils/usercentrics-consent.js +88 -0
  94. package/dist/runtime/utils/youtube-readiness.d.ts +7 -0
  95. package/dist/runtime/utils/youtube-readiness.js +45 -0
  96. package/dist/runtime/utils.d.ts +3 -1
  97. package/dist/runtime/utils.js +29 -0
  98. package/package.json +2 -1
  99. package/dist/devtools-client/_nuxt/BGGk5RYW.js +0 -1
  100. package/dist/devtools-client/_nuxt/C8xLTMBy.js +0 -28
  101. package/dist/devtools-client/_nuxt/builds/meta/0c193d7f-fdc4-4ec6-b4c0-7ba4cc94709b.json +0 -1
  102. package/dist/devtools-client/_nuxt/error-404.CIn5oEzb.css +0 -1
  103. package/dist/devtools-client/_nuxt/error-500.B1YZl8g8.css +0 -1
package/dist/module.mjs CHANGED
@@ -1,23 +1,27 @@
1
1
  import { createHash, randomBytes } from 'node:crypto';
2
- import { existsSync, readFileSync, appendFileSync, writeFileSync, readdirSync } from 'node:fs';
3
- import { useNuxt, addDevServerHandler, extendRouteRules, tryUseNuxt, createResolver, extendViteConfig, logger as logger$1, useLogger, addTypeTemplate, defineNuxtModule, addPluginTemplate, addServerHandler, addImports, addComponentsDir, addTemplate, hasNuxtModule, addBuildPlugin, addPlugin } from '@nuxt/kit';
2
+ import { existsSync, readFileSync, writeFileSync, appendFileSync, readdirSync } from 'node:fs';
3
+ import fsp, { open, stat, unlink } from 'node:fs/promises';
4
+ import { setTimeout } from 'node:timers/promises';
5
+ import { useNuxt, addDevServerHandler, extendRouteRules, tryUseNuxt, createResolver, extendViteConfig, logger as logger$1, useLogger, getNuxtVersion, addTypeTemplate, resolvePath, defineNuxtModule, addPluginTemplate, addServerHandler, addImports, addComponentsDir, addTemplate, hasNuxtModule, addBuildPlugin, addPlugin } from '@nuxt/kit';
4
6
  import { defu } from 'defu';
5
- import { join, resolve } from 'pathe';
7
+ import { join, resolve, dirname } from 'pathe';
6
8
  import { resolvePackageJSON, readPackageJSON } from 'pkg-types';
7
9
  import { lazyEventHandler, eventHandler, createError, setHeader } from 'h3';
8
10
  import { fetch, $fetch } from 'ofetch';
9
11
  import { joinURL, parseURL, parseQuery, hasProtocol } from 'ufo';
10
12
  import { createStorage } from 'unstorage';
11
13
  import fsDriver from 'unstorage/drivers/fs-lite';
14
+ import { Buffer as Buffer$1 } from 'node:buffer';
12
15
  import { isCI, provider } from 'std-env';
16
+ import { pathToFileURL } from 'node:url';
13
17
  import { parseAndWalk, ScopeTracker, walk, ScopeTrackerFunction, ScopeTrackerIdentifier, ScopeTrackerFunctionParam, ScopeTrackerVariable } from 'oxc-walker';
14
18
  import { createUnplugin } from 'unplugin';
15
- import { pathToFileURL } from 'node:url';
16
- import fsp from 'node:fs/promises';
17
19
  import { colors } from 'consola/utils';
18
20
  import MagicString from 'magic-string';
19
21
  import { hash } from 'ohash';
20
22
  import { getBundleResolve, registry, resolveCapabilities, getPartytownForwards, buildProxyConfigsFromRegistry, generatePartytownResolveUrl } from './registry.mjs';
23
+ import { ensureNuxtScriptsCacheStorage } from '../dist/runtime/server/utils/cache-config.js';
24
+ import { isPublicNetworkHostname } from '../dist/runtime/server/utils/network-hostname.js';
21
25
  import '../dist/runtime/registry/schemas.js';
22
26
 
23
27
  const renderedScript = /* @__PURE__ */ new Map();
@@ -83,6 +87,7 @@ function setupPublicAssetStrategy(assetsBaseURL) {
83
87
  const DEVTOOLS_UI_ROUTE = "/__nuxt-scripts";
84
88
  const DEVTOOLS_UI_LOCAL_PORT = 3030;
85
89
  const DEVTOOLS_API_STATE_ROUTE = "/__nuxt-scripts-api/state";
90
+ const DEVTOOLS_API_MAX_BODY_SIZE = 2 * 1024 * 1024;
86
91
  async function setupDevtools(nuxt, options = {}) {
87
92
  const { addCustomTab } = await import('@nuxt/devtools-kit');
88
93
  const { resolve } = createResolver(import.meta.url);
@@ -139,13 +144,38 @@ function setupStandaloneApi(nuxt) {
139
144
  return;
140
145
  }
141
146
  if (req.method === "POST") {
142
- let body = "";
143
- req.on("data", (chunk) => {
144
- body += chunk.toString();
145
- });
146
- req.on("end", () => {
147
+ let cleanup = function() {
148
+ req.off("data", onData);
149
+ req.off("end", onEnd);
150
+ req.off("aborted", onAborted);
151
+ req.off("error", onAborted);
152
+ }, onAborted = function() {
153
+ finished = true;
154
+ chunks = [];
155
+ cleanup();
156
+ }, onData = function(chunk) {
157
+ if (finished)
158
+ return;
159
+ size += chunk.byteLength;
160
+ if (size > DEVTOOLS_API_MAX_BODY_SIZE) {
161
+ finished = true;
162
+ chunks = [];
163
+ cleanup();
164
+ req.once("error", () => {
165
+ });
166
+ req.resume();
167
+ res.statusCode = 413;
168
+ res.end("payload too large");
169
+ return;
170
+ }
171
+ chunks.push(chunk);
172
+ }, onEnd = function() {
173
+ if (finished)
174
+ return;
175
+ finished = true;
176
+ cleanup();
147
177
  try {
148
- const data = JSON.parse(body);
178
+ const data = JSON.parse(Buffer$1.concat(chunks, size).toString("utf8"));
149
179
  scriptsState = { ...data, updatedAt: Date.now() };
150
180
  res.statusCode = 200;
151
181
  res.end("ok");
@@ -153,7 +183,15 @@ function setupStandaloneApi(nuxt) {
153
183
  res.statusCode = 400;
154
184
  res.end("invalid json");
155
185
  }
156
- });
186
+ chunks = [];
187
+ };
188
+ let chunks = [];
189
+ let size = 0;
190
+ let finished = false;
191
+ req.on("data", onData);
192
+ req.on("end", onEnd);
193
+ req.on("aborted", onAborted);
194
+ req.on("error", onAborted);
157
195
  return;
158
196
  }
159
197
  res.statusCode = 405;
@@ -214,8 +252,11 @@ function buildDevtoolsData(proxyPrefix, privacyLabel, scripts, aliasToDomain) {
214
252
 
215
253
  const isStackblitz = provider === "stackblitz";
216
254
  async function promptToInstall(name, installCommand, options) {
217
- if (await resolvePackageJSON(name).catch(() => null))
255
+ if (await resolvePackageJSON(name).catch(() => {
256
+ return null;
257
+ })) {
218
258
  return true;
259
+ }
219
260
  logger$1.info(`Package ${name} is missing`);
220
261
  if (isCI)
221
262
  return false;
@@ -254,6 +295,89 @@ function installNuxtModule(name, options) {
254
295
 
255
296
  const logger = useLogger("@nuxt/scripts");
256
297
 
298
+ const NITRO_RUNTIME_MODULE = "#nuxt-scripts/nitro";
299
+ const H3_RUNTIME_MODULE = "#nuxt-scripts/h3";
300
+ const TYPE_TEMPLATE_FILENAME = "types/nuxt-scripts-nitro.d.ts";
301
+ const defaultDependencies = {
302
+ addTypeTemplate,
303
+ getNuxtVersion
304
+ };
305
+ const nitroV2Runtime = `export {
306
+ defineCachedFunction,
307
+ useNitroApp,
308
+ useRuntimeConfig,
309
+ } from 'nitropack/runtime'
310
+ `;
311
+ const nitroV3RuntimeTypes = `export { useNitroApp } from 'nitro/app'
312
+ export { defineCachedFunction } from 'nitro/cache'
313
+ export function useRuntimeConfig(event?: import('nitro/h3').H3Event): ReturnType<typeof import('nitro/runtime-config').useRuntimeConfig>
314
+ `;
315
+ function indent(value, spaces) {
316
+ const padding = " ".repeat(spaces);
317
+ return value.split("\n").map((line) => `${padding}${line}`).join("\n");
318
+ }
319
+ function renderRuntimeDeclarations(compatibility) {
320
+ const nitroRuntime = compatibility._tag === "nitro-v3" ? nitroV3RuntimeTypes : nitroV2Runtime;
321
+ const h3Runtime = compatibility._tag === "nitro-v3" ? `export * from 'nitro/h3'
322
+ ` : `export * from 'h3'
323
+ `;
324
+ return `declare module '${NITRO_RUNTIME_MODULE}' {
325
+ ${indent(nitroRuntime.trim(), 2)}
326
+ }
327
+
328
+ declare module '${H3_RUNTIME_MODULE}' {
329
+ ${indent(h3Runtime.trim(), 2)}
330
+ }
331
+ `;
332
+ }
333
+ function renderNitroV3Runtime(compatibility) {
334
+ return `export { useNitroApp } from ${JSON.stringify(compatibility.app)}
335
+ export { defineCachedFunction } from ${JSON.stringify(compatibility.cache)}
336
+ import { useRuntimeConfig as _useRuntimeConfig } from ${JSON.stringify(compatibility.runtimeConfig)}
337
+ export function useRuntimeConfig(_event) { return _useRuntimeConfig() }
338
+ `;
339
+ }
340
+ function applyNitroRuntimeCompatibility(nuxt, compatibility) {
341
+ const nuxtOptions = nuxt.options;
342
+ const nitroOptions = nuxtOptions.nitro ||= {};
343
+ const h3Runtime = compatibility._tag === "nitro-v3" ? compatibility.h3 : "h3";
344
+ nitroOptions.alias ||= {};
345
+ nitroOptions.virtual ||= {};
346
+ const nuxtAliases = nuxtOptions.alias ||= {};
347
+ delete nuxtAliases[H3_RUNTIME_MODULE];
348
+ nuxtOptions.alias = { [H3_RUNTIME_MODULE]: h3Runtime, ...nuxtAliases };
349
+ nitroOptions.alias[H3_RUNTIME_MODULE] = h3Runtime;
350
+ nitroOptions.virtual[NITRO_RUNTIME_MODULE] = compatibility._tag === "nitro-v3" ? renderNitroV3Runtime(compatibility) : nitroV2Runtime;
351
+ }
352
+ async function createNuxtNitroImportResolver() {
353
+ const nuxtDir = dirname(await resolvePath("nuxt/package.json"));
354
+ const nitroDir = dirname(await resolvePath("@nuxt/nitro-server/package.json", { cwd: nuxtDir }));
355
+ return async (id) => {
356
+ const resolved = await resolvePath(id, { cwd: nitroDir });
357
+ if (!existsSync(resolved))
358
+ throw new Error(`[nuxt-scripts] Could not resolve Nitro runtime helper "${id}" from "${nitroDir}".`);
359
+ return pathToFileURL(resolved).href;
360
+ };
361
+ }
362
+ async function resolveNitroV3Compatibility(resolveNitroImport) {
363
+ const [app, cache, h3, runtimeConfig] = await Promise.all([
364
+ resolveNitroImport("nitro/app"),
365
+ resolveNitroImport("nitro/cache"),
366
+ resolveNitroImport("nitro/h3"),
367
+ resolveNitroImport("nitro/runtime-config")
368
+ ]);
369
+ return { _tag: "nitro-v3", app, cache, h3, runtimeConfig };
370
+ }
371
+ async function setupNitroRuntimeCompatibility(nuxt, dependencies = defaultDependencies) {
372
+ const compatibility = Number.parseInt(dependencies.getNuxtVersion(nuxt), 10) >= 5 ? await resolveNitroV3Compatibility(dependencies.resolveNitroImport || await createNuxtNitroImportResolver()) : { _tag: "nitro-v2" };
373
+ applyNitroRuntimeCompatibility(nuxt, compatibility);
374
+ nuxt.hooks.hookOnce("modules:done", () => applyNitroRuntimeCompatibility(nuxt, compatibility));
375
+ dependencies.addTypeTemplate({
376
+ filename: TYPE_TEMPLATE_FILENAME,
377
+ getContents: async () => renderRuntimeDeclarations(compatibility)
378
+ }, { nitro: true, node: true, nuxt: true });
379
+ }
380
+
257
381
  const SCRIPT_OPTION_KEYS = ["trigger", "proxy", "bundle", "partytown"];
258
382
  function extractRequiredFields(schema) {
259
383
  if (!schema)
@@ -424,12 +548,14 @@ function NuxtScriptsCheckScripts() {
424
548
 
425
549
  function generateInterceptPluginContents(proxyPrefix, options) {
426
550
  const testMode = options?.testMode ?? false;
427
- return `export default defineNuxtPlugin({
551
+ return `import { defineNuxtPlugin } from 'nuxt/app'
552
+
553
+ export default defineNuxtPlugin({
428
554
  name: 'nuxt-scripts:intercept',
429
555
  enforce: 'pre',
430
556
  setup() {
431
557
  const proxyPrefix = ${JSON.stringify(proxyPrefix)};
432
- const domainAliases = ${JSON.stringify(options?.domainAliases ?? {})};
558
+ const domainAliases = Object.assign(Object.create(null), ${JSON.stringify(options?.domainAliases ?? {})});
433
559
  const origBeacon = typeof navigator !== 'undefined' && navigator.sendBeacon
434
560
  ? navigator.sendBeacon.bind(navigator)
435
561
  : () => false;
@@ -438,11 +564,11 @@ function generateInterceptPluginContents(proxyPrefix, options) {
438
564
  function proxyUrl(url) {
439
565
  try {
440
566
  const parsed = new URL(url, location.origin);
441
- if (parsed.origin !== location.origin) {
567
+ if ((parsed.protocol === 'http:' || parsed.protocol === 'https:') && parsed.origin !== location.origin) {
442
568
  const seg = domainAliases[parsed.host] || parsed.host;
443
569
  return location.origin + proxyPrefix + '/' + seg + parsed.pathname + parsed.search;
444
570
  }
445
- } catch {}
571
+ } catch { /* Invalid URL inputs retain native behavior. */ }
446
572
  return url;
447
573
  }
448
574
 
@@ -1339,7 +1465,7 @@ function NuxtScriptBundleTransformer(options = {
1339
1465
  const WILDCARD_RE = /\*/;
1340
1466
  const SAFE_ALIAS_SEGMENT_RE = /^[\w.-]+$/;
1341
1467
  function isSafeAliasSegment(alias) {
1342
- return SAFE_ALIAS_SEGMENT_RE.test(alias);
1468
+ return alias !== "." && alias !== ".." && SAFE_ALIAS_SEGMENT_RE.test(alias);
1343
1469
  }
1344
1470
  function aliasForDomain(domain, alias) {
1345
1471
  if (!alias || WILDCARD_RE.test(domain))
@@ -1349,19 +1475,16 @@ function aliasForDomain(domain, alias) {
1349
1475
  return Object.hasOwn(alias, domain) ? alias[domain] || void 0 : void 0;
1350
1476
  }
1351
1477
  function buildDomainAliasMap(domains, alias) {
1352
- const map = {};
1478
+ const entries = [];
1353
1479
  for (const domain of domains) {
1354
1480
  const value = aliasForDomain(domain, alias);
1355
1481
  if (value)
1356
- map[domain] = value;
1482
+ entries.push([domain, value]);
1357
1483
  }
1358
- return map;
1484
+ return Object.fromEntries(entries);
1359
1485
  }
1360
1486
  function invertAliasMap(map) {
1361
- const out = {};
1362
- for (const [domain, alias] of Object.entries(map))
1363
- out[alias] = domain;
1364
- return out;
1487
+ return Object.fromEntries(Object.entries(map).map(([domain, alias]) => [alias, domain]));
1365
1488
  }
1366
1489
  function aliasProxyValue(value, proxyPrefix, alias) {
1367
1490
  const prefix = `${proxyPrefix}/`;
@@ -1595,6 +1718,20 @@ function templatePlugin(config, registry) {
1595
1718
  ].join("\n");
1596
1719
  }
1597
1720
 
1721
+ const SOURCE_LESS_SCRIPT_LOADER_TYPE = /\bUseScriptLoaderInput\b/;
1722
+ function hasUnheadSourceLessScriptLoader(typesSource) {
1723
+ return SOURCE_LESS_SCRIPT_LOADER_TYPE.test(typesSource);
1724
+ }
1725
+ function hasUnheadSourceLessScriptLoaderFile(typesPath) {
1726
+ if (!typesPath || !existsSync(typesPath))
1727
+ return false;
1728
+ try {
1729
+ return hasUnheadSourceLessScriptLoader(readFileSync(typesPath, "utf8"));
1730
+ } catch {
1731
+ return false;
1732
+ }
1733
+ }
1734
+
1598
1735
  const UPPER_RE$1 = /([A-Z])/g;
1599
1736
  const toScreamingSnake$1 = (s) => s.replace(UPPER_RE$1, "_$1").toUpperCase();
1600
1737
  const ENV_PREFIX = "NUXT_PUBLIC_SCRIPTS_";
@@ -1802,9 +1939,57 @@ function fixSelfClosingScriptComponents(nuxt) {
1802
1939
  const UPPER_RE = /([A-Z])/g;
1803
1940
  const toScreamingSnake = (s) => s.replace(UPPER_RE, "_$1").toUpperCase();
1804
1941
  const PROXY_SECRET_ENV_KEY = "NUXT_SCRIPTS_PROXY_SECRET";
1805
- const PROXY_SECRET_ENV_LINE_RE = /^NUXT_SCRIPTS_PROXY_SECRET=/m;
1942
+ const PROXY_SECRET_ENV_LINE_RE = /^NUXT_SCRIPTS_PROXY_SECRET=.*$/m;
1806
1943
  const PROXY_SECRET_ENV_VALUE_RE = /^NUXT_SCRIPTS_PROXY_SECRET=(.+)$/m;
1807
- function resolveProxySecret(rootDir, isDev, configSecret, autoGenerate = true) {
1944
+ const PROXY_SECRET_LOCK_RETRY_MS = 10;
1945
+ const PROXY_SECRET_LOCK_TIMEOUT_MS = 2e3;
1946
+ async function withProxySecretFileLock(envPath, effect) {
1947
+ const lockPath = `${envPath}.nuxt-scripts.lock`;
1948
+ const deadline = Date.now() + PROXY_SECRET_LOCK_TIMEOUT_MS;
1949
+ let lockHandle;
1950
+ while (!lockHandle) {
1951
+ const acquisition = await open(lockPath, "wx").then((handle) => ({ _tag: "Acquired", handle })).catch((error) => {
1952
+ if (error.code === "EEXIST")
1953
+ return { _tag: "Busy" };
1954
+ throw error;
1955
+ });
1956
+ if (acquisition._tag === "Acquired") {
1957
+ lockHandle = acquisition.handle;
1958
+ break;
1959
+ }
1960
+ const existingLock = await stat(lockPath).then((lockStat) => ({ _tag: "Found", mtimeMs: lockStat.mtimeMs })).catch((error) => {
1961
+ if (error.code === "ENOENT")
1962
+ return { _tag: "Missing" };
1963
+ throw error;
1964
+ });
1965
+ if (existingLock._tag === "Found" && Date.now() - existingLock.mtimeMs >= PROXY_SECRET_LOCK_TIMEOUT_MS) {
1966
+ await unlink(lockPath).catch((error) => {
1967
+ if (error.code !== "ENOENT")
1968
+ throw error;
1969
+ });
1970
+ continue;
1971
+ }
1972
+ if (Date.now() >= deadline)
1973
+ throw Object.assign(new Error("Timed out waiting for proxy secret file lock"), { code: "ETIMEDOUT" });
1974
+ await setTimeout(PROXY_SECRET_LOCK_RETRY_MS);
1975
+ }
1976
+ let effectResult;
1977
+ try {
1978
+ effectResult = { _tag: "Success", value: effect() };
1979
+ } catch (error) {
1980
+ effectResult = { _tag: "Failure", error };
1981
+ }
1982
+ const closeResult = await lockHandle.close().then(() => ({ _tag: "Success" })).catch((error) => ({ _tag: "Failure", error }));
1983
+ const unlinkResult = await unlink(lockPath).then(() => ({ _tag: "Success" })).catch((error) => error.code === "ENOENT" ? { _tag: "Success" } : { _tag: "Failure", error });
1984
+ if (closeResult._tag === "Failure")
1985
+ logger.warn(`[security] Failed to close the proxy secret lock: ${closeResult.error.message}`);
1986
+ if (unlinkResult._tag === "Failure")
1987
+ logger.warn(`[security] Failed to remove the proxy secret lock: ${unlinkResult.error.message}`);
1988
+ if (effectResult._tag === "Failure")
1989
+ throw effectResult.error;
1990
+ return effectResult.value;
1991
+ }
1992
+ async function resolveProxySecret(rootDir, isDev, configSecret, autoGenerate = true) {
1808
1993
  if (configSecret)
1809
1994
  return { secret: configSecret, ephemeral: false, source: "config" };
1810
1995
  const envSecret = process.env[PROXY_SECRET_ENV_KEY];
@@ -1817,21 +2002,26 @@ function resolveProxySecret(rootDir, isDev, configSecret, autoGenerate = true) {
1817
2002
  const line = `${PROXY_SECRET_ENV_KEY}=${secret}
1818
2003
  `;
1819
2004
  try {
1820
- if (existsSync(envPath)) {
1821
- const contents = readFileSync(envPath, "utf-8");
1822
- if (PROXY_SECRET_ENV_LINE_RE.test(contents)) {
1823
- const match = contents.match(PROXY_SECRET_ENV_VALUE_RE);
1824
- if (match?.[1])
1825
- return { secret: match[1].trim(), ephemeral: false, source: "dotenv-generated" };
1826
- }
1827
- appendFileSync(envPath, contents.endsWith("\n") ? line : `
2005
+ const persistedSecret = await withProxySecretFileLock(envPath, () => {
2006
+ if (existsSync(envPath)) {
2007
+ const contents = readFileSync(envPath, "utf-8");
2008
+ const existingSecret = contents.match(PROXY_SECRET_ENV_VALUE_RE)?.[1]?.trim();
2009
+ if (existingSecret)
2010
+ return existingSecret;
2011
+ if (PROXY_SECRET_ENV_LINE_RE.test(contents)) {
2012
+ writeFileSync(envPath, contents.replace(PROXY_SECRET_ENV_LINE_RE, `${PROXY_SECRET_ENV_KEY}=${secret}`));
2013
+ } else {
2014
+ appendFileSync(envPath, contents.endsWith("\n") ? line : `
1828
2015
  ${line}`);
1829
- } else {
1830
- writeFileSync(envPath, `# Generated by @nuxt/scripts
2016
+ }
2017
+ } else {
2018
+ writeFileSync(envPath, `# Generated by @nuxt/scripts
1831
2019
  ${line}`);
1832
- }
1833
- process.env[PROXY_SECRET_ENV_KEY] = secret;
1834
- return { secret, ephemeral: false, source: "dotenv-generated" };
2020
+ }
2021
+ return secret;
2022
+ });
2023
+ process.env[PROXY_SECRET_ENV_KEY] = persistedSecret;
2024
+ return { secret: persistedSecret, ephemeral: false, source: "dotenv-generated" };
1835
2025
  } catch {
1836
2026
  process.env[PROXY_SECRET_ENV_KEY] = secret;
1837
2027
  return { secret, ephemeral: true, source: "memory-generated" };
@@ -1874,7 +2064,10 @@ function resolveConfiguredProxyDomain(value) {
1874
2064
  if (!trimmed || !ABSOLUTE_URL_RE.test(trimmed) && !trimmed.startsWith("//"))
1875
2065
  return;
1876
2066
  try {
1877
- return new URL(trimmed, "https://nuxt-scripts.local").hostname || void 0;
2067
+ const url = new URL(trimmed, "https://nuxt-scripts.local");
2068
+ if (url.protocol !== "http:" && url.protocol !== "https:")
2069
+ return;
2070
+ return isPublicNetworkHostname(url.hostname) ? url.hostname : void 0;
1878
2071
  } catch {
1879
2072
  }
1880
2073
  }
@@ -1939,6 +2132,14 @@ const module$1 = defineNuxtModule({
1939
2132
  logger.debug("The module is disabled, skipping setup.");
1940
2133
  return;
1941
2134
  }
2135
+ const networkDispatcherAlias = "#nuxt-scripts/network-dispatcher";
2136
+ const nodeNetworkDispatcherPath = await resolvePath("./runtime/server/utils/network-dispatcher.node");
2137
+ const platformNetworkDispatcherPath = await resolvePath("./runtime/server/utils/network-dispatcher.platform");
2138
+ nuxt.options.alias[networkDispatcherAlias] = nodeNetworkDispatcherPath;
2139
+ nuxt.hook("nitro:init", (nitro) => {
2140
+ nitro.options.alias[networkDispatcherAlias] = nitro.options.node ? nodeNetworkDispatcherPath : platformNetworkDispatcherPath;
2141
+ });
2142
+ await setupNitroRuntimeCompatibility(nuxt);
1942
2143
  if (nuxt.options.dev) {
1943
2144
  setupDevtools(nuxt, { standalone: config._standaloneDevtools });
1944
2145
  if (config._standaloneDevtools) {
@@ -1951,9 +2152,21 @@ const module$1 = defineNuxtModule({
1951
2152
  });
1952
2153
  }
1953
2154
  }
1954
- const { version: unheadVersion } = await readPackageJSON("@unhead/vue", {
1955
- from: nuxt.options.modulesDir
1956
- }).catch(() => ({ version: null }));
2155
+ const unheadScriptsAlias = nuxt.options.alias["@unhead/vue/scripts"];
2156
+ const unheadPackagePath = await (typeof unheadScriptsAlias === "string" ? resolvePackageJSON(unheadScriptsAlias) : Promise.reject(new Error("No Unhead scripts alias"))).catch(() => resolvePackageJSON("@unhead/vue", {
2157
+ // Match the package instance imported by the built runtime. An app can
2158
+ // contain another Unhead version with different loader capabilities.
2159
+ from: [resolveModule("./runtime")]
2160
+ })).catch(() => {
2161
+ return null;
2162
+ });
2163
+ const unheadPackage = unheadPackagePath ? await readPackageJSON(unheadPackagePath).catch(() => {
2164
+ return null;
2165
+ }) : null;
2166
+ const unheadVersion = unheadPackage?.version;
2167
+ const scriptsTypesExport = unheadPackage?.exports?.["./scripts"]?.types;
2168
+ const scriptsTypesPath = unheadPackagePath && typeof scriptsTypesExport === "string" ? resolve(dirname(unheadPackagePath), scriptsTypesExport) : null;
2169
+ const unheadSourceLessScriptLoader = hasUnheadSourceLessScriptLoaderFile(scriptsTypesPath);
1957
2170
  if (unheadVersion?.startsWith("1")) {
1958
2171
  logger.error(`Nuxt Scripts requires Unhead >= 2, you are using v${unheadVersion}. Please run \`nuxi upgrade --clean\` to upgrade...`);
1959
2172
  }
@@ -2012,10 +2225,19 @@ const module$1 = defineNuxtModule({
2012
2225
  googleStaticMapsProxy: googleMapsEnabled ? { enabled: true, cacheMaxAge: config.googleStaticMapsProxy?.cacheMaxAge ?? 3600 } : void 0
2013
2226
  };
2014
2227
  const debugConst = JSON.stringify(!!config.debug);
2228
+ const unheadSourceLessConst = JSON.stringify(unheadSourceLessScriptLoader);
2015
2229
  nuxt.options.vite ||= {};
2016
- nuxt.options.vite.define = { ...nuxt.options.vite.define, __NUXT_SCRIPTS_DEBUG__: debugConst };
2230
+ nuxt.options.vite.define = {
2231
+ ...nuxt.options.vite.define,
2232
+ __NUXT_SCRIPTS_DEBUG__: debugConst,
2233
+ __NUXT_SCRIPTS_UNHEAD_SOURCELESS__: unheadSourceLessConst
2234
+ };
2017
2235
  nuxt.options.nitro ||= {};
2018
- nuxt.options.nitro.replace = { ...nuxt.options.nitro.replace, __NUXT_SCRIPTS_DEBUG__: debugConst };
2236
+ nuxt.options.nitro.replace = {
2237
+ ...nuxt.options.nitro.replace,
2238
+ __NUXT_SCRIPTS_DEBUG__: debugConst,
2239
+ __NUXT_SCRIPTS_UNHEAD_SOURCELESS__: unheadSourceLessConst
2240
+ };
2019
2241
  const scriptsBase = config.prefix || "/_scripts";
2020
2242
  const proxyPrefix = `${scriptsBase}/p`;
2021
2243
  const assetsPrefix = `${scriptsBase}/assets`;
@@ -2369,6 +2591,7 @@ Options: configure platform rewrites, switch to server-rendered mode, or disable
2369
2591
  );
2370
2592
  }
2371
2593
  }
2594
+ ensureNuxtScriptsCacheStorage(nuxt.options.nitro);
2372
2595
  nuxt.options.runtimeConfig.public["nuxt-scripts"] = defu(
2373
2596
  { endpoints: enabledEndpoints },
2374
2597
  nuxt.options.runtimeConfig.public["nuxt-scripts"]
@@ -2388,7 +2611,7 @@ Options: configure platform rewrites, switch to server-rendered mode, or disable
2388
2611
  To enable signing, deploy with a server-rendered target or configure platform-level rewrites.`
2389
2612
  );
2390
2613
  } else if (anyHandlerRequiresSigning) {
2391
- const proxySecretResolved = resolveProxySecret(
2614
+ const proxySecretResolved = await resolveProxySecret(
2392
2615
  nuxt.options.rootDir,
2393
2616
  !!nuxt.options.dev,
2394
2617
  config.security?.secret,
package/dist/registry.mjs CHANGED
@@ -808,8 +808,8 @@ async function registry(resolve) {
808
808
  }
809
809
  function generatePartytownResolveUrl(proxyPrefix, domainAliases = {}) {
810
810
  return `function(url, location, type) {
811
- if (url.origin !== location.origin) {
812
- var aliases = ${JSON.stringify(domainAliases)};
811
+ if ((url.protocol === 'http:' || url.protocol === 'https:') && url.origin !== location.origin) {
812
+ var aliases = Object.assign(Object.create(null), ${JSON.stringify(domainAliases)});
813
813
  var seg = aliases[url.host] || url.host;
814
814
  return new URL(${JSON.stringify(proxyPrefix)} + '/' + seg + url.pathname + url.search, location.origin);
815
815
  }
@@ -5,10 +5,11 @@ export { MAP_INJECTION_KEY } from "./useGoogleMapsResource";
5
5
  <script setup>
6
6
  import { defu } from "defu";
7
7
  import { tryUseNuxtApp, useHead, useRuntimeConfig } from "nuxt/app";
8
- import { computed, nextTick, onBeforeUnmount, onMounted, provide, ref, shallowRef, toRaw, useAttrs, useTemplateRef, watch } from "vue";
8
+ import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, provide, ref, shallowRef, toRaw, useAttrs, useTemplateRef, watch } from "vue";
9
9
  import { useScriptTriggerElement } from "#nuxt-scripts/composables/useScriptTriggerElement";
10
10
  import { useScriptGoogleMaps } from "#nuxt-scripts/registry/google-maps";
11
11
  import { scriptRuntimeConfig, scriptsPrefix } from "#nuxt-scripts/utils";
12
+ import { createAbortablePromise } from "../../utils/abortable-promise";
12
13
  import ScriptAriaLoadingIndicator from "../ScriptAriaLoadingIndicator.vue";
13
14
  import { defineDeprecatedAlias, MAP_INJECTION_KEY, waitForMapsReady, warnDeprecatedTopLevelMapProps } from "./useGoogleMapsResource";
14
15
  const props = defineProps({
@@ -48,6 +49,8 @@ const currentColorScheme = computed(() => {
48
49
  return currentColorMode.value === "dark" ? "DARK" : "LIGHT";
49
50
  });
50
51
  const mapsApi = shallowRef();
52
+ const lifecycleController = new AbortController();
53
+ let isUnmounted = false;
51
54
  if (import.meta.dev) {
52
55
  if (!apiKey)
53
56
  throw new Error("GoogleMaps requires an API key. Enable it in your nuxt.config:\n\n scripts: {\n registry: {\n googleMaps: true\n }\n }\n\nThen set NUXT_PUBLIC_SCRIPTS_GOOGLE_MAPS_API_KEY in your .env file.\n\nAlternatively, pass `api-key` directly on the <ScriptGoogleMaps> component (note: this exposes the key client-side).");
@@ -144,7 +147,8 @@ async function resolveQueryToLatLng(query) {
144
147
  const endpoints = runtimeConfig.public["nuxt-scripts"]?.endpoints;
145
148
  if (endpoints?.googleMaps) {
146
149
  const data = await $fetch(`${scriptsPrefix()}/proxy/google-maps-geocode`, {
147
- params: { address: query }
150
+ params: { address: query },
151
+ signal: lifecycleController.signal
148
152
  });
149
153
  if (data.status === "OK" && data.results?.[0]?.geometry?.location) {
150
154
  const loc = data.results[0].geometry.location;
@@ -154,7 +158,7 @@ async function resolveQueryToLatLng(query) {
154
158
  }
155
159
  throw new Error(`No location found for ${query}`);
156
160
  }
157
- await waitForMapsReady({ mapsApi, map, status, load });
161
+ await waitForMapsReady({ mapsApi, map, status, load, signal: lifecycleController.signal });
158
162
  const placesService = new mapsApi.value.places.PlacesService(map.value);
159
163
  const result = await new Promise((resolve, reject) => {
160
164
  placesService.findPlaceFromQuery(
@@ -178,14 +182,22 @@ const libraries = /* @__PURE__ */ new Map();
178
182
  function importLibrary(key) {
179
183
  if (libraries.has(key))
180
184
  return libraries.get(key);
181
- const p = mapsApi.value?.importLibrary(key) || new Promise((resolve) => {
182
- const stop = watch(mapsApi, (api) => {
185
+ const p = createAbortablePromise((resolve, reject) => {
186
+ let stop = () => {
187
+ };
188
+ stop = watch(mapsApi, (api) => {
183
189
  if (api) {
184
- const p2 = api.importLibrary(key);
185
- resolve(p2);
186
- stop();
190
+ try {
191
+ resolve(api.importLibrary(key));
192
+ } catch (error) {
193
+ reject(error);
194
+ }
187
195
  }
188
196
  }, { immediate: true });
197
+ return () => stop();
198
+ }, {
199
+ signal: lifecycleController.signal,
200
+ abortMessage: `Google Maps library import "${key}" was aborted`
189
201
  });
190
202
  const cached = Promise.resolve(p).catch((err) => {
191
203
  libraries.delete(key);
@@ -251,13 +263,15 @@ onMounted(() => {
251
263
  const zoom = map.value.getZoom();
252
264
  if (center)
253
265
  centerOverride.value = { lat: center.lat(), lng: center.lng() };
254
- map.value.unbindAll();
266
+ const previousMap = map.value;
267
+ mapsApi.value.event.clearInstanceListeners(previousMap);
268
+ previousMap.unbindAll();
255
269
  map.value = void 0;
256
270
  slotMounted.value = false;
257
271
  if (mapEl.value)
258
272
  mapEl.value.innerHTML = "";
259
273
  await nextTick();
260
- if (!mapEl.value || !mapsApi.value)
274
+ if (isUnmounted || !mapEl.value || !mapsApi.value)
261
275
  return;
262
276
  const _options = {
263
277
  ...options.value,
@@ -276,40 +290,66 @@ onMounted(() => {
276
290
  watch([() => getCenterWatchKey(props.center), () => getCenterWatchKey(props.mapOptions?.center)], () => {
277
291
  centerOverride.value = void 0;
278
292
  });
279
- watch([controlledCenterKey, isMapReady, map], async () => {
280
- if (!map.value) {
293
+ watch([controlledCenterKey, isMapReady, map], async (_, __, onCleanup) => {
294
+ const currentMap = map.value;
295
+ if (!currentMap) {
281
296
  return;
282
297
  }
298
+ let stale = false;
299
+ onCleanup(() => {
300
+ stale = true;
301
+ });
283
302
  let center = toRaw(options.value.center);
284
303
  if (center) {
285
304
  if (isLocationQuery(center) && isMapReady.value) {
286
- center = await resolveQueryToLatLng(center);
305
+ try {
306
+ center = await resolveQueryToLatLng(center);
307
+ } catch (error) {
308
+ if (error?.name === "AbortError")
309
+ return;
310
+ throw error;
311
+ }
287
312
  }
288
- const current = map.value.getCenter();
313
+ if (stale || isUnmounted || map.value !== currentMap)
314
+ return;
315
+ const current = currentMap.getCenter();
289
316
  if (current) {
290
317
  const newLat = typeof center.lat === "function" ? center.lat() : center.lat;
291
318
  const newLng = typeof center.lng === "function" ? center.lng() : center.lng;
292
319
  if (current.lat() === newLat && current.lng() === newLng)
293
320
  return;
294
321
  }
295
- map.value.setCenter(center);
322
+ currentMap.setCenter(center);
296
323
  }
297
324
  }, {
298
325
  immediate: true
299
326
  });
300
327
  onLoaded(async (instance) => {
301
- mapsApi.value = await instance.maps;
328
+ const api = await instance.maps;
329
+ if (isUnmounted || !mapEl.value)
330
+ return;
331
+ mapsApi.value = api;
302
332
  const center = options.value.center;
303
333
  const _options = {
304
334
  ...options.value,
305
335
  // @ts-expect-error broken
306
336
  center: !center || isLocationQuery(center) ? void 0 : center
307
337
  };
308
- map.value = new mapsApi.value.Map(mapEl.value, _options);
338
+ map.value = new api.Map(mapEl.value, _options);
309
339
  if (center && isLocationQuery(center)) {
310
- centerOverride.value = await resolveQueryToLatLng(center);
311
- if (centerOverride.value)
312
- map.value?.setCenter(centerOverride.value);
340
+ let resolvedCenter;
341
+ try {
342
+ resolvedCenter = await resolveQueryToLatLng(center);
343
+ } catch (error) {
344
+ if (error?.name === "AbortError")
345
+ return;
346
+ throw error;
347
+ }
348
+ if (isUnmounted)
349
+ return;
350
+ centerOverride.value = resolvedCenter;
351
+ if (resolvedCenter)
352
+ map.value?.setCenter(resolvedCenter);
313
353
  }
314
354
  isMapReady.value = true;
315
355
  });
@@ -356,11 +396,21 @@ const rootAttrs = computed(() => {
356
396
  });
357
397
  });
358
398
  onBeforeUnmount(() => {
359
- map.value?.unbindAll();
399
+ isUnmounted = true;
400
+ lifecycleController.abort();
401
+ if (map.value && mapsApi.value) {
402
+ mapsApi.value.event.clearInstanceListeners(map.value);
403
+ map.value.unbindAll();
404
+ }
360
405
  map.value = void 0;
406
+ activeInfoWindow?.close();
407
+ activeInfoWindow = void 0;
361
408
  libraries.clear();
362
409
  queryToLatLngCache.clear();
363
410
  });
411
+ onUnmounted(() => {
412
+ mapsApi.value = void 0;
413
+ });
364
414
  </script>
365
415
 
366
416
  <template>