@nuxt/scripts 1.0.6 → 1.1.0

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 (73) 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/{YlRaZkPa.js → 1wb58MKb.js} +1 -1
  4. package/dist/devtools-client/_nuxt/{CZp-OuKP.js → BbLmrp_o.js} +1 -1
  5. package/dist/devtools-client/_nuxt/{DyyF3uw_.js → Cx46cS8a.js} +1 -1
  6. package/dist/devtools-client/_nuxt/{Djr8-0jV.js → D-M51CV3.js} +1 -1
  7. package/dist/devtools-client/_nuxt/D4HTNcLU.js +188 -0
  8. package/dist/devtools-client/_nuxt/{W-xcwSaJ.js → DU3BlAm5.js} +1 -1
  9. package/dist/devtools-client/_nuxt/{GzJXdFDa.js → DiaY4J4_.js} +1 -1
  10. package/dist/devtools-client/_nuxt/builds/latest.json +1 -1
  11. package/dist/devtools-client/_nuxt/builds/meta/0b4ab733-07a6-40b2-b25e-aca95fa55188.json +1 -0
  12. package/dist/devtools-client/_nuxt/error-404.D2T48gBS.css +1 -0
  13. package/dist/devtools-client/_nuxt/error-500.sMTZJbsP.css +1 -0
  14. package/dist/devtools-client/docs/index.html +1 -1
  15. package/dist/devtools-client/first-party/index.html +1 -1
  16. package/dist/devtools-client/index.html +1 -1
  17. package/dist/devtools-client/registry/index.html +1 -1
  18. package/dist/module.d.mts +7 -1
  19. package/dist/module.d.ts +7 -1
  20. package/dist/module.json +1 -1
  21. package/dist/module.mjs +266 -34
  22. package/dist/registry.mjs +76 -5
  23. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +36 -5
  24. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsGeoJson.d.vue.ts +2 -2
  25. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsGeoJson.vue.d.ts +2 -2
  26. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.d.vue.ts +2 -2
  27. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.vue.d.ts +2 -2
  28. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.d.vue.ts +2 -2
  29. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.vue.d.ts +2 -2
  30. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.d.vue.ts +2 -2
  31. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.vue.d.ts +2 -2
  32. package/dist/runtime/components/ScriptCalendlyInlineWidget.d.vue.ts +59 -0
  33. package/dist/runtime/components/ScriptCalendlyInlineWidget.vue +79 -0
  34. package/dist/runtime/components/ScriptCalendlyInlineWidget.vue.d.ts +59 -0
  35. package/dist/runtime/components/ScriptPayPalButtons.d.vue.ts +1 -1
  36. package/dist/runtime/components/ScriptPayPalButtons.vue.d.ts +1 -1
  37. package/dist/runtime/components/ScriptPayPalMessages.d.vue.ts +1 -1
  38. package/dist/runtime/components/ScriptPayPalMessages.vue.d.ts +1 -1
  39. package/dist/runtime/composables/useScript.js +48 -0
  40. package/dist/runtime/debug.d.ts +1 -0
  41. package/dist/runtime/debug.js +1 -0
  42. package/dist/runtime/devtools-standalone-bridge.client.js +3 -1
  43. package/dist/runtime/logger.js +4 -0
  44. package/dist/runtime/registry/_gcm-consent.d.ts +14 -0
  45. package/dist/runtime/registry/_gcm-consent.js +24 -0
  46. package/dist/runtime/registry/ahrefs-analytics.d.ts +39 -0
  47. package/dist/runtime/registry/ahrefs-analytics.js +18 -0
  48. package/dist/runtime/registry/calendly.d.ts +76 -0
  49. package/dist/runtime/registry/calendly.js +63 -0
  50. package/dist/runtime/registry/google-analytics.d.ts +5 -6
  51. package/dist/runtime/registry/google-analytics.js +4 -10
  52. package/dist/runtime/registry/google-tag-manager.d.ts +5 -6
  53. package/dist/runtime/registry/google-tag-manager.js +13 -18
  54. package/dist/runtime/registry/linkedin-insight.d.ts +35 -0
  55. package/dist/runtime/registry/linkedin-insight.js +49 -0
  56. package/dist/runtime/registry/schemas.d.ts +124 -0
  57. package/dist/runtime/registry/schemas.js +115 -2
  58. package/dist/runtime/registry/tiktok-pixel.d.ts +28 -2
  59. package/dist/runtime/registry/tiktok-pixel.js +18 -1
  60. package/dist/runtime/registry/usercentrics.d.ts +85 -0
  61. package/dist/runtime/registry/usercentrics.js +54 -0
  62. package/dist/runtime/server/proxy-handler.js +13 -4
  63. package/dist/runtime/types.d.ts +36 -1
  64. package/dist/runtime/utils.d.ts +8 -2
  65. package/dist/runtime/utils.js +5 -1
  66. package/dist/stats.mjs +19 -0
  67. package/dist/types-source.mjs +274 -9
  68. package/dist/types.d.mts +1 -1
  69. package/package.json +9 -6
  70. package/dist/devtools-client/_nuxt/DtB6K90V.js +0 -188
  71. package/dist/devtools-client/_nuxt/builds/meta/57f43375-6c5e-40af-a5bc-9479e5286aac.json +0 -1
  72. package/dist/devtools-client/_nuxt/error-404.DsZYSkA7.css +0 -1
  73. package/dist/devtools-client/_nuxt/error-500.Cqipl6_j.css +0 -1
