@nuxt/scripts 0.13.2 → 1.0.0-beta.12

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 (150) hide show
  1. package/README.md +15 -0
  2. package/dist/client/200.html +1 -1
  3. package/dist/client/404.html +1 -1
  4. package/dist/client/_nuxt/48AF9EJD.js +1 -0
  5. package/dist/client/_nuxt/Bk6ed9rg.js +1 -0
  6. package/dist/client/_nuxt/C4Cj8gBr.js +162 -0
  7. package/dist/client/_nuxt/{Bje-0OHL.js → DP0kj6Xn.js} +1 -1
  8. package/dist/client/_nuxt/builds/latest.json +1 -1
  9. package/dist/client/_nuxt/builds/meta/919b81d8-ed3a-4222-8a40-df0031cc3b99.json +1 -0
  10. package/dist/client/_nuxt/entry.D45OuV0w.css +1 -0
  11. package/dist/client/_nuxt/error-404.B57D-jUQ.css +1 -0
  12. package/dist/client/_nuxt/error-500.DTHUW7BI.css +1 -0
  13. package/dist/client/index.html +1 -1
  14. package/dist/module.d.mts +113 -4
  15. package/dist/module.d.ts +176 -0
  16. package/dist/module.json +1 -1
  17. package/dist/module.mjs +780 -299
  18. package/dist/registry.d.ts +6 -0
  19. package/dist/registry.mjs +94 -18
  20. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.d.vue.ts +30 -2
  21. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +40 -15
  22. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue.d.ts +30 -2
  23. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue +6 -6
  24. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsCircle.vue +7 -7
  25. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.vue +6 -6
  26. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue +12 -12
  27. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue +6 -6
  28. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.d.vue.ts +21 -9
  29. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue +8 -8
  30. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue.d.ts +21 -9
  31. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPinElement.vue +11 -5
  32. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.vue +7 -7
  33. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.vue +7 -7
  34. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.vue +7 -7
  35. package/dist/runtime/components/ScriptCrisp.d.vue.ts +1 -1
  36. package/dist/runtime/components/ScriptCrisp.vue +1 -1
  37. package/dist/runtime/components/ScriptCrisp.vue.d.ts +1 -1
  38. package/dist/runtime/components/ScriptGoogleAdsense.vue +1 -1
  39. package/dist/runtime/components/ScriptInstagramEmbed.d.vue.ts +53 -0
  40. package/dist/runtime/components/ScriptInstagramEmbed.vue +38 -0
  41. package/dist/runtime/components/ScriptInstagramEmbed.vue.d.ts +53 -0
  42. package/dist/runtime/components/ScriptIntercom.d.vue.ts +1 -1
  43. package/dist/runtime/components/ScriptIntercom.vue +4 -3
  44. package/dist/runtime/components/ScriptIntercom.vue.d.ts +1 -1
  45. package/dist/runtime/components/ScriptPayPalButtons.d.vue.ts +2 -2
  46. package/dist/runtime/components/ScriptPayPalButtons.vue +13 -11
  47. package/dist/runtime/components/ScriptPayPalButtons.vue.d.ts +2 -2
  48. package/dist/runtime/components/ScriptPayPalMarks.d.vue.ts +2 -2
  49. package/dist/runtime/components/ScriptPayPalMarks.vue +10 -8
  50. package/dist/runtime/components/ScriptPayPalMarks.vue.d.ts +2 -2
  51. package/dist/runtime/components/ScriptPayPalMessages.d.vue.ts +2 -2
  52. package/dist/runtime/components/ScriptPayPalMessages.vue +11 -9
  53. package/dist/runtime/components/ScriptPayPalMessages.vue.d.ts +2 -2
  54. package/dist/runtime/components/ScriptStripePricingTable.vue +2 -2
  55. package/dist/runtime/components/ScriptVimeoPlayer.d.vue.ts +2 -2
  56. package/dist/runtime/components/ScriptVimeoPlayer.vue +1 -1
  57. package/dist/runtime/components/ScriptVimeoPlayer.vue.d.ts +2 -2
  58. package/dist/runtime/components/ScriptXEmbed.d.vue.ts +82 -0
  59. package/dist/runtime/components/ScriptXEmbed.vue +76 -0
  60. package/dist/runtime/components/ScriptXEmbed.vue.d.ts +82 -0
  61. package/dist/runtime/components/ScriptYouTubePlayer.d.vue.ts +12 -1
  62. package/dist/runtime/components/ScriptYouTubePlayer.vue +44 -16
  63. package/dist/runtime/components/ScriptYouTubePlayer.vue.d.ts +12 -1
  64. package/dist/runtime/composables/useScript.js +36 -5
  65. package/dist/runtime/composables/useScriptEventPage.js +2 -2
  66. package/dist/runtime/composables/useScriptTriggerConsent.js +1 -1
  67. package/dist/runtime/composables/useScriptTriggerElement.js +1 -1
  68. package/dist/runtime/composables/useScriptTriggerIdleTimeout.js +1 -1
  69. package/dist/runtime/composables/useScriptTriggerServiceWorker.d.ts +7 -0
  70. package/dist/runtime/composables/useScriptTriggerServiceWorker.js +39 -0
  71. package/dist/runtime/npm-script-stub.d.ts +20 -0
  72. package/dist/runtime/npm-script-stub.js +73 -0
  73. package/dist/runtime/registry/clarity.js +21 -25
  74. package/dist/runtime/registry/cloudflare-web-analytics.js +1 -1
  75. package/dist/runtime/registry/crisp.js +1 -1
  76. package/dist/runtime/registry/databuddy-analytics.js +1 -1
  77. package/dist/runtime/registry/fathom-analytics.js +1 -1
  78. package/dist/runtime/registry/google-adsense.js +1 -1
  79. package/dist/runtime/registry/google-analytics.js +2 -2
  80. package/dist/runtime/registry/google-maps.d.ts +1 -1
  81. package/dist/runtime/registry/google-maps.js +1 -1
  82. package/dist/runtime/registry/google-recaptcha.d.ts +27 -0
  83. package/dist/runtime/registry/google-recaptcha.js +45 -0
  84. package/dist/runtime/registry/google-sign-in.d.ts +84 -0
  85. package/dist/runtime/registry/google-sign-in.js +50 -0
  86. package/dist/runtime/registry/google-tag-manager.d.ts +4 -2
  87. package/dist/runtime/registry/google-tag-manager.js +16 -6
  88. package/dist/runtime/registry/hotjar.js +1 -1
  89. package/dist/runtime/registry/instagram-embed.d.ts +23 -0
  90. package/dist/runtime/registry/instagram-embed.js +22 -0
  91. package/dist/runtime/registry/intercom.js +1 -1
  92. package/dist/runtime/registry/lemon-squeezy.d.ts +0 -1
  93. package/dist/runtime/registry/matomo-analytics.js +3 -3
  94. package/dist/runtime/registry/meta-pixel.js +1 -1
  95. package/dist/runtime/registry/npm.js +1 -1
  96. package/dist/runtime/registry/paypal.d.ts +1 -1
  97. package/dist/runtime/registry/paypal.js +2 -2
  98. package/dist/runtime/registry/plausible-analytics.js +21 -13
  99. package/dist/runtime/registry/posthog.d.ts +27 -0
  100. package/dist/runtime/registry/posthog.js +88 -0
  101. package/dist/runtime/registry/reddit-pixel.js +1 -1
  102. package/dist/runtime/registry/rybbit-analytics.js +41 -9
  103. package/dist/runtime/registry/segment.js +1 -1
  104. package/dist/runtime/registry/snapchat-pixel.js +1 -1
  105. package/dist/runtime/registry/stripe.d.ts +1 -1
  106. package/dist/runtime/registry/stripe.js +1 -1
  107. package/dist/runtime/registry/tiktok-pixel.d.ts +44 -0
  108. package/dist/runtime/registry/tiktok-pixel.js +44 -0
  109. package/dist/runtime/registry/umami-analytics.js +1 -1
  110. package/dist/runtime/registry/vimeo-player.d.ts +2 -2
  111. package/dist/runtime/registry/vimeo-player.js +1 -1
  112. package/dist/runtime/registry/x-embed.d.ts +77 -0
  113. package/dist/runtime/registry/x-embed.js +41 -0
  114. package/dist/runtime/registry/x-pixel.js +1 -1
  115. package/dist/runtime/registry/youtube-player.d.ts +7 -7
  116. package/dist/runtime/registry/youtube-player.js +1 -1
  117. package/dist/runtime/server/google-static-maps-proxy.d.ts +2 -0
  118. package/dist/runtime/server/google-static-maps-proxy.js +54 -0
  119. package/dist/runtime/server/instagram-embed-asset.d.ts +2 -0
  120. package/dist/runtime/server/instagram-embed-asset.js +42 -0
  121. package/dist/runtime/server/instagram-embed-image.d.ts +2 -0
  122. package/dist/runtime/server/instagram-embed-image.js +54 -0
  123. package/dist/runtime/server/instagram-embed.d.ts +2 -0
  124. package/dist/runtime/server/instagram-embed.js +91 -0
  125. package/dist/runtime/server/proxy-handler.d.ts +6 -0
  126. package/dist/runtime/server/proxy-handler.js +264 -0
  127. package/dist/runtime/server/utils/privacy.d.ts +141 -0
  128. package/dist/runtime/server/utils/privacy.js +324 -0
  129. package/dist/runtime/server/x-embed-image.d.ts +2 -0
  130. package/dist/runtime/server/x-embed-image.js +53 -0
  131. package/dist/runtime/server/x-embed.d.ts +49 -0
  132. package/dist/runtime/server/x-embed.js +31 -0
  133. package/dist/runtime/types.d.ts +61 -20
  134. package/dist/runtime/utils/pure.d.ts +9 -0
  135. package/dist/runtime/utils/pure.js +0 -0
  136. package/dist/runtime/utils.d.ts +5 -4
  137. package/dist/runtime/utils.js +12 -2
  138. package/dist/shared/scripts.DLRgvHQg.mjs +288 -0
  139. package/dist/stats.d.mts +39 -0
  140. package/dist/stats.d.ts +39 -0
  141. package/dist/stats.mjs +711 -0
  142. package/dist/types.d.mts +1 -1
  143. package/package.json +59 -46
  144. package/dist/client/_nuxt/DMut0W-e.js +0 -162
  145. package/dist/client/_nuxt/builds/meta/5e0206fe-a683-423c-8d59-2596d0b16fee.json +0 -1
  146. package/dist/client/_nuxt/entry.BjfcJo5q.css +0 -1
  147. package/dist/client/_nuxt/error-404.B0ZhSNwd.css +0 -1
  148. package/dist/client/_nuxt/error-500.D4MdgPaC.css +0 -1
  149. package/dist/client/_nuxt/iNmKC7TZ.js +0 -1
  150. package/dist/client/_nuxt/rttsH3SL.js +0 -1
