@nuxt/scripts 1.0.0-rc.1 → 1.0.0-rc.11

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 (164) hide show
  1. package/bin/cli.mjs +2 -0
  2. package/dist/cli.d.mts +2 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.mjs +50 -0
  5. package/dist/devtools-client/200.html +1 -1
  6. package/dist/devtools-client/404.html +1 -1
  7. package/dist/devtools-client/_nuxt/{ajngqPCs.js → BgPDxVUn.js} +1 -1
  8. package/dist/devtools-client/_nuxt/{DKL6PHO3.js → BmlapxLP.js} +1 -1
  9. package/dist/devtools-client/_nuxt/CM2vefXI.js +188 -0
  10. package/dist/devtools-client/_nuxt/{CfOsp0mU.js → DAF5Qk9P.js} +1 -1
  11. package/dist/devtools-client/_nuxt/{B3kN3DAy.js → Dx6HhVmj.js} +1 -1
  12. package/dist/devtools-client/_nuxt/{dlaR8P-P.js → S8LiR9M1.js} +1 -1
  13. package/dist/devtools-client/_nuxt/builds/latest.json +1 -1
  14. package/dist/devtools-client/_nuxt/builds/meta/d788053e-f511-4867-b557-1952fcbcae82.json +1 -0
  15. package/dist/devtools-client/_nuxt/{entry.BwpOBArY.css → entry.BKkVrcJj.css} +1 -1
  16. package/dist/devtools-client/_nuxt/error-404.d44aGwWI.css +1 -0
  17. package/dist/devtools-client/_nuxt/error-500.NthMfIEt.css +1 -0
  18. package/dist/devtools-client/_nuxt/index.DZD1lwyI.css +1 -0
  19. package/dist/devtools-client/_nuxt/vBkR1GJq.js +1 -0
  20. package/dist/devtools-client/docs/index.html +1 -1
  21. package/dist/devtools-client/first-party/index.html +1 -1
  22. package/dist/devtools-client/index.html +1 -1
  23. package/dist/devtools-client/registry/index.html +1 -1
  24. package/dist/module.d.mts +66 -2
  25. package/dist/module.d.ts +66 -2
  26. package/dist/module.json +1 -1
  27. package/dist/module.mjs +151 -30
  28. package/dist/registry.d.mts +1 -0
  29. package/dist/registry.d.ts +1 -0
  30. package/dist/registry.mjs +14 -14
  31. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.d.vue.ts +73 -97
  32. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +81 -58
  33. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue.d.ts +73 -97
  34. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.d.vue.ts +2 -3
  35. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue +1 -0
  36. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue.d.ts +2 -3
  37. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.d.vue.ts +2 -3
  38. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue +2 -1
  39. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue.d.ts +2 -3
  40. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.d.vue.ts +10 -43
  41. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue +3 -1
  42. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue.d.ts +10 -43
  43. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.d.vue.ts +50 -30
  44. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue +145 -104
  45. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue.d.ts +50 -30
  46. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue +7 -2
  47. package/dist/runtime/components/GoogleMaps/types.d.ts +42 -0
  48. package/dist/runtime/components/GoogleMaps/types.js +1 -0
  49. package/dist/runtime/components/GoogleMaps/useGoogleMapsResource.d.ts +50 -0
  50. package/dist/runtime/components/GoogleMaps/useGoogleMapsResource.js +76 -1
  51. package/dist/runtime/components/ScriptBlueskyEmbed.d.vue.ts +10 -12
  52. package/dist/runtime/components/ScriptBlueskyEmbed.vue +13 -10
  53. package/dist/runtime/components/ScriptBlueskyEmbed.vue.d.ts +10 -12
  54. package/dist/runtime/components/ScriptCarbonAds.d.vue.ts +4 -7
  55. package/dist/runtime/components/ScriptCarbonAds.vue +1 -0
  56. package/dist/runtime/components/ScriptCarbonAds.vue.d.ts +4 -7
  57. package/dist/runtime/components/ScriptCrisp.d.vue.ts +7 -11
  58. package/dist/runtime/components/ScriptCrisp.vue +1 -0
  59. package/dist/runtime/components/ScriptCrisp.vue.d.ts +7 -11
  60. package/dist/runtime/components/ScriptGoogleAdsense.d.vue.ts +4 -7
  61. package/dist/runtime/components/ScriptGoogleAdsense.vue +1 -0
  62. package/dist/runtime/components/ScriptGoogleAdsense.vue.d.ts +4 -7
  63. package/dist/runtime/components/ScriptInstagramEmbed.d.vue.ts +11 -13
  64. package/dist/runtime/components/ScriptInstagramEmbed.vue +4 -1
  65. package/dist/runtime/components/ScriptInstagramEmbed.vue.d.ts +11 -13
  66. package/dist/runtime/components/ScriptIntercom.d.vue.ts +7 -11
  67. package/dist/runtime/components/ScriptIntercom.vue +1 -0
  68. package/dist/runtime/components/ScriptIntercom.vue.d.ts +7 -11
  69. package/dist/runtime/components/ScriptLemonSqueezy.d.vue.ts +2 -3
  70. package/dist/runtime/components/ScriptLemonSqueezy.vue +1 -0
  71. package/dist/runtime/components/ScriptLemonSqueezy.vue.d.ts +2 -3
  72. package/dist/runtime/components/ScriptPayPalButtons.d.vue.ts +8 -13
  73. package/dist/runtime/components/ScriptPayPalButtons.vue +1 -0
  74. package/dist/runtime/components/ScriptPayPalButtons.vue.d.ts +8 -13
  75. package/dist/runtime/components/ScriptPayPalMessages.d.vue.ts +8 -13
  76. package/dist/runtime/components/ScriptPayPalMessages.vue +1 -0
  77. package/dist/runtime/components/ScriptPayPalMessages.vue.d.ts +8 -13
  78. package/dist/runtime/components/ScriptStripePricingTable.d.vue.ts +5 -9
  79. package/dist/runtime/components/ScriptStripePricingTable.vue +1 -0
  80. package/dist/runtime/components/ScriptStripePricingTable.vue.d.ts +5 -9
  81. package/dist/runtime/components/ScriptVimeoPlayer.d.vue.ts +8 -11
  82. package/dist/runtime/components/ScriptVimeoPlayer.vue +1 -0
  83. package/dist/runtime/components/ScriptVimeoPlayer.vue.d.ts +8 -11
  84. package/dist/runtime/components/ScriptXEmbed.d.vue.ts +10 -12
  85. package/dist/runtime/components/ScriptXEmbed.vue +12 -9
  86. package/dist/runtime/components/ScriptXEmbed.vue.d.ts +10 -12
  87. package/dist/runtime/components/ScriptYouTubePlayer.d.vue.ts +8 -13
  88. package/dist/runtime/components/ScriptYouTubePlayer.vue +1 -0
  89. package/dist/runtime/components/ScriptYouTubePlayer.vue.d.ts +8 -13
  90. package/dist/runtime/composables/useScript.js +17 -6
  91. package/dist/runtime/composables/useScriptProxyToken.d.ts +12 -0
  92. package/dist/runtime/composables/useScriptProxyToken.js +4 -0
  93. package/dist/runtime/composables/useScriptProxyUrl.d.ts +12 -0
  94. package/dist/runtime/composables/useScriptProxyUrl.js +27 -0
  95. package/dist/runtime/plugins/proxy-token.server.d.ts +10 -0
  96. package/dist/runtime/plugins/proxy-token.server.js +17 -0
  97. package/dist/runtime/registry/bing-uet.d.ts +189 -11
  98. package/dist/runtime/registry/bing-uet.js +16 -2
  99. package/dist/runtime/registry/bluesky-embed.d.ts +0 -4
  100. package/dist/runtime/registry/bluesky-embed.js +0 -4
  101. package/dist/runtime/registry/clarity.d.ts +6 -2
  102. package/dist/runtime/registry/clarity.js +12 -1
  103. package/dist/runtime/registry/google-analytics.d.ts +6 -2
  104. package/dist/runtime/registry/google-analytics.js +12 -1
  105. package/dist/runtime/registry/google-tag-manager.d.ts +6 -2
  106. package/dist/runtime/registry/google-tag-manager.js +10 -1
  107. package/dist/runtime/registry/gravatar.js +10 -13
  108. package/dist/runtime/registry/matomo-analytics.d.ts +9 -3
  109. package/dist/runtime/registry/matomo-analytics.js +28 -1
  110. package/dist/runtime/registry/meta-pixel.d.ts +8 -2
  111. package/dist/runtime/registry/meta-pixel.js +10 -1
  112. package/dist/runtime/registry/mixpanel-analytics.d.ts +12 -2
  113. package/dist/runtime/registry/mixpanel-analytics.js +16 -4
  114. package/dist/runtime/registry/posthog.d.ts +8 -2
  115. package/dist/runtime/registry/posthog.js +15 -4
  116. package/dist/runtime/registry/schemas.d.ts +65 -0
  117. package/dist/runtime/registry/schemas.js +75 -8
  118. package/dist/runtime/registry/tiktok-pixel.d.ts +16 -2
  119. package/dist/runtime/registry/tiktok-pixel.js +22 -1
  120. package/dist/runtime/registry/x-embed.d.ts +0 -4
  121. package/dist/runtime/registry/x-embed.js +0 -4
  122. package/dist/runtime/server/bluesky-embed-image.d.ts +1 -1
  123. package/dist/runtime/server/bluesky-embed.d.ts +1 -15
  124. package/dist/runtime/server/bluesky-embed.js +25 -6
  125. package/dist/runtime/server/google-maps-geocode-proxy.js +12 -8
  126. package/dist/runtime/server/google-static-maps-proxy.d.ts +1 -1
  127. package/dist/runtime/server/google-static-maps-proxy.js +17 -11
  128. package/dist/runtime/server/gravatar-proxy.d.ts +1 -1
  129. package/dist/runtime/server/gravatar-proxy.js +10 -10
  130. package/dist/runtime/server/instagram-embed-asset.d.ts +1 -1
  131. package/dist/runtime/server/instagram-embed-image.d.ts +1 -1
  132. package/dist/runtime/server/instagram-embed.d.ts +1 -16
  133. package/dist/runtime/server/instagram-embed.js +26 -125
  134. package/dist/runtime/server/proxy-handler.js +1 -2
  135. package/dist/runtime/server/utils/cached-upstream.d.ts +55 -0
  136. package/dist/runtime/server/utils/cached-upstream.js +65 -0
  137. package/dist/runtime/server/utils/embed-rewriters.d.ts +19 -0
  138. package/dist/runtime/server/utils/embed-rewriters.js +41 -0
  139. package/dist/runtime/server/utils/image-proxy.d.ts +3 -1
  140. package/dist/runtime/server/utils/image-proxy.js +11 -8
  141. package/dist/runtime/server/utils/instagram-embed.d.ts +16 -0
  142. package/dist/runtime/server/utils/instagram-embed.js +153 -0
  143. package/dist/runtime/server/utils/proxy-url.d.ts +9 -0
  144. package/dist/runtime/server/utils/proxy-url.js +21 -0
  145. package/dist/runtime/server/utils/sign-constants.d.ts +16 -0
  146. package/dist/runtime/server/utils/sign-constants.js +5 -0
  147. package/dist/runtime/server/utils/sign.d.ts +101 -0
  148. package/dist/runtime/server/utils/sign.js +91 -0
  149. package/dist/runtime/server/utils/withSigning.d.ts +23 -0
  150. package/dist/runtime/server/utils/withSigning.js +19 -0
  151. package/dist/runtime/server/x-embed-image.d.ts +1 -1
  152. package/dist/runtime/server/x-embed.js +23 -4
  153. package/dist/runtime/types.d.ts +41 -6
  154. package/dist/runtime/types.js +1 -0
  155. package/dist/stats.mjs +298 -338
  156. package/dist/types-source.mjs +537 -164
  157. package/dist/types.d.mts +2 -2
  158. package/package.json +10 -6
  159. package/dist/devtools-client/_nuxt/C8jhSQ8l.js +0 -1
  160. package/dist/devtools-client/_nuxt/CJD6wrkT.js +0 -188
  161. package/dist/devtools-client/_nuxt/builds/meta/b800a0be-5cab-4ea6-89e3-dd3a85690a73.json +0 -1
  162. package/dist/devtools-client/_nuxt/error-404.CvOVjXeC.css +0 -1
  163. package/dist/devtools-client/_nuxt/error-500.BIm53nmx.css +0 -1
  164. package/dist/devtools-client/_nuxt/index.CA-OpSj0.css +0 -1
