@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,10 +1,10 @@
1
1
  import { useRegistryScript } from "../utils.js";
2
2
  import { MixpanelAnalyticsOptions } from "./schemas.js";
3
3
  export { MixpanelAnalyticsOptions };
4
- const methods = ["track", "identify", "reset", "register"];
4
+ const methods = ["track", "identify", "reset", "register", "opt_in_tracking", "opt_out_tracking"];
5
5
  const peopleMethods = ["set"];
6
6
  export function useScriptMixpanelAnalytics(_options) {
7
- return useRegistryScript("mixpanelAnalytics", (options) => {
7
+ const instance = useRegistryScript("mixpanelAnalytics", (options) => {
8
8
  return {
9
9
  scriptInput: {
10
10
  src: "https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js"
@@ -38,9 +38,21 @@ export function useScriptMixpanelAnalytics(_options) {
38
38
  mp._i.push([token, config, name]);
39
39
  };
40
40
  }
41
- if (options?.token)
42
- mp.init(options.token);
41
+ if (options?.token) {
42
+ const optOutByDefault = options?.defaultConsent === "opt-out";
43
+ mp.init(options.token, optOutByDefault ? { opt_out_tracking_by_default: true } : void 0);
44
+ if (options?.defaultConsent === "opt-in") {
45
+ mp.opt_in_tracking?.();
46
+ }
47
+ }
43
48
  }
44
49
  };
45
50
  }, _options);
51
+ if (import.meta.client && !instance.consent) {
52
+ instance.consent = {
53
+ optIn: () => instance.proxy.mixpanel.opt_in_tracking?.(),
54
+ optOut: () => instance.proxy.mixpanel.opt_out_tracking?.()
55
+ };
56
+ }
57
+ return instance;
46
58
  }
@@ -1,4 +1,4 @@
1
- import type { RegistryScriptInput } from '#nuxt-scripts/types';
1
+ import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import type { PostHog, PostHogConfig } from 'posthog-js';
3
3
  import { PostHogOptions } from './schemas.js';
4
4
  export { PostHogOptions };
@@ -22,4 +22,10 @@ declare global {
22
22
  }[];
23
23
  }
24
24
  }
25
- export declare function useScriptPostHog<T extends PostHogApi>(_options?: PostHogInput): import("#nuxt-scripts/types").UseScriptContext<T>;
25
+ export interface PostHogConsent {
26
+ /** Call `posthog.opt_in_capturing()`. */
27
+ optIn: () => void;
28
+ /** Call `posthog.opt_out_capturing()`. For boot-time opt-out, use `defaultConsent: 'opt-out'` instead. */
29
+ optOut: () => void;
30
+ }
31
+ export declare function useScriptPostHog<T extends PostHogApi>(_options?: PostHogInput): UseScriptContext<T, PostHogConsent>;
@@ -3,7 +3,7 @@ import { useRegistryScript } from "../utils.js";
3
3
  import { PostHogOptions } from "./schemas.js";
4
4
  export { PostHogOptions };