@@ -1,3 +1,22 @@
1
+ export declare const gcmConsentState: import("valibot").ObjectSchema<{
2
+ readonly ad_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
3
+ readonly ad_user_data: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
4
+ readonly ad_personalization: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
5
+ readonly analytics_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
6
+ readonly functionality_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
7
+ readonly personalization_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
8
+ readonly security_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
9
+ readonly wait_for_update: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
10
+ readonly region: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
11
+ }, undefined>;
12
+ export declare const AhrefsAnalyticsOptions: import("valibot").ObjectSchema<{
13
+ /**
14
+ * Your Ahrefs Web Analytics project key. Set as the `data-key` attribute
15
+ * on the loaded `analytics.js` script tag.
16
+ * @see https://ahrefs.com/web-analytics
17
+ */
18
+ readonly key: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>]>;
19
+ }, undefined>;
1
20
  export declare const BlueskyEmbedOptions: import("valibot").ObjectSchema<{
2
21
  /**
3
22
  * The Bluesky post URL to embed.
@@ -808,6 +827,105 @@ export declare const BingUetOptions: import("valibot").ObjectSchema<{
808
827
  readonly ad_storage: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"granted", undefined>, import("valibot").LiteralSchema<"denied", undefined>], undefined>, undefined>;
809
828
  }, undefined>, undefined>;
810
829
  }, undefined>;
830
+ export declare const LinkedInInsightOptions: import("valibot").ObjectSchema<{
831
+ /**
832
+ * Your LinkedIn Insight Tag Partner ID, or an array of Partner IDs to push
833
+ * onto window._linkedin_data_partner_ids. The first ID is used as the
834
+ * primary _linkedin_partner_id global.
835
+ * @example '111143'
836
+ * @example ['111143', '111154']
837
+ * @see https://www.linkedin.com/help/lms/answer/a417869/access-your-linkedin-partner-id
838
+ */
839
+ readonly id: import("valibot").UnionSchema<[import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>]>, import("valibot").SchemaWithPipe<readonly [import("valibot").ArraySchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>]>, undefined>, import("valibot").MinLengthAction<string[], 1, undefined>]>], undefined>;
840
+ /**
841
+ * Optional page-load event ID for Conversions API deduplication. Assigned
842
+ * to window._linkedin_event_id BEFORE the Insight Tag base code runs. Must
843
+ * match the eventId sent with the corresponding server-side Conversions
844
+ * API event.
845
+ *
846
+ * Per-event conversion deduplication uses the per-call event_id passed to
847
+ * lintrk('track', { conversion_id, event_id }) instead.
848
+ * @see https://learn.microsoft.com/en-us/linkedin/marketing/conversions/deduplication
849
+ */
850
+ readonly eventId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
851
+ /**
852
+ * Auto-fire lintrk('track') on Vue Router route changes (SPA virtual page
853
+ * views). When true, suppresses the script's built-in auto-page-view via
854
+ * window._wait_for_lintrk and tracks every navigation including the
855
+ * initial page through Nuxt's page:finish hook. When false, the script
856
+ * fires its own page-view exactly once on load and SPA navigations are
857
+ * not tracked unless lintrk('track') is called manually.
858
+ * @default false
859
+ */
860
+ readonly enableAutoSpaTracking: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
861
+ }, undefined>;
862
+ export declare const UsercentricsOptions: import("valibot").ObjectSchema<{
863
+ /**
864
+ * Your Usercentrics CMP v3 ruleset ID. Find it in the admin under
865
+ * Implementation; the snippet's `data-ruleset-id` value.
866
+ */
867
+ readonly rulesetId: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>]>;
868
+ /**
869
+ * Inject the Usercentrics autoblocker (`autoblocker.js`) ahead of the loader.
870
+ * Enable when your ruleset relies on Auto Blocking (vs. Manual Blocking) to
871
+ * gate third-party scripts before consent is granted.
872
+ * @default false
873
+ */
874
+ readonly autoblocker: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
875
+ /**
876
+ * Override the language displayed by the CMP UI (BCP-47 code, e.g. `'en'`, `'de'`).
877
+ */
878
+ readonly language: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
879
+ }, undefined>;
880
+ export declare const CalendlyOptions: import("valibot").ObjectSchema<{
881
+ /**
882
+ * The Calendly event URL to embed.
883
+ * Required for inline, popup, and badge widgets when called via the composable.
884
+ * @example 'https://calendly.com/your-name/30min'
885
+ * @see https://help.calendly.com/hc/en-us/articles/223147027
886
+ */
887
+ readonly url: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
888
+ /**
889
+ * Pre-fill invitee fields on the booking form.
890
+ * @see https://help.calendly.com/hc/en-us/articles/360020052833
891
+ */
892
+ readonly prefill: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
893
+ readonly name: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
894
+ readonly email: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
895
+ readonly firstName: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
896
+ readonly lastName: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
897
+ /** Custom answers keyed by `a1`, `a2`, ... matching custom question order. */
898
+ readonly customAnswers: import("valibot").OptionalSchema<import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").StringSchema<undefined>, undefined>, undefined>;
899
+ }, undefined>, undefined>;
900
+ /**
901
+ * UTM parameters appended to the booking URL for marketing attribution.
902
+ * @see https://help.calendly.com/hc/en-us/articles/360020052833
903
+ */
904
+ readonly utm: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
905
+ readonly utmCampaign: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
906
+ readonly utmSource: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
907
+ readonly utmMedium: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
908
+ readonly utmContent: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
909
+ readonly utmTerm: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
910
+ }, undefined>, undefined>;
911
+ /**
912
+ * Theme and layout overrides applied to the booking page.
913
+ * @see https://help.calendly.com/hc/en-us/articles/360020052833
914
+ */
915
+ readonly pageSettings: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
916
+ readonly backgroundColor: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
917
+ readonly hideEventTypeDetails: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
918
+ readonly hideLandingPageDetails: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
919
+ readonly primaryColor: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
920
+ readonly textColor: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
921
+ }, undefined>, undefined>;
922
+ /**
923
+ * CSS selector for the element that hosts the inline widget.
924
+ * Required when the widget is initialised inline; the element should have a
925
+ * minimum height of around 700px so the booking iframe is fully visible.
926
+ */
927
+ readonly parentElement: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
928
+ }, undefined>;
811
929
  export declare const SegmentOptions: import("valibot").ObjectSchema<{
812
930
  /**
813
931
  * Your Segment write key.
@@ -957,6 +1075,12 @@ export declare const TikTokPixelOptions: import("valibot").ObjectSchema<{
957
1075
  * @see https://business-api.tiktok.com/portal/docs?id=1739585600931842
958
1076
  */
959
1077
  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>;
1078
+ /**
1079
+ * Data residency region for the Pixel SDK.
1080
+ * - `'global'` (default) -> `analytics.tiktok.com`
1081
+ * - `'us'` -> `analytics.us.tiktok.com` (US enterprise data residency)
1082
+ */
1083
+ readonly region: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"global", undefined>, import("valibot").LiteralSchema<"us", undefined>], undefined>, undefined>;
960
1084
  }, undefined>;
