@nuxt/scripts 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) 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/BHx4OUbM.js +195 -0
  4. package/dist/devtools-client/_nuxt/CGpx20cA.js +1 -0
  5. package/dist/devtools-client/_nuxt/CrquxyIP.js +1 -0
  6. package/dist/devtools-client/_nuxt/D2og3hsL.js +1 -0
  7. package/dist/devtools-client/_nuxt/DSsHxmoa.js +1 -0
  8. package/dist/devtools-client/_nuxt/DfHxEc1R.js +1 -0
  9. package/dist/devtools-client/_nuxt/HwG19HWB.js +1 -0
  10. package/dist/devtools-client/_nuxt/builds/latest.json +1 -1
  11. package/dist/devtools-client/_nuxt/builds/meta/95e11f41-6ffd-4129-ac40-6ad3d141308e.json +1 -0
  12. package/dist/devtools-client/_nuxt/entry.DehJww9T.css +1 -0
  13. package/dist/devtools-client/_nuxt/error-404.LWbgYmYe.css +1 -0
  14. package/dist/devtools-client/_nuxt/error-500.C19ZIySL.css +1 -0
  15. package/dist/devtools-client/docs/index.html +1 -1
  16. package/dist/devtools-client/first-party/index.html +1 -1
  17. package/dist/devtools-client/index.html +1 -1
  18. package/dist/devtools-client/registry/index.html +1 -1
  19. package/dist/module.d.mts +29 -1
  20. package/dist/module.d.ts +29 -1
  21. package/dist/module.json +1 -1
  22. package/dist/module.mjs +92 -24
  23. package/dist/registry.d.mts +5 -2
  24. package/dist/registry.d.ts +5 -2
  25. package/dist/registry.mjs +4 -2
  26. package/dist/runtime/composables/useScript.js +6 -1
  27. package/dist/runtime/registry/speedcurve.js +4 -2
  28. package/dist/runtime/server/proxy-handler.js +3 -2
  29. package/dist/runtime/server/utils/match-domain.js +1 -1
  30. package/dist/runtime/utils.js +10 -1
  31. package/package.json +6 -6
  32. package/dist/devtools-client/_nuxt/BTXw0v4h.js +0 -1
  33. package/dist/devtools-client/_nuxt/Bf6N2ObH.js +0 -1
  34. package/dist/devtools-client/_nuxt/C5Bq9Qgz.js +0 -1
  35. package/dist/devtools-client/_nuxt/CSw0kWhI.js +0 -1
  36. package/dist/devtools-client/_nuxt/DWvCkA0U.js +0 -195
  37. package/dist/devtools-client/_nuxt/TPgAGQc8.js +0 -1
  38. package/dist/devtools-client/_nuxt/builds/meta/df290ad6-a770-4973-bb7f-110a630b368c.json +0 -1
  39. package/dist/devtools-client/_nuxt/dvDf1_6X.js +0 -1
  40. package/dist/devtools-client/_nuxt/entry.VwiedW44.css +0 -1
  41. package/dist/devtools-client/_nuxt/error-404.DBJH6QEN.css +0 -1
  42. package/dist/devtools-client/_nuxt/error-500.BIIPjeaA.css +0 -1
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.VwiedW44.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-scripts/_nuxt/DWvCkA0U.js"><script type="module" src="/__nuxt-scripts/_nuxt/DWvCkA0U.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-scripts",buildId:"df290ad6-a770-4973-bb7f-110a630b368c",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1780372324345,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.DehJww9T.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-scripts/_nuxt/BHx4OUbM.js"><script type="module" src="/__nuxt-scripts/_nuxt/BHx4OUbM.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/__nuxt-scripts/_nuxt/B8PEiB0p.js"><link rel="prefetch" as="script" crossorigin href="/__nuxt-scripts/_nuxt/Cp-IABpG.js"><link rel="prefetch" as="script" crossorigin href="/__nuxt-scripts/_nuxt/wDzz0qaB.js"><link rel="prefetch" as="script" crossorigin href="/__nuxt-scripts/_nuxt/CVO1_9PV.js"><link rel="prefetch" as="script" crossorigin href="/__nuxt-scripts/_nuxt/D0r3Knsf.js"><link rel="prefetch" as="style" crossorigin href="/__nuxt-scripts/_nuxt/error-500.C19ZIySL.css"><link rel="prefetch" as="script" crossorigin href="/__nuxt-scripts/_nuxt/D2og3hsL.js"><script>"use strict";(()=>{const o=window,e=document.documentElement,c=["dark","light"],s=getStorageValue("localStorage","nuxt-color-mode")||"system";let r=s==="system"?f():s;const l=e.getAttribute("data-color-mode-forced");l&&(r=l),i(r),o["__NUXT_COLOR_MODE__"]={preference:s,value:r,getColorScheme:f,addColorScheme:i,removeColorScheme:d};function i(t){const a=""+t+"",n="";e.classList?e.classList.add(a):e.className+=" "+a,n&&e.setAttribute("data-"+n,t)}function d(t){const a=""+t+"",n="";e.classList?e.classList.remove(a):e.className=e.className.replace(new RegExp(a,"g"),""),n&&e.removeAttribute("data-"+n)}function u(t){return o.matchMedia("(prefers-color-scheme"+t+")")}function f(){if(o.matchMedia&&u("").media!=="not all"){for(const t of c)if(u(":"+t).matches)return t}return"light"}})();function getStorageValue(o,e){switch(o){case"localStorage":try{return window.localStorage.getItem(e)}catch{return null}case"sessionStorage":try{return window.sessionStorage.getItem(e)}catch{return null}case"cookie":try{return getCookie(e)}catch{return null}default:return null}}function getCookie(o){const c=("; "+window.document.cookie).split("; "+o+"=");if(c.length===2){const s=c.pop();return s?s.split(";").shift():null}}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-scripts",buildId:"95e11f41-6ffd-4129-ac40-6ad3d141308e",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1782832582381,false]</script></body></html>
package/dist/module.d.mts CHANGED
@@ -3,6 +3,17 @@ import { FetchOptions } from 'ofetch';
3
3
  import { RegistryScripts, FirstPartyPrivacy, NuxtConfigScriptRegistry, NuxtUseScriptOptionsSerializable, NuxtUseScriptInput, ResolvedProxyAutoInject, ProxyConfig } from '../dist/runtime/types.js';