5
5
  export function useScriptPostHog(_options) {
6
- return useRegistryScript("posthog", (options) => {
6
+ const instance = useRegistryScript("posthog", (options) => {
7
7
  return {
8
8
  scriptMode: "npm",
9
9
  // Use NPM mode - no external script tag
@@ -55,13 +55,17 @@ export function useScriptPostHog(_options) {
55
55
  config.capture_pageleave = options.capturePageleave;
56
56
  if (typeof options?.disableSessionRecording === "boolean")
57
57
  config.disable_session_recording = options.disableSessionRecording;
58
- const instance = posthog.init(options.apiKey, config);
59
- if (!instance) {
58
+ if (options?.defaultConsent === "opt-out")
59
+ config.opt_out_capturing_by_default = true;
60
+ const instance2 = posthog.init(options.apiKey, config);
61
+ if (!instance2) {
60
62
  logger.error("PostHog init returned undefined - initialization failed");
61
63
  delete window._posthogQueue;
62
64
  return void 0;
63
65
  }
64
- window.posthog = instance;
66
+ window.posthog = instance2;
67
+ if (options?.defaultConsent === "opt-in")
68
+ instance2.opt_in_capturing?.();
65
69
  if (window._posthogQueue && window._posthogQueue.length > 0) {
66
70
  window._posthogQueue.forEach((q) => window.posthog[q.prop]?.(...q.args));
67
71
  delete window._posthogQueue;
@@ -76,4 +80,11 @@ export function useScriptPostHog(_options) {
76
80
  }
77
81
  };
78
82
  }, _options);
83
+ if (import.meta.client && !instance.consent) {
84
+ instance.consent = {
85
+ optIn: () => instance.proxy.posthog?.opt_in_capturing?.(),
86
+ optOut: () => instance.proxy.posthog?.opt_out_capturing?.()
87
+ };
88
+ }
89
+ return instance;
79
90
  }
@@ -21,6 +21,13 @@ export declare const ClarityOptions: import("valibot").ObjectSchema<{
21
21
  * @see https://learn.microsoft.com/en-us/clarity/setup-clarity
22
22
  */
23
23
  readonly id: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 10, undefined>]>;
24
+ /**
25
+ * Default consent state applied before Clarity starts.
26
+ * - `boolean` - enable / disable cookies.
27
+ * - `Record<string, string>` - advanced consent vector (see Clarity docs).
28
+ * @see https://learn.microsoft.com/en-us/clarity/setup-and-installation/cookie-consent
29
+ */
30
+ readonly defaultConsent: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").BooleanSchema<undefined>, import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").StringSchema<undefined>, undefined>], undefined>, undefined>;
24
31
  }, undefined>;
25
32
  export declare const CloudflareWebAnalyticsOptions: import("valibot").ObjectSchema<{
26
33
  /**
@@ -267,6 +274,21 @@ export declare const GoogleAnalyticsOptions: import("valibot").ObjectSchema<{
267
274
  * @see https://developers.google.com/analytics/devguides/collection/gtagjs/setting-up-gtag#rename_the_data_layer
268
275
  */
269
276
  readonly l: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
277
+ /**
278
+ * Default GCMv2 consent state fired as `gtag('consent', 'default', ...)` before `gtag('js', ...)`.
279
+ * @see https://developers.google.com/tag-platform/security/guides/consent
280
+ */
281
+ readonly defaultConsent: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
282
+ readonly ad_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
283
+ readonly ad_user_data: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
284
+ readonly ad_personalization: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
285
+ readonly analytics_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
286
+ readonly functionality_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
287
+ readonly personalization_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
288
+ readonly security_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
289
+ readonly wait_for_update: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
290
+ readonly region: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
291
+ }, undefined>, undefined>;
270
292
  }, undefined>;
271
293
  export declare const GoogleMapsOptions: import("valibot").ObjectSchema<{
272
294
  /**
@@ -533,6 +555,14 @@ export declare const MatomoAnalyticsOptions: import("valibot").ObjectSchema<{
533
555
  * @default true
534
556
  */
535
557
  readonly watch: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
558
+ /**
559
+ * Default tracking-consent state applied BEFORE the tracker is initialised.
560
+ * - `'required'` — call `requireConsent` without granting (user must opt in later).
561
+ * - `'given'` — call `requireConsent` then `setConsentGiven`.
562
+ * - `'not-required'` — no consent gating (default Matomo behaviour).
563
+ * @see https://developer.matomo.org/guides/tracking-consent
564
+ */
565
+ readonly defaultConsent: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"required", undefined>, import("valibot").LiteralSchema<"given", undefined>, import("valibot").LiteralSchema<"not-required", undefined>], undefined>, undefined>;
536
566
  }, undefined>;
537
567
  export declare const MetaPixelOptions: import("valibot").ObjectSchema<{
538
568
  /**
@@ -540,6 +570,12 @@ export declare const MetaPixelOptions: import("valibot").ObjectSchema<{
540
570
  * @see https://developers.facebook.com/docs/meta-pixel/get-started
541
571
  */
542
572
  readonly id: import("valibot").UnionSchema<[import("valibot").StringSchema<undefined>, import("valibot").NumberSchema<undefined>], undefined>;
573
+ /**
574
+ * Default consent state. `'granted'` fires `fbq('consent', 'grant')`,
575
+ * `'denied'` fires `fbq('consent', 'revoke')`, both called before `fbq('init', id)`.
576
+ * @see https://www.facebook.com/business/help/1151321516677370
577
+ */
578
+ readonly defaultConsent: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
543
579
  }, undefined>;