961
1085
  export declare const UmamiAnalyticsOptions: import("valibot").ObjectSchema<{
962
1086
  /**
@@ -1,6 +1,6 @@
1
1
  import { any, array, boolean, custom, literal, minLength, number, object, optional, pipe, record, string, union } from "valibot";
2
2
  const consentCategoryValue = union([literal("granted"), literal("denied")]);
3
- const gcmConsentState = object({
3
+ export const gcmConsentState = object({
4
4
  ad_storage: optional(consentCategoryValue),
5
5
  ad_user_data: optional(consentCategoryValue),
6
6
  ad_personalization: optional(consentCategoryValue),
@@ -11,6 +11,14 @@ const gcmConsentState = object({
11
11
  wait_for_update: optional(number()),
12
12
  region: optional(array(string()))
13
13
  });
14
+ export const AhrefsAnalyticsOptions = object({
15
+ /**
16
+ * Your Ahrefs Web Analytics project key. Set as the `data-key` attribute
17
+ * on the loaded `analytics.js` script tag.
18
+ * @see https://ahrefs.com/web-analytics
19
+ */
20
+ key: pipe(string(), minLength(1))
21
+ });
14
22
  export const BlueskyEmbedOptions = object({
15
23
  /**
16
24
  * The Bluesky post URL to embed.
@@ -778,6 +786,105 @@ export const BingUetOptions = object({
778
786
  ad_storage: optional(consentCategoryValue)
779
787
  }))
780
788
  });
789
+ export const LinkedInInsightOptions = object({
790
+ /**
791
+ * Your LinkedIn Insight Tag Partner ID, or an array of Partner IDs to push
792
+ * onto window._linkedin_data_partner_ids. The first ID is used as the
793
+ * primary _linkedin_partner_id global.
794
+ * @example '111143'
795
+ * @example ['111143', '111154']
796
+ * @see https://www.linkedin.com/help/lms/answer/a417869/access-your-linkedin-partner-id
797
+ */
798
+ id: union([pipe(string(), minLength(1)), pipe(array(pipe(string(), minLength(1))), minLength(1))]),
799
+ /**
800
+ * Optional page-load event ID for Conversions API deduplication. Assigned
801
+ * to window._linkedin_event_id BEFORE the Insight Tag base code runs. Must
802
+ * match the eventId sent with the corresponding server-side Conversions
803
+ * API event.
804
+ *
805
+ * Per-event conversion deduplication uses the per-call event_id passed to
806
+ * lintrk('track', { conversion_id, event_id }) instead.
807
+ * @see https://learn.microsoft.com/en-us/linkedin/marketing/conversions/deduplication
808
+ */
809
+ eventId: optional(string()),
810
+ /**
811
+ * Auto-fire lintrk('track') on Vue Router route changes (SPA virtual page
812
+ * views). When true, suppresses the script's built-in auto-page-view via
813
+ * window._wait_for_lintrk and tracks every navigation including the
814
+ * initial page through Nuxt's page:finish hook. When false, the script
815
+ * fires its own page-view exactly once on load and SPA navigations are
816
+ * not tracked unless lintrk('track') is called manually.
817
+ * @default false
818
+ */
819
+ enableAutoSpaTracking: optional(boolean())
820
+ });
821
+ export const UsercentricsOptions = object({
822
+ /**
823
+ * Your Usercentrics CMP v3 ruleset ID. Find it in the admin under
824
+ * Implementation; the snippet's `data-ruleset-id` value.
825
+ */
826
+ rulesetId: pipe(string(), minLength(1)),
827
+ /**
828
+ * Inject the Usercentrics autoblocker (`autoblocker.js`) ahead of the loader.
829
+ * Enable when your ruleset relies on Auto Blocking (vs. Manual Blocking) to
830
+ * gate third-party scripts before consent is granted.
831
+ * @default false
832
+ */
833
+ autoblocker: optional(boolean()),
834
+ /**
835
+ * Override the language displayed by the CMP UI (BCP-47 code, e.g. `'en'`, `'de'`).
836
+ */
837
+ language: optional(string())
838
+ });
839
+ export const CalendlyOptions = object({
840
+ /**
841
+ * The Calendly event URL to embed.
842
+ * Required for inline, popup, and badge widgets when called via the composable.
843
+ * @example 'https://calendly.com/your-name/30min'
844
+ * @see https://help.calendly.com/hc/en-us/articles/223147027
845
+ */
846
+ url: optional(string()),
847
+ /**
848
+ * Pre-fill invitee fields on the booking form.
849
+ * @see https://help.calendly.com/hc/en-us/articles/360020052833
850
+ */
851
+ prefill: optional(object({
852
+ name: optional(string()),
853
+ email: optional(string()),
854
+ firstName: optional(string()),
855
+ lastName: optional(string()),
856
+ /** Custom answers keyed by `a1`, `a2`, ... matching custom question order. */
857
+ customAnswers: optional(record(string(), string()))
858
+ })),
859
+ /**
860
+ * UTM parameters appended to the booking URL for marketing attribution.
861
+ * @see https://help.calendly.com/hc/en-us/articles/360020052833
862
+ */
863
+ utm: optional(object({
864
+ utmCampaign: optional(string()),
865
+ utmSource: optional(string()),
866
+ utmMedium: optional(string()),
867
+ utmContent: optional(string()),
868
+ utmTerm: optional(string())
869
+ })),
870
+ /**
871
+ * Theme and layout overrides applied to the booking page.
872
+ * @see https://help.calendly.com/hc/en-us/articles/360020052833
873
+ */
874
+ pageSettings: optional(object({
875
+ backgroundColor: optional(string()),
876
+ hideEventTypeDetails: optional(boolean()),
877
+ hideLandingPageDetails: optional(boolean()),
878
+ primaryColor: optional(string()),
879
+ textColor: optional(string())
880
+ })),
881
+ /**
882
+ * CSS selector for the element that hosts the inline widget.
883
+ * Required when the widget is initialised inline; the element should have a
884
+ * minimum height of around 700px so the booking iframe is fully visible.
885
+ */
886
+ parentElement: optional(string())
887
+ });
781
888
  export const SegmentOptions = object({
782
889
  /**
783
890
  * Your Segment write key.
@@ -879,7 +986,13 @@ export const TikTokPixelOptions = object({
879
986
  * - `'hold'` fires `ttq.holdConsent()` to defer until an explicit update
880
987
  * @see https://business-api.tiktok.com/portal/docs?id=1739585600931842
881
988
  */
882
- defaultConsent: optional(union([literal("granted"), literal("denied"), literal("hold")]))
989
+ defaultConsent: optional(union([literal("granted"), literal("denied"), literal("hold")])),
990
+ /**
991
+ * Data residency region for the Pixel SDK.
992
+ * - `'global'` (default) -> `analytics.tiktok.com`
993
+ * - `'us'` -> `analytics.us.tiktok.com` (US enterprise data residency)
994
+ */
995
+ region: optional(union([literal("global"), literal("us")]))
883
996
  });