4
4
  export { FirstPartyPrivacy } from '../dist/runtime/types.js';
5
5
 
6
+ /**
7
+ * Proxy path alias configuration.
8
+ * - `false` / `undefined`: proxy paths use the verbatim third-party hostname
9
+ * (`/_scripts/p/us.i.posthog.com/...`).
10
+ * - `true`: every proxied domain gets a short deterministic opaque alias
11
+ * (`/_scripts/p/a1b2c3d4/...`), so the real hostname never appears in client URLs.
12
+ * - `Record<domain, alias>`: explicit aliases (domain → alias). Domains not listed
13
+ * keep their verbatim hostname.
14
+ */
15
+ type ProxyAliasConfig = boolean | Record<string, string> | undefined;
16
+
6
17
  interface ResolvedProxySecret {
7
18
  secret: string;
8
19
  /** True when the secret exists only in memory (dev-only fallback; won't survive restarts). */
@@ -21,7 +32,7 @@ interface ResolvedProxySecret {
21
32
  */
22
33
  declare function resolveProxySecret(rootDir: string, isDev: boolean, configSecret?: string, autoGenerate?: boolean): ResolvedProxySecret | undefined;
23
34
  declare function isProxyDisabled(registryKey: string, registry?: NuxtConfigScriptRegistry, runtimeConfig?: Record<string, any>): boolean;
24
- declare function applyAutoInject(registry: NuxtConfigScriptRegistry, runtimeConfig: Record<string, any>, proxyPrefix: string, registryKey: string, autoInject: ResolvedProxyAutoInject): void;
35
+ declare function applyAutoInject(registry: NuxtConfigScriptRegistry, runtimeConfig: Record<string, any>, proxyPrefix: string, registryKey: string, autoInject: ResolvedProxyAutoInject, alias?: ProxyAliasConfig): void;
25
36
  declare function resolveConfiguredProxyDomains(config: Record<string, any> | undefined, proxyConfig?: Pick<ProxyConfig, 'autoInject' | 'configDomainFields'>): string[];
26
37
  /**
27
38
  * Compute missing required fields for a registry entry, using the merged
@@ -50,6 +61,23 @@ interface ModuleOptions {
50
61
  * @default undefined (per-script defaults)
51
62
  */
52
63
  privacy?: FirstPartyPrivacy;
64
+ /**
65
+ * First-party proxy behaviour.
66
+ */
67
+ proxy?: {
68
+ /**
69
+ * Replace third-party hostnames in proxy paths with aliases, so the real domain
70
+ * (e.g. a self-hosted analytics host) never appears in client-facing URLs.
71
+ *
72
+ * - `false` (default): paths embed the verbatim hostname (`/_scripts/p/us.i.posthog.com/...`)
73
+ * - `true`: auto-generate a short opaque alias per domain (`/_scripts/p/a1b2c3d4/...`)
74
+ * - `Record<domain, alias>`: explicit aliases (domain → alias); unlisted domains stay verbatim
75
+ *
76
+ * @default false
77
+ * @example { 'us.i.posthog.com': 'ph', 'analytics.internal.example.com': 'a' }
78
+ */
79
+ alias?: ProxyAliasConfig;
80
+ };
53
81
  /**
54
82
  * The registry of supported third-party scripts. Presence enables infrastructure (proxy routes, types, bundling, composable auto-imports).
55
83
  * Scripts only auto-load globally when `trigger` is explicitly set in the config object.
package/dist/module.d.ts CHANGED
@@ -3,6 +3,17 @@ import { FetchOptions } from 'ofetch';
3
3
  import { RegistryScripts, FirstPartyPrivacy, NuxtConfigScriptRegistry, NuxtUseScriptOptionsSerializable, NuxtUseScriptInput, ResolvedProxyAutoInject, ProxyConfig } from '../dist/runtime/types.js';
4
4
  export { FirstPartyPrivacy } from '../dist/runtime/types.js';
5
5
 
6
+ /**
7
+ * Proxy path alias configuration.
8
+ * - `false` / `undefined`: proxy paths use the verbatim third-party hostname
9
+ * (`/_scripts/p/us.i.posthog.com/...`).
10
+ * - `true`: every proxied domain gets a short deterministic opaque alias
11
+ * (`/_scripts/p/a1b2c3d4/...`), so the real hostname never appears in client URLs.
12
+ * - `Record<domain, alias>`: explicit aliases (domain → alias). Domains not listed
13
+ * keep their verbatim hostname.
14
+ */
15
+ type ProxyAliasConfig = boolean | Record<string, string> | undefined;
16
+
6
17
  interface ResolvedProxySecret {
7
18
  secret: string;
8
19
  /** True when the secret exists only in memory (dev-only fallback; won't survive restarts). */
@@ -21,7 +32,7 @@ interface ResolvedProxySecret {
21
32
  */
22
33
  declare function resolveProxySecret(rootDir: string, isDev: boolean, configSecret?: string, autoGenerate?: boolean): ResolvedProxySecret | undefined;
23
34
  declare function isProxyDisabled(registryKey: string, registry?: NuxtConfigScriptRegistry, runtimeConfig?: Record<string, any>): boolean;
24
- declare function applyAutoInject(registry: NuxtConfigScriptRegistry, runtimeConfig: Record<string, any>, proxyPrefix: string, registryKey: string, autoInject: ResolvedProxyAutoInject): void;
35
+ declare function applyAutoInject(registry: NuxtConfigScriptRegistry, runtimeConfig: Record<string, any>, proxyPrefix: string, registryKey: string, autoInject: ResolvedProxyAutoInject, alias?: ProxyAliasConfig): void;
25
36
  declare function resolveConfiguredProxyDomains(config: Record<string, any> | undefined, proxyConfig?: Pick<ProxyConfig, 'autoInject' | 'configDomainFields'>): string[];
26
37
  /**
27
38
  * Compute missing required fields for a registry entry, using the merged
@@ -50,6 +61,23 @@ interface ModuleOptions {
50
61
  * @default undefined (per-script defaults)
51
62
  */
52
63
  privacy?: FirstPartyPrivacy;
64
+ /**
65
+ * First-party proxy behaviour.
66
+ */
67
+ proxy?: {
68
+ /**
69
+ * Replace third-party hostnames in proxy paths with aliases, so the real domain
70
+ * (e.g. a self-hosted analytics host) never appears in client-facing URLs.
71
+ *
72
+ * - `false` (default): paths embed the verbatim hostname (`/_scripts/p/us.i.posthog.com/...`)
73
+ * - `true`: auto-generate a short opaque alias per domain (`/_scripts/p/a1b2c3d4/...`)
74
+ * - `Record<domain, alias>`: explicit aliases (domain → alias); unlisted domains stay verbatim
75
+ *
76
+ * @default false
77
+ * @example { 'us.i.posthog.com': 'ph', 'analytics.internal.example.com': 'a' }
78
+ */
79
+ alias?: ProxyAliasConfig;
80
+ };
53
81
  /**
54
82
  * The registry of supported third-party scripts. Presence enables infrastructure (proxy routes, types, bundling, composable auto-imports).
55
83
  * Scripts only auto-load globally when `trigger` is explicitly set in the config object.
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.16"
6
6
  },
7
- "version": "1.2.0",
7
+ "version": "1.3.0",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -196,7 +196,7 @@ function buildDevtoolsEntry(key, script, configKey, proxyConfig) {
196
196
  domains: [...proxyConfig.domains]
197
197
  };
198
198
  }
199
- function buildDevtoolsData(proxyPrefix, privacyLabel, scripts) {
199
+ function buildDevtoolsData(proxyPrefix, privacyLabel, scripts, aliasToDomain) {
200
200
  const allDomains = /* @__PURE__ */ new Set();
201
201
  for (const s of scripts) {
202
202
  for (const d of s.domains)
@@ -207,7 +207,8 @@ function buildDevtoolsData(proxyPrefix, privacyLabel, scripts) {
207
207
  proxyPrefix,
208
208
  privacyMode: privacyLabel,
209
209
  scripts,
210
- totalDomains: allDomains.size
210
+ totalDomains: allDomains.size,
211
+ aliasToDomain
211
212
  };
212
213
  }
213
214
 
@@ -428,6 +429,7 @@ function generateInterceptPluginContents(proxyPrefix, options) {
428
429
  enforce: 'pre',
429
430
  setup() {
430
431
  const proxyPrefix = ${JSON.stringify(proxyPrefix)};
432
+ const domainAliases = ${JSON.stringify(options?.domainAliases ?? {})};
431
433
  const origBeacon = typeof navigator !== 'undefined' && navigator.sendBeacon
432
434
  ? navigator.sendBeacon.bind(navigator)
433
435
  : () => false;
@@ -436,8 +438,10 @@ function generateInterceptPluginContents(proxyPrefix, options) {
436
438
  function proxyUrl(url) {
437
439
  try {
438
440
  const parsed = new URL(url, location.origin);
439
- if (parsed.origin !== location.origin)
440
- return location.origin + proxyPrefix + '/' + parsed.host + parsed.pathname + parsed.search;
441
+ if (parsed.origin !== location.origin) {
442
+ const seg = domainAliases[parsed.host] || parsed.host;
443
+ return location.origin + proxyPrefix + '/' + seg + parsed.pathname + parsed.search;
444
+ }
441
445
  } catch {}
442
446
  return url;
443
447
  }
@@ -1078,7 +1082,7 @@ function NuxtScriptBundleTransformer(options = {
1078
1082
  const proxyConfig = !firstPartyOptOut && proxyConfigKey ? options.proxyConfigs?.[proxyConfigKey] : void 0;
1079
1083
  const proxyRewrites = proxyConfig?.domains?.filter((domain) => !domain.includes("*")).map((domain) => ({
1080
1084
  from: domain,
1081
- to: `${options.proxyPrefix}/${domain}`
1085
+ to: `${options.proxyPrefix}/${options.domainAliases?.[domain] ?? domain}`
1082
1086
  }));
1083
1087
  const bundleConfig = typeof script?.bundle === "object" ? script.bundle : void 0;
1084
1088
  const sdkPatches = proxyConfig?.sdkPatches ?? bundleConfig?.sdkPatches;
@@ -1170,6 +1174,45 @@ function NuxtScriptBundleTransformer(options = {
1170
1174
  });
1171
1175
  }
1172
1176
 
1177
+ const WILDCARD_RE = /\*/;
1178
+ const SAFE_ALIAS_SEGMENT_RE = /^[\w.-]+$/;
1179
+ function isSafeAliasSegment(alias) {
1180
+ return SAFE_ALIAS_SEGMENT_RE.test(alias);
1181
+ }
1182
+ function aliasForDomain(domain, alias) {
1183
+ if (!alias || WILDCARD_RE.test(domain))
1184
+ return void 0;
1185
+ if (alias === true)
1186
+ return createHash("sha256").update(domain).digest("hex").slice(0, 12);
1187
+ return Object.hasOwn(alias, domain) ? alias[domain] || void 0 : void 0;
1188
+ }
1189
+ function buildDomainAliasMap(domains, alias) {
1190
+ const map = {};
1191
+ for (const domain of domains) {
1192
+ const value = aliasForDomain(domain, alias);
1193
+ if (value)
1194
+ map[domain] = value;
1195
+ }
1196
+ return map;
1197
+ }
1198
+ function invertAliasMap(map) {
1199
+ const out = {};
1200
+ for (const [domain, alias] of Object.entries(map))
1201
+ out[alias] = domain;
1202
+ return out;
1203
+ }
1204
+ function aliasProxyValue(value, proxyPrefix, alias) {
1205
+ const prefix = `${proxyPrefix}/`;
1206
+ if (!alias || !value.startsWith(prefix))
1207
+ return value;
1208
+ const rest = value.slice(prefix.length);
1209
+ const host = rest.match(/^[^/?#]+/)?.[0];
1210
+ if (!host)
1211
+ return value;
1212
+ const aliased = aliasForDomain(host, alias);
1213
+ return aliased ? `${prefix}${aliased}${rest.slice(host.length)}` : value;
1214
+ }
1215
+
1173
1216
  const TRIGGER_PLACEHOLDER_RE = /"__TRIGGER_PLACEHOLDER__"/g;
1174
1217
  function registerTypeTemplates({ config, newScripts }) {
1175
1218
  addTypeTemplate({
@@ -1646,7 +1689,7 @@ function isProxyDisabled(registryKey, registry2, runtimeConfig) {
1646
1689
  }
1647
1690
  return false;
1648
1691
  }
1649
- function applyAutoInject(registry2, runtimeConfig, proxyPrefix, registryKey, autoInject) {
1692
+ function applyAutoInject(registry2, runtimeConfig, proxyPrefix, registryKey, autoInject, alias) {
1650
1693
  if (isProxyDisabled(registryKey, registry2, runtimeConfig))
1651
1694
  return;
1652
1695
  const entry = registry2[registryKey];
@@ -1656,7 +1699,7 @@ function applyAutoInject(registry2, runtimeConfig, proxyPrefix, registryKey, aut
1656
1699
  const config = rtEntry && typeof rtEntry === "object" ? rtEntry : input;
1657
1700
  if (!config || config[autoInject.configField])
1658
1701
  return;
1659
- const value = autoInject.computeValue(proxyPrefix, config);
1702
+ const value = aliasProxyValue(autoInject.computeValue(proxyPrefix, config), proxyPrefix, alias);
1660
1703
  input[autoInject.configField] = value;
1661
1704
  if (rtEntry && typeof rtEntry === "object" && rtEntry !== input)
1662
1705
  rtEntry[autoInject.configField] = value;
@@ -1853,20 +1896,27 @@ const module$1 = defineNuxtModule({
1853
1896
  return templateTriggerResolver(config.defaultScriptOptions);
1854
1897
  }
1855
1898
  });
1856
- if (config.registry?.speedcurve) {
1857
- addTemplate({
1858
- filename: "nuxt-scripts-speedcurve-snippet.mjs",
1859
- async getContents() {
1860
- const snippetPath = await resolvePath("@speedcurve/lux/dist/lux-snippet.js");
1861
- if (!existsSync(snippetPath)) {
1862
- throw new Error("[nuxt-scripts] useScriptSpeedCurve requires the @speedcurve/lux package. Install it with: npm i -D @speedcurve/lux");
1863
- }
1864
- const source = readFileSync(snippetPath, "utf-8");
1865
- return `export const luxSnippetSource = ${JSON.stringify(source)}
1866
- `;
1899
+ const snippets = {
1900
+ async speedcurveLuxSnippet() {
1901
+ if (!config.registry?.speedcurve)
1902
+ return "";
1903
+ const snippetPath = await resolvePath("@speedcurve/lux/dist/lux-snippet.js");
1904
+ if (!existsSync(snippetPath)) {
1905
+ throw new Error("[nuxt-scripts] useScriptSpeedCurve requires the @speedcurve/lux package. Install it with: npm i -D @speedcurve/lux");
1867
1906
  }
1868
- });
1869
- }
1907
+ return readFileSync(snippetPath, "utf-8");
1908
+ }
1909
+ };
1910
+ addTemplate({
1911
+ filename: "nuxt-scripts-snippets.mjs",
1912
+ async getContents() {
1913
+ const exports = await Promise.all(
1914
+ Object.entries(snippets).map(async ([name2, getSource]) => `export const ${name2} = ${JSON.stringify(await getSource())}
1915
+ `)
1916
+ );
1917
+ return exports.join("");
1918
+ }
1919
+ });
1870
1920
  logger.debug("[nuxt-scripts] Proxy prefix:", proxyPrefix);
1871
1921
  for (const script of scripts) {
1872
1922
  if (script.import?.name) {
@@ -1984,6 +2034,8 @@ const module$1 = defineNuxtModule({
1984
2034
  }
1985
2035
  }
1986
2036
  }
2037
+ const proxyAlias = config.proxy?.alias;
2038
+ let domainAliases = {};
1987
2039
  if (anyNeedsProxy) {
1988
2040
  const builtConfigs = buildProxyConfigsFromRegistry(registryScripts, scriptByKey);
1989
2041
  Object.assign(proxyConfigs, builtConfigs);
@@ -2023,7 +2075,7 @@ const module$1 = defineNuxtModule({
2023
2075
  }
2024
2076
  }
2025
2077
  if (proxyConfig.autoInject && config.registry)
2026
- applyAutoInject(config.registry, nuxt.options.runtimeConfig, proxyPrefix, key, proxyConfig.autoInject);
2078
+ applyAutoInject(config.registry, nuxt.options.runtimeConfig, proxyPrefix, key, proxyConfig.autoInject, proxyAlias);
2027
2079
  if (nuxt.options.dev)
2028
2080
  devtoolsScripts.push(buildDevtoolsEntry(key, script, configKey, proxyConfig));
2029
2081
  }
@@ -2039,15 +2091,30 @@ These scripts will not have proxy routes registered.`
2039
2091
  They will load directly from third-party servers.`
2040
2092
  );
2041
2093
  }
2094
+ domainAliases = buildDomainAliasMap(Object.keys(domainPrivacy), proxyAlias);
2095
+ const realDomains = new Set(Object.keys(domainPrivacy));
2096
+ const aliasOwner = /* @__PURE__ */ new Map();
2097
+ for (const [domain, alias] of Object.entries(domainAliases)) {
2098
+ if (!isSafeAliasSegment(alias))
2099
+ throw new Error(`[nuxt-scripts] Invalid proxy alias "${alias}" for "${domain}": use a single URL-safe path segment (letters, digits, '-', '_', '.').`);
2100
+ if (realDomains.has(alias))
2101
+ throw new Error(`[nuxt-scripts] Proxy alias "${alias}" for "${domain}" collides with proxied domain "${alias}". Pick an alias that is not also a proxied hostname.`);
2102
+ const prev = aliasOwner.get(alias);
2103
+ if (prev)
2104
+ throw new Error(`[nuxt-scripts] Proxy alias collision: "${prev}" and "${domain}" both map to "${alias}". Give each domain a unique alias.`);
2105
+ aliasOwner.set(alias, domain);
2106
+ }
2107
+ const aliasToDomain = invertAliasMap(domainAliases);
2042
2108
  addPluginTemplate({
2043
2109
  filename: "nuxt-scripts-intercept.client.mjs",
2044
2110
  getContents() {
2045
- return generateInterceptPluginContents(proxyPrefix, { testMode: !!nuxt.options.test });
2111
+ return generateInterceptPluginContents(proxyPrefix, { testMode: !!nuxt.options.test, domainAliases });
2046
2112
  }
2047
2113
  });
2048
2114
  nuxt.options.runtimeConfig["nuxt-scripts-proxy"] = {
2049
2115
  proxyPrefix,
2050
2116
  domainPrivacy,
2117
+ aliasToDomain,
2051
2118
  privacy: config.privacy
2052
2119
  };
2053
2120
  const privacyLabel = config.privacy === void 0 ? "per-script" : typeof config.privacy === "boolean" ? config.privacy ? "anonymize" : "passthrough" : "custom";
@@ -2064,12 +2131,12 @@ Options: configure platform rewrites, switch to server-rendered mode, or disable
2064
2131
  );
2065
2132
  }
2066
2133
  if (nuxt.options.dev) {
2067
- nuxt.options.runtimeConfig.public["nuxt-scripts-devtools"] = buildDevtoolsData(proxyPrefix, privacyLabel, devtoolsScripts);
2134
+ nuxt.options.runtimeConfig.public["nuxt-scripts-devtools"] = buildDevtoolsData(proxyPrefix, privacyLabel, devtoolsScripts, aliasToDomain);
2068
2135
  }
2069
2136
  if (partytownScripts.size && hasNuxtModule("@nuxtjs/partytown")) {
2070
2137
  const partytownConfig = nuxt.options.partytown || {};
2071
2138
  if (!partytownConfig.resolveUrl) {
2072
- partytownConfig.resolveUrl = generatePartytownResolveUrl(proxyPrefix);
2139
+ partytownConfig.resolveUrl = generatePartytownResolveUrl(proxyPrefix, domainAliases);
2073
2140
  nuxt.options.partytown = partytownConfig;
2074
2141
  logger.info("[partytown] Auto-configured resolveUrl for proxy");
2075
2142
  } else {
@@ -2086,6 +2153,7 @@ Options: configure platform rewrites, switch to server-rendered mode, or disable
2086
2153
  registryConfig: nuxt.options.runtimeConfig.public.scripts,
2087
2154
  proxyConfigs,
2088
2155
  proxyPrefix,
2156
+ domainAliases,
2089
2157
  partytownScripts,
2090
2158
  moduleDetected(module) {
2091
2159
  if (nuxt.options.dev && module !== "@nuxt/scripts" && !moduleInstallPromises.has(module) && !hasNuxtModule(module))
@@ -71,9 +71,12 @@ declare function registry(resolve?: (path: string) => Promise<string>): Promise<
71
71
  /**
72
72
  * Generate a Partytown `resolveUrl` function string for proxy routing.
73
73
  * Partytown calls this for every network request made by worker-executed scripts.
74
- * Any non-same-origin URL is proxied through `proxyPrefix/<host><path>`.
74
+ * Any non-same-origin URL is proxied through `proxyPrefix/<host-or-alias><path>`.
75
+ *
76
+ * `domainAliases` (real domain → path alias) is embedded so worker requests use the
77
+ * same opaque path segment as build-time rewrites, keeping hostnames out of URLs.
75
78
  */
76
- declare function generatePartytownResolveUrl(proxyPrefix: string): string;
79
+ declare function generatePartytownResolveUrl(proxyPrefix: string, domainAliases?: Record<string, string>): string;
77
80
  /**
78
81
  * Resolve the effective capabilities for a script by merging:
79
82
  * 1. Derive ceiling from script's bundle/proxy/partytown keys
@@ -71,9 +71,12 @@ declare function registry(resolve?: (path: string) => Promise<string>): Promise<
71
71
  /**
72
72
  * Generate a Partytown `resolveUrl` function string for proxy routing.
73
73
  * Partytown calls this for every network request made by worker-executed scripts.
74
- * Any non-same-origin URL is proxied through `proxyPrefix/<host><path>`.
74
+ * Any non-same-origin URL is proxied through `proxyPrefix/<host-or-alias><path>`.
75
+ *
76
+ * `domainAliases` (real domain → path alias) is embedded so worker requests use the
77
+ * same opaque path segment as build-time rewrites, keeping hostnames out of URLs.
75
78
  */
76
- declare function generatePartytownResolveUrl(proxyPrefix: string): string;
79
+ declare function generatePartytownResolveUrl(proxyPrefix: string, domainAliases?: Record<string, string>): string;
77
80
  /**
78
81
  * Resolve the effective capabilities for a script by merging:
79
82
  * 1. Derive ceiling from script's bundle/proxy/partytown keys
package/dist/registry.mjs CHANGED
@@ -800,10 +800,12 @@ async function registry(resolve) {
800
800
  })
801
801
  ]);
802
802
  }
803
- function generatePartytownResolveUrl(proxyPrefix) {
803
+ function generatePartytownResolveUrl(proxyPrefix, domainAliases = {}) {
804
804
  return `function(url, location, type) {
805
805
  if (url.origin !== location.origin) {
806
- return new URL(${JSON.stringify(proxyPrefix)} + '/' + url.host + url.pathname + url.search, location.origin);
806
+ var aliases = ${JSON.stringify(domainAliases)};
807
+ var seg = aliases[url.host] || url.host;
808
+ return new URL(${JSON.stringify(proxyPrefix)} + '/' + seg + url.pathname + url.search, location.origin);
807
809
  }
808
810
  }`;
809
811
  }
@@ -29,6 +29,7 @@ function toNetworkRequest(entry, proxyPrefix) {
29
29
  }
30
30
  function createDomainMatcher(domains, proxyPrefix, scriptSrc) {
31
31
  const localHostname = window.location.hostname;
32
+ const aliasToDomain = useRuntimeConfig().public["nuxt-scripts-devtools"]?.aliasToDomain || {};
32
33
  const scriptUrl = (() => {
33
34
  if (!scriptSrc)
34
35
  return "";
@@ -49,7 +50,8 @@ function createDomainMatcher(domains, proxyPrefix, scriptSrc) {
49
50
  const proxyIdx = entryUrl.pathname.indexOf(proxyPath);
50
51
  if (proxyIdx !== -1) {
51
52
  const afterPrefix = entryUrl.pathname.slice(proxyIdx + proxyPath.length);
52
- const proxyDomain = afterPrefix.split("/")[0];
53
+ const proxySegment = afterPrefix.split("/")[0];
54
+ const proxyDomain = proxySegment ? aliasToDomain[proxySegment] || proxySegment : void 0;
53
55
  if (proxyDomain && domains.has(proxyDomain))
54
56
  return true;
55
57
  }
@@ -116,6 +118,9 @@ export function resolveScriptKey(input) {
116
118
  export function useScript(input, options) {
117
119
  input = typeof input === "string" ? { src: input } : input;
118
120
  options = defu(options, useNuxtScriptRuntimeConfig()?.defaultScriptOptions);
121
+ if (!import.meta.client && options.use) {
122
+ options.use = (() => void 0);
123
+ }
119
124
  if (options.partytown) {
120
125
  const src = input.src;
121
126
  if (!src) {
@@ -1,5 +1,5 @@
1
1
  import { useHead, useNuxtApp, useRouter } from "nuxt/app";
2
- import { luxSnippetSource } from "#build/nuxt-scripts-speedcurve-snippet";
2
+ import { speedcurveLuxSnippet } from "#build/nuxt-scripts-snippets";
3
3
  import { useRegistryScript } from "../utils.js";
4
4
  import { afterNextPaint } from "../utils/after-next-paint.js";
5
5
  import { SpeedCurveOptions } from "./schemas.js";
@@ -19,12 +19,14 @@ export function useScriptSpeedCurve(_options) {
19
19
  trigger: "client",
20
20
  use: () => ({ LUX: window.LUX }),
21
21
  beforeInit: () => {
22
+ if (!speedcurveLuxSnippet)
23
+ return;
22
24
  useHead({
23
25
  script: [{
24
26
  key: "speedcurve-lux-primer",
25
27
  tagPosition: "head",
26
28
  tagPriority: "critical",
27
- innerHTML: luxSnippetSource
29
+ innerHTML: speedcurveLuxSnippet
28
30
  }]
29
31
  });
30
32
  }
@@ -42,7 +42,7 @@ export default defineEventHandler(async (event) => {
42
42
  statusMessage: "First-party proxy not configured"
43
43
  });
44
44
  }
45
- const { proxyPrefix, domainPrivacy, privacy: globalPrivacy, debug = import.meta.dev } = proxyConfig;
45
+ const { proxyPrefix, domainPrivacy, aliasToDomain, privacy: globalPrivacy, debug = import.meta.dev } = proxyConfig;
46
46
  const path = event.path;
47
47
  const log = debug ? (message, ...args) => {
48
48
  console.debug(message, ...args);
@@ -50,8 +50,9 @@ export default defineEventHandler(async (event) => {
50
50
  };
51
51
  const afterPrefix = path.slice(proxyPrefix.length + 1);
52
52
  const slashIdx = afterPrefix.indexOf("/");
53
- const domain = slashIdx > 0 ? afterPrefix.slice(0, slashIdx) : afterPrefix;
53
+ const segment = slashIdx > 0 ? afterPrefix.slice(0, slashIdx) : afterPrefix;
54
54
  const remainingPath = slashIdx > 0 ? afterPrefix.slice(slashIdx) : "/";
55
+ const domain = aliasToDomain && Object.hasOwn(aliasToDomain, segment) ? aliasToDomain[segment] : segment;
55
56
  if (!domain) {
56
57
  log("[proxy] No domain in path:", path);
57
58
  throw createError({
@@ -3,7 +3,7 @@ const SUBDOMAIN_LABEL_RE = /^[^.]+$/;
3
3
  export function matchDomain(domain, pattern) {
4
4
  if (!pattern.includes("*"))
5
5
  return domain === pattern || domain.endsWith(`.${pattern}`);
6
- if (pattern.startsWith("*.") && pattern.indexOf("*") === 0) {
6
+ if (pattern.startsWith("*.") && pattern.startsWith("*")) {
7
7
  const suffix = pattern.slice(2);
8
8
  if (!domain.endsWith(`.${suffix}`))
9
9
  return false;
@@ -19,6 +19,12 @@ function validateScriptInputSchema(schema, options) {
19
19
  }
20
20
  return null;
21
21
  }
22
+ function resolveClientUse(use) {
23
+ if (!import.meta.client && use) {
24
+ return (() => void 0);
25
+ }
26
+ return use;
27
+ }
22
28
  export function scriptRuntimeConfig(key) {
23
29
  return (useRuntimeConfig().public.scripts || {})[key];
24
30
  }
@@ -41,7 +47,7 @@ export function useRegistryScript(registryKey, optionsFn, _userOptions) {
41
47
  if (options.scriptMode === "npm") {
42
48
  return createNpmScriptStub({
43
49
  key: String(registryKey),
44
- use: options.scriptOptions?.use,
50
+ use: resolveClientUse(options.scriptOptions?.use),
45
51
  clientInit: options.clientInit,
46
52
  trigger: userOptions.scriptOptions?.trigger
47
53
  });
@@ -63,6 +69,9 @@ export function useRegistryScript(registryKey, optionsFn, _userOptions) {
63
69
  }
64
70
  const scriptInput = defu(finalScriptInput, userOptions.scriptInput, { key: registryKey });
65
71
  const scriptOptions = { ...userOptions?.scriptOptions, ...options.scriptOptions };
72
+ if (scriptOptions.use) {
73
+ scriptOptions.use = resolveClientUse(scriptOptions.use);
74
+ }
66
75
  if (import.meta.dev) {
67
76
  const error = new Error("Stack trace for component location");
68
77
  const stack = error.stack?.split("\n");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nuxt/scripts",
3
3
  "type": "module",
4
- "version": "1.2.0",
4
+ "version": "1.3.0",
5
5
  "description": "Load third-party scripts with better performance, privacy and DX in Nuxt Apps.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -115,7 +115,7 @@
115
115
  "magic-string": "^0.30.21",
116
116
  "ofetch": "^1.5.1",
117
117
  "ohash": "^2.0.11",
118
- "oxc-parser": "^0.134.0",
118
+ "oxc-parser": "^0.137.0",
119
119
  "oxc-walker": "^1.0.0",
120
120
  "pathe": "^2.0.3",
121
121
  "pkg-types": "^2.3.1",
@@ -123,15 +123,15 @@
123
123
  "std-env": "^4.1.0",
124
124
  "ufo": "^1.6.4",
125
125
  "ultrahtml": "^1.6.0",
126
- "unplugin": "^3.0.0",
126
+ "unplugin": "^3.3.0",
127
127
  "unstorage": "^1.17.5",
128
- "valibot": "^1.4.1"
128
+ "valibot": "^1.4.2"
129
129
  },
130
130
  "devDependencies": {
131
- "@nuxt/kit": "^4.4.6",
131
+ "@nuxt/kit": "^4.4.8",
132
132
  "@nuxt/module-builder": "^1.0.2",
133
133
  "@speedcurve/lux": "^4.4.3",
134
- "rollup": "^4.60.4",
134
+ "rollup": "^4.62.2",
135
135
  "unbuild": "^3.6.1",
136
136
  "unimport": "^6.3.0"
137
137
  },
@@ -1 +0,0 @@
1
- import{y as c,a3 as o,s as n,o as l,h as r,p as a}from"./DWvCkA0U.js";const _={class:"h-full max-h-full overflow-hidden"},u=["src","title"],i=c({__name:"DevtoolsDocs",props:{url:{}},setup(e){return(s,t)=>(o(),n("div",_,[l("iframe",{src:e.url,title:`Documentation - ${e.url}`,class:"w-full h-full border-none",style:{"min-height":"calc(100vh - 100px)"}},null,8,u)]))}}),m=Object.assign(i,{__name:"DevtoolsDocs"}),f={};function h(e,s){const t=m;return o(),a(t,{url:"https://scripts.nuxt.com"})}const p=r(f,[["render",h]]);export{p as default};
@@ -1 +0,0 @@
1
- import{h as s,aA as a,a3 as i,s as u,o as t,ai as n,x as c,aJ as l,w as d,_ as f}from"./DWvCkA0U.js";const p={class:"antialiased bg-white dark:bg-[#020420] dark:text-white font-sans grid min-h-screen overflow-hidden place-content-center text-[#020420] tracking-wide"},m={class:"max-w-520px text-center"},h=["textContent"],x=["textContent"],b=["textContent"],g={class:"flex items-center justify-center w-full"},y={__name:"error-404",props:{appName:{type:String,default:"Nuxt"},status:{type:Number,default:404},statusText:{type:String,default:"Page not found"},description:{type:String,default:"Sorry, the page you are looking for could not be found."},backHome:{type:String,default:"Go back home"}},setup(e){const r=e;return a({title:`${r.status} - ${r.statusText} | ${r.appName}`,script:[{innerHTML:`!function(){const e=document.createElement("link").relList;if(!(e&&e.supports&&e.supports("modulepreload"))){for(const e of document.querySelectorAll('link[rel="modulepreload"]'))r(e);new MutationObserver(e=>{for(const o of e)if("childList"===o.type)for(const e of o.addedNodes)"LINK"===e.tagName&&"modulepreload"===e.rel&&r(e)}).observe(document,{childList:!0,subtree:!0})}function r(e){if(e.ep)return;e.ep=!0;const r=function(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),"use-credentials"===e.crossOrigin?r.credentials="include":"anonymous"===e.crossOrigin?r.credentials="omit":r.credentials="same-origin",r}(e);fetch(e.href,r)}}();`}],style:[{innerHTML:'*,:after,:before{box-sizing:border-box;border-width:0;border-style:solid;border-color:var(--un-default-border-color,#e5e7eb)}:after,:before{--un-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}h1,h2{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}h1,h2,p{margin:0}*,:after,:before{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 transparent;--un-ring-shadow:0 0 transparent;--un-shadow-inset: ;--un-shadow:0 0 transparent;--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }'}]}),(k,w)=>{const o=f;return i(),u("div",p,[t("div",m,[t("h1",{class:"font-semibold leading-none mb-4 sm:text-[110px] tabular-nums text-[80px]",textContent:n(e.status)},null,8,h),t("h2",{class:"font-semibold mb-2 sm:text-3xl text-2xl",textContent:n(e.statusText)},null,8,x),t("p",{class:"mb-4 px-2 text-[#64748B] text-md",textContent:n(e.description)},null,8,b),t("div",g,[c(o,{to:"/",class:"font-medium hover:text-[#00DC82] text-sm underline underline-offset-3"},{default:l(()=>[d(n(e.backHome),1)]),_:1})])])])}}},v=s(y,[["__scopeId","data-v-d10dcac5"]]);export{v as default};