544
580
  export declare const NpmOptions: import("valibot").ObjectSchema<{
545
581
  /**
@@ -630,6 +666,13 @@ export declare const PostHogOptions: import("valibot").ObjectSchema<{
630
666
  * @see https://posthog.com/docs/libraries/js#config
631
667
  */
632
668
  readonly config: import("valibot").OptionalSchema<import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").AnySchema, undefined>, undefined>;
669
+ /**
670
+ * Default capture-consent state for PostHog.
671
+ * - `'opt-out'`: passed as `opt_out_capturing_by_default: true` to `posthog.init`, so capturing is suppressed from the first event.
672
+ * - `'opt-in'`: applied after `posthog.init` via `posthog.opt_in_capturing()` on the returned instance.
673
+ * @see https://posthog.com/docs/privacy/opting-out
674
+ */
675
+ readonly defaultConsent: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"opt-in", undefined>, import("valibot").LiteralSchema<"opt-out", undefined>], undefined>, undefined>;
633
676
  }, undefined>;
634
677
  export declare const RedditPixelOptions: import("valibot").ObjectSchema<{
635
678
  /**
@@ -703,6 +746,13 @@ export declare const MixpanelAnalyticsOptions: import("valibot").ObjectSchema<{
703
746
  * @see https://docs.mixpanel.com/docs/tracking-methods/sdks/javascript#1-initialize-the-library
704
747
  */
705
748
  readonly token: import("valibot").StringSchema<undefined>;
749
+ /**
750
+ * Default tracking-consent state for Mixpanel.
751
+ * - `'opt-out'`: passed as `opt_out_tracking_by_default: true` to `mixpanel.init`, so tracking is suppressed from the first call.
752
+ * - `'opt-in'`: queued via `mixpanel.push(['opt_in_tracking'])` so the real SDK runs it immediately after load.
753
+ * @see https://docs.mixpanel.com/docs/privacy/opt-out-of-tracking
754
+ */
755
+ readonly defaultConsent: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"opt-in", undefined>, import("valibot").LiteralSchema<"opt-out", undefined>], undefined>, undefined>;
706
756
  }, undefined>;
707
757
  export declare const BingUetOptions: import("valibot").ObjectSchema<{
708
758
  /**
@@ -715,6 +765,13 @@ export declare const BingUetOptions: import("valibot").ObjectSchema<{
715
765
  * @default true
716
766
  */
717
767
  readonly enableAutoSpaTracking: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
768
+ /**
769
+ * Default consent state fired as `uetq.push('consent', 'default', ...)` before UET init.
770
+ * @see https://help.ads.microsoft.com/#apex/ads/en/60119/1-500
771
+ */
772
+ readonly defaultConsent: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
773
+ readonly ad_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
774
+ }, undefined>, undefined>;
718
775
  }, undefined>;
719
776
  export declare const SegmentOptions: import("valibot").ObjectSchema<{
720
777
  /**
@@ -857,6 +914,14 @@ export declare const TikTokPixelOptions: import("valibot").ObjectSchema<{
857
914
  * @default true
858
915
  */
859
916
  readonly trackPageView: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
917
+ /**
918
+ * Default consent state, applied before `ttq('init', id)`.
919
+ * - `'granted'` fires `ttq.grantConsent()`
920
+ * - `'denied'` fires `ttq.revokeConsent()`
921
+ * - `'hold'` fires `ttq.holdConsent()` to defer until an explicit update
922
+ * @see https://business-api.tiktok.com/portal/docs?id=1739585600931842
923
+ */
924
+ readonly defaultConsent: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>, import("valibot").LiteralSchema<"hold", undefined>], undefined>, undefined>;
860
925
  }, undefined>;
