@nuxt/scripts 1.0.0 → 1.0.2

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 (33) 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/{D2o5loaz.js → 348WW8S2.js} +1 -1
  4. package/dist/devtools-client/_nuxt/{Cg_OIb5q.js → B6vzhpP9.js} +1 -1
  5. package/dist/devtools-client/_nuxt/{pN4-T8ZD.js → BBkg4uxE.js} +1 -1
  6. package/dist/devtools-client/_nuxt/{DnVCfhVR.js → Bo8cAJTo.js} +1 -1
  7. package/dist/devtools-client/_nuxt/{Br5kvbNb.js → DBnmHlYd.js} +1 -1
  8. package/dist/devtools-client/_nuxt/builds/latest.json +1 -1
  9. package/dist/devtools-client/_nuxt/builds/meta/831017e7-487a-40a4-83f3-dd537354844c.json +1 -0
  10. package/dist/devtools-client/_nuxt/{entry.BSxy0W1q.css → entry.BKkVrcJj.css} +1 -1
  11. package/dist/devtools-client/_nuxt/error-404.B3yGjJCG.css +1 -0
  12. package/dist/devtools-client/_nuxt/error-500.njrud7Pk.css +1 -0
  13. package/dist/devtools-client/_nuxt/{De7Wf2b9.js → fSf6EEYR.js} +23 -23
  14. package/dist/devtools-client/_nuxt/{C25MBdR1.js → r9yOu_bc.js} +1 -1
  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 +3 -2
  20. package/dist/module.d.ts +3 -2
  21. package/dist/module.json +1 -1
  22. package/dist/module.mjs +105 -50
  23. package/dist/registry.mjs +20 -11
  24. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +1 -2
  25. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue +3 -0
  26. package/dist/runtime/server/vercel-insights-sink.d.ts +2 -0
  27. package/dist/runtime/server/vercel-insights-sink.js +5 -0
  28. package/dist/runtime/types.d.ts +12 -0
  29. package/dist/types.d.mts +1 -1
  30. package/package.json +2 -2
  31. package/dist/devtools-client/_nuxt/builds/meta/9d868e70-bc5a-425c-8c84-8defe5186920.json +0 -1
  32. package/dist/devtools-client/_nuxt/error-404.d44aGwWI.css +0 -1
  33. package/dist/devtools-client/_nuxt/error-500.NthMfIEt.css +0 -1
package/dist/module.mjs CHANGED
@@ -704,14 +704,15 @@ function rewriteScriptUrlsAST(content, filename, rewrites, sdkPatches, options)
704
704
  }
705
705
  }
706
706
  }
707
- if (sdkPatches?.some((p) => p.type === "neutralize-domain-check") && node.type === "BinaryExpression" && node.operator === "<") {
707
+ const neutralizePatches = sdkPatches?.filter((p) => p.type === "neutralize-domain-check");
708
+ if (neutralizePatches?.length && node.type === "BinaryExpression" && node.operator === "<") {
708
709
  const left = node.left;
709
710
  const right = node.right;
710
711
  if (right?.type === "Literal" && right.value === 0 && left?.type === "CallExpression" && left.callee?.type === "MemberExpression") {
711
712
  const prop = left.callee.computed ? left.callee.property?.type === "Literal" && typeof left.callee.property.value === "string" ? left.callee.property.value : null : left.callee.property?.name;
712
713
  if (prop === "indexOf" && left.arguments?.length === 1) {
713
714
  const arg = left.arguments[0];
714
- if (arg?.type === "Literal" && typeof arg.value === "string" && rewrites.some((r) => arg.value.includes(r.from))) {
715
+ if (arg?.type === "Literal" && typeof arg.value === "string" && neutralizePatches.some((p) => arg.value.includes(p.domain))) {
715
716
  s.overwrite(right.start, right.end, "-1");
716
717
  }
717
718
  }
@@ -789,46 +790,42 @@ async function isCacheExpired(storage, filename, cacheMaxAge = SEVEN_DAYS_IN_MS)
789
790
  }
790
791
  return Date.now() - meta.timestamp > cacheMaxAge;
791
792
  }
793
+ function safeFilename(h) {
794
+ return `${h.startsWith("-") ? `_${h.slice(1)}` : h}.js`;
795
+ }
796
+ function buildAssetUrl(filename, assetsBaseURL = "/_scripts/assets") {
797
+ const nuxt = tryUseNuxt();
798
+ const cdnURL = nuxt?.options.runtimeConfig?.app?.cdnURL || nuxt?.options.app?.cdnURL || "";
799
+ const baseURL = cdnURL || nuxt?.options.app.baseURL || "";
800
+ return joinURL(joinURL(baseURL, assetsBaseURL), filename);
801
+ }
792
802
  function normalizeScriptData(src, assetsBaseURL = "/_scripts/assets") {
793
803
  if (hasProtocol(src, { acceptRelative: true })) {
794
804
  src = src.replace(PROTOCOL_RELATIVE_RE, "https://");
795
805
  const url = parseURL(src);
796
- const h = hash(url);
797
- const file = `${h.startsWith("-") ? `_${h.slice(1)}` : h}.js`;
798
- const nuxt = tryUseNuxt();
799
- const cdnURL = nuxt?.options.runtimeConfig?.app?.cdnURL || nuxt?.options.app?.cdnURL || "";
800
- const baseURL = cdnURL || nuxt?.options.app.baseURL || "";
801
- return { url: joinURL(joinURL(baseURL, assetsBaseURL), file), filename: file };
806
+ const file = safeFilename(hash(url));
807
+ return { url: buildAssetUrl(file, assetsBaseURL), filename: file };
802
808
  }
803
809
  return { url: src };
804
810
  }
805
811
  async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
806
- const { src, url, filename, forceDownload, integrity, proxyRewrites, sdkPatches, skipApiRewrites, neutralizeCanvas } = opts;
812
+ const { src, url, filename, forceDownload, integrity, proxyRewrites, sdkPatches, skipApiRewrites, neutralizeCanvas, assetsBaseURL } = opts;
807
813
  if (src === url || !filename) {
808
814
  return;
809
815
  }
810
816
  const storage = bundleStorage();
811
- const scriptContent = renderedScript.get(src);
812
- let res = scriptContent instanceof Error ? void 0 : scriptContent?.content;
813
- if (!res) {
814
- const proxyRewritesHash = proxyRewrites?.length ? `-${hash(proxyRewrites)}` : "";
815
- const cacheKey = proxyRewrites?.length ? `bundle-proxy:${filename.replace(".js", `${proxyRewritesHash}.js`)}` : `bundle:${filename}`;
816
- const shouldUseCache = !forceDownload && await storage.hasItem(cacheKey) && !await isCacheExpired(storage, filename, cacheMaxAge);
817
- if (shouldUseCache) {
818
- const cachedContent = await storage.getItemRaw(cacheKey);
819
- const meta = await storage.getItem(`bundle-meta:${filename}`);
820
- renderedScript.set(url, {
821
- content: cachedContent,
822
- size: cachedContent.length / 1024,
823
- encoding: "utf-8",
824
- src,
825
- filename,
826
- integrity: meta?.integrity
827
- });
828
- return;
829
- }
830
- let encoding;
831
- let size = 0;
817
+ let res;
818
+ let encoding;
819
+ let size = 0;
820
+ let fetched = false;
821
+ const hasRewrites = !!(proxyRewrites?.length || sdkPatches?.length);
822
+ const rewriteHash = hasRewrites ? `-${hash({ proxyRewrites, sdkPatches })}` : "";
823
+ const cacheKey = hasRewrites ? `bundle-patched:${filename.replace(".js", `${rewriteHash}.js`)}` : `bundle:${filename}`;
824
+ const shouldUseCache = !forceDownload && await storage.hasItem(cacheKey) && !await isCacheExpired(storage, filename, cacheMaxAge);
825
+ if (shouldUseCache) {
826
+ res = await storage.getItemRaw(cacheKey);
827
+ encoding = "utf-8";
828
+ } else {
832
829
  res = await $fetch.raw(src, { ...fetchOptions, responseType: "arrayBuffer" }).then(async (r) => {
833
830
  if (!r.ok) {
834
831
  throw new Error(`Failed to fetch ${src} (HTTP ${r.status})`);
@@ -838,32 +835,41 @@ async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
838
835
  size = contentLength ? Number(contentLength) / 1024 : 0;
839
836
  return Buffer.from(r._data || await r.arrayBuffer());
840
837
  });
838
+ fetched = true;
841
839
  await storage.setItemRaw(`bundle:${filename}`, res);
842
- if (proxyRewrites?.length && res) {
840
+ if (hasRewrites && res) {
843
841
  const content = res.toString("utf-8");
844
- const rewritten = rewriteScriptUrlsAST(content, filename || "script.js", proxyRewrites, sdkPatches, { skipApiRewrites, neutralizeCanvas });
842
+ const rewritten = rewriteScriptUrlsAST(content, filename, proxyRewrites ?? [], sdkPatches, { skipApiRewrites, neutralizeCanvas });
845
843
  res = Buffer.from(rewritten, "utf-8");
846
- logger.debug(`Rewrote ${proxyRewrites.length} URL patterns in ${filename}`);
844
+ logger.debug(`Rewrote ${proxyRewrites?.length ?? 0} URL patterns + ${sdkPatches?.length ?? 0} sdk patches in ${filename}`);
847
845
  }
848
- const integrityHash = integrity && res ? calculateIntegrity(res, integrity === true ? "sha384" : integrity) : void 0;
849
846
  await storage.setItemRaw(cacheKey, res);
850
847
  await storage.setItem(`bundle-meta:${filename}`, {
851
848
  timestamp: Date.now(),
852
849
  src,
853
- filename,
854
- integrity: integrityHash
855
- });
856
- size = size || res.length / 1024;
857
- logger.info(`Downloading script ${colors.gray(`${src} \u2192 ${filename} (${size.toFixed(2)} kB ${encoding})${integrityHash ? ` [${integrityHash.slice(0, 15)}...]` : ""}`)}`);
858
- renderedScript.set(url, {
859
- content: res,
860
- size,
861
- encoding,
862
- src,
863
- filename,
864
- integrity: integrityHash
850
+ filename
865
851
  });
866
852
  }
853
+ if (!res) {
854
+ return;
855
+ }
856
+ const contentHash = createHash("sha256").update(res).digest("hex").slice(0, 16);
857
+ const publicFilename = safeFilename(contentHash);
858
+ const publicUrl = buildAssetUrl(publicFilename, assetsBaseURL);
859
+ const integrityHash = integrity ? calculateIntegrity(res, integrity === true ? "sha384" : integrity) : void 0;
860
+ size = size || res.length / 1024;
861
+ if (fetched) {
862
+ logger.info(`Downloading script ${colors.gray(`${src} \u2192 ${publicFilename} (${size.toFixed(2)} kB ${encoding})${integrityHash ? ` [${integrityHash.slice(0, 15)}...]` : ""}`)}`);
863
+ }
864
+ renderedScript.set(publicUrl, {
865
+ content: res,
866
+ size,
867
+ encoding: encoding || void 0,
868
+ src,
869
+ filename: publicFilename,
870
+ integrity: integrityHash
871
+ });
872
+ return { url: publicUrl, filename: publicFilename };
867
873
  }
868
874
  function NuxtScriptBundleTransformer(options = {
869
875
  renderedScript: /* @__PURE__ */ new Map()
@@ -1058,13 +1064,17 @@ function NuxtScriptBundleTransformer(options = {
1058
1064
  from: domain,
1059
1065
  to: `${options.proxyPrefix}/${domain}`
1060
1066
  }));
1061
- const sdkPatches = proxyConfig?.sdkPatches;
1062
- const skipApiRewrites = !!(registryKey && options.partytownScripts?.has(registryKey));
1067
+ const bundleConfig = typeof script?.bundle === "object" ? script.bundle : void 0;
1068
+ const sdkPatches = proxyConfig?.sdkPatches ?? bundleConfig?.sdkPatches;
1069
+ const skipApiRewrites = !!(registryKey && options.partytownScripts?.has(registryKey)) || !proxyConfig;
1063
1070
  const neutralizeCanvas = proxyConfig?.privacy !== void 0 && typeof proxyConfig.privacy === "object" ? proxyConfig.privacy.hardware ?? true : true;
1064
1071
  deferredOps.push(async () => {
1065
1072
  let url = _url;
1066
1073
  try {
1067
- await downloadScript({ src, url, filename, forceDownload, proxyRewrites, sdkPatches, integrity: options.integrity, skipApiRewrites, neutralizeCanvas }, renderedScript, options.fetchOptions, options.cacheMaxAge);
1074
+ const result = await downloadScript({ src, url, filename, forceDownload, proxyRewrites, sdkPatches, integrity: options.integrity, skipApiRewrites, neutralizeCanvas, assetsBaseURL: options.assetsBaseURL }, renderedScript, options.fetchOptions, options.cacheMaxAge);
1075
+ if (result) {
1076
+ url = result.url;
1077
+ }
1068
1078
  } catch (e) {
1069
1079
  if (options.fallbackOnSrcOnBundleFail) {
1070
1080
  logger.warn(`[Nuxt Scripts: Bundle Transformer] Failed to bundle ${src}. Fallback to remote loading.`);
@@ -1442,6 +1452,37 @@ function applyAutoInject(registry2, runtimeConfig, proxyPrefix, registryKey, aut
1442
1452
  if (rtEntry && typeof rtEntry === "object" && rtEntry !== input)
1443
1453
  rtEntry[autoInject.configField] = value;
1444
1454
  }
1455
+ const ABSOLUTE_URL_RE = /^[a-z][a-z\d+.-]*:\/\//i;
1456
+ function resolveConfiguredProxyDomain(value) {
1457
+ if (typeof value !== "string")
1458
+ return;
1459
+ const trimmed = value.trim();
1460
+ if (!trimmed || !ABSOLUTE_URL_RE.test(trimmed) && !trimmed.startsWith("//"))
1461
+ return;
1462
+ try {
1463
+ return new URL(trimmed, "https://nuxt-scripts.local").hostname || void 0;
1464
+ } catch {
1465
+ }
1466
+ }
1467
+ function resolveConfiguredProxyDomains(config, proxyConfig) {
1468
+ if (!config || typeof config !== "object")
1469
+ return [];
1470
+ const domains = /* @__PURE__ */ new Set();
1471
+ const scriptSrc = resolveConfiguredProxyDomain(config.scriptInput?.src);
1472
+ if (scriptSrc)
1473
+ domains.add(scriptSrc);
1474
+ if (proxyConfig?.autoInject?.configField) {
1475
+ const endpointDomain = resolveConfiguredProxyDomain(config[proxyConfig.autoInject.configField]);
1476
+ if (endpointDomain)
1477
+ domains.add(endpointDomain);
1478
+ }
1479
+ for (const field of proxyConfig?.configDomainFields || []) {
1480
+ const domain = resolveConfiguredProxyDomain(config[field]);
1481
+ if (domain)
1482
+ domains.add(domain);
1483
+ }
1484
+ return [...domains].sort();
1485
+ }
1445
1486
  const module$1 = defineNuxtModule({
1446
1487
  meta: {
1447
1488
  name: "@nuxt/scripts",
@@ -1552,6 +1593,12 @@ const module$1 = defineNuxtModule({
1552
1593
  const proxyConfigs = {};
1553
1594
  const proxyHandlerPath = await resolvePath("./runtime/server/proxy-handler");
1554
1595
  addServerHandler({ route: `${proxyPrefix}/**`, handler: proxyHandlerPath });
1596
+ if (nuxt.options.dev && config.registry?.vercelAnalytics) {
1597
+ addServerHandler({
1598
+ route: "/_vercel/insights/**",
1599
+ handler: await resolvePath("./runtime/server/vercel-insights-sink")
1600
+ });
1601
+ }
1555
1602
  const composables = [
1556
1603
  "useScript",
1557
1604
  "useScriptEventPage",
@@ -1686,6 +1733,7 @@ const module$1 = defineNuxtModule({
1686
1733
  const unmatchedScripts = [];
1687
1734
  let totalDomains = 0;
1688
1735
  const devtoolsScripts = [];
1736
+ const publicScripts = nuxt.options.runtimeConfig.public?.scripts;
1689
1737
  for (const key of registryKeys) {
1690
1738
  const script = scriptByKey.get(key);
1691
1739
  if (!script) {
@@ -1704,10 +1752,17 @@ const module$1 = defineNuxtModule({
1704
1752
  }
1705
1753
  const entry = config.registry?.[key];
1706
1754
  const inputPrivacy = entry?.[0]?.privacy;
1755
+ const runtimeEntry = publicScripts?.[key] && typeof publicScripts[key] === "object" ? publicScripts[key] : void 0;
1707
1756
  for (const domain of proxyConfig.domains) {
1708
1757
  domainPrivacy[domain] = inputPrivacy ?? proxyConfig.privacy;
1709
1758
  totalDomains++;
1710
1759
  }
1760
+ for (const source of [entry?.[0], runtimeEntry]) {
1761
+ for (const domain of resolveConfiguredProxyDomains(source, proxyConfig)) {
1762
+ domainPrivacy[domain] = inputPrivacy ?? proxyConfig.privacy;
1763
+ totalDomains++;
1764
+ }
1765
+ }
1711
1766
  if (proxyConfig.autoInject && config.registry)
1712
1767
  applyAutoInject(config.registry, nuxt.options.runtimeConfig, proxyPrefix, key, proxyConfig.autoInject);
1713
1768
  if (nuxt.options.dev)
@@ -1869,4 +1924,4 @@ Options: configure platform rewrites, switch to server-rendered mode, or disable
1869
1924
  }
1870
1925
  });
1871
1926
 
1872
- export { applyAutoInject, module$1 as default, isProxyDisabled, resolveProxySecret };
1927
+ export { applyAutoInject, module$1 as default, isProxyDisabled, resolveConfiguredProxyDomains, resolveProxySecret };
package/dist/registry.mjs CHANGED
@@ -89,7 +89,12 @@ const registryMeta = [
89
89
  m("plausibleAnalytics", "Plausible Analytics", "analytics", "useScriptPlausibleAnalytics", { bundle: true, proxy: true, partytown: true }, PRIVACY_IP_ONLY),
90
90
  m("cloudflareWebAnalytics", "Cloudflare Web Analytics", "analytics", "useScriptCloudflareWebAnalytics", { bundle: true, proxy: true, partytown: true }, PRIVACY_IP_ONLY),
91
91
  m("posthog", "PostHog", "analytics", "useScriptPostHog", { proxy: true }, PRIVACY_IP_ONLY),
92
- m("fathomAnalytics", "Fathom Analytics", "analytics", "useScriptFathomAnalytics", { bundle: true, proxy: true, partytown: true }, PRIVACY_IP_ONLY),
92
+ // proxy intentionally off: proxied beacons reach Fathom from the server's IP
93
+ // (datacenter) and Fathom's bot detection ignores X-Forwarded-For, flagging
94
+ // every visitor as a bot. Bundle is supported via neutralize-domain-check —
95
+ // the script is served from the user's origin but beacons still go directly
96
+ // to cdn.usefathom.com so Fathom sees real client IPs. See nuxt/scripts#720.
97
+ m("fathomAnalytics", "Fathom Analytics", "analytics", "useScriptFathomAnalytics", { bundle: true }, null),
93
98
  m("matomoAnalytics", "Matomo Analytics", "analytics", "useScriptMatomoAnalytics", { proxy: true, partytown: true }, PRIVACY_IP_ONLY),
94
99
  m("rybbitAnalytics", "Rybbit Analytics", "analytics", "useScriptRybbitAnalytics", { bundle: true, proxy: true }, PRIVACY_IP_ONLY),
95
100
  m("databuddyAnalytics", "Databuddy Analytics", "analytics", "useScriptDatabuddyAnalytics", { bundle: true, proxy: true }, PRIVACY_IP_ONLY),
@@ -240,7 +245,8 @@ async function registry(resolve) {
240
245
  bundle: true,
241
246
  proxy: {
242
247
  domains: ["va.vercel-scripts.com", "vitals.vercel-insights.com"],
243
- privacy: PRIVACY_IP_ONLY
248
+ privacy: PRIVACY_IP_ONLY,
249
+ configDomainFields: ["endpoint"]
244
250
  }
245
251
  }),
246
252
  def("posthog", {
@@ -269,13 +275,13 @@ async function registry(resolve) {
269
275
  src: "https://cdn.usefathom.com/script.js",
270
276
  category: "analytics",
271
277
  envDefaults: { site: "" },
272
- bundle: true,
273
- proxy: {
274
- domains: ["cdn.usefathom.com", "usefathom.com"],
275
- privacy: PRIVACY_IP_ONLY,
276
- sdkPatches: [{ type: "neutralize-domain-check" }]
277
- },
278
- partytown: { forwards: ["fathom", "fathom.trackEvent", "fathom.trackPageview"] }
278
+ // Bundle without proxy: serve the script from the user's origin (faster
279
+ // load, ad-blocker resistant for domain-based blocking) but keep beacons
280
+ // pointed at cdn.usefathom.com via the neutralize-domain-check patch so
281
+ // Fathom sees real client IPs. Proxying is unsupported (see #720).
282
+ bundle: {
283
+ sdkPatches: [{ type: "neutralize-domain-check", domain: "cdn.usefathom.com" }]
284
+ }
279
285
  }),
280
286
  def("matomoAnalytics", {
281
287
  schema: MatomoAnalyticsOptions,
@@ -284,7 +290,8 @@ async function registry(resolve) {
284
290
  envDefaults: { matomoUrl: "" },
285
291
  proxy: {
286
292
  domains: ["cdn.matomo.cloud"],
287
- privacy: PRIVACY_IP_ONLY
293
+ privacy: PRIVACY_IP_ONLY,
294
+ configDomainFields: ["matomoUrl", "trackerUrl"]
288
295
  },
289
296
  partytown: { forwards: ["_paq.push"] }
290
297
  }),
@@ -319,7 +326,8 @@ async function registry(resolve) {
319
326
  proxy: {
320
327
  domains: ["cdn.databuddy.cc", "basket.databuddy.cc"],
321
328
  privacy: PRIVACY_IP_ONLY,
322
- autoInject: { field: "apiUrl", target: "basket.databuddy.cc" }
329
+ autoInject: { field: "apiUrl", target: "basket.databuddy.cc" },
330
+ configDomainFields: ["scriptUrl"]
323
331
  }
324
332
  }),
325
333
  def("segment", {
@@ -746,6 +754,7 @@ function buildProxyConfigsFromRegistry(scripts, scriptByKey) {
746
754
  domains: proxyDef.domains.map((d) => typeof d === "string" ? d : d.domain),
747
755
  privacy: proxyDef.privacy || { ip: false, userAgent: false, language: false, screen: false, timezone: false, hardware: false },
748
756
  autoInject: proxyDef.autoInject ? resolveAutoInject(proxyDef.autoInject) : void 0,
757
+ configDomainFields: proxyDef.configDomainFields,
749
758
  sdkPatches: proxyDef.sdkPatches
750
759
  };
751
760
  }
@@ -74,7 +74,7 @@ const { load, status, onLoaded } = useScriptGoogleMaps({
74
74
  v: props.version
75
75
  });
76
76
  const options = computed(() => {
77
- const mapId = props.mapOptions?.styles ? void 0 : currentMapId.value || "map";
77
+ const mapId = props.mapOptions?.styles ? void 0 : currentMapId.value || "DEMO_MAP_ID";
78
78
  return defu(
79
79
  { center: centerOverride.value, mapId },
80
80
  props.mapOptions,
@@ -280,7 +280,6 @@ const rootAttrs = computed(() => {
280
280
  onBeforeUnmount(() => {
281
281
  map.value?.unbindAll();
282
282
  map.value = void 0;
283
- mapEl.value?.firstChild?.remove();
284
283
  libraries.clear();
285
284
  queryToLatLngCache.clear();
286
285
  });
@@ -20,6 +20,9 @@ let gmpClickHandler;
20
20
  const advancedMarkerElement = useGoogleMapsResource({
21
21
  ready: () => !slots.content || !!markerContent.value,
22
22
  async create({ mapsApi, map }) {
23
+ if (import.meta.dev && !map.get("mapId")) {
24
+ console.warn("[nuxt-scripts] <ScriptGoogleMapsMarker> requires the parent <ScriptGoogleMaps> to have a `mapId` set, but none was found. This usually happens when `mapOptions.styles` (JSON styles) is set, since Google Maps treats `styles` and `mapId` as mutually exclusive. Use cloud-based map styling instead: https://scripts.nuxt.com/scripts/google-maps/guides/map-styling");
25
+ }
23
26
  await mapsApi.importLibrary("marker");
24
27
  const marker = new mapsApi.marker.AdvancedMarkerElement({
25
28
  ...props.options,
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, null>;
2
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { defineEventHandler, setResponseStatus } from "h3";
2
+ export default defineEventHandler((event) => {
3
+ setResponseStatus(event, 204);
4
+ return null;
5
+ });
@@ -337,6 +337,13 @@ export interface ScriptDomain {
337
337
  export interface BundleCapability {
338
338
  /** Custom URL resolution. If omitted, the script's `src` is used. */
339
339
  resolve?: (options?: any) => string | false;
340
+ /**
341
+ * AST-level SDK patches applied during bundling, independent of proxy.
342
+ * Use for scripts that need self-hosted detection neutralization but should
343
+ * still send beacons directly to the origin (e.g. Fathom, where proxying
344
+ * triggers bot detection but bundling is otherwise safe).
345
+ */
346
+ sdkPatches?: SdkPatch[];
340
347
  }
341
348
  /**
342
349
  * Proxy capability config. When present, collection requests can be
@@ -351,6 +358,8 @@ export interface ProxyCapability {
351
358
  privacy: import('../runtime/server/utils/privacy').ProxyPrivacyInput;
352
359
  /** Auto-inject proxy endpoint into the script's SDK config. */
353
360
  autoInject?: ProxyAutoInject;
361
+ /** Config fields that may contain custom external hosts or endpoints. */
362
+ configDomainFields?: string[];
354
363
  /** AST-level SDK patches applied during URL rewriting. */
355
364
  sdkPatches?: SdkPatch[];
356
365
  }
@@ -360,6 +369,7 @@ export interface ProxyCapability {
360
369
  */
361
370
  export type SdkPatch = {
362
371
  type: 'neutralize-domain-check';
372
+ domain: string;
363
373
  }
364
374
  /**
365
375
  * Replace `<expr>.split("<separator>")[0]` patterns used by SDKs that derive
@@ -486,6 +496,8 @@ export interface ProxyConfig {
486
496
  privacy: ProxyPrivacyInput;
487
497
  /** Auto-inject proxy endpoint config into the script's SDK options (resolved form) */
488
498
  autoInject?: ResolvedProxyAutoInject;
499
+ /** Config fields that may contain custom external hosts or endpoints. */
500
+ configDomainFields?: string[];
489
501
  /** AST-level SDK patches applied during URL rewriting. */
490
502
  sdkPatches?: SdkPatch[];
491
503
  }
package/dist/types.d.mts CHANGED
@@ -6,6 +6,6 @@ declare module '@nuxt/schema' {
6
6
 
7
7
  export { type FirstPartyPrivacy } from '../dist/runtime/types.js'
8
8
 
9
- export { type applyAutoInject, default, type isProxyDisabled, type resolveProxySecret } from './module.mjs'
9
+ export { type applyAutoInject, default, type isProxyDisabled, type resolveConfiguredProxyDomains, type resolveProxySecret } from './module.mjs'
10
10
 
11
11
  export { type ModuleHooks, type ModuleOptions, type ResolvedProxySecret } from './module.mjs'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nuxt/scripts",
3
3
  "type": "module",
4
- "version": "1.0.0",
4
+ "version": "1.0.2",
5
5
  "description": "Load third-party scripts with better performance, privacy and DX in Nuxt Apps.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -112,7 +112,7 @@
112
112
  "magic-string": "^0.30.21",
113
113
  "ofetch": "^1.5.1",
114
114
  "ohash": "^2.0.11",
115
- "oxc-parser": "^0.125.0",
115
+ "oxc-parser": "^0.127.0",
116
116
  "oxc-walker": "^0.7.0",
117
117
  "pathe": "^2.0.3",
118
118
  "pkg-types": "^2.3.0",
@@ -1 +0,0 @@
1
- {"id":"9d868e70-bc5a-425c-8c84-8defe5186920","timestamp":1776270303707,"prerendered":[]}
@@ -1 +0,0 @@
1
- .grid[data-v-3ecdecd2]{display:grid}.mb-2[data-v-3ecdecd2]{margin-bottom:.5rem}.mb-4[data-v-3ecdecd2]{margin-bottom:1rem}.max-w-520px[data-v-3ecdecd2]{max-width:520px}.min-h-screen[data-v-3ecdecd2]{min-height:100vh}.w-full[data-v-3ecdecd2]{width:100%}.flex[data-v-3ecdecd2]{display:flex}.place-content-center[data-v-3ecdecd2]{place-content:center}.items-center[data-v-3ecdecd2]{align-items:center}.justify-center[data-v-3ecdecd2]{justify-content:center}.overflow-hidden[data-v-3ecdecd2]{overflow:hidden}.bg-white[data-v-3ecdecd2]{--un-bg-opacity:1;background-color:rgb(255 255 255/var(--un-bg-opacity))}.px-2[data-v-3ecdecd2]{padding-left:.5rem;padding-right:.5rem}.text-center[data-v-3ecdecd2]{text-align:center}.text-\[80px\][data-v-3ecdecd2]{font-size:80px}.text-2xl[data-v-3ecdecd2]{font-size:1.5rem;line-height:2rem}.text-sm[data-v-3ecdecd2]{font-size:.875rem;line-height:1.25rem}.text-\[\#020420\][data-v-3ecdecd2]{--un-text-opacity:1;color:rgb(2 4 32/var(--un-text-opacity))}.text-\[\#64748B\][data-v-3ecdecd2]{--un-text-opacity:1;color:rgb(100 116 139/var(--un-text-opacity))}.hover\:text-\[\#00DC82\][data-v-3ecdecd2]:hover{--un-text-opacity:1;color:rgb(0 220 130/var(--un-text-opacity))}.font-medium[data-v-3ecdecd2]{font-weight:500}.font-semibold[data-v-3ecdecd2]{font-weight:600}.leading-none[data-v-3ecdecd2]{line-height:1}.tracking-wide[data-v-3ecdecd2]{letter-spacing:.025em}.font-sans[data-v-3ecdecd2]{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.tabular-nums[data-v-3ecdecd2]{--un-numeric-spacing:tabular-nums;font-variant-numeric:var(--un-ordinal) var(--un-slashed-zero) var(--un-numeric-figure) var(--un-numeric-spacing) var(--un-numeric-fraction)}.underline[data-v-3ecdecd2]{text-decoration-line:underline}.underline-offset-3[data-v-3ecdecd2]{text-underline-offset:3px}.antialiased[data-v-3ecdecd2]{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media(prefers-color-scheme:dark){.dark\:bg-\[\#020420\][data-v-3ecdecd2]{--un-bg-opacity:1;background-color:rgb(2 4 32/var(--un-bg-opacity))}.dark\:text-white[data-v-3ecdecd2]{--un-text-opacity:1;color:rgb(255 255 255/var(--un-text-opacity))}}@media(min-width:640px){.sm\:text-\[110px\][data-v-3ecdecd2]{font-size:110px}.sm\:text-3xl[data-v-3ecdecd2]{font-size:1.875rem;line-height:2.25rem}}
@@ -1 +0,0 @@
1
- .grid[data-v-10ed44ef]{display:grid}.mb-2[data-v-10ed44ef]{margin-bottom:.5rem}.mb-4[data-v-10ed44ef]{margin-bottom:1rem}.max-w-520px[data-v-10ed44ef]{max-width:520px}.min-h-screen[data-v-10ed44ef]{min-height:100vh}.place-content-center[data-v-10ed44ef]{place-content:center}.overflow-hidden[data-v-10ed44ef]{overflow:hidden}.bg-white[data-v-10ed44ef]{--un-bg-opacity:1;background-color:rgb(255 255 255/var(--un-bg-opacity))}.px-2[data-v-10ed44ef]{padding-left:.5rem;padding-right:.5rem}.text-center[data-v-10ed44ef]{text-align:center}.text-\[80px\][data-v-10ed44ef]{font-size:80px}.text-2xl[data-v-10ed44ef]{font-size:1.5rem;line-height:2rem}.text-\[\#020420\][data-v-10ed44ef]{--un-text-opacity:1;color:rgb(2 4 32/var(--un-text-opacity))}.text-\[\#64748B\][data-v-10ed44ef]{--un-text-opacity:1;color:rgb(100 116 139/var(--un-text-opacity))}.font-semibold[data-v-10ed44ef]{font-weight:600}.leading-none[data-v-10ed44ef]{line-height:1}.tracking-wide[data-v-10ed44ef]{letter-spacing:.025em}.font-sans[data-v-10ed44ef]{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.tabular-nums[data-v-10ed44ef]{--un-numeric-spacing:tabular-nums;font-variant-numeric:var(--un-ordinal) var(--un-slashed-zero) var(--un-numeric-figure) var(--un-numeric-spacing) var(--un-numeric-fraction)}.antialiased[data-v-10ed44ef]{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media(prefers-color-scheme:dark){.dark\:bg-\[\#020420\][data-v-10ed44ef]{--un-bg-opacity:1;background-color:rgb(2 4 32/var(--un-bg-opacity))}.dark\:text-white[data-v-10ed44ef]{--un-text-opacity:1;color:rgb(255 255 255/var(--un-text-opacity))}}@media(min-width:640px){.sm\:text-\[110px\][data-v-10ed44ef]{font-size:110px}.sm\:text-3xl[data-v-10ed44ef]{font-size:1.875rem;line-height:2.25rem}}