@@ -1,7 +1,7 @@
1
1
  <script setup>
2
- import { computed, onMounted, ref, watch } from "vue";
3
2
  import { defu } from "defu";
4
3
  import { useHead } from "nuxt/app";
4
+ import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
5
5
  import { useScriptTriggerElement } from "../composables/useScriptTriggerElement";
6
6
  import { useScriptYouTubePlayer } from "../registry/youtube-player";
7
7
  import ScriptAriaLoadingIndicator from "./ScriptAriaLoadingIndicator.vue";
@@ -14,12 +14,14 @@ const props = defineProps({
14
14
  playerVars: { type: null, required: false, default: { autoplay: 0, playsinline: 1 } },
15
15
  width: { type: Number, required: false, default: 640 },
16
16
  height: { type: Number, required: false, default: 360 },
17
+ ratio: { type: String, required: false, default: "16/9" },
17
18
  cookies: { type: Boolean, required: false, default: false },
18
19
  playerOptions: { type: null, required: false },
19
20
  thumbnailSize: { type: String, required: false, default: "hq720" },
20
- webp: { type: Boolean, required: false, default: true }
21
+ webp: { type: Boolean, required: false, default: true },
22
+ placeholderObjectFit: { type: String, required: false, default: "cover" }
21
23
  });
22
- const emits = defineEmits(["ready", "state-change", "playback-quality-change", "playback-rate-change", "error"]);
24
+ const emits = defineEmits(["ready", "state-change", "playback-quality-change", "playback-rate-change", "error", "api-change"]);
23
25
  const events = [
24
26
  "onReady",
25
27
  "onStateChange",
@@ -31,24 +33,48 @@ const events = [
31
33
  const rootEl = ref();
32
34
  const youtubeEl = ref();
33
35
  const ready = ref(false);
36
+ const isTriggered = ref(false);
34
37
  const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl });
35
38
  const script = useScriptYouTubePlayer({
36
39
  scriptOptions: {
40
+ // Use immediate trigger so script loads when ANY player needs it
41
+ // Each player will wait for its own trigger before creating iframe
37
42
  trigger
38
43
  }
39
44
  });
40
45
  const { onLoaded, status } = script;
41
46
  const player = ref();
42
- let clickTriggered = false;
43
- if (props.trigger === "mousedown" && trigger instanceof Promise) {
47
+ const clickTriggered = ref(false);
48
+ if (trigger instanceof Promise) {
44
49
  trigger.then((triggered) => {
45
50
  if (triggered) {
46
- clickTriggered = true;
51
+ isTriggered.value = true;
52
+ if (props.trigger === "mousedown") {
53
+ clickTriggered.value = true;
54
+ }
47
55
  }
48
56
  });
57
+ } else {
58
+ isTriggered.value = true;
49
59
  }
60
+ const stopVideoIdWatch = watch(() => props.videoId, (newId) => {
61
+ if (ready.value && player.value) {
62
+ player.value.loadVideoById(newId);
63
+ }
64
+ });
65
+ onBeforeUnmount(() => {
66
+ stopVideoIdWatch();
67
+ player.value?.destroy();
68
+ });
50
69
  onMounted(() => {
51
70
  onLoaded(async (instance) => {
71
+ if (!isTriggered.value && trigger instanceof Promise) {
72
+ const triggered = await trigger;
73
+ if (!triggered)
74
+ return;
75
+ }
76
+ if (!youtubeEl.value)
77
+ return;
52
78
  const YouTube = instance.YT instanceof Promise ? await instance.YT : instance.YT;
53
79
  await new Promise((resolve) => {
54
80
  if (typeof YT.Player === "undefined")
@@ -56,22 +82,24 @@ onMounted(() => {
56
82
  else
57
83
  resolve();
58
84
  });
85
+ if (!youtubeEl.value)
86
+ return;
59
87
  player.value = new YT.Player(youtubeEl.value, {
60
88
  host: !props.cookies ? "https://www.youtube-nocookie.com" : "https://www.youtube.com",
61
- ...props,
89
+ videoId: props.videoId,
90
+ width: props.width,
91
+ height: props.height,
92
+ playerVars: props.playerVars,
62
93
  ...props.playerOptions,
63
94
  events: Object.fromEntries(events.map((event) => [event, (e) => {
64
95
  const emitEventName = event.replace(/([A-Z])/g, "-$1").replace("on-", "").toLowerCase();
65
96
  emits(emitEventName, e);
66
97
  if (event === "onReady") {
67
98
  ready.value = true;
68
- if (clickTriggered) {
99
+ if (clickTriggered.value) {
69
100
  player.value?.playVideo();
70
- clickTriggered = false;
101
+ clickTriggered.value = false;
71
102
  }
72
- watch(() => props.videoId, () => {
73
- player.value?.loadVideoById(props.videoId);
74
- });
75
103
  }
76
104
  }]))
77
105
  });
@@ -96,7 +124,7 @@ const rootAttrs = computed(() => {
96
124
  position: "relative",
97
125
  backgroundColor: "black",
98
126
  width: "100%",
99
- aspectRatio: `${props.width}/${props.height}`
127
+ aspectRatio: props.ratio
100
128
  },
101
129
  ...trigger instanceof Promise ? trigger.ssrAttrs || {} : {}
102
130
  });
@@ -108,12 +136,12 @@ if (import.meta.server) {
108
136
  useHead({
109
137
  link: [
110
138
  {
111
- key: `nuxt-script-youtube-img`,
139
+ key: "nuxt-script-youtube-img-preconnect",
112
140
  rel: props.aboveTheFold ? "preconnect" : "dns-prefetch",
113
141
  href: "https://i.ytimg.com"
114
142
  },
115
143
  props.aboveTheFold ? {
116
- key: `nuxt-script-youtube-img`,
144
+ key: `nuxt-script-youtube-img-preload-${props.videoId}`,
117
145
  rel: "preload",
118
146
  as: "image",
119
147
  href: placeholder.value
@@ -128,7 +156,7 @@ const placeholderAttrs = computed(() => {
128
156
  loading: props.aboveTheFold ? "eager" : "lazy",
129
157
  style: {
130
158
  width: "100%",
131
- objectFit: "contain",
159
+ objectFit: props.placeholderObjectFit,
132
160
  height: "100%"
133
161
  },
134
162
  onLoad(payload) {
@@ -10,6 +10,7 @@ type __VLS_Props = {
10
10
  playerVars?: YT.PlayerVars;
11
11
  width?: number;
12
12
  height?: number;
13
+ ratio?: string;
13
14
  /**
14
15
  * Whether to use youtube-nocookie.com for embedding.
15
16
  *
@@ -19,9 +20,15 @@ type __VLS_Props = {
19
20
  playerOptions?: YT.PlayerOptions;
20
21
  thumbnailSize?: YoutubeThumbnailSize;
21
22
  webp?: boolean;
23
+ /**
24
+ * Object-fit for the placeholder image.
25
+ *
26
+ * @default 'cover'
27
+ */
28
+ placeholderObjectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down';
22
29
  };
23
30
  declare var __VLS_1: {
24
- placeholder: any;
31
+ placeholder: string;
25
32
  }, __VLS_3: {}, __VLS_10: {}, __VLS_12: {}, __VLS_14: {};
26
33
  type __VLS_Slots = {} & {
27
34
  placeholder?: (props: typeof __VLS_1) => any;
@@ -42,20 +49,24 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
42
49
  "state-change": (e: YT.OnStateChangeEvent, target: YT.Player) => any;
43
50
  "playback-quality-change": (e: YT.OnPlaybackQualityChangeEvent, target: YT.Player) => any;
44
51
  "playback-rate-change": (e: YT.OnPlaybackRateChangeEvent, target: YT.Player) => any;
52
+ "api-change": (e: YT.PlayerEvent, target: YT.Player) => any;
45
53
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
46
54
  onError?: ((e: YT.OnErrorEvent, target: YT.Player) => any) | undefined;
47
55
  onReady?: ((e: YT.PlayerEvent) => any) | undefined;
48
56
  "onState-change"?: ((e: YT.OnStateChangeEvent, target: YT.Player) => any) | undefined;
49
57
  "onPlayback-quality-change"?: ((e: YT.OnPlaybackQualityChangeEvent, target: YT.Player) => any) | undefined;
50
58
  "onPlayback-rate-change"?: ((e: YT.OnPlaybackRateChangeEvent, target: YT.Player) => any) | undefined;
59
+ "onApi-change"?: ((e: YT.PlayerEvent, target: YT.Player) => any) | undefined;
51
60
  }>, {
52
61
  trigger: ElementScriptTrigger;
53
62
  width: number;
54
63
  height: number;
55
64
  playerVars: YT.PlayerVars;
65
+ ratio: string;
56
66
  cookies: boolean;
57
67
  thumbnailSize: YoutubeThumbnailSize;
58
68
  webp: boolean;
69
+ placeholderObjectFit: "cover" | "contain" | "fill" | "none" | "scale-down";
59
70
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
60
71
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
61
72
  declare const _default: typeof __VLS_export;
@@ -1,9 +1,9 @@
1
- import { defu } from "defu";
1
+ import { resolveTrigger } from "#build/nuxt-scripts-trigger-resolver";
2
2
  import { useScript as _useScript } from "@unhead/vue/scripts";
3
- import { reactive } from "vue";
4
- import { onNuxtReady, useNuxtApp, useRuntimeConfig, injectHead } from "nuxt/app";
3
+ import { defu } from "defu";
4
+ import { injectHead, onNuxtReady, useHead, useNuxtApp, useRuntimeConfig } from "nuxt/app";
5
+ import { reactive, ref } from "vue";
5
6
  import { logger } from "../logger.js";
6
- import { resolveTrigger } from "#build/nuxt-scripts-trigger-resolver";
7
7
  function useNuxtScriptRuntimeConfig() {
8
8
  return useRuntimeConfig().public["nuxt-scripts"];
9
9
  }
@@ -13,6 +13,27 @@ export function resolveScriptKey(input) {
13
13
  export function useScript(input, options) {
14
14
  input = typeof input === "string" ? { src: input } : input;
15
15
  options = defu(options, useNuxtScriptRuntimeConfig()?.defaultScriptOptions);
16
+ if (options.partytown) {
17
+ const src = input.src;
18
+ if (!src) {
19
+ throw new Error("useScript with partytown requires a src");
20
+ }
21
+ useHead({
22
+ script: [{ src, type: "text/partytown" }]
23
+ });
24
+ const nuxtApp2 = useNuxtApp();
25
+ nuxtApp2.$scripts = nuxtApp2.$scripts || reactive({});
26
+ const status = ref("loaded");
27
+ const stub = {
28
+ id: src,
29
+ status,
30
+ load: () => Promise.resolve({}),
31
+ remove: () => false,
32
+ entry: void 0
33
+ };
34
+ nuxtApp2.$scripts[src] = stub;
35
+ return stub;
36
+ }
16
37
  if (import.meta.dev && options.bundle === "unsupported") {
17
38
  console.warn("[Nuxt Scripts] Bundling is not supported for dynamic script sources. Static URLs are required for bundling.");
18
39
  options.bundle = false;
@@ -23,8 +44,8 @@ export function useScript(input, options) {
23
44
  options.trigger = resolved;
24
45
  }
25
46
  }
26
- const id = String(resolveScriptKey(input));
27
47
  const nuxtApp = useNuxtApp();
48
+ const id = String(resolveScriptKey(input));
28
49
  options.head = options.head || injectHead();
29
50
  if (!options.head) {
30
51
  throw new Error("useScript() has been called without Nuxt context.");
@@ -65,6 +86,16 @@ export function useScript(input, options) {
65
86
  }
66
87
  return _load();
67
88
  };
89
+ instance.reload = async () => {
90
+ instance.remove();
91
+ const reloadInput = typeof input === "string" ? { src: input, key: `${id}-${Date.now()}` } : { ...input, key: `${id}-${Date.now()}` };
92
+ const reloaded = _useScript(reloadInput, { ...options, trigger: "client" });
93
+ Object.assign(instance, {
94
+ status: reloaded.status,
95
+ entry: reloaded.entry
96
+ });
97
+ return reloaded.load();
98
+ };
68
99
  nuxtApp.$scripts[id] = instance;
69
100
  if (import.meta.dev && import.meta.client) {
70
101
  let syncScripts = function() {
@@ -1,5 +1,5 @@
1
- import { useNuxtApp, useRoute, injectHead } from "nuxt/app";
2
- import { ref, onScopeDispose } from "vue";
1
+ import { injectHead, useNuxtApp, useRoute } from "nuxt/app";
2
+ import { onScopeDispose, ref } from "vue";
3
3
  export function useScriptEventPage(onChange) {
4
4
  const nuxt = useNuxtApp();
5
5
  const route = useRoute();
@@ -1,5 +1,5 @@
1
+ import { onNuxtReady, requestIdleCallback, tryUseNuxtApp } from "nuxt/app";
1
2
  import { isRef, ref, toValue, watch } from "vue";
2
- import { tryUseNuxtApp, onNuxtReady, requestIdleCallback } from "nuxt/app";
3
3
  export function useScriptTriggerConsent(options) {
4
4
  if (import.meta.server)
5
5
  return new Promise(() => {
@@ -2,7 +2,7 @@ import {
2
2
  useEventListener,
3
3
  useIntersectionObserver
4
4
  } from "@vueuse/core";
5
- import { tryOnScopeDispose, tryOnMounted } from "@vueuse/shared";
5
+ import { tryOnMounted, tryOnScopeDispose } from "@vueuse/shared";
6
6
  import { watch } from "vue";
7
7
  function useElementVisibilityPromise(element) {
8
8
  let observer;
@@ -1,5 +1,5 @@
1
- import { tryOnScopeDispose } from "@vueuse/shared";
2
1
  import { useTimeoutFn } from "@vueuse/core";
2
+ import { tryOnScopeDispose } from "@vueuse/shared";
3
3
  import { onNuxtReady } from "nuxt/app";
4
4
  export function useScriptTriggerIdleTimeout(options) {
5
5
  if (import.meta.server) {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Create a trigger that loads a script after the service worker is controlling the page.
3
+ * Falls back to immediate loading if service workers are not supported or after timeout.
4
+ */
5
+ export declare function useScriptTriggerServiceWorker(options?: {
6
+ timeout?: number;
7
+ }): Promise<boolean>;
@@ -0,0 +1,39 @@
1
+ import { tryOnScopeDispose } from "@vueuse/shared";
2
+ export function useScriptTriggerServiceWorker(options) {
3
+ if (import.meta.server)
4
+ return new Promise(() => {
5
+ });
6
+ const timeout = options?.timeout ?? 3e3;
7
+ return new Promise((resolve) => {
8
+ if (!("serviceWorker" in navigator)) {
9
+ resolve(true);
10
+ return;
11
+ }
12
+ let resolved = false;
13
+ const done = () => {
14
+ if (resolved)
15
+ return;
16
+ resolved = true;
17
+ resolve(true);
18
+ };
19
+ if (navigator.serviceWorker.controller) {
20
+ done();
21
+ return;
22
+ }
23
+ const onControllerChange = () => {
24
+ navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange);
25
+ done();
26
+ };
27
+ navigator.serviceWorker.addEventListener("controllerchange", onControllerChange);
28
+ const timer = setTimeout(() => {
29
+ navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange);
30
+ console.warn("[nuxt-scripts] Service worker not controlling after timeout, loading scripts anyway");
31
+ done();
32
+ }, timeout);
33
+ tryOnScopeDispose(() => {
34
+ navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange);
35
+ clearTimeout(timer);
36
+ resolve(false);
37
+ });
38
+ });
39
+ }
@@ -0,0 +1,20 @@
1
+ import type { Ref } from 'vue';
2
+ import type { NuxtUseScriptOptions } from './types.js';
3
+ export interface NpmScriptStubOptions {
4
+ key: string;
5
+ use?: () => any;
6
+ clientInit?: () => void | Promise<any>;
7
+ trigger?: NuxtUseScriptOptions['trigger'];
8
+ }
9
+ export interface NpmScriptStub<T = any> {
10
+ status: Ref<'awaitingLoad' | 'loading' | 'loaded' | 'error'>;
11
+ load: () => Promise<void>;
12
+ onLoaded: (callback: (api: T) => void) => void;
13
+ proxy: T;
14
+ $script?: any;
15
+ }
16
+ /**
17
+ * Creates a script stub for NPM-only packages (no external script tag)
18
+ * Manages lifecycle and status without relying on script tag loading
19
+ */
20
+ export declare function createNpmScriptStub<T = any>(options: NpmScriptStubOptions): NpmScriptStub<T>;
@@ -0,0 +1,73 @@
1
+ import { ref } from "vue";
2
+ import { logger } from "./logger.js";
3
+ export function createNpmScriptStub(options) {
4
+ const status = ref("awaitingLoad");
5
+ const loadedCallbacks = [];
6
+ let initPromise = null;
7
+ let hasInitialized = false;
8
+ const proxy = options.use?.() || {};
9
+ const stub = {
10
+ status,
11
+ proxy,
12
+ async load() {
13
+ if (hasInitialized || status.value !== "awaitingLoad")
14
+ return;
15
+ hasInitialized = true;
16
+ status.value = "loading";
17
+ try {
18
+ if (options.clientInit) {
19
+ console.log(`[NpmScriptStub] Initializing ${options.key}...`);
20
+ initPromise = Promise.resolve(options.clientInit());
21
+ await initPromise;
22
+ console.log(`[NpmScriptStub] ${options.key} initialized successfully`);
23
+ }
24
+ status.value = "loaded";
25
+ loadedCallbacks.forEach((cb) => {
26
+ try {
27
+ cb(proxy);
28
+ } catch (error) {
29
+ logger.error(`[NpmScriptStub] Error in onLoaded callback for ${options.key}:`, error);
30
+ }
31
+ });
32
+ } catch (error) {
33
+ logger.error(`[NpmScriptStub] Failed to initialize ${options.key}:`, error);
34
+ status.value = "error";
35
+ }
36
+ },
37
+ onLoaded(callback) {
38
+ if (status.value === "loaded") {
39
+ callback(proxy);
40
+ } else {
41
+ loadedCallbacks.push(callback);
42
+ }
43
+ },
44
+ // Mock $script for compatibility with useScript API
45
+ get $script() {
46
+ return {
47
+ status: status.value,
48
+ load: stub.load
49
+ };
50
+ }
51
+ };
52
+ if (options.trigger) {
53
+ if (typeof options.trigger === "function") {
54
+ const res = options.trigger(() => stub.load());
55
+ if (res && typeof res === "object" && "then" in res)
56
+ res.then(() => stub.load());
57
+ } else if (options.trigger === "manual") {
58
+ } else if (options.trigger === "onNuxtReady") {
59
+ import("nuxt/app").then(({ onNuxtReady }) => {
60
+ onNuxtReady(() => stub.load());
61
+ });
62
+ } else if (options.trigger === "client") {
63
+ if (import.meta.client) {
64
+ stub.load();
65
+ }
66
+ }
67
+ } else {
68
+ if (import.meta.client) {
69
+ stub.load();
70
+ }
71
+ }
72
+ return stub;
73
+ }
@@ -1,5 +1,5 @@
1
+ import { minLength, object, pipe, string } from "#nuxt-scripts-validator";
1
2
  import { useRegistryScript } from "../utils.js";
2
- import { minLength, object, string, pipe } from "#nuxt-scripts-validator";
3
3
  export const ClarityOptions = object({
4
4
  /**
5
5
  * The Clarity token.
@@ -7,30 +7,26 @@ export const ClarityOptions = object({
7
7
  id: pipe(string(), minLength(10))
8
8
  });
9
9
  export function useScriptClarity(_options) {
10
- return useRegistryScript(
11
- "clarity",
12
- (options) => ({
13
- scriptInput: {
14
- src: `https://www.clarity.ms/tag/${options.id}`
15
- },
16
- schema: import.meta.dev ? ClarityOptions : void 0,
17
- scriptOptions: {
18
- use() {
19
- return {
20
- // @ts-expect-error untyped
21
- clarity: Object.assign(function(...params) {
22
- const clarity = window.clarity;
23
- return clarity.apply(this, params);
24
- }, window.clarity)
25
- };
26
- }
27
- },
28
- clientInit: import.meta.server ? void 0 : () => {
29
- window.clarity = window.clarity || function(...params) {
30
- (window.clarity.q = window.clarity.q || []).push(params);
10
+ return useRegistryScript("clarity", (options) => ({
11
+ scriptInput: {
12
+ src: `https://www.clarity.ms/tag/${options.id}`
13
+ },
14
+ schema: import.meta.dev ? ClarityOptions : void 0,
15
+ scriptOptions: {
16
+ use() {
17
+ return {
18
+ // @ts-expect-error untyped
19
+ clarity: Object.assign(function(...params) {
20
+ const clarity = window.clarity;
21
+ return clarity.apply(this, params);
22
+ }, window.clarity)
31
23
  };
32
24
  }
33
- }),
34
- _options
35
- );
25
+ },
26
+ clientInit: import.meta.server ? void 0 : () => {
27
+ window.clarity = window.clarity || function(...params) {
28
+ (window.clarity.q = window.clarity.q || []).push(params);
29
+ };
30
+ }
31
+ }), _options);
36
32
  }
@@ -1,5 +1,5 @@
1
- import { useRegistryScript } from "../utils.js";
2
1
  import { boolean, minLength, object, optional, pipe, string } from "#nuxt-scripts-validator";
2
+ import { useRegistryScript } from "../utils.js";
3
3
  export const CloudflareWebAnalyticsOptions = object({
4
4
  /**
5
5
  * The Cloudflare Web Analytics token.
@@ -1,5 +1,5 @@
1
+ import { number, object, optional, string } from "#nuxt-scripts-validator";
1
2
  import { useRegistryScript } from "../utils.js";
2
- import { object, string, optional, number } from "#nuxt-scripts-validator";
3
3
  export const CrispOptions = object({
4
4
  /**
5
5
  * The Crisp ID.
@@ -1,5 +1,5 @@
1
+ import { boolean, number, object, optional, string } from "#nuxt-scripts-validator";
1
2
  import { useRegistryScript } from "../utils.js";
2
- import { object, optional, string, boolean, number } from "#nuxt-scripts-validator";
3
3
  export const DatabuddyAnalyticsOptions = object({
4
4
  // Required
5
5
  clientId: string(),
@@ -1,5 +1,5 @@
1
- import { useRegistryScript } from "../utils.js";
2
1
  import { boolean, literal, object, optional, string, union } from "#nuxt-scripts-validator";
2
+ import { useRegistryScript } from "../utils.js";
3
3
  export const FathomAnalyticsOptions = object({
4
4
  /**
5
5
  * The Fathom Analytics site ID.
@@ -1,6 +1,6 @@
1
+ import { boolean, object, optional, string } from "#nuxt-scripts-validator";
1
2
  import { useHead } from "nuxt/app";
2
3
  import { useRegistryScript } from "../utils.js";
3
- import { object, string, optional, boolean } from "#nuxt-scripts-validator";
4
4
  export const GoogleAdsenseOptions = object({
5
5
  /**
6
6
  * The Google Adsense ID.
@@ -1,6 +1,6 @@
1
- import { withQuery } from "ufo";
1
+ import { object, optional, string } from "#nuxt-scripts-validator";
2
2
  import { useRegistryScript } from "#nuxt-scripts/utils";
3
- import { object, string, optional } from "#nuxt-scripts-validator";
3
+ import { withQuery } from "ufo";
4
4
  export const GoogleAnalyticsOptions = object({
5
5
  id: optional(string()),
6
6
  // The GA4 measurement ID (format: G-XXXXXXXX)
@@ -15,7 +15,7 @@ declare global {
15
15
  interface Window {
16
16
  google: {
17
17
  maps: {
18
- __ib__(): void;
18
+ __ib__: () => void;
19
19
  };
20
20
  };
21
21
  }
@@ -1,6 +1,6 @@
1
+ import { array, literal, object, optional, string, union } from "#nuxt-scripts-validator";
1
2
  import { withQuery } from "ufo";
2
3
  import { useRegistryScript } from "../utils.js";
3
- import { array, literal, object, optional, string, union } from "#nuxt-scripts-validator";
4
4
  export const GoogleMapsOptions = object({
5
5
  apiKey: string(),
6
6
  libraries: optional(array(string())),
@@ -0,0 +1,27 @@
1
+ import type { RegistryScriptInput } from '#nuxt-scripts/types';
2
+ export declare const GoogleRecaptchaOptions: import("valibot").ObjectSchema<{
3
+ readonly siteKey: import("valibot").StringSchema<undefined>;
4
+ readonly enterprise: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
5
+ readonly recaptchaNet: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
6
+ readonly hl: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
7
+ }, undefined>;
8
+ export type GoogleRecaptchaInput = RegistryScriptInput<typeof GoogleRecaptchaOptions>;
9
+ export interface GoogleRecaptchaApi {
10
+ grecaptcha: {
11
+ ready: (callback: () => void) => void;
12
+ execute: (siteKey: string, options: {
13
+ action: string;
14
+ }) => Promise<string>;
15
+ enterprise?: {
16
+ ready: (callback: () => void) => void;
17
+ execute: (siteKey: string, options: {
18
+ action: string;
19
+ }) => Promise<string>;
20
+ };
21
+ };
22
+ }
23
+ declare global {
24
+ interface Window extends GoogleRecaptchaApi {
25
+ }
26
+ }
27
+ export declare function useScriptGoogleRecaptcha<T extends GoogleRecaptchaApi>(_options?: GoogleRecaptchaInput): import("#nuxt-scripts/types").UseScriptContext<T>;
@@ -0,0 +1,45 @@
1
+ import { boolean, object, optional, string } from "#nuxt-scripts-validator";
2
+ import { useRegistryScript } from "#nuxt-scripts/utils";
3
+ import { withQuery } from "ufo";
4
+ export const GoogleRecaptchaOptions = object({
5
+ siteKey: string(),
6
+ // Use enterprise.js instead of api.js
7
+ enterprise: optional(boolean()),
8
+ // Use recaptcha.net (works in China)
9
+ recaptchaNet: optional(boolean()),
10
+ // Language code
11
+ hl: optional(string())
12
+ });
13
+ export function useScriptGoogleRecaptcha(_options) {
14
+ return useRegistryScript(_options?.key || "googleRecaptcha", (options) => {
15
+ const baseUrl = options?.recaptchaNet ? "https://www.recaptcha.net/recaptcha" : "https://www.google.com/recaptcha";
16
+ const scriptPath = options?.enterprise ? "enterprise.js" : "api.js";
17
+ return {
18
+ scriptInput: {
19
+ src: withQuery(`${baseUrl}/${scriptPath}`, {
20
+ render: options?.siteKey,
21
+ hl: options?.hl
22
+ }),
23
+ crossorigin: false
24
+ },
25
+ schema: import.meta.dev ? GoogleRecaptchaOptions : void 0,
26
+ scriptOptions: {
27
+ use() {
28
+ return { grecaptcha: window.grecaptcha };
29
+ }
30
+ },
31
+ clientInit: import.meta.server ? void 0 : () => {
32
+ const w = window;
33
+ w.grecaptcha = w.grecaptcha || {};
34
+ const readyFn = function(cb) {
35
+ (w.___grecaptcha_cfg = w.___grecaptcha_cfg || {}).fns = (w.___grecaptcha_cfg.fns || []).concat([cb]);
36
+ };
37
+ w.grecaptcha.ready = w.grecaptcha.ready || readyFn;
38
+ if (options?.enterprise) {
39
+ w.grecaptcha.enterprise = w.grecaptcha.enterprise || {};
40
+ w.grecaptcha.enterprise.ready = w.grecaptcha.enterprise.ready || readyFn;
41
+ }
42
+ }
43
+ };
44
+ }, _options);
45
+ }