861
926
  export declare const UmamiAnalyticsOptions: import("valibot").ObjectSchema<{
862
927
  /**
@@ -1,4 +1,16 @@
1
1
  import { any, array, boolean, custom, literal, minLength, number, object, optional, pipe, record, string, union } from "valibot";
2
+ const consentCategoryValue = union([literal("granted"), literal("denied")]);
3
+ const gcmConsentState = object({
4
+ ad_storage: optional(consentCategoryValue),
5
+ ad_user_data: optional(consentCategoryValue),
6
+ ad_personalization: optional(consentCategoryValue),
7
+ analytics_storage: optional(consentCategoryValue),
8
+ functionality_storage: optional(consentCategoryValue),
9
+ personalization_storage: optional(consentCategoryValue),
10
+ security_storage: optional(consentCategoryValue),
11
+ wait_for_update: optional(number()),
12
+ region: optional(array(string()))
13
+ });
2
14
  export const BlueskyEmbedOptions = object({
3
15
  /**
4
16
  * The Bluesky post URL to embed.
@@ -21,7 +33,14 @@ export const ClarityOptions = object({
21
33
  * The Clarity token.
22
34
  * @see https://learn.microsoft.com/en-us/clarity/setup-clarity
23
35
  */
24
- id: pipe(string(), minLength(10))
36
+ id: pipe(string(), minLength(10)),
37
+ /**
38
+ * Default consent state applied before Clarity starts.
39
+ * - `boolean` - enable / disable cookies.
40
+ * - `Record<string, string>` - advanced consent vector (see Clarity docs).
41
+ * @see https://learn.microsoft.com/en-us/clarity/setup-and-installation/cookie-consent
42
+ */
43
+ defaultConsent: optional(union([boolean(), record(string(), string())]))
25
44
  });
26
45
  export const CloudflareWebAnalyticsOptions = object({
27
46
  /**
@@ -264,7 +283,12 @@ export const GoogleAnalyticsOptions = object({
264
283
  * @default 'dataLayer'
265
284
  * @see https://developers.google.com/analytics/devguides/collection/gtagjs/setting-up-gtag#rename_the_data_layer
266
285
  */
267
- l: optional(string())
286
+ l: optional(string()),
287
+ /**
288
+ * Default GCMv2 consent state fired as `gtag('consent', 'default', ...)` before `gtag('js', ...)`.
289
+ * @see https://developers.google.com/tag-platform/security/guides/consent
290
+ */
291
+ defaultConsent: optional(gcmConsentState)
268
292
  });
269
293
  export const GoogleMapsOptions = object({
270
294
  /**
@@ -527,14 +551,28 @@ export const MatomoAnalyticsOptions = object({
527
551
  * Automatically track page views on route change.
528
552
  * @default true
529
553
  */
530
- watch: optional(boolean())
554
+ watch: optional(boolean()),
555
+ /**
556
+ * Default tracking-consent state applied BEFORE the tracker is initialised.
557
+ * - `'required'` — call `requireConsent` without granting (user must opt in later).
558
+ * - `'given'` — call `requireConsent` then `setConsentGiven`.
559
+ * - `'not-required'` — no consent gating (default Matomo behaviour).
560
+ * @see https://developer.matomo.org/guides/tracking-consent
561
+ */
562
+ defaultConsent: optional(union([literal("required"), literal("given"), literal("not-required")]))
531
563
  });
532
564
  export const MetaPixelOptions = object({
533
565
  /**
534
566
  * Your Meta (Facebook) Pixel ID.
535
567
  * @see https://developers.facebook.com/docs/meta-pixel/get-started
536
568
  */
537
- id: union([string(), number()])
569
+ id: union([string(), number()]),
570
+ /**
571
+ * Default consent state. `'granted'` fires `fbq('consent', 'grant')`,
572
+ * `'denied'` fires `fbq('consent', 'revoke')`, both called before `fbq('init', id)`.
573
+ * @see https://www.facebook.com/business/help/1151321516677370
574
+ */
575
+ defaultConsent: optional(union([literal("granted"), literal("denied")]))
538
576
  });
539
577
  export const NpmOptions = object({
540
578
  /**
@@ -627,7 +665,14 @@ export const PostHogOptions = object({
627
665
  * Additional PostHog configuration options passed directly to `posthog.init()`.
628
666
  * @see https://posthog.com/docs/libraries/js#config
629
667
  */
630
- config: optional(record(string(), any()))
668
+ config: optional(record(string(), any())),
669
+ /**
670
+ * Default capture-consent state for PostHog.
671
+ * - `'opt-out'`: passed as `opt_out_capturing_by_default: true` to `posthog.init`, so capturing is suppressed from the first event.
672
+ * - `'opt-in'`: applied after `posthog.init` via `posthog.opt_in_capturing()` on the returned instance.
673
+ * @see https://posthog.com/docs/privacy/opting-out
674
+ */
675
+ defaultConsent: optional(union([literal("opt-in"), literal("opt-out")]))
631
676
  });