884
997
  export const UmamiAnalyticsOptions = object({
885
998
  /**
@@ -1,6 +1,6 @@
1
1
  import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
2
  import { TikTokPixelOptions } from './schemas.js';
3
- type StandardEvents = 'ViewContent' | 'ClickButton' | 'Search' | 'AddToWishlist' | 'AddToCart' | 'InitiateCheckout' | 'AddPaymentInfo' | 'CompletePayment' | 'PlaceAnOrder' | 'Contact' | 'Download' | 'SubmitForm' | 'CompleteRegistration' | 'Subscribe';
3
+ type StandardEvents = 'ViewContent' | 'ClickButton' | 'Search' | 'AddToWishlist' | 'AddToCart' | 'InitiateCheckout' | 'AddPaymentInfo' | 'CompletePayment' | 'PlaceAnOrder' | 'Purchase' | 'Contact' | 'Download' | 'SubmitForm' | 'CompleteRegistration' | 'Subscribe' | 'StartTrial' | 'ApplicationApproval' | 'CustomizeProduct' | 'FindLocation' | 'Schedule' | 'SubmitApplication';
4
4
  interface EventProperties {
5
5
  content_id?: string;
6
6
  content_type?: string;
@@ -16,14 +16,38 @@ interface EventProperties {
16
16
  value?: number;
17
17
  description?: string;
18
18
  query?: string;
19
+ /** Order/transaction identifier; complements `event_id` for transaction-level dedup. */
20
+ order_id?: string;
19
21
  [key: string]: any;
20
22
  }
23
+ /**
24
+ * Advanced matching parameters. TikTok requires SHA-256-hashed values for `email`,
25
+ * `phone_number`, `external_id`, and the name/address fields to enable matching.
26
+ * Passing raw values disables matching silently; a dev-mode warning is logged.
27
+ * @see https://business-api.tiktok.com/portal/docs?id=1739585702922241
28
+ */
21
29
  interface IdentifyProperties {
22
30
  email?: string;
23
31
  phone_number?: string;
24
32
  external_id?: string;
33
+ first_name?: string;
34
+ last_name?: string;
35
+ city?: string;
36
+ state?: string;
37
+ country?: string;
38
+ zip_code?: string;
25
39
  }
26
- type TtqFns = ((cmd: 'track', event: StandardEvents | (string & {}), properties?: EventProperties) => void) & ((cmd: 'page') => void) & ((cmd: 'identify', properties: IdentifyProperties) => void) & ((cmd: (string & {}), ...args: any[]) => void);
40
+ interface TrackOptions {
41
+ /** Used to deduplicate events sent from both the browser Pixel and the server-side Events API. */
42
+ event_id?: string;
43
+ /**
44
+ * Sandbox test-event identifier. When set, events route to TikTok's Test Events panel
45
+ * without affecting production reporting.
46
+ */
47
+ test_event_code?: string;
48
+ [key: string]: any;
49
+ }
50
+ type TtqFns = ((cmd: 'track', event: StandardEvents | (string & {}), properties?: EventProperties, options?: TrackOptions) => void) & ((cmd: 'page') => void) & ((cmd: 'identify', properties: IdentifyProperties) => void) & ((cmd: (string & {}), ...args: any[]) => void);
27
51
  export interface TikTokPixelApi {
28
52
  ttq: TtqFns & {
29
53
  push: TtqFns;
@@ -44,6 +68,8 @@ declare global {
44
68
  }
45
69
  export { TikTokPixelOptions };
46
70
  export type TikTokPixelInput = RegistryScriptInput<typeof TikTokPixelOptions, true, false>;
71
+ /** Resolve the Pixel SDK URL for a given data-residency region. */
72
+ export declare function tiktokPixelSrc(region?: 'global' | 'us'): string;
47
73
  export interface TikTokPixelConsent {
48
74
  /** Call `ttq.grantConsent()`. */
49
75
  grant: () => void;
@@ -1,11 +1,26 @@
1
1
  import { withQuery } from "ufo";
2
+ import { logger } from "../logger.js";
2
3
  import { useRegistryScript } from "../utils.js";
3
4
  import { TikTokPixelOptions } from "./schemas.js";
4
5
  export { TikTokPixelOptions };
6
+ export function tiktokPixelSrc(region) {
7
+ return region === "us" ? "https://analytics.us.tiktok.com/i18n/pixel/events.js" : "https://analytics.tiktok.com/i18n/pixel/events.js";
8
+ }
9
+ const SHA256_HEX = /^[a-f0-9]{64}$/i;
10
+ function warnUnhashedIdentify(props) {
11
+ const hashFields = ["email", "phone_number", "external_id", "first_name", "last_name", "city", "state", "country", "zip_code"];
12
+ const offenders = hashFields.filter((f) => {
13
+ const v = props[f];
14
+ return typeof v === "string" && v.length > 0 && !SHA256_HEX.test(v);
15
+ });
16
+ if (offenders.length) {
17
+ logger.withTag("tiktokPixel").warn(`identify() received unhashed value(s) for ${offenders.join(", ")}. TikTok requires SHA-256 hashing for advanced matching; raw values will be ignored. See https://business-api.tiktok.com/portal/docs?id=1739585702922241`);
18
+ }
19
+ }
5
20
  export function useScriptTikTokPixel(_options) {
6
21
  const instance = useRegistryScript("tiktokPixel", (options) => ({
7
22
  scriptInput: {
8
- src: withQuery("https://analytics.tiktok.com/i18n/pixel/events.js", {
23
+ src: withQuery(tiktokPixelSrc(options?.region), {
9
24
  sdkid: options?.id,
10
25
  lib: "ttq"
11
26
  }),
@@ -20,6 +35,8 @@ export function useScriptTikTokPixel(_options) {
20
35
  clientInit: import.meta.server ? void 0 : () => {
21
36
  window.TiktokAnalyticsObject = "ttq";
22
37
  const ttq = window.ttq = function(...params) {
38
+ if (import.meta.dev && params[0] === "identify" && params[1])
39
+ warnUnhashedIdentify(params[1]);
23
40
  if (ttq.callMethod) {
24
41
  ttq.callMethod(...params);
25
42
  } else {
@@ -0,0 +1,85 @@
1
+ import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
2
+ import { UsercentricsOptions } from './schemas.js';
3
+ export { UsercentricsOptions };
4
+ export type UsercentricsInput = RegistryScriptInput<typeof UsercentricsOptions, false, false>;
5
+ export interface UsercentricsCmpEventDetail {
6
+ type: string;
7
+ source?: string;
8
+ [key: string]: any;
9
+ }
10
+ /**
11
+ * The Usercentrics CMP v3 programmatic API exposed on `window.__ucCmp`.
12
+ * Each method returns a Promise resolved once the CMP is ready.
13
+ */
14
+ export interface UsercentricsCmp {
15
+ isInitialized: () => Promise<boolean>;
16
+ isConsentRequired: () => Promise<boolean>;
17
+ showFirstLayer: () => Promise<void>;
18
+ showSecondLayer: () => Promise<void>;
19
+ showServiceDetails: (id: string) => Promise<void>;
20
+ showAutoblockerMoreInfoView: () => Promise<void>;
21
+ closeCmp: () => Promise<void>;
22
+ acceptAllConsents: () => Promise<void>;
23
+ denyAllConsents: () => Promise<void>;
24
+ saveConsents: () => Promise<void>;
25
+ updateCategoriesConsents: (consents: Array<{
26
+ categorySlug: string;
27
+ consent: boolean;
28
+ }>) => Promise<void>;
29
+ updateServicesConsents: (consents: Array<{
30
+ templateId: string;
31
+ consent: boolean;
32
+ }>) => Promise<void>;
33
+ updateTcfConsents: (...args: unknown[]) => Promise<void>;
34
+ refreshScripts: () => Promise<void>;
35
+ clearUserSession: () => Promise<void>;
36
+ getConsentDetails: () => Promise<Record<string, any>>;
37
+ getCmpConfig: () => Promise<Record<string, any>>;
38
+ getActiveLanguage: () => Promise<string>;
39
+ getControllerId: () => Promise<string>;
40
+ changeLanguage: (lang: string) => Promise<void>;
41
+ [key: string]: any;
42
+ }
43
+ export interface UsercentricsApi {
44
+ ucCmp: UsercentricsCmp;
45
+ }
46
+ declare global {
47
+ interface Window {
48
+ __ucCmp?: UsercentricsCmp;
49
+ }
50
+ }
51
+ /**
52
+ * Vendor-native Usercentrics consent helpers exposed on the composable result.
53
+ * Use these to drive `useScript` consent triggers from CMP events.
54
+ */
55
+ export interface UsercentricsConsent {
56
+ /**
57
+ * Resolves once the CMP API is ready (`UC_CMP_API_READY`) or immediately if
58
+ * it already is. Resolves with `window.__ucCmp` so callers can query
59
+ * consent state without polling.
60
+ */
61
+ whenReady: () => Promise<UsercentricsCmp>;
62
+ /**
63
+ * Subscribe to `UC_UI_CMP_EVENT` browser events (the v3 consent change
64
+ * event). Returns a teardown function. The callback receives the event
65
+ * detail, e.g. `{ type: 'ACCEPT_ALL' | 'DENY_ALL' | 'SAVE', ... }`.
66
+ */
67
+ onConsentChange: (cb: (detail: UsercentricsCmpEventDetail, event: Event) => void) => () => void;
68
+ /** Open the privacy settings (first layer banner). */
69
+ showFirstLayer: () => Promise<void> | void;
70
+ /** Open the detailed settings (second layer modal). */
71
+ showSecondLayer: () => Promise<void> | void;
72
+ /** Accept all consents. */
73
+ acceptAll: () => Promise<void> | void;
74
+ /** Reject all consents. */
75
+ denyAll: () => Promise<void> | void;
76
+ }
77
+ /**
78
+ * Load the Usercentrics CMP v3 ("Web CMP") loader and expose typed access to
79
+ * the `window.__ucCmp` programmatic API plus a `consent` helper with
80
+ * `onConsentChange` for wiring consent triggers (`useScript({ trigger: ... })`)
81
+ * to Usercentrics events.
82
+ *
83
+ * @see https://usercentrics.com/knowledge-hub/usercentrics-cmp-v3-migrations/
84
+ */
85
+ export declare function useScriptUsercentrics<T extends UsercentricsApi>(_options?: UsercentricsInput): UseScriptContext<T, UsercentricsConsent>;
@@ -0,0 +1,54 @@
1
+ import { useHead } from "@unhead/vue";
2
+ import { useRegistryScript } from "../utils.js";
3
+ import { UsercentricsOptions } from "./schemas.js";
4
+ export { UsercentricsOptions };
5
+ export function useScriptUsercentrics(_options) {
6
+ const instance = useRegistryScript("usercentrics", (options) => {
7
+ if (import.meta.client && options.autoblocker) {
8
+ useHead({
9
+ script: [{
10
+ src: "https://web.cmp.usercentrics.eu/modules/autoblocker.js",
11
+ tagPosition: "head",
12
+ tagPriority: "high"
13
+ }]
14
+ });
15
+ }
16
+ return {
17
+ scriptInput: {
18
+ "src": "https://web.cmp.usercentrics.eu/ui/loader.js",
19
+ "id": "usercentrics-cmp",
20
+ "data-ruleset-id": options.rulesetId,
21
+ "data-language": options.language,
22
+ "crossorigin": false
23
+ },
24
+ schema: import.meta.dev ? UsercentricsOptions : void 0,
25
+ scriptOptions: {
26
+ use() {
27
+ return { ucCmp: window.__ucCmp };
28
+ }
29
+ }
30
+ };
31
+ }, _options);
32
+ if (import.meta.client && !instance.consent) {
33
+ const whenReady = () => new Promise((resolve) => {
34
+ const onReady = () => {
35
+ window.removeEventListener("UC_CMP_API_READY", onReady);
36
+ resolve(window.__ucCmp);
37
+ };
38
+ window.addEventListener("UC_CMP_API_READY", onReady);
39
+ });
40
+ instance.consent = {
41
+ whenReady,
42
+ onConsentChange(cb) {
43
+ const handler = (e) => cb(e.detail, e);
44
+ window.addEventListener("UC_UI_CMP_EVENT", handler);
45
+ return () => window.removeEventListener("UC_UI_CMP_EVENT", handler);
46
+ },
47
+ showFirstLayer: () => window.__ucCmp?.showFirstLayer?.(),
48
+ showSecondLayer: () => window.__ucCmp?.showSecondLayer?.(),
49
+ acceptAll: () => window.__ucCmp?.acceptAllConsents?.(),
50
+ denyAll: () => window.__ucCmp?.denyAllConsents?.()
51
+ };
52
+ }
53
+ return instance;
54
+ }
@@ -230,7 +230,11 @@ export default defineEventHandler(async (event) => {
230
230
  });
231
231
  log("[proxy] Fetching:", targetUrl);
232
232
  const controller = new AbortController();
233
- const timeoutId = setTimeout(() => controller.abort(), 15e3);
233
+ let timedOut = false;
234
+ const timeoutId = setTimeout(() => {
235
+ timedOut = true;
236
+ controller.abort();
237
+ }, 15e3);
234
238
  let fetchBody;
235
239
  if (passthroughBody) {
236
240
  fetchBody = getRequestWebStream(event);
@@ -252,9 +256,14 @@ export default defineEventHandler(async (event) => {
252
256
  } catch (err) {
253
257
  log("[proxy] Upstream error:", err);
254
258
  throw createError({
255
- statusCode: 502,
256
- statusMessage: "Bad Gateway",
257
- message: `Proxy upstream request failed: ${targetUrl}`
259
+ statusCode: timedOut ? 504 : 502,
260
+ statusMessage: timedOut ? "Gateway Timeout" : "Bad Gateway",
261
+ message: `Proxy upstream request failed: ${targetUrl}`,
262
+ cause: err,
263
+ data: {
264
+ errorName: err?.name,
265
+ errorCode: timedOut ? "TIMEOUT" : err?.code
266
+ }
258
267
  });
259
268
  } finally {
260
269
  clearTimeout(timeoutId);