@nuxt/scripts 1.0.0-rc.9 → 1.0.1

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 (106) 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/{Cxq4HLPL.js → BjIIVRlr.js} +1 -1
  4. package/dist/devtools-client/_nuxt/{BBS9G2Kb.js → C3h_qg0j.js} +1 -1
  5. package/dist/devtools-client/_nuxt/{DCBsJT4N.js → CKrGhxlH.js} +1 -1
  6. package/dist/devtools-client/_nuxt/DD1eKorn.js +1 -0
  7. package/dist/devtools-client/_nuxt/{B4uHpJPz.js → DTVoxnk-.js} +1 -1
  8. package/dist/devtools-client/_nuxt/{DvZScWzI.js → TnW0ti1s.js} +1 -1
  9. package/dist/devtools-client/_nuxt/UTyLw2F_.js +188 -0
  10. package/dist/devtools-client/_nuxt/builds/latest.json +1 -1
  11. package/dist/devtools-client/_nuxt/builds/meta/8eda1fb3-23bc-456f-8373-7e503f9580ec.json +1 -0
  12. package/dist/devtools-client/_nuxt/{entry.BwpOBArY.css → entry.BKkVrcJj.css} +1 -1
  13. package/dist/devtools-client/_nuxt/error-404.Rdq9GpXu.css +1 -0
  14. package/dist/devtools-client/_nuxt/error-500.BPHNCR4E.css +1 -0
  15. package/dist/devtools-client/_nuxt/index.DZD1lwyI.css +1 -0
  16. package/dist/devtools-client/docs/index.html +1 -1
  17. package/dist/devtools-client/first-party/index.html +1 -1
  18. package/dist/devtools-client/index.html +1 -1
  19. package/dist/devtools-client/registry/index.html +1 -1
  20. package/dist/module.d.mts +18 -2
  21. package/dist/module.d.ts +18 -2
  22. package/dist/module.json +1 -1
  23. package/dist/module.mjs +81 -9
  24. package/dist/registry.mjs +10 -6
  25. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +1 -2
  26. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue +3 -0
  27. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue +6 -2
  28. package/dist/runtime/components/ScriptBlueskyEmbed.d.vue.ts +0 -1
  29. package/dist/runtime/components/ScriptBlueskyEmbed.vue +12 -10
  30. package/dist/runtime/components/ScriptBlueskyEmbed.vue.d.ts +0 -1
  31. package/dist/runtime/components/ScriptInstagramEmbed.vue +3 -1
  32. package/dist/runtime/components/ScriptXEmbed.d.vue.ts +0 -1
  33. package/dist/runtime/components/ScriptXEmbed.vue +11 -9
  34. package/dist/runtime/components/ScriptXEmbed.vue.d.ts +0 -1
  35. package/dist/runtime/composables/useScript.js +17 -6
  36. package/dist/runtime/composables/useScriptProxyToken.d.ts +12 -0
  37. package/dist/runtime/composables/useScriptProxyToken.js +4 -0
  38. package/dist/runtime/composables/useScriptProxyUrl.d.ts +12 -0
  39. package/dist/runtime/composables/useScriptProxyUrl.js +27 -0
  40. package/dist/runtime/plugins/proxy-token.server.d.ts +10 -0
  41. package/dist/runtime/plugins/proxy-token.server.js +17 -0
  42. package/dist/runtime/registry/bing-uet.d.ts +6 -2
  43. package/dist/runtime/registry/bing-uet.js +13 -1
  44. package/dist/runtime/registry/bluesky-embed.d.ts +0 -4
  45. package/dist/runtime/registry/bluesky-embed.js +0 -4
  46. package/dist/runtime/registry/clarity.d.ts +6 -2
  47. package/dist/runtime/registry/clarity.js +12 -1
  48. package/dist/runtime/registry/google-analytics.d.ts +6 -2
  49. package/dist/runtime/registry/google-analytics.js +12 -1
  50. package/dist/runtime/registry/google-tag-manager.d.ts +6 -2
  51. package/dist/runtime/registry/google-tag-manager.js +10 -1
  52. package/dist/runtime/registry/gravatar.js +10 -13
  53. package/dist/runtime/registry/matomo-analytics.d.ts +9 -3
  54. package/dist/runtime/registry/matomo-analytics.js +28 -1
  55. package/dist/runtime/registry/meta-pixel.d.ts +8 -2
  56. package/dist/runtime/registry/meta-pixel.js +10 -1
  57. package/dist/runtime/registry/mixpanel-analytics.d.ts +12 -2
  58. package/dist/runtime/registry/mixpanel-analytics.js +16 -4
  59. package/dist/runtime/registry/posthog.d.ts +8 -2
  60. package/dist/runtime/registry/posthog.js +15 -4
  61. package/dist/runtime/registry/schemas.d.ts +65 -0
  62. package/dist/runtime/registry/schemas.js +75 -8
  63. package/dist/runtime/registry/tiktok-pixel.d.ts +16 -2
  64. package/dist/runtime/registry/tiktok-pixel.js +22 -1
  65. package/dist/runtime/registry/x-embed.d.ts +0 -4
  66. package/dist/runtime/registry/x-embed.js +0 -4
  67. package/dist/runtime/server/bluesky-embed-image.d.ts +1 -1
  68. package/dist/runtime/server/bluesky-embed.d.ts +1 -15
  69. package/dist/runtime/server/bluesky-embed.js +22 -4
  70. package/dist/runtime/server/google-maps-geocode-proxy.js +8 -5
  71. package/dist/runtime/server/google-static-maps-proxy.d.ts +1 -1
  72. package/dist/runtime/server/google-static-maps-proxy.js +13 -8
  73. package/dist/runtime/server/gravatar-proxy.d.ts +1 -1
  74. package/dist/runtime/server/gravatar-proxy.js +6 -7
  75. package/dist/runtime/server/instagram-embed-asset.d.ts +1 -1
  76. package/dist/runtime/server/instagram-embed-image.d.ts +1 -1
  77. package/dist/runtime/server/instagram-embed.js +22 -10
  78. package/dist/runtime/server/utils/cached-upstream.d.ts +55 -0
  79. package/dist/runtime/server/utils/cached-upstream.js +65 -0
  80. package/dist/runtime/server/utils/embed-rewriters.d.ts +19 -0
  81. package/dist/runtime/server/utils/embed-rewriters.js +41 -0
  82. package/dist/runtime/server/utils/image-proxy.d.ts +3 -1
  83. package/dist/runtime/server/utils/image-proxy.js +8 -6
  84. package/dist/runtime/server/utils/instagram-embed.d.ts +4 -4
  85. package/dist/runtime/server/utils/instagram-embed.js +10 -9
  86. package/dist/runtime/server/utils/proxy-url.d.ts +9 -0
  87. package/dist/runtime/server/utils/proxy-url.js +21 -0
  88. package/dist/runtime/server/utils/sign-constants.d.ts +16 -0
  89. package/dist/runtime/server/utils/sign-constants.js +5 -0
  90. package/dist/runtime/server/utils/sign.d.ts +2 -10
  91. package/dist/runtime/server/utils/sign.js +8 -5
  92. package/dist/runtime/server/utils/withSigning.js +3 -2
  93. package/dist/runtime/server/vercel-insights-sink.d.ts +2 -0
  94. package/dist/runtime/server/vercel-insights-sink.js +5 -0
  95. package/dist/runtime/server/x-embed-image.d.ts +1 -1
  96. package/dist/runtime/server/x-embed.js +20 -2
  97. package/dist/runtime/types.d.ts +28 -1
  98. package/dist/types-source.mjs +104 -11
  99. package/dist/types.d.mts +1 -1
  100. package/package.json +3 -3
  101. package/dist/devtools-client/_nuxt/CQR4zIAm.js +0 -1
  102. package/dist/devtools-client/_nuxt/DTxy5P8N.js +0 -188
  103. package/dist/devtools-client/_nuxt/builds/meta/bd58b869-1eb5-4c50-871c-707f9b71e8f9.json +0 -1
  104. package/dist/devtools-client/_nuxt/error-404.d44aGwWI.css +0 -1
  105. package/dist/devtools-client/_nuxt/error-500.NthMfIEt.css +0 -1
  106. package/dist/devtools-client/_nuxt/index.CA-OpSj0.css +0 -1