632
677
  export const RedditPixelOptions = object({
633
678
  /**
@@ -700,7 +745,14 @@ export const MixpanelAnalyticsOptions = object({
700
745
  * Your Mixpanel project token.
701
746
  * @see https://docs.mixpanel.com/docs/tracking-methods/sdks/javascript#1-initialize-the-library
702
747
  */
703
- token: string()
748
+ token: string(),
749
+ /**
750
+ * Default tracking-consent state for Mixpanel.
751
+ * - `'opt-out'`: passed as `opt_out_tracking_by_default: true` to `mixpanel.init`, so tracking is suppressed from the first call.
752
+ * - `'opt-in'`: queued via `mixpanel.push(['opt_in_tracking'])` so the real SDK runs it immediately after load.
753
+ * @see https://docs.mixpanel.com/docs/privacy/opt-out-of-tracking
754
+ */
755
+ defaultConsent: optional(union([literal("opt-in"), literal("opt-out")]))
704
756
  });
705
757
  export const BingUetOptions = object({
706
758
  /**
@@ -712,7 +764,14 @@ export const BingUetOptions = object({
712
764
  * Enable automatic SPA page tracking.
713
765
  * @default true
714
766
  */
715
- enableAutoSpaTracking: optional(boolean())
767
+ enableAutoSpaTracking: optional(boolean()),
768
+ /**
769
+ * Default consent state fired as `uetq.push('consent', 'default', ...)` before UET init.
770
+ * @see https://help.ads.microsoft.com/#apex/ads/en/60119/1-500
771
+ */
772
+ defaultConsent: optional(object({
773
+ ad_storage: optional(consentCategoryValue)
774
+ }))
716
775
  });
717
776
  export const SegmentOptions = object({
718
777
  /**
@@ -807,7 +866,15 @@ export const TikTokPixelOptions = object({
807
866
  * Whether to automatically track a page view on initialization.
808
867
  * @default true
809
868
  */
810
- trackPageView: optional(boolean())
869
+ trackPageView: optional(boolean()),
870
+ /**
871
+ * Default consent state, applied before `ttq('init', id)`.
872
+ * - `'granted'` fires `ttq.grantConsent()`
873
+ * - `'denied'` fires `ttq.revokeConsent()`
874
+ * - `'hold'` fires `ttq.holdConsent()` to defer until an explicit update
875
+ * @see https://business-api.tiktok.com/portal/docs?id=1739585600931842
876
+ */
877
+ defaultConsent: optional(union([literal("granted"), literal("denied"), literal("hold")]))
811
878
  });
812
879
  export const UmamiAnalyticsOptions = object({
813
880
  /**
@@ -1,4 +1,4 @@
1
- import type { RegistryScriptInput } from '#nuxt-scripts/types';
1
+ import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import { TikTokPixelOptions } from './schemas.js';
3
3
  type StandardEvents = 'ViewContent' | 'ClickButton' | 'Search' | 'AddToWishlist' | 'AddToCart' | 'InitiateCheckout' | 'AddPaymentInfo' | 'CompletePayment' | 'PlaceAnOrder' | 'Contact' | 'Download' | 'SubmitForm' | 'CompleteRegistration' | 'Subscribe';
4
4
  interface EventProperties {
@@ -29,6 +29,12 @@ export interface TikTokPixelApi {
29
29
  push: TtqFns;
30
30
  loaded: boolean;
31
31
  queue: any[];
32
+ /** Opt user in to tracking. Queued before the script loads; live once `events.js` binds. */
33
+ grantConsent: () => void;
34
+ /** Opt user out of tracking. Queued before the script loads; live once `events.js` binds. */
35
+ revokeConsent: () => void;
36
+ /** Defer consent until an explicit grant/revoke. Queued before the script loads; live once `events.js` binds. */
37
+ holdConsent: () => void;
32
38
  };
33
39
  }