package/dist/module.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
- import { useNuxt, addDevServerHandler, extendRouteRules, tryUseNuxt, createResolver, extendViteConfig, logger as logger$1, useLogger, addTypeTemplate, defineNuxtModule, addPluginTemplate, addServerHandler, addImports, addComponentsDir, addTemplate, hasNuxtModule, addBuildPlugin } from '@nuxt/kit';
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';
3
4
  import { defu } from 'defu';
4
5
  import { join, resolve } from 'pathe';
5
6
  import { resolvePackageJSON, readPackageJSON } from 'pkg-types';
@@ -12,7 +13,6 @@ import { isCI, provider } from 'std-env';
12
13
  import { parseAndWalk, ScopeTracker, walk, ScopeTrackerFunction, ScopeTrackerIdentifier, ScopeTrackerFunctionParam, ScopeTrackerVariable } from 'oxc-walker';
13
14
  import { createUnplugin } from 'unplugin';
14
15
  import { pathToFileURL } from 'node:url';
15
- import { createHash } from 'node:crypto';
16
16
  import fsp from 'node:fs/promises';
17
17
  import { colors } from 'consola/utils';
18
18
  import MagicString from 'magic-string';
@@ -288,7 +288,7 @@ function migrateDeprecatedRegistryKeys(registry, warn) {
288
288
  }