@@ -1,7 +1,8 @@
1
1
  <script setup>
2
2
  import { useAsyncData } from "nuxt/app";
3
3
  import { computed } from "vue";
4
- import { formatCount, formatTweetDate, proxyXImageUrl } from "../registry/x-embed";
4
+ import { useScriptProxyUrl } from "../composables/useScriptProxyUrl";
5
+ import { formatCount, formatTweetDate } from "../registry/x-embed";
5
6
  import { requireRegistryEndpoint, scriptsPrefix } from "../utils";
6
7
  const props = defineProps({
7
8
  tweetId: { type: String, required: true },
@@ -15,10 +16,11 @@ const apiEndpoint = computed(() => props.apiEndpoint || `${prefix}/embed/x`);
15
16
  const resolvedImageProxyEndpoint = computed(() => props.imageProxyEndpoint || `${prefix}/embed/x-image`);
16
17
  if (!props.apiEndpoint)
17
18
  requireRegistryEndpoint("ScriptXEmbed", "xEmbed");
19
+ const proxyUrl = useScriptProxyUrl();
18
20
  const cacheKey = computed(() => `x-embed-${props.tweetId}`);
19
21
  const { data: tweet, status, error } = useAsyncData(
20
22
  cacheKey,
21
- () => $fetch(`${apiEndpoint.value}?id=${props.tweetId}`)
23
+ () => $fetch(proxyUrl(apiEndpoint.value, { id: props.tweetId }))
22
24
  );
23
25
  const slotProps = computed(() => {
24
26
  if (!tweet.value)
@@ -30,8 +32,7 @@ const slotProps = computed(() => {
30
32
  // User info
31
33
  userName: t.user.name,
32
34
  userHandle: t.user.screen_name,
33
- userAvatar: proxyXImageUrl(t.user.profile_image_url_https, resolvedImageProxyEndpoint.value),
34
- userAvatarOriginal: t.user.profile_image_url_https,
35
+ userAvatar: t.user.profile_image_url_https,
35
36
  isVerified: t.user.verified || t.user.is_blue_verified,
36
37
  // Tweet content
37
38
  text: t.text,
@@ -42,14 +43,14 @@ const slotProps = computed(() => {
42
43
  likesFormatted: formatCount(t.favorite_count),
43
44
  replies: t.conversation_count,
44
45
  repliesFormatted: formatCount(t.conversation_count),
45
- // Media
46
+ // Media (already proxied)
46
47
  photos: t.photos?.map((p) => ({
47
48
  ...p,
48
- proxiedUrl: proxyXImageUrl(p.url, resolvedImageProxyEndpoint.value)
49
+ proxiedUrl: p.url
49
50
  })),
50
51
  video: t.video ? {
51
52
  ...t.video,
52
- posterProxied: proxyXImageUrl(t.video.poster, resolvedImageProxyEndpoint.value)
53
+ posterProxied: t.video.poster
53
54
  } : null,
54
55
  // Links
55
56
  tweetUrl: `https://x.com/${t.user.screen_name}/status/${t.id_str}`,
@@ -59,8 +60,9 @@ const slotProps = computed(() => {
59
60
  // Reply context
60
61
  isReply: !!t.parent,
61
62
  replyToUser: t.parent?.user.screen_name,
62
- // Helpers
63
- proxyImage: (url) => proxyXImageUrl(url, resolvedImageProxyEndpoint.value)
63
+ // Helpers — proxy an arbitrary URL through the image endpoint at runtime.
64
+ // Uses the page token emitted during SSR so client-generated URLs validate.
65
+ proxyImage: (url) => proxyUrl(resolvedImageProxyEndpoint.value, { url })
64
66
  };
65
67
  });
66
68
  defineExpose({
@@ -31,7 +31,6 @@ declare const slotProps: import("vue").ComputedRef<{
31
31
  userName: string;
32
32
  userHandle: string;
33
33
  userAvatar: string;
34
- userAvatarOriginal: string;
35
34
  isVerified: boolean | undefined;
36
35
  text: string;
37
36
  datetime: string;
@@ -26,11 +26,22 @@ function toNetworkRequest(entry, proxyPrefix) {
26
26
  isProxied
27
27
  };
28
28
  }
29
- function createDomainMatcher(domains, proxyPrefix) {
29
+ function createDomainMatcher(domains, proxyPrefix, scriptSrc) {
30
30
  const localHostname = window.location.hostname;
31
+ const scriptUrl = (() => {
32
+ if (!scriptSrc)
33
+ return "";
34
+ try {
35
+ return new URL(scriptSrc, window.location.origin).href;
36
+ } catch {
37
+ return "";
38
+ }
39
+ })();
31
40
  return function matchesScript(entry) {
32
41
  try {
33
42
  const entryUrl = new URL(entry.name, window.location.origin);
43
+ if (scriptUrl && entryUrl.href === scriptUrl)
44
+ return true;
34
45
  if (entryUrl.hostname !== localHostname && domains.has(entryUrl.hostname))
35
46
  return true;
36
47
  const proxyPath = `${proxyPrefix}/`;
@@ -46,12 +57,12 @@ function createDomainMatcher(domains, proxyPrefix) {
46
57
  return false;
47
58
  };
48
59
  }
49
- function observeNetworkRequests(payload, domains, onUpdate) {
60
+ function observeNetworkRequests(payload, domains, onUpdate, scriptSrc) {
50
61
  if (typeof PerformanceObserver === "undefined")
51
62
  return () => {
52
63
  };
53
64
  const proxyPrefix = resolveProxyPrefix();
54
- const matchesScript = createDomainMatcher(domains, proxyPrefix);
65
+ const matchesScript = createDomainMatcher(domains, proxyPrefix, scriptSrc);
55
66
  const seen = /* @__PURE__ */ new Set();
56
67
  function entryKey(entry) {
57
68
  return `${entry.name}@${entry.startTime}`;
@@ -148,7 +159,7 @@ export function useScript(input, options) {
148
159
  ],
149
160
  networkRequests: []
150
161
  };
151
- disconnectObserver = observeNetworkRequests(payload, domains, syncScripts);
162
+ disconnectObserver = observeNetworkRequests(payload, domains, syncScripts, src);
152
163
  syncScripts();
153
164
  }
154
165
  return stub;
@@ -274,7 +285,7 @@ export function useScript(input, options) {
274
285
  ...scriptHostname ? [scriptHostname] : [],
275
286
  ...options.devtools?.domains || []
276
287
  ]);
277
- let disconnectObserver = observeNetworkRequests(payload, domains, syncScripts);
288
+ let disconnectObserver = observeNetworkRequests(payload, domains, syncScripts, input.src);
278
289
  const _origRemove = instance.remove;
279
290
  const _origReload = instance.reload;
280
291
  instance.remove = () => {
@@ -284,7 +295,7 @@ export function useScript(input, options) {
284
295
  instance.reload = async () => {
285
296
  disconnectObserver();
286
297
  const result = await _origReload();
287
- disconnectObserver = observeNetworkRequests(payload, domains, syncScripts);
298
+ disconnectObserver = observeNetworkRequests(payload, domains, syncScripts, input.src);
288
299
  return result;
289
300
  };
290
301
  syncScripts();
@@ -0,0 +1,12 @@
1
+ export interface ScriptProxyToken {
2
+ token: string;
3
+ ts: number;
4
+ }
5
+ /**
6
+ * Shared `useState` holding the proxy page token emitted during SSR.
7
+ *
8
+ * Populated by the `nuxt-scripts:proxy-token` server plugin when
9
+ * `runtimeConfig['nuxt-scripts'].proxySecret` is set, and hydrated to the
10
+ * client via the Nuxt payload. Stays null when signing is disabled.
11
+ */
12
+ export declare function useScriptProxyToken(): import("vue").Ref<ScriptProxyToken | null, ScriptProxyToken | null>;
@@ -0,0 +1,4 @@
1
+ import { useState } from "nuxt/app";
2
+ export function useScriptProxyToken() {
3
+ return useState("nuxt-scripts:proxy-token", () => null);
4
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Build proxy URLs that the server's `withSigning` middleware accepts.
3
+ *
4
+ * Attaches the page token emitted during SSR (`_pt` + `_ts`) when one is
5
+ * available, so client-driven proxy calls (e.g. reactive fetches, dynamic
6
+ * image helpers exposed in slot props) authenticate without needing a
7
+ * server round-trip to sign each URL.
8
+ *
9
+ * When no token is present (signing disabled or no secret), emits plain
10
+ * `?url=...` URLs, matching the pre-signing behavior.
11
+ */
12
+ export declare function useScriptProxyUrl(): (path: string, query?: Record<string, unknown>) => string;
@@ -0,0 +1,27 @@
1
+ import { PAGE_TOKEN_PARAM, PAGE_TOKEN_TS_PARAM } from "../server/utils/sign-constants.js";
2
+ import { useScriptProxyToken } from "./useScriptProxyToken.js";
3
+ export function useScriptProxyUrl() {
4
+ const token = useScriptProxyToken();
5
+ return (path, query = {}) => {
6
+ const parts = [];
7
+ for (const [key, value] of Object.entries(query)) {
8
+ if (value === void 0 || value === null)
9
+ continue;
10
+ const encodedKey = encodeURIComponent(key);
11
+ if (Array.isArray(value)) {
12
+ for (const item of value) {
13
+ if (item === void 0 || item === null)
14
+ continue;
15
+ parts.push(`${encodedKey}=${encodeURIComponent(String(item))}`);
16
+ }
17
+ } else {
18
+ parts.push(`${encodedKey}=${encodeURIComponent(String(value))}`);
19
+ }
20
+ }
21
+ if (token.value) {
22
+ parts.push(`${PAGE_TOKEN_PARAM}=${encodeURIComponent(token.value.token)}`);
23
+ parts.push(`${PAGE_TOKEN_TS_PARAM}=${token.value.ts}`);
24
+ }
25
+ return parts.length ? `${path}?${parts.join("&")}` : path;
26
+ };
27
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Emit a per-request proxy page token into the SSR payload.
3
+ *
4
+ * The token authorizes client-side proxy calls (`/embed/x-image?url=...`,
5
+ * `/embed/bluesky?url=...`, etc.) without needing each URL to be signed
6
+ * ahead of time. It stays null when no proxy secret is configured, in
7
+ * which case `withSigning` passes requests through unchecked.
8
+ */
9
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
10
+ export default _default;
@@ -0,0 +1,17 @@
1
+ import { defineNuxtPlugin, useRuntimeConfig } from "nuxt/app";
2
+ import { useScriptProxyToken } from "../composables/useScriptProxyToken.js";
3
+ import { generateProxyToken } from "../server/utils/sign.js";
4
+ export default defineNuxtPlugin({
5
+ name: "nuxt-scripts:proxy-token",
6
+ enforce: "pre",
7
+ setup() {
8
+ const secret = useRuntimeConfig()["nuxt-scripts"]?.proxySecret;
9
+ if (!secret)
10
+ return;
11
+ const ts = Math.floor(Date.now() / 1e3);
12
+ useScriptProxyToken().value = {
13
+ token: generateProxyToken(secret, ts),
14
+ ts
15
+ };
16
+ }
17
+ });
@@ -1,4 +1,4 @@
1
- import type { RegistryScriptInput } from '#nuxt-scripts/types';
1
+ import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import { BingUetOptions } from './schemas.js';
3
3
  export { BingUetOptions };
4
4
  export type BingUetInput = RegistryScriptInput<typeof BingUetOptions, true, false>;
@@ -189,6 +189,10 @@ declare global {
189
189
  uetq: any[] | BingUetQueue;
190
190
  }
191
191
  }
192
+ export interface BingUetConsent {
193
+ /** Push `['consent','update', state]` with the `ad_storage` signal. */
194
+ update: (state: BingUetConsentOptions) => void;
195
+ }
192
196
  export declare function useScriptBingUet<T extends BingUetApi>(_options?: BingUetInput & {
193
197
  onBeforeUetStart?: (uetq: BingUetQueue) => void;
194
- }): import("#nuxt-scripts/types").UseScriptContext<T>;
198
+ }): UseScriptContext<T, BingUetConsent>;
@@ -2,7 +2,7 @@ import { useRegistryScript } from "../utils.js";
2
2
  import { BingUetOptions } from "./schemas.js";
3
3
  export { BingUetOptions };
4
4
  export function useScriptBingUet(_options) {
5
- return useRegistryScript("bingUet", (options) => ({
5
+ const instance = useRegistryScript("bingUet", (options) => ({
6
6
  scriptInput: {
7
7
  src: "https://bat.bing.com/bat.js",
8
8
  crossorigin: false
@@ -25,7 +25,19 @@ export function useScriptBingUet(_options) {
25
25
  clientInit: import.meta.server ? void 0 : () => {
26
26
  const uetq = window.uetq || [];
27
27
  window.uetq = uetq;
28
+ if (options?.defaultConsent) {
29
+ uetq.push("consent", "default", options.defaultConsent);
30
+ }
28
31
  _options?.onBeforeUetStart?.(uetq);
29
32
  }
30
33
  }), _options);
34
+ if (import.meta.client && !instance.consent) {
35
+ instance.consent = {
36
+ update: (state) => {
37
+ ;
38
+ instance.proxy.uetq.push("consent", "update", state);
39
+ }
40
+ };
41
+ }
42
+ return instance;
31
43
  }
@@ -98,10 +98,6 @@ export declare function extractBlueskyPostId(url: string): {
98
98
  actor: string;
99
99
  rkey: string;
100
100
  } | undefined;
101
- /**
102
- * Proxy a Bluesky image URL through the server
103
- */
104
- export declare function proxyBlueskyImageUrl(url: string, proxyEndpoint?: string): string;
105
101
  /**
106
102
  * Format a Bluesky post date for display
107
103
  */
@@ -7,10 +7,6 @@ export function extractBlueskyPostId(url) {
7
7
  return void 0;
8
8
  return { actor: match[1], rkey: match[2] };
9
9
  }
10
- export function proxyBlueskyImageUrl(url, proxyEndpoint = "/_scripts/embed/bluesky-image") {
11
- const separator = proxyEndpoint.includes("?") ? "&" : "?";
12
- return `${proxyEndpoint}${separator}url=${encodeURIComponent(url)}`;
13
- }
14
10
  export function formatBlueskyDate(dateString) {
15
11
  const date = new Date(dateString);
16
12
  const time = date.toLocaleString("en-US", {
@@ -1,4 +1,4 @@
1
- import type { RegistryScriptInput } from '#nuxt-scripts/types';
1
+ import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import { ClarityOptions } from './schemas.js';
3
3
  export { ClarityOptions };
4
4
  type ClarityFunctions = ((fn: 'start', options?: {
@@ -25,4 +25,8 @@ declare global {
25
25
  }
26
26
  }
27
27
  export type ClarityInput = RegistryScriptInput<typeof ClarityOptions>;
28
- export declare function useScriptClarity<T extends ClarityApi>(_options?: ClarityInput): import("#nuxt-scripts/types").UseScriptContext<T>;
28
+ export interface ClarityConsent {
29
+ /** Call `clarity('consent', value)` with either a boolean (default) or Clarity's advanced vector. */
30
+ set: (value: boolean | Record<string, string>) => void;
31
+ }
32
+ export declare function useScriptClarity<T extends ClarityApi>(_options?: ClarityInput): UseScriptContext<T, ClarityConsent>;
@@ -2,7 +2,7 @@ import { useRegistryScript } from "../utils.js";
2
2
  import { ClarityOptions } from "./schemas.js";
3
3
  export { ClarityOptions };
4
4
  export function useScriptClarity(_options) {
5
- return useRegistryScript("clarity", (options) => ({
5
+ const instance = useRegistryScript("clarity", (options) => ({
6
6
  scriptInput: {
7
7
  src: `https://www.clarity.ms/tag/${options.id}`
8
8
  },
@@ -22,6 +22,17 @@ export function useScriptClarity(_options) {
22
22
  window.clarity = window.clarity || function(...params) {
23
23
  (window.clarity.q = window.clarity.q || []).push(params);
24
24
  };
25
+ if (options?.defaultConsent !== void 0)
26
+ window.clarity("consent", options.defaultConsent);
25
27
  }
26
28
  }), _options);
29
+ if (import.meta.client && !instance.consent) {
30
+ instance.consent = {
31
+ set: (value) => {
32
+ ;
33
+ instance.proxy.clarity("consent", value);
34
+ }
35
+ };
36
+ }
37
+ return instance;
27
38
  }
@@ -1,4 +1,4 @@
1
- import type { RegistryScriptInput } from '#nuxt-scripts/types';
1
+ import type { ConsentState, RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import { GoogleAnalyticsOptions } from './schemas.js';
3
3
  export type GtagCustomParams = Record<string, any>;
4
4
  export type ConsentStatus = 'granted' | 'denied';
@@ -58,6 +58,10 @@ export interface GoogleAnalyticsApi {
58
58
  }
59
59
  export { GoogleAnalyticsOptions };
60
60
  export type GoogleAnalyticsInput = RegistryScriptInput<typeof GoogleAnalyticsOptions>;
61
+ export interface GoogleAnalyticsConsent {
62
+ /** Send `gtag('consent','update', state)` with GCMv2 partial state. */
63
+ update: (state: ConsentState) => void;
64
+ }
61
65
  export declare function useScriptGoogleAnalytics<T extends GoogleAnalyticsApi>(_options?: GoogleAnalyticsInput & {
62
66
  onBeforeGtagStart?: (gtag: GTag) => void;
63
- }): import("#nuxt-scripts/types").UseScriptContext<T>;
67
+ }): UseScriptContext<T, GoogleAnalyticsConsent>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { GoogleAnalyticsOptions } from "./schemas.js";
4
4
  export { GoogleAnalyticsOptions };
5
5
  export function useScriptGoogleAnalytics(_options) {
6
- return useRegistryScript(_options?.key || "googleAnalytics", (options) => {
6
+ const instance = useRegistryScript(_options?.key || "googleAnalytics", (options) => {
7
7
  const dataLayerName = options?.l ?? "dataLayer";
8
8
  const w = import.meta.client ? window : {};
9
9
  return {
@@ -24,6 +24,8 @@ export function useScriptGoogleAnalytics(_options) {
24
24
  w.gtag = function() {
25
25
  w[dataLayerName].push(arguments);
26
26
  };
27
+ if (options?.defaultConsent)
28
+ w.gtag("consent", "default", options.defaultConsent);
27
29
  _options?.onBeforeGtagStart?.(w.gtag);
28
30
  w.gtag("js", /* @__PURE__ */ new Date());
29
31
  if (options?.id) {
@@ -32,4 +34,13 @@ export function useScriptGoogleAnalytics(_options) {
32
34
  }
33
35
  };
34
36
  }, _options);
37
+ if (import.meta.client && !instance.consent) {
38
+ instance.consent = {
39
+ update: (state) => {
40
+ ;
41
+ instance.proxy.gtag("consent", "update", state);
42
+ }
43
+ };
44
+ }
45
+ return instance;
35
46
  }
@@ -1,4 +1,4 @@
1
- import type { NuxtUseScriptOptions, RegistryScriptInput, UseFunctionType, UseScriptContext } from '#nuxt-scripts/types';
1
+ import type { ConsentState, NuxtUseScriptOptions, RegistryScriptInput, UseFunctionType, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import type { GTag } from './google-analytics.js';
3
3
  import { GoogleTagManagerOptions } from './schemas.js';
4
4
  /**
@@ -68,6 +68,10 @@ declare global {
68
68
  }
69
69
  export { GoogleTagManagerOptions };
70
70
  export type GoogleTagManagerInput = RegistryScriptInput<typeof GoogleTagManagerOptions>;
71
+ export interface GoogleTagManagerConsent {
72
+ /** Push `['consent','update', state]` onto dataLayer with GCMv2 partial state. */
73
+ update: (state: ConsentState) => void;
74
+ }
71
75
  /**
72
76
  * Hook to use Google Tag Manager in Nuxt applications
73
77
  */
@@ -77,4 +81,4 @@ export declare function useScriptGoogleTagManager<T extends GoogleTagManagerApi>
77
81
  * Allows for custom initialization or configuration
78
82
  */
79
83
  onBeforeGtmStart?: (gtag: DataLayerPush) => void;
80
- }): UseScriptContext<UseFunctionType<NuxtUseScriptOptions<T>, T>>;
84
+ }): UseScriptContext<UseFunctionType<NuxtUseScriptOptions<T>, T>, GoogleTagManagerConsent>;
@@ -54,5 +54,14 @@ export function useScriptGoogleTagManager(options) {
54
54
  if (gtag)
55
55
  options.onBeforeGtmStart(gtag);
56
56
  }
57
- return instance;
57
+ const typed = instance;
58
+ if (import.meta.client && !typed.consent) {
59
+ typed.consent = {
60
+ update: (state) => {
61
+ ;
62
+ typed.proxy.dataLayer.push(["consent", "update", state]);
63
+ }
64
+ };
65
+ }
66
+ return typed;
58
67
  }
@@ -1,4 +1,5 @@
1
1
  import { scriptsPrefix, useRegistryScript } from "#nuxt-scripts/utils";
2
+ import { useScriptProxyUrl } from "../composables/useScriptProxyUrl.js";
2
3
  import { GravatarOptions } from "./schemas.js";
3
4
  export { GravatarOptions } from "./schemas.js";
4
5
  export function useScriptGravatar(_options) {
@@ -6,13 +7,11 @@ export function useScriptGravatar(_options) {
6
7
  const size = options?.size ?? 80;
7
8
  const defaultImg = options?.default ?? "mp";
8
9
  const rating = options?.rating ?? "g";
9
- const buildQuery = (overrides) => {
10
- const params = new URLSearchParams();
11
- params.set("s", String(overrides?.size ?? size));
12
- params.set("d", overrides?.default ?? defaultImg);
13
- params.set("r", overrides?.rating ?? rating);
14
- return params.toString();
15
- };
10
+ const buildQuery = (overrides) => ({
11
+ s: overrides?.size ?? size,
12
+ d: overrides?.default ?? defaultImg,
13
+ r: overrides?.rating ?? rating
14
+ });
16
15
  return {
17
16
  scriptInput: {
18
17
  src: "https://secure.gravatar.com/js/gprofiles.js"
@@ -21,13 +20,11 @@ export function useScriptGravatar(_options) {
21
20
  scriptOptions: {
22
21
  use: () => {
23
22
  const prefix = scriptsPrefix();
23
+ const proxyUrl = useScriptProxyUrl();
24
+ const path = `${prefix}/proxy/gravatar`;
24
25
  return {
25
- getAvatarUrl: (hash, overrides) => {
26
- return `${prefix}/proxy/gravatar?hash=${encodeURIComponent(hash)}&${buildQuery(overrides)}`;
27
- },
28
- getAvatarUrlFromEmail: (email, overrides) => {
29
- return `${prefix}/proxy/gravatar?email=${encodeURIComponent(email)}&${buildQuery(overrides)}`;
30
- }
26
+ getAvatarUrl: (hash, overrides) => proxyUrl(path, { hash, ...buildQuery(overrides) }),
27
+ getAvatarUrlFromEmail: (email, overrides) => proxyUrl(path, { email, ...buildQuery(overrides) })
31
28
  };
32
29
  }
33
30
  }
@@ -1,12 +1,18 @@
1
- import type { RegistryScriptInput } from '#nuxt-scripts/types';
1
+ import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import { MatomoAnalyticsOptions } from './schemas.js';
3
3
  export { MatomoAnalyticsOptions };
4
4
  export type MatomoAnalyticsInput = RegistryScriptInput<typeof MatomoAnalyticsOptions, false, false>;
5
- interface MatomoAnalyticsApi {
5
+ export interface MatomoAnalyticsApi {
6
6
  _paq: unknown[];
7
7
  }
8
8
  declare global {
9
9
  interface Window extends MatomoAnalyticsApi {
10
10
  }
11
11
  }
12
- export declare function useScriptMatomoAnalytics<T extends MatomoAnalyticsApi>(_options?: MatomoAnalyticsInput): import("#nuxt-scripts/types").UseScriptContext<T>;
12
+ export interface MatomoConsent {
13
+ /** Push `setConsentGiven`. Requires `defaultConsent: 'required' | 'given'` at registration to have an effect. */
14
+ give: () => void;
15
+ /** Push `forgetConsentGiven`. Requires `defaultConsent: 'required' | 'given'` at registration to have an effect. */
16
+ forget: () => void;
17
+ }
18
+ export declare function useScriptMatomoAnalytics<T extends MatomoAnalyticsApi>(_options?: MatomoAnalyticsInput): UseScriptContext<T, MatomoConsent>;
@@ -5,7 +5,7 @@ import { useRegistryScript } from "../utils.js";
5
5
  import { MatomoAnalyticsOptions } from "./schemas.js";
6
6
  export { MatomoAnalyticsOptions };
7
7
  export function useScriptMatomoAnalytics(_options) {
8
- return useRegistryScript("matomoAnalytics", (options) => {
8
+ const instance = useRegistryScript("matomoAnalytics", (options) => {
9
9
  const normalizedCloudId = options?.cloudId ? withoutTrailingSlash(withoutProtocol(options.cloudId)) : void 0;
10
10
  const origin = options?.matomoUrl ? options.matomoUrl : `https://cdn.matomo.cloud/${normalizedCloudId}/`;
11
11
  const _paq = import.meta.client ? window._paq = window._paq || [] : [];
@@ -30,6 +30,12 @@ export function useScriptMatomoAnalytics(_options) {
30
30
  }
31
31
  },
32
32
  clientInit: import.meta.server ? void 0 : () => {
33
+ if (options?.defaultConsent === "required") {
34
+ _paq.push(["requireConsent"]);
35
+ } else if (options?.defaultConsent === "given") {
36
+ _paq.push(["requireConsent"]);
37
+ _paq.push(["setConsentGiven"]);
38
+ }
33
39
  if (options?.enableLinkTracking) {
34
40
  _paq.push(["enableLinkTracking"]);
35
41
  }
@@ -59,4 +65,25 @@ export function useScriptMatomoAnalytics(_options) {
59
65
  }
60
66
  };
61
67
  }, _options);
68
+ if (import.meta.client && !instance.consent) {
69
+ const requiresConsent = _options?.defaultConsent === "required" || _options?.defaultConsent === "given";
70
+ const warnIfUnsafe = import.meta.dev ? (method) => {
71
+ if (!requiresConsent) {
72
+ logger.warn(`matomo consent.${method}() is a no-op unless \`defaultConsent: 'required'\` or \`'given'\` is set at registration.`);
73
+ }
74
+ } : () => {
75
+ };
76
+ const paq = instance.proxy._paq;
77
+ instance.consent = {
78
+ give: () => {
79
+ warnIfUnsafe("give");
80
+ paq.push(["setConsentGiven"]);
81
+ },
82
+ forget: () => {
83
+ warnIfUnsafe("forget");
84
+ paq.push(["forgetConsentGiven"]);
85
+ }
86
+ };
87
+ }
88
+ return instance;
62
89
  }
@@ -1,4 +1,4 @@
1
- import type { RegistryScriptInput } from '#nuxt-scripts/types';
1
+ import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import { MetaPixelOptions } from './schemas.js';
3
3
  type StandardEvents = 'AddPaymentInfo' | 'AddToCart' | 'AddToWishlist' | 'CompleteRegistration' | 'Contact' | 'CustomizeProduct' | 'Donate' | 'FindLocation' | 'InitiateCheckout' | 'Lead' | 'Purchase' | 'Schedule' | 'Search' | 'StartTrial' | 'SubmitApplication' | 'Subscribe' | 'ViewContent';
4
4
  interface EventObjectProperties {
@@ -38,4 +38,10 @@ declare global {
38
38
  }
39
39
  export { MetaPixelOptions };
40
40
  export type MetaPixelInput = RegistryScriptInput<typeof MetaPixelOptions, true, false>;
41
- export declare function useScriptMetaPixel<T extends MetaPixelApi>(_options?: MetaPixelInput): import("#nuxt-scripts/types").UseScriptContext<T>;
41
+ export interface MetaPixelConsent {
42
+ /** Call `fbq('consent','grant')`. */
43
+ grant: () => void;
44
+ /** Call `fbq('consent','revoke')`. */
45
+ revoke: () => void;
46
+ }
47
+ export declare function useScriptMetaPixel<T extends MetaPixelApi>(_options?: MetaPixelInput): UseScriptContext<T, MetaPixelConsent>;
@@ -2,7 +2,7 @@ import { useRegistryScript } from "../utils.js";
2
2
  import { MetaPixelOptions } from "./schemas.js";
3
3
  export { MetaPixelOptions };
4
4
  export function useScriptMetaPixel(_options) {
5
- return useRegistryScript("metaPixel", (options) => ({
5
+ const instance = useRegistryScript("metaPixel", (options) => ({
6
6
  scriptInput: {
7
7
  src: "https://connect.facebook.net/en_US/fbevents.js",
8
8
  crossorigin: false
@@ -27,8 +27,17 @@ export function useScriptMetaPixel(_options) {
27
27
  fbq.loaded = true;
28
28
  fbq.version = "2.0";
29
29
  fbq.queue = [];
30
+ if (options?.defaultConsent)
31
+ fbq("consent", options.defaultConsent === "granted" ? "grant" : "revoke");
30
32
  fbq("init", options?.id);
31
33
  fbq("track", "PageView");
32
34
  }
33
35
  }), _options);
36
+ if (import.meta.client && !instance.consent) {
37
+ instance.consent = {
38
+ grant: () => instance.proxy.fbq("consent", "grant"),
39
+ revoke: () => instance.proxy.fbq("consent", "revoke")
40
+ };
41
+ }
42
+ return instance;
34
43
  }
@@ -1,4 +1,4 @@
1
- import type { RegistryScriptInput } from '#nuxt-scripts/types';
1
+ import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import { MixpanelAnalyticsOptions } from './schemas.js';
3
3
  export { MixpanelAnalyticsOptions };
4
4
  export type MixpanelAnalyticsInput = RegistryScriptInput<typeof MixpanelAnalyticsOptions>;
@@ -12,6 +12,10 @@ export interface MixpanelAnalyticsApi {
12
12
  };
13
13
  register: (properties: Record<string, any>) => void;
14
14
  init: (token: string, config?: Record<string, any>) => void;
15
+ /** Opt the user in to tracking. Available after the real SDK loads. */
16
+ opt_in_tracking?: () => void;
17
+ /** Opt the user out of tracking. Available after the real SDK loads. */
18
+ opt_out_tracking?: () => void;
15
19
  };
16
20
  }
17
21
  declare global {
@@ -19,4 +23,10 @@ declare global {
19
23
  mixpanel: MixpanelAnalyticsApi['mixpanel'];
20
24
  }
21
25
  }
22
- export declare function useScriptMixpanelAnalytics<T extends MixpanelAnalyticsApi>(_options?: MixpanelAnalyticsInput): import("#nuxt-scripts/types").UseScriptContext<T>;
26
+ export interface MixpanelConsent {
27
+ /** Call `mixpanel.opt_in_tracking()`. */
28
+ optIn: () => void;
29
+ /** Call `mixpanel.opt_out_tracking()`. For boot-time opt-out, use `defaultConsent: 'opt-out'` instead. */
30
+ optOut: () => void;
31
+ }
32
+ export declare function useScriptMixpanelAnalytics<T extends MixpanelAnalyticsApi>(_options?: MixpanelAnalyticsInput): UseScriptContext<T, MixpanelConsent>;