34
40
  declare global {
@@ -38,4 +44,12 @@ declare global {
38
44
  }
39
45
  export { TikTokPixelOptions };
40
46
  export type TikTokPixelInput = RegistryScriptInput<typeof TikTokPixelOptions, true, false>;
41
- export declare function useScriptTikTokPixel<T extends TikTokPixelApi>(_options?: TikTokPixelInput): import("#nuxt-scripts/types").UseScriptContext<T>;
47
+ export interface TikTokPixelConsent {
48
+ /** Call `ttq.grantConsent()`. */
49
+ grant: () => void;
50
+ /** Call `ttq.revokeConsent()`. */
51
+ revoke: () => void;
52
+ /** Call `ttq.holdConsent()` to defer the decision. */
53
+ hold: () => void;
54
+ }
55
+ export declare function useScriptTikTokPixel<T extends TikTokPixelApi>(_options?: TikTokPixelInput): UseScriptContext<T, TikTokPixelConsent>;
@@ -3,7 +3,7 @@ import { useRegistryScript } from "../utils.js";
3
3
  import { TikTokPixelOptions } from "./schemas.js";
4
4
  export { TikTokPixelOptions };
5
5
  export function useScriptTikTokPixel(_options) {
6
- return useRegistryScript("tiktokPixel", (options) => ({
6
+ const instance = useRegistryScript("tiktokPixel", (options) => ({
7
7
  scriptInput: {
8
8
  src: withQuery("https://analytics.tiktok.com/i18n/pixel/events.js", {
9
9
  sdkid: options?.id,
@@ -29,6 +29,19 @@ export function useScriptTikTokPixel(_options) {
29
29
  ttq.push = ttq;
30
30
  ttq.loaded = true;
31
31
  ttq.queue = [];
32
+ const consentMethods = ["grantConsent", "revokeConsent", "holdConsent"];
33
+ for (const name of consentMethods) {
34
+ ;
35
+ ttq[name] = function(...params) {
36
+ ttq.queue.push([name, ...params]);
37
+ };
38
+ }
39
+ if (options?.defaultConsent === "granted")
40
+ ttq.grantConsent();
41
+ else if (options?.defaultConsent === "denied")
42
+ ttq.revokeConsent();
43
+ else if (options?.defaultConsent === "hold")
44
+ ttq.holdConsent();
32
45
  if (options?.id) {
33
46
  ttq("init", options.id);
34
47
  if (options?.trackPageView !== false) {
@@ -37,4 +50,12 @@ export function useScriptTikTokPixel(_options) {
37
50
  }
38
51
  }
39
52
  }), _options);
53
+ if (import.meta.client && !instance.consent) {
54
+ instance.consent = {
55
+ grant: () => instance.proxy.ttq.grantConsent(),
56
+ revoke: () => instance.proxy.ttq.revokeConsent(),
57
+ hold: () => instance.proxy.ttq.holdConsent()
58
+ };
59
+ }
60
+ return instance;
40
61
  }
@@ -49,10 +49,6 @@ export interface XEmbedTweetData {
49
49
  };
50
50
  }
51
51
  export type XEmbedInput = RegistryScriptInput<typeof XEmbedOptions, false, false>;
52
- /**
53
- * Proxy an X/Twitter image URL through the server
54
- */
55
- export declare function proxyXImageUrl(url: string, proxyEndpoint?: string): string;
56
52
  /**
57
53
  * Format a tweet date for display
58
54
  */
@@ -1,9 +1,5 @@
1
1
  import { XEmbedOptions } from "./schemas.js";
2
2
  export { XEmbedOptions };
3
- export function proxyXImageUrl(url, proxyEndpoint = "/_scripts/embed/x-image") {
4
- const separator = proxyEndpoint.includes("?") ? "&" : "?";
5
- return `${proxyEndpoint}${separator}url=${encodeURIComponent(url)}`;
6
- }
7
3
  export function formatTweetDate(dateString) {
8
4
  const date = new Date(dateString);
9
5
  const time = date.toLocaleString("en-US", {
@@ -1,2 +1,2 @@
1
- declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Buffer<ArrayBufferLike>>>;
2
2
  export default _default;
@@ -1,16 +1,2 @@
1
- declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
2
- uri: string;
3
- cid: string;
4
- author: Record<string, any>;
5
- record: Record<string, any>;
6
- embed?: Record<string, any>;
7
- likeCount: number;
8
- repostCount: number;
9
- replyCount: number;
10
- quoteCount: number;
11
- indexedAt: string;
12
- labels: Array<{
13
- val: string;
14
- }>;
15
- }>>;
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Record<string, any>>>;
16
2
  export default _default;
@@ -1,7 +1,20 @@
1
1
  import { createError, defineEventHandler, getQuery, setHeader } from "h3";
2
- import { $fetch } from "ofetch";
2
+ import { useRuntimeConfig } from "nitropack/runtime";
3
+ import { createCachedJsonFetch } from "./utils/cached-upstream.js";
4
+ import { rewriteBlueskyPostImages } from "./utils/embed-rewriters.js";
3
5
  import { withSigning } from "./utils/withSigning.js";
4
6
  const BSKY_POST_URL_RE = /^https:\/\/bsky\.app\/profile\/([^/]+)\/post\/([^/?]+)$/;
7
+ const EMBED_BSKY_SUFFIX_RE = /\/embed\/bluesky$/;
8
+ const cachedProfileFetch = createCachedJsonFetch(
9
+ "nuxt-scripts-bsky-profile",
10
+ 86400,
11
+ (url) => url
12
+ );
13
+ const cachedPostFetch = createCachedJsonFetch(
14
+ "nuxt-scripts-bsky-post",
15
+ 600,
16
+ (url) => url
17
+ );
5
18
  export default withSigning(defineEventHandler(async (event) => {
6
19
  const query = getQuery(event);
7
20
  const postUrl = query.url;
@@ -21,7 +34,7 @@ export default withSigning(defineEventHandler(async (event) => {
21
34
  const [, actor, rkey] = match;
22
35
  let did = actor;
23
36
  if (!actor.startsWith("did:")) {
24
- const profile = await $fetch(
37
+ const profile = await cachedProfileFetch(
25
38
  `https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(actor)}`
26
39
  ).catch((error) => {
27
40
  throw createError({
@@ -32,7 +45,7 @@ export default withSigning(defineEventHandler(async (event) => {
32
45
  did = profile.did;
33
46
  }
34
47
  const uri = `at://${did}/app.bsky.feed.post/${rkey}`;
35
- const response = await $fetch(
48
+ const response = await cachedPostFetch(
36
49
  `https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=${encodeURIComponent(uri)}&depth=0&parentHeight=0`
37
50
  ).catch((error) => {
38
51
  throw createError({
@@ -46,7 +59,7 @@ export default withSigning(defineEventHandler(async (event) => {
46
59
  statusMessage: "Post not found"
47
60
  });
48
61
  }
49
- const post = response.thread.post;
62
+ const post = structuredClone(response.thread.post);
50
63
  const hasOptOut = post.labels?.some((l) => l.val === "!no-unauthenticated") || post.author?.labels?.some((l) => l.val === "!no-unauthenticated");
51
64
  if (hasOptOut) {
52
65
  throw createError({
@@ -54,6 +67,11 @@ export default withSigning(defineEventHandler(async (event) => {
54
67
  statusMessage: "Author has opted out of external embedding"
55
68
  });
56
69
  }
70
+ const handlerPath = event.path?.split("?")[0] || "";
71
+ const prefix = handlerPath.replace(EMBED_BSKY_SUFFIX_RE, "") || "/_scripts";
72
+ const imagePath = `${prefix}/embed/bluesky-image`;
73
+ const secret = useRuntimeConfig(event)["nuxt-scripts"]?.proxySecret;
74
+ rewriteBlueskyPostImages(post, imagePath, secret);
57
75
  setHeader(event, "Content-Type", "application/json");
58
76
  setHeader(event, "Cache-Control", "public, max-age=600, s-maxage=600");
59
77
  return post;
@@ -1,8 +1,13 @@
1
1
  import { createError, defineEventHandler, getQuery, setHeader } from "h3";
2
2
  import { useRuntimeConfig } from "nitropack/runtime";
3
- import { $fetch } from "ofetch";
4
3
  import { withQuery } from "ufo";
4
+ import { createCachedJsonFetch } from "./utils/cached-upstream.js";
5
5
  import { withSigning } from "./utils/withSigning.js";
6
+ const cachedGeocodeFetch = createCachedJsonFetch(
7
+ "nuxt-scripts-geocode",
8
+ 2592e3,
9
+ (url) => url
10
+ );
6
11
  export default withSigning(defineEventHandler(async (event) => {
7
12
  const runtimeConfig = useRuntimeConfig();
8
13
  const privateConfig = runtimeConfig["nuxt-scripts"]?.googleMapsGeocodeProxy;
@@ -19,10 +24,8 @@ export default withSigning(defineEventHandler(async (event) => {
19
24
  ...safeQuery,
20
25
  key: apiKey
21
26
  });
22
- const data = await $fetch(geocodeUrl, {
23
- headers: {
24
- "User-Agent": "Nuxt Scripts Google Geocode Proxy"
25
- }
27
+ const data = await cachedGeocodeFetch(geocodeUrl, {
28
+ headers: { "User-Agent": "Nuxt Scripts Google Geocode Proxy" }
26
29
  }).catch((error) => {
27
30
  throw createError({
28
31
  statusCode: error.statusCode || 500,
@@ -1,2 +1,2 @@
1
- declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Buffer<ArrayBufferLike>>>;
2
2
  export default _default;
@@ -1,8 +1,11 @@
1
1
  import { createError, defineEventHandler, getQuery, setHeader } from "h3";
2
2
  import { useRuntimeConfig } from "nitropack/runtime";
3
- import { $fetch } from "ofetch";
4
3
  import { withQuery } from "ufo";
4
+ import { createCachedBinaryFetch } from "./utils/cached-upstream.js";
5
+ import { PAGE_TOKEN_PARAM, PAGE_TOKEN_TS_PARAM, SIG_PARAM } from "./utils/sign-constants.js";
5
6
  import { withSigning } from "./utils/withSigning.js";
7
+ const cachedMapFetch = createCachedBinaryFetch("nuxt-scripts-static-map", 604800);
8
+ const STRIP_PARAMS = /* @__PURE__ */ new Set([SIG_PARAM, PAGE_TOKEN_PARAM, PAGE_TOKEN_TS_PARAM, "key"]);
6
9
  export default withSigning(defineEventHandler(async (event) => {
7
10
  const runtimeConfig = useRuntimeConfig();
8
11
  const publicConfig = runtimeConfig.public["nuxt-scripts"]?.googleStaticMapsProxy;
@@ -21,15 +24,17 @@ export default withSigning(defineEventHandler(async (event) => {
21
24
  });
22
25
  }
23
26
  const query = getQuery(event);
24
- const { key: _clientKey, ...safeQuery } = query;
27
+ const safeQuery = {};
28
+ for (const [k, v] of Object.entries(query)) {
29
+ if (!STRIP_PARAMS.has(k))
30
+ safeQuery[k] = v;
31
+ }
25
32
  const googleMapsUrl = withQuery("https://maps.googleapis.com/maps/api/staticmap", {
26
33
  ...safeQuery,
27
34
  key: apiKey
28
35
  });
29
- const response = await $fetch.raw(googleMapsUrl, {
30
- headers: {
31
- "User-Agent": "Nuxt Scripts Google Static Maps Proxy"
32
- }
36
+ const result = await cachedMapFetch(googleMapsUrl, {
37
+ headers: { "User-Agent": "Nuxt Scripts Google Static Maps Proxy" }
33
38
  }).catch((error) => {
34
39
  throw createError({
35
40
  statusCode: error.statusCode || 500,
@@ -37,8 +42,8 @@ export default withSigning(defineEventHandler(async (event) => {
37
42
  });
38
43
  });
39
44
  const cacheMaxAge = publicConfig.cacheMaxAge || 3600;
40
- setHeader(event, "Content-Type", response.headers.get("content-type") || "image/png");
45
+ setHeader(event, "Content-Type", result.contentType || "image/png");
41
46
  setHeader(event, "Cache-Control", `public, max-age=${cacheMaxAge}, s-maxage=${cacheMaxAge}`);
42
47
  setHeader(event, "Vary", "Accept-Encoding");
43
- return response._data;
48
+ return result.body;
44
49
  }));
@@ -1,2 +1,2 @@
1
- declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Buffer<ArrayBufferLike>>>;
2
2
  export default _default;