289
289
  }
290
290
  }
291
- function normalizeRegistryConfig(registry, warn) {
291
+ function normalizeRegistryConfig(registry, warn, componentOnlyKeys) {
292
292
  for (const key of Object.keys(registry)) {
293
293
  const entry = registry[key];
294
294
  if (!entry) {
@@ -296,6 +296,10 @@ function normalizeRegistryConfig(registry, warn) {
296
296
  continue;
297
297
  }
298
298
  if (entry === true) {
299
+ if (componentOnlyKeys?.has(key)) {
300
+ registry[key] = [{}];
301
+ continue;
302
+ }
299
303
  warn?.(`[nuxt-scripts] registry.${key}: \`true\` shorthand is deprecated. Use \`{ trigger: 'onNuxtReady' }\` instead.`);
300
304
  registry[key] = [{}, { trigger: "onNuxtReady" }];
301
305
  continue;
@@ -416,7 +420,8 @@ function NuxtScriptsCheckScripts() {
416
420
  });
417
421
  }
418
422
 
419
- function generateInterceptPluginContents(proxyPrefix) {
423
+ function generateInterceptPluginContents(proxyPrefix, options) {
424
+ const testMode = options?.testMode ?? false;
420
425
  return `export default defineNuxtPlugin({
421
426
  name: 'nuxt-scripts:intercept',
422
427
  enforce: 'pre',
@@ -461,8 +466,14 @@ function generateInterceptPluginContents(proxyPrefix) {
461
466
  return img;
462
467
  }
463
468
 
464
- globalThis.__nuxtScripts = {
465
- sendBeacon: (url, data) => origBeacon(proxyUrl(url), data),
469
+ globalThis.__nuxtScripts = {${testMode ? `
470
+ // Test mode: replace sendBeacon with fetch for immediate, observable requests
471
+ sendBeacon: (url, data) => {
472
+ const proxied = proxyUrl(url);
473
+ origFetch(proxied, { method: 'POST', body: data, keepalive: true }).catch(() => {});
474
+ return true;
475
+ },` : `
476
+ sendBeacon: (url, data) => origBeacon(proxyUrl(url), data),`}
466
477
  fetch: (url, opts) => {
467
478
  if (typeof url === 'string') return origFetch(proxyUrl(url), opts);
468
479
  if (url instanceof Request) return origFetch(new Request(proxyUrl(url.url), url), opts);
@@ -908,6 +919,7 @@ function NuxtScriptBundleTransformer(options = {
908
919
  const node = _node;
909
920
  let scriptSrcNode;
910
921
  let src;
922
+ let registryConfig = {};
911
923
  let registryKey;
912
924
  if (fnName !== "useScript") {
913
925
  const baseName = fnName.replace(USE_SCRIPT_RE, "");
@@ -930,7 +942,7 @@ function NuxtScriptBundleTransformer(options = {
930
942
  const bundleResolve = getBundleResolve(registryNode);
931
943
  if (!bundleResolve && !registryNode.src)
932
944
  return;
933
- const registryConfig = options.registryConfig?.[registryKey || ""] || {};
945
+ registryConfig = options.registryConfig?.[registryKey || ""] || {};
934
946
  const fnArg0 = {};
935
947
  if (node.arguments[0]?.type === "ObjectExpression") {
936
948
  const optionsNode = node.arguments[0];
@@ -978,12 +990,14 @@ function NuxtScriptBundleTransformer(options = {
978
990
  const registryScript = fnName !== "useScript" ? options.scripts?.find((s2) => s2.import.name === fnName) : void 0;
979
991
  let canBundle = !!registryScript?.bundle;
980
992
  let forceDownload = false;
993
+ let explicitBundleInCall = false;
981
994
  if (node.arguments[1]?.type === "ObjectExpression") {
982
995
  const scriptOptionsArg = node.arguments[1];
983
996
  const bundleProperty = scriptOptionsArg.properties.find(
984
997
  (p) => (p.key?.name === "bundle" || p.key?.value === "bundle") && p.type === "Property"
985
998
  );
986
999
  if (bundleProperty && bundleProperty.value.type === "Literal") {
1000
+ explicitBundleInCall = true;
987
1001
  const bundleValue = bundleProperty.value.value;
988
1002
  if (bundleValue !== true && bundleValue !== "force" && String(bundleValue) !== "true") {
989
1003
  canBundle = false;
@@ -1008,10 +1022,16 @@ function NuxtScriptBundleTransformer(options = {
1008
1022
  return prop.type === "Property" && prop.key?.name === "bundle" && prop.value.type === "Literal";
1009
1023
  });
1010
1024
  if (bundleOption) {
1025
+ explicitBundleInCall = true;
1011
1026
  const bundleValue = bundleOption.value.value;
1012
1027
  canBundle = bundleValue === true || bundleValue === "force" || String(bundleValue) === "true";
1013
1028
  forceDownload = bundleValue === "force";
1014
1029
  }
1030
+ if (!explicitBundleInCall && registryConfig?.scriptOptions?.bundle !== void 0) {
1031
+ const bundleValue = registryConfig.scriptOptions.bundle;
1032
+ canBundle = bundleValue === true || bundleValue === "force" || String(bundleValue) === "true";
1033
+ forceDownload = bundleValue === "force";
1034
+ }
1015
1035
  const rpiOption = scriptOptions?.value.properties?.find((prop) => {
1016
1036
  return prop.type === "Property" && prop.key?.name === "proxy" && prop.value.type === "Literal";
1017
1037
  });
@@ -1214,14 +1234,15 @@ function templatePlugin(config, registry) {
1214
1234
  for (const [k, c] of Object.entries(config.registry || {})) {
1215
1235
  if (c === false)
1216
1236
  continue;
1217
- const [, scriptOptions] = c;
1237
+ const entry = c;
1238
+ const [, scriptOptions] = entry;
1218
1239
  if (!scriptOptions?.trigger)
1219
1240
  continue;
1220
1241
  const importDefinition = registry.find((i) => i.import.name.toLowerCase() === `usescript${k.toLowerCase()}`);
1221
1242
  if (importDefinition) {
1222
1243
  resolvedRegistryKeys.push(k);
1223
1244
  imports.unshift(`import { ${importDefinition.import.name} } from '${importDefinition.import.from}'`);
1224
- const [input] = c;
1245
+ const [input] = entry;
1225
1246
  const opts = { ...scriptOptions };
1226
1247
  const triggerResolved = resolveTriggerForTemplate(opts.trigger);
1227
1248
  if (triggerResolved) {
@@ -1356,6 +1377,42 @@ function fixSelfClosingScriptComponents(nuxt) {
1356
1377
  }
1357
1378
  const UPPER_RE = /([A-Z])/g;
1358
1379
  const toScreamingSnake = (s) => s.replace(UPPER_RE, "_$1").toUpperCase();
1380
+ const PROXY_SECRET_ENV_KEY = "NUXT_SCRIPTS_PROXY_SECRET";
1381
+ const PROXY_SECRET_ENV_LINE_RE = /^NUXT_SCRIPTS_PROXY_SECRET=/m;
1382
+ const PROXY_SECRET_ENV_VALUE_RE = /^NUXT_SCRIPTS_PROXY_SECRET=(.+)$/m;
1383
+ function resolveProxySecret(rootDir, isDev, configSecret, autoGenerate = true) {
1384
+ if (configSecret)
1385
+ return { secret: configSecret, ephemeral: false, source: "config" };
1386
+ const envSecret = process.env[PROXY_SECRET_ENV_KEY];
1387
+ if (envSecret)
1388
+ return { secret: envSecret, ephemeral: false, source: "env" };
1389
+ if (!isDev || !autoGenerate)
1390
+ return void 0;
1391
+ const secret = randomBytes(32).toString("hex");
1392
+ const envPath = resolve(rootDir, ".env");
1393
+ const line = `${PROXY_SECRET_ENV_KEY}=${secret}
1394
+ `;
1395
+ try {
1396
+ if (existsSync(envPath)) {
1397
+ const contents = readFileSync(envPath, "utf-8");
1398
+ if (PROXY_SECRET_ENV_LINE_RE.test(contents)) {
1399
+ const match = contents.match(PROXY_SECRET_ENV_VALUE_RE);
1400
+ if (match?.[1])
1401
+ return { secret: match[1].trim(), ephemeral: false, source: "dotenv-generated" };
1402
+ }
1403
+ appendFileSync(envPath, contents.endsWith("\n") ? line : `
1404
+ ${line}`);
1405
+ } else {
1406
+ writeFileSync(envPath, `# Generated by @nuxt/scripts
1407
+ ${line}`);
1408
+ }
1409
+ process.env[PROXY_SECRET_ENV_KEY] = secret;
1410
+ return { secret, ephemeral: false, source: "dotenv-generated" };
1411
+ } catch {
1412
+ process.env[PROXY_SECRET_ENV_KEY] = secret;
1413
+ return { secret, ephemeral: true, source: "memory-generated" };
1414
+ }
1415
+ }
1359
1416
  function isProxyDisabled(registryKey, registry2, runtimeConfig) {
1360
1417
  const entry = registry2?.[registryKey];
1361
1418
  if (!entry)
@@ -1443,25 +1500,32 @@ const module$1 = defineNuxtModule({
1443
1500
  }
1444
1501
  const scripts = await registry(resolvePath);
1445
1502
  if (config.registry) {
1503
+ const componentOnlyKeys = new Set(scripts.filter((s) => !s.import).map((s) => s.registryKey));
1446
1504
  migrateDeprecatedRegistryKeys(config.registry, (msg) => logger.warn(msg));
1447
- normalizeRegistryConfig(config.registry, (msg) => logger.warn(msg));
1505
+ normalizeRegistryConfig(config.registry, (msg) => logger.warn(msg), componentOnlyKeys);
1448
1506
  nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
1449
1507
  const registryWithDefaults = {};
1450
1508
  for (const [key, entry] of Object.entries(config.registry)) {
1451
1509
  if (entry === false)
1452
1510
  continue;
1453
1511
  const input = entry[0];
1512
+ const scriptOptions = entry[1];
1454
1513
  const envDefaults = scripts.find((s) => s.registryKey === key)?.envDefaults;
1514
+ const base = {};
1455
1515
  if (!envDefaults || !Object.keys(envDefaults).length) {
1456
- registryWithDefaults[key] = input;
1457
- continue;
1516
+ Object.assign(base, input);
1517
+ } else {
1518
+ const envResolved = {};
1519
+ for (const [field, defaultValue] of Object.entries(envDefaults)) {
1520
+ const envKey = `NUXT_PUBLIC_SCRIPTS_${toScreamingSnake(key)}_${toScreamingSnake(field)}`;
1521
+ envResolved[field] = process.env[envKey] || defaultValue;
1522
+ }
1523
+ Object.assign(base, defu(input, envResolved));
1458
1524
  }
1459
- const envResolved = {};
1460
- for (const [field, defaultValue] of Object.entries(envDefaults)) {
1461
- const envKey = `NUXT_PUBLIC_SCRIPTS_${toScreamingSnake(key)}_${toScreamingSnake(field)}`;
1462
- envResolved[field] = process.env[envKey] || defaultValue;
1525
+ if (scriptOptions && Object.keys(scriptOptions).length > 0) {
1526
+ base.scriptOptions = scriptOptions;
1463
1527
  }
1464
- registryWithDefaults[key] = defu(input, envResolved);
1528
+ registryWithDefaults[key] = base;
1465
1529
  }
1466
1530
  nuxt.options.runtimeConfig.public.scripts = defu(
1467
1531
  nuxt.options.runtimeConfig.public.scripts || {},
@@ -1491,6 +1555,8 @@ const module$1 = defineNuxtModule({
1491
1555
  const composables = [
1492
1556
  "useScript",
1493
1557
  "useScriptEventPage",
1558
+ "useScriptProxyToken",
1559
+ "useScriptProxyUrl",
1494
1560
  "useScriptTriggerConsent",
1495
1561
  "useScriptTriggerElement",
1496
1562
  "useScriptTriggerIdleTimeout",
@@ -1533,10 +1599,23 @@ const module$1 = defineNuxtModule({
1533
1599
  const script = scripts.find((s) => s.registryKey === key);
1534
1600
  if (!script?.schema)
1535
1601
  continue;
1536
- const requiredFields = extractRequiredFields(script.schema);
1537
- const missing = requiredFields.filter((f) => !input[f]);
1538
- if (missing.length) {
1539
- logger.warn(`[nuxt-scripts] registry.${key}: missing required field${missing.length > 1 ? "s" : ""} ${missing.map((f) => `'${f}'`).join(", ")}. The script infrastructure is registered but will not function without ${missing.length > 1 ? "them" : "it"}.`);
1602
+ const isComponentOnly = !script.import;
1603
+ if (isComponentOnly) {
1604
+ if (scriptOptions && "trigger" in scriptOptions && scriptOptions.trigger !== false) {
1605
+ const pascal = key.charAt(0).toUpperCase() + key.slice(1);
1606
+ logger.warn(
1607
+ `[nuxt-scripts] registry.${key}: \`trigger\` has no effect on component-only scripts. Render <Script${pascal}> in your template to load the embed.`
1608
+ );
1609
+ }
1610
+ continue;
1611
+ }
1612
+ const willAutoLoad = scriptOptions && "trigger" in scriptOptions && scriptOptions.trigger !== false;
1613
+ if (willAutoLoad) {
1614
+ const requiredFields = extractRequiredFields(script.schema);
1615
+ const missing = requiredFields.filter((f) => !input[f]);
1616
+ if (missing.length) {
1617
+ logger.warn(`[nuxt-scripts] registry.${key}: missing required field${missing.length > 1 ? "s" : ""} ${missing.map((f) => `'${f}'`).join(", ")}. The script infrastructure is registered but will not function without ${missing.length > 1 ? "them" : "it"}.`);
1618
+ }
1540
1619
  }
1541
1620
  const envDefaultKeys = new Set(Object.keys(script.envDefaults || {}));
1542
1621
  const userProvidedFields = Object.keys(input).filter((f) => !envDefaultKeys.has(f));
@@ -1649,7 +1728,7 @@ They will load directly from third-party servers.`
1649
1728
  addPluginTemplate({
1650
1729
  filename: "nuxt-scripts-intercept.client.mjs",
1651
1730
  getContents() {
1652
- return generateInterceptPluginContents(proxyPrefix);
1731
+ return generateInterceptPluginContents(proxyPrefix, { testMode: !!nuxt.options.test });
1653
1732
  }
1654
1733
  });
1655
1734
  nuxt.options.runtimeConfig["nuxt-scripts-proxy"] = {
@@ -1661,12 +1740,12 @@ They will load directly from third-party servers.`
1661
1740
  if (totalDomains > 0 && nuxt.options.dev) {
1662
1741
  logger.success(`Proxy mode enabled for ${registryKeys.length} script(s), ${totalDomains} domain(s) proxied (privacy: ${privacyLabel})`);
1663
1742
  }
1664
- const staticPresets = ["static", "github-pages", "cloudflare-pages-static", "netlify-static", "azure-static", "firebase-static"];
1665
- const preset = process.env.NITRO_PRESET || "";
1666
- if (staticPresets.includes(preset)) {
1743
+ const proxyStaticPresets = ["static", "github-pages", "cloudflare-pages-static", "netlify-static", "azure-static", "firebase-static"];
1744
+ const proxyPreset = process.env.NITRO_PRESET || "";
1745
+ if (proxyStaticPresets.includes(proxyPreset)) {
1667
1746
  logger.warn(
1668
- `Proxy collection endpoints require a server runtime (detected: ${preset || "static"}).
1669
- Scripts will be bundled, but collection requests will not be proxied.
1747
+ `Proxy collection endpoints require a server runtime (detected: ${proxyPreset || "static"}).
1748
+ Scripts will be bundled, but collection requests will not be proxied and URL signing will be unavailable.
1670
1749
  Options: configure platform rewrites, switch to server-rendered mode, or disable with proxy: false.`
1671
1750
  );
1672
1751
  }
@@ -1713,6 +1792,7 @@ Options: configure platform rewrites, switch to server-rendered mode, or disable
1713
1792
  });
1714
1793
  const scriptsPrefix = config.prefix || "/_scripts";
1715
1794
  const enabledEndpoints = {};
1795
+ let anyHandlerRequiresSigning = false;
1716
1796
  for (const script of scripts) {
1717
1797
  if (!script.serverHandlers?.length || !script.registryKey)
1718
1798
  continue;
@@ -1721,11 +1801,14 @@ Options: configure platform rewrites, switch to server-rendered mode, or disable
1721
1801
  continue;
1722
1802
  enabledEndpoints[script.registryKey] = true;
1723
1803
  for (const handler of script.serverHandlers) {
1804
+ const resolvedRoute = handler.route.replace("/_scripts", scriptsPrefix);
1724
1805
  addServerHandler({
1725
- route: handler.route.replace("/_scripts", scriptsPrefix),
1806
+ route: resolvedRoute,
1726
1807
  handler: handler.handler,
1727
1808
  middleware: handler.middleware
1728
1809
  });
1810
+ if (handler.requiresSigning)
1811
+ anyHandlerRequiresSigning = true;
1729
1812
  }
1730
1813
  if (script.registryKey === "gravatar") {
1731
1814
  const gravatarConfig = config.registry?.gravatar?.[0] || {};
@@ -1745,7 +1828,45 @@ Options: configure platform rewrites, switch to server-rendered mode, or disable
1745
1828
  { endpoints: enabledEndpoints },
1746
1829
  nuxt.options.runtimeConfig.public["nuxt-scripts"]
1747
1830
  );
1831
+ const staticPresets = ["static", "github-pages", "cloudflare-pages-static", "netlify-static", "azure-static", "firebase-static"];
1832
+ const nitroPreset = process.env.NITRO_PRESET || "";
1833
+ const isStaticTarget = staticPresets.includes(nitroPreset);
1834
+ const isSpa = nuxt.options.ssr === false;
1835
+ if (anyHandlerRequiresSigning && (isSpa || isStaticTarget)) {
1836
+ logger.warn(
1837
+ `[security] URL signing requires a server runtime${isStaticTarget ? ` (detected preset: ${nitroPreset})` : " (ssr: false)"}.
1838
+ Proxy endpoints will work without signature verification.
1839
+ To enable signing, deploy with a server-rendered target or configure platform-level rewrites.`
1840
+ );
1841
+ } else if (anyHandlerRequiresSigning) {
1842
+ const proxySecretResolved = resolveProxySecret(
1843
+ nuxt.options.rootDir,
1844
+ !!nuxt.options.dev,
1845
+ config.security?.secret,
1846
+ config.security?.autoGenerateSecret !== false
1847
+ );
1848
+ if (proxySecretResolved?.source === "dotenv-generated")
1849
+ logger.info(`[security] Generated ${PROXY_SECRET_ENV_KEY} in .env for signed proxy URLs.`);
1850
+ else if (proxySecretResolved?.source === "memory-generated")
1851
+ logger.warn(`[security] Generated an in-memory ${PROXY_SECRET_ENV_KEY} (could not write .env). Signed URLs will break across restarts.`);
1852
+ if (proxySecretResolved?.secret) {
1853
+ const scriptsRuntime = nuxt.options.runtimeConfig["nuxt-scripts"];
1854
+ scriptsRuntime.proxySecret = proxySecretResolved.secret;
1855
+ if (config.security?.pageTokenMaxAge !== void 0)
1856
+ scriptsRuntime.pageTokenMaxAge = config.security.pageTokenMaxAge;
1857
+ addPlugin({
1858
+ src: await resolvePath("./runtime/plugins/proxy-token.server"),
1859
+ mode: "server"
1860
+ });
1861
+ } else if (!nuxt.options.dev) {
1862
+ logger.warn(
1863
+ `[security] ${PROXY_SECRET_ENV_KEY} is not set. Proxy endpoints will pass requests through without signature verification.
1864
+ Generate one with: npx @nuxt/scripts generate-secret
1865
+ Then set the env var: ${PROXY_SECRET_ENV_KEY}=<secret>`
1866
+ );
1867
+ }
1868
+ }
1748
1869
  }
1749
1870
  });
1750
1871
 
1751
- export { applyAutoInject, module$1 as default, isProxyDisabled };
1872
+ export { applyAutoInject, module$1 as default, isProxyDisabled, resolveProxySecret };
@@ -1,5 +1,6 @@
1
1
  import { ProxyPrivacyInput } from '../dist/runtime/server/utils/privacy.js';
2
2
  import { ScriptCapabilities, RegistryScript, RegistryScriptKey, ProxyConfig, ProxyCapability, ProxyAutoInject, ResolvedProxyAutoInject } from '../dist/runtime/types.js';
3
+ export { ScriptCapabilities } from '../dist/runtime/types.js';
3
4
 
4
5
  interface RegistryScriptMeta {
5
6
  /** Registry key (e.g. 'plausibleAnalytics') */
@@ -1,5 +1,6 @@
1
1
  import { ProxyPrivacyInput } from '../dist/runtime/server/utils/privacy.js';
2
2
  import { ScriptCapabilities, RegistryScript, RegistryScriptKey, ProxyConfig, ProxyCapability, ProxyAutoInject, ResolvedProxyAutoInject } from '../dist/runtime/types.js';
3
+ export { ScriptCapabilities } from '../dist/runtime/types.js';
3
4
 
4
5
  interface RegistryScriptMeta {
5
6
  /** Registry key (e.g. 'plausibleAnalytics') */
package/dist/registry.mjs CHANGED
@@ -126,7 +126,7 @@ const registryMeta = [
126
126
  m("intercom", "Intercom", "support", "useScriptIntercom", { bundle: true, proxy: true }, PRIVACY_IP_ONLY),
127
127
  m("crisp", "Crisp", "support", "useScriptCrisp", { bundle: true }, null),
128
128
  // cdn
129
- m("npm", "NPM", "cdn", "useScriptNpm", {}, null),
129
+ m("npm", "NPM", "cdn", "useScriptNpm", { bundle: true }, null),
130
130
  // utility
131
131
  m("googleRecaptcha", "Google reCAPTCHA", "utility", "useScriptGoogleRecaptcha", {}, null),
132
132
  m("googleSignIn", "Google Sign-In", "utility", "useScriptGoogleSignIn", {}, null),
@@ -346,7 +346,7 @@ async function registry(resolve) {
346
346
  return "https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";
347
347
  }
348
348
  },
349
- partytown: { forwards: ["mixpanel", "mixpanel.init", "mixpanel.track", "mixpanel.identify", "mixpanel.people.set", "mixpanel.reset", "mixpanel.register"] }
349
+ partytown: { forwards: ["mixpanel", "mixpanel.init", "mixpanel.track", "mixpanel.identify", "mixpanel.people.set", "mixpanel.reset", "mixpanel.register", "mixpanel.opt_in_tracking", "mixpanel.opt_out_tracking"] }
350
350
  }),
351
351
  // ad
352
352
  def("bingUet", {
@@ -401,7 +401,7 @@ async function registry(resolve) {
401
401
  domains: ["analytics.tiktok.com", "mon.tiktok.com", "mcs.tiktok.com"],
402
402
  privacy: PRIVACY_FULL
403
403
  },
404
- partytown: { forwards: ["ttq.track", "ttq.page", "ttq.identify"] }
404
+ partytown: { forwards: ["ttq.track", "ttq.page", "ttq.identify", "ttq.grantConsent", "ttq.revokeConsent", "ttq.holdConsent"] }
405
405
  }),
406
406
  def("snapchatPixel", {
407
407
  schema: SnapTrPixelOptions,
@@ -503,7 +503,7 @@ async function registry(resolve) {
503
503
  domains: ["www.clarity.ms", "scripts.clarity.ms", "d.clarity.ms", "e.clarity.ms", "k.clarity.ms", "c.clarity.ms", "a.clarity.ms", "b.clarity.ms"],
504
504
  privacy: PRIVACY_HEATMAP
505
505
  },
506
- partytown: { forwards: [] }
506
+ partytown: { forwards: ["clarity"] }
507
507
  }),
508
508
  // payments
509
509
  def("stripe", {
@@ -554,8 +554,8 @@ async function registry(resolve) {
554
554
  envDefaults: { apiKey: "" },
555
555
  category: "content",
556
556
  serverHandlers: [
557
- { route: "/_scripts/proxy/google-static-maps", handler: "./runtime/server/google-static-maps-proxy" },
558
- { route: "/_scripts/proxy/google-maps-geocode", handler: "./runtime/server/google-maps-geocode-proxy" }
557
+ { route: "/_scripts/proxy/google-static-maps", handler: "./runtime/server/google-static-maps-proxy", requiresSigning: true },
558
+ { route: "/_scripts/proxy/google-maps-geocode", handler: "./runtime/server/google-maps-geocode-proxy", requiresSigning: true }
559
559
  ]
560
560
  }),
561
561
  def("blueskyEmbed", {
@@ -564,8 +564,8 @@ async function registry(resolve) {
564
564
  label: "Bluesky Embed",
565
565
  category: "content",
566
566
  serverHandlers: [
567
- { route: "/_scripts/embed/bluesky", handler: "./runtime/server/bluesky-embed" },
568
- { route: "/_scripts/embed/bluesky-image", handler: "./runtime/server/bluesky-embed-image" }
567
+ { route: "/_scripts/embed/bluesky", handler: "./runtime/server/bluesky-embed", requiresSigning: true },
568
+ { route: "/_scripts/embed/bluesky-image", handler: "./runtime/server/bluesky-embed-image", requiresSigning: true }
569
569
  ]
570
570
  }),
571
571
  def("instagramEmbed", {
@@ -574,9 +574,9 @@ async function registry(resolve) {
574
574
  label: "Instagram Embed",
575
575
  category: "content",
576
576
  serverHandlers: [
577
- { route: "/_scripts/embed/instagram", handler: "./runtime/server/instagram-embed" },
578
- { route: "/_scripts/embed/instagram-image", handler: "./runtime/server/instagram-embed-image" },
579
- { route: "/_scripts/embed/instagram-asset", handler: "./runtime/server/instagram-embed-asset" }
577
+ { route: "/_scripts/embed/instagram", handler: "./runtime/server/instagram-embed", requiresSigning: true },
578
+ { route: "/_scripts/embed/instagram-image", handler: "./runtime/server/instagram-embed-image", requiresSigning: true },
579
+ { route: "/_scripts/embed/instagram-asset", handler: "./runtime/server/instagram-embed-asset", requiresSigning: true }
580
580
  ]
581
581
  }),
582
582
  def("xEmbed", {
@@ -585,8 +585,8 @@ async function registry(resolve) {
585
585
  label: "X Embed",
586
586
  category: "content",
587
587
  serverHandlers: [
588
- { route: "/_scripts/embed/x", handler: "./runtime/server/x-embed" },
589
- { route: "/_scripts/embed/x-image", handler: "./runtime/server/x-embed-image" }
588
+ { route: "/_scripts/embed/x", handler: "./runtime/server/x-embed", requiresSigning: true },
589
+ { route: "/_scripts/embed/x-image", handler: "./runtime/server/x-embed-image", requiresSigning: true }
590
590
  ]
591
591
  }),
592
592
  // support
@@ -690,7 +690,7 @@ async function registry(resolve) {
690
690
  privacy: PRIVACY_IP_ONLY
691
691
  },
692
692
  serverHandlers: [
693
- { route: "/_scripts/proxy/gravatar", handler: "./runtime/server/gravatar-proxy" }
693
+ { route: "/_scripts/proxy/gravatar", handler: "./runtime/server/gravatar-proxy", requiresSigning: true }
694
694
  ]
695
695
  })
696
696
  ]);