@nuxt/scripts 1.0.0-beta.19 → 1.0.0-beta.20

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 (55) hide show
  1. package/dist/client/200.html +1 -1
  2. package/dist/client/404.html +1 -1
  3. package/dist/client/_nuxt/{BAII0Gd6.js → 9LJPrOyI.js} +1 -1
  4. package/dist/client/_nuxt/DFEfk2pB.js +162 -0
  5. package/dist/client/_nuxt/{BFIM6xmj.js → DMlY-BNa.js} +1 -1
  6. package/dist/client/_nuxt/{XsmoCkZQ.js → __ZZTkMj.js} +1 -1
  7. package/dist/client/_nuxt/builds/latest.json +1 -1
  8. package/dist/client/_nuxt/builds/meta/8212d4fa-7985-421b-815a-03a886e667d4.json +1 -0
  9. package/dist/client/_nuxt/entry.CACgbLJl.css +1 -0
  10. package/dist/client/_nuxt/error-404.CHeaW3dp.css +1 -0
  11. package/dist/client/_nuxt/error-500.DvOvWme_.css +1 -0
  12. package/dist/client/index.html +1 -1
  13. package/dist/module.d.mts +7 -5
  14. package/dist/module.d.ts +7 -5
  15. package/dist/module.json +1 -1
  16. package/dist/module.mjs +389 -197
  17. package/dist/registry.mjs +5 -2
  18. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +1 -1
  19. package/dist/runtime/components/ScriptYouTubePlayer.vue +2 -1
  20. package/dist/runtime/registry/clarity.d.ts +8 -8
  21. package/dist/runtime/registry/crisp.d.ts +7 -7
  22. package/dist/runtime/registry/databuddy-analytics.js +18 -0
  23. package/dist/runtime/registry/fathom-analytics.d.ts +4 -3
  24. package/dist/runtime/registry/fathom-analytics.js +0 -1
  25. package/dist/runtime/registry/google-analytics.d.ts +1 -1
  26. package/dist/runtime/registry/google-recaptcha.js +1 -1
  27. package/dist/runtime/registry/google-tag-manager.js +1 -1
  28. package/dist/runtime/registry/hotjar.d.ts +1 -1
  29. package/dist/runtime/registry/instagram-embed.js +2 -1
  30. package/dist/runtime/registry/intercom.d.ts +1 -1
  31. package/dist/runtime/registry/meta-pixel.d.ts +1 -1
  32. package/dist/runtime/registry/reddit-pixel.d.ts +2 -1
  33. package/dist/runtime/registry/rybbit-analytics.js +1 -1
  34. package/dist/runtime/registry/schemas.d.ts +6 -0
  35. package/dist/runtime/registry/schemas.js +7 -1
  36. package/dist/runtime/registry/snapchat-pixel.d.ts +1 -1
  37. package/dist/runtime/registry/tiktok-pixel.d.ts +1 -1
  38. package/dist/runtime/registry/x-pixel.d.ts +1 -1
  39. package/dist/runtime/server/gravatar-proxy.js +1 -1
  40. package/dist/runtime/server/instagram-embed-asset.js +2 -1
  41. package/dist/runtime/server/instagram-embed-image.js +2 -1
  42. package/dist/runtime/server/instagram-embed.js +21 -12
  43. package/dist/runtime/server/proxy-handler.js +37 -27
  44. package/dist/runtime/server/utils/privacy.js +14 -7
  45. package/dist/runtime/server/x-embed.js +3 -2
  46. package/dist/runtime/utils.js +7 -3
  47. package/dist/shared/{scripts.Bg4pl9Yo.mjs → scripts.Crpn87WB.mjs} +15 -7
  48. package/dist/stats.mjs +7 -4
  49. package/dist/types-source.mjs +29 -18
  50. package/package.json +14 -14
  51. package/dist/client/_nuxt/8nZpL1GZ.js +0 -162
  52. package/dist/client/_nuxt/builds/meta/4f48c83d-e40d-436a-afd0-3b8e6ac6f303.json +0 -1
  53. package/dist/client/_nuxt/entry.D45OuV0w.css +0 -1
  54. package/dist/client/_nuxt/error-404.Cqp3ffuH.css +0 -1
  55. package/dist/client/_nuxt/error-500.B9hH8BAi.css +0 -1
package/dist/registry.mjs CHANGED
@@ -56,8 +56,7 @@ async function registry(resolve) {
56
56
  {
57
57
  label: "Fathom Analytics",
58
58
  proxy: "fathom",
59
- scriptBundling: false,
60
- // breaks script
59
+ src: "https://cdn.usefathom.com/script.js",
61
60
  category: "analytics",
62
61
  logo: `<svg width="32" height="32" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><circle cx="512" cy="512" r="512" style="fill:#9187ff"/><path d="M558.62 256c-36.31.16-78.78 10-129.45 28.4-170.71 62.15-206.9 139.74-144.79 310.45s139.73 206.89 310.45 144.76S801.74 599.88 739.6 429.16c-43.69-120-95-173.55-181-173.17zm59.1 140.16h26.73a5.33 5.33 0 0 1 5.16 6.72l-59.26 220.48a5.34 5.34 0 0 1-5.15 4h-26.75a5.33 5.33 0 0 1-5.16-6.72l3.6-13.4 2.63-9.75 53-197.38a5.33 5.33 0 0 1 5.14-3.94zM421.79 413.4h10.75a5.33 5.33 0 0 1 5.33 5.33v18a5.33 5.33 0 0 1-5.33 5.33h-9.13a36.76 36.76 0 0 0-5.51.24 4.7 4.7 0 0 0-2.56 1 4.19 4.19 0 0 0-1 1.66 18.91 18.91 0 0 0-.92 6.72v13.67h19.16a5.33 5.33 0 0 1 5.33 5.33v18a5.34 5.34 0 0 1-5.33 5.33h-19.21v108.71a5.34 5.34 0 0 1-5.34 5.34H387a5.33 5.33 0 0 1-5.33-5.34V448.48a36.74 36.74 0 0 1 3.6-16.64 29.76 29.76 0 0 1 9.73-11.16c7.9-5.48 17.62-7.27 26.82-7.31zm82.14 50c16.37 0 30.27 4.65 40.17 13.27s15.47 21.21 15.42 35.59v35.91l-16.11 59.92h-10.24a5.33 5.33 0 0 1-5.33-5.34v-4a39.13 39.13 0 0 1-4.76 3.56c-7.14 4.55-16.85 7.51-29.65 7.51a62.65 62.65 0 0 1-28.52-6.18 40.49 40.49 0 0 1-18.84-19.35 46.81 46.81 0 0 1-4-19.54 40.72 40.72 0 0 1 5.23-21.12 36.78 36.78 0 0 1 13.78-13.18c11.09-6.25 24.75-8.45 38.14-10.24 7.3-1 13.14-1.61 17.64-2.2a42 42 0 0 0 9.2-1.88 3.16 3.16 0 0 0 1.39-.86l.24-.48a6.77 6.77 0 0 0 .16-1.84v-.73a17.24 17.24 0 0 0-5.85-13.6c-3.8-3.31-9.77-5.55-18.07-5.57s-14.64 2.26-19 5.59a17.51 17.51 0 0 0-7.21 12.54 5.33 5.33 0 0 1-5.31 4.86h-22.25a5.33 5.33 0 0 1-5.33-5.57 45.64 45.64 0 0 1 17.6-34c10.47-8.34 24.85-13.12 41.49-13.12zm23.92 80.71c-1.92.48-4 1-6.31 1.45-6.47 1.28-14.29 2.41-21.87 3.48a61 61 0 0 0-14.76 3.65c-4.18 1.75-7.1 4-8.68 6.57a12.12 12.12 0 0 0-1.71 6.54v.2a12.93 12.93 0 0 0 1.32 5.87 11.81 11.81 0 0 0 3.76 4.22c3.41 2.45 9.13 4.14 16.85 4.14 11.95 0 19.52-3.5 24.32-8.32s7-11.56 7.08-19.11v-8.65zm0 0" style="fill:#fff"/></svg>`,
63
62
  import: {
@@ -79,6 +78,8 @@ async function registry(resolve) {
79
78
  {
80
79
  label: "Rybbit Analytics",
81
80
  proxy: "rybbit",
81
+ scriptBundling: false,
82
+ // SDK reads document.currentScript.src to derive API host — analyticsHost config injection handles proxy instead
82
83
  category: "analytics",
83
84
  logo: {
84
85
  light: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 263.33 173.53" width="37.24" height="32"><g><polygon fill="#0a3a3a" points="181.28 171.2 227.21 123.96 261.15 171.2 181.28 171.2"/><path fill="#0a3a3a" d="M261.15,89.05L206.64,2.33l-33.22,17.75-34.61-7.4c2.88,5.56,4.56,12.11,4.56,19.15,0,20.03-13.46,36.26-30.06,36.26-13.66,0-25.17-11-28.83-26.06l-39.92,71.46L2.18,94.19l22.66,77.01h55.81l22.28-54.01v54.01h64.66l-49.95-82.15h143.51Z"/></g><ellipse fill="#0a3a3a" cx="105.94" cy="28.62" rx="12.9" ry="18.88"/></svg>`,
@@ -92,6 +93,7 @@ async function registry(resolve) {
92
93
  {
93
94
  label: "Databuddy Analytics",
94
95
  proxy: "databuddy",
96
+ scriptBundling: () => "https://cdn.databuddy.cc/databuddy.js",
95
97
  category: "analytics",
96
98
  logo: `<svg xmlns="http://www.w3.org/2000/svg" width="56.5" height="32" viewBox="0 0 8 8" shape-rendering="crispEdges"><path d="M0 0h8v8H0z"/><path fill="#fff" d="M1 1h1v6H1zm1 0h4v1H2zm4 1h1v1H6zm0 1h1v1H6zm0 1h1v1H6zm0 1h1v1H6zM2 6h4v1H2zm1-3h1v1H3zm1 1h1v1H4z"/></svg>`,
97
99
  import: {
@@ -426,6 +428,7 @@ async function registry(resolve) {
426
428
  {
427
429
  label: "Umami Analytics",
428
430
  proxy: "umami",
431
+ scriptBundling: () => "https://cloud.umami.is/script.js",
429
432
  category: "analytics",
430
433
  logo: `<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 24 24"><path fill="currentColor" d="M2.203 8.611H.857a.845.845 0 0 0-.841.841v.858a13 13 0 0 0-.016.6c0 6.627 5.373 12 12 12c6.527 0 11.837-5.212 11.996-11.701c0-.025.004-.05.004-.075V9.452a.845.845 0 0 0-.841-.841h-1.346c-1.159-4.329-5.112-7.521-9.805-7.521S3.363 4.282 2.203 8.611m18.444 0H3.37c1.127-3.702 4.57-6.399 8.638-6.399c4.069 0 7.512 2.697 8.639 6.399"/></svg>`,
431
434
  import: {
@@ -355,7 +355,7 @@ const rootAttrs = computed(() => {
355
355
  });
356
356
  });
357
357
  onBeforeUnmount(async () => {
358
- await Promise.all([...mapMarkers.value.entries()].map(([, marker]) => resetMapMarkerMap(marker)));
358
+ await Promise.all(Array.from(mapMarkers.value.entries(), ([, marker]) => resetMapMarkerMap(marker)));
359
359
  mapMarkers.value.clear();
360
360
  map.value?.unbindAll();
361
361
  map.value = void 0;
@@ -30,6 +30,7 @@ const events = [
30
30
  "onError",
31
31
  "onApiChange"
32
32
  ];
33
+ const CAMEL_CASE_RE = /([A-Z])/g;
33
34
  const rootEl = ref();
34
35
  const youtubeEl = ref();
35
36
  const ready = ref(false);
@@ -92,7 +93,7 @@ onMounted(() => {
92
93
  playerVars: props.playerVars,
93
94
  ...props.playerOptions,
94
95
  events: Object.fromEntries(events.map((event) => [event, (e) => {
95
- const emitEventName = event.replace(/([A-Z])/g, "-$1").replace("on-", "").toLowerCase();
96
+ const emitEventName = event.replace(CAMEL_CASE_RE, "-$1").replace("on-", "").toLowerCase();
96
97
  emits(emitEventName, e);
97
98
  if (event === "onReady") {
98
99
  ready.value = true;
@@ -1,19 +1,19 @@
1
1
  import type { RegistryScriptInput } from '#nuxt-scripts/types';
2
2
  import { ClarityOptions } from './schemas.js';
3
3
  export { ClarityOptions };
4
- type ClarityFunctions = ((fn: 'start', options: {
5
- content: boolean;
6
- cookies: string[];
7
- dob: number;
8
- expire: number;
9
- projectId: string;
10
- upload: string;
4
+ type ClarityFunctions = ((fn: 'start', options?: {
5
+ content?: boolean;
6
+ cookies?: string[];
7
+ dob?: number;
8
+ expire?: number;
9
+ projectId?: string;
10
+ upload?: string;
11
11
  }) => void) & ((fn: 'identify', id: string, session?: string, page?: string, userHint?: string) => Promise<{
12
12
  id: string;
13
13
  session: string;
14
14
  page: string;
15
15
  userHint: string;
16
- }>) & ((fn: 'consent', enabled?: boolean) => void) & ((fn: 'set', key: any, value: any) => void) & ((fn: 'event', value: any) => void) & ((fn: 'upgrade', upgradeReason: any) => void) & ((fn: string, ...args: any[]) => void);
16
+ }>) & ((fn: 'consent', enabled?: boolean | Record<string, string>) => void) & ((fn: 'set', key: string, value: string | string[]) => void) & ((fn: 'event', value: string) => void) & ((fn: 'upgrade', upgradeReason: string) => void) & ((fn: (string & {}), ...args: any[]) => void);
17
17
  export interface ClarityApi {
18
18
  clarity: ClarityFunctions & {
19
19
  q: any[];
@@ -4,13 +4,13 @@ export { CrispOptions };
4
4
  export type CrispInput = RegistryScriptInput<typeof CrispOptions, false, false, false>;
5
5
  export interface CrispApi {
6
6
  push: (...args: any[]) => void;
7
- is: (name: 'chat:opened' | 'chat:closed' | 'chat:visible' | 'chat:hidden' | 'chat:small' | 'chat:large' | 'session:ongoing' | 'website:available' | 'overlay:opened' | 'overlay:closed' | string) => boolean;
8
- set: (name: 'message:text' | 'session:data' | 'session:segments' | 'session:event' | 'user:email' | 'user:phone' | 'user:nickname' | 'user:avatar' | 'user:company' | string, value: any) => void;
9
- get: (name: 'chat:unread:count' | 'message:text' | 'session:identifier' | 'session:data' | 'user:email' | 'user:phone' | 'user:nickname' | 'user:avatar' | 'user:company' | string) => any;
10
- do: (name: 'chat:open' | 'chat:close' | 'chat:toggle' | 'chat:show' | 'chat:hide' | 'helpdesk:search' | 'helpdesk:article:open' | 'helpdesk:query' | 'overlay:open' | 'overlay:close' | 'message:send' | 'message:show' | 'message:read' | 'message:thread:start' | 'message:thread:end' | 'session:reset' | 'trigger:run' | string, arg2?: any) => any;
11
- on: (name: 'session:loaded' | 'chat:initiated' | 'chat:opened' | 'chat:closed' | 'message:sent' | 'message:received' | 'message:compose:sent' | 'message:compose:received' | 'user:email:changed' | 'user:phone:changed' | 'user:nickname:changed' | 'user:avatar:changed' | 'website:availability:changed' | 'helpdesk:queried' | string, callback: (...args: any[]) => any) => void;
12
- off: (name: 'session:loaded' | 'chat:initiated' | 'chat:opened' | 'chat:closed' | 'message:sent' | 'message:received' | 'message:compose:sent' | 'message:compose:received' | 'user:email:changed' | 'user:phone:changed' | 'user:nickname:changed' | 'user:avatar:changed' | 'website:availability:changed' | 'helpdesk:queried' | string, callback: (...args: any[]) => any) => void;
13
- config: (options: any) => void;
7
+ is: (name: 'chat:opened' | 'chat:closed' | 'chat:visible' | 'chat:hidden' | 'chat:small' | 'chat:large' | 'session:ongoing' | 'website:available' | 'overlay:opened' | 'overlay:closed' | (string & {})) => boolean;
8
+ set: ((name: 'message:text' | 'user:email' | 'user:phone' | 'user:nickname' | 'user:avatar' | 'user:company', value: string) => void) & ((name: 'session:data', value: [[string, string | number | boolean], ...[string, string | number | boolean][]]) => void) & ((name: 'session:segments', value: string[]) => void) & ((name: 'session:event', value: [[string, Record<string, any>?, string?]]) => void) & ((name: (string & {}), value: any) => void);
9
+ get: ((name: 'chat:unread:count') => number) & ((name: 'message:text' | 'session:identifier' | 'user:email' | 'user:phone' | 'user:nickname' | 'user:avatar' | 'user:company') => string) & ((name: 'session:data', key: string) => string | number | boolean) & ((name: (string & {})) => any);
10
+ do: (name: 'chat:open' | 'chat:close' | 'chat:toggle' | 'chat:show' | 'chat:hide' | 'helpdesk:search' | 'helpdesk:article:open' | 'helpdesk:query' | 'overlay:open' | 'overlay:close' | 'message:send' | 'message:show' | 'message:read' | 'message:thread:start' | 'message:thread:end' | 'session:reset' | 'trigger:run', arg2?: any) => any;
11
+ on: (name: 'session:loaded' | 'chat:initiated' | 'chat:opened' | 'chat:closed' | 'message:sent' | 'message:received' | 'message:compose:sent' | 'message:compose:received' | 'user:email:changed' | 'user:phone:changed' | 'user:nickname:changed' | 'user:avatar:changed' | 'website:availability:changed' | 'helpdesk:queried' | (string & {}), callback: (...args: any[]) => any) => void;
12
+ off: (name: 'session:loaded' | 'chat:initiated' | 'chat:opened' | 'chat:closed' | 'message:sent' | 'message:received' | 'message:compose:sent' | 'message:compose:received' | 'user:email:changed' | 'user:phone:changed' | 'user:nickname:changed' | 'user:avatar:changed' | 'website:availability:changed' | 'helpdesk:queried' | (string & {}), callback: (...args: any[]) => any) => void;
13
+ config: ((name: 'container:index', value: number) => void) & ((name: 'color:theme', value: 'default' | 'amber' | 'black' | 'blue' | 'blue_grey' | 'light_blue' | 'brown' | 'cyan' | 'green' | 'light_green' | 'grey' | 'indigo' | 'orange' | 'deep_orange' | 'pink' | 'purple' | 'deep_purple' | 'red' | 'teal') => void) & ((name: 'position:reverse' | 'hide:on:mobile' | 'hide:on:away' | 'lock:maximized' | 'lock:fullview' | 'show:operator:count' | 'sound:mute', value: boolean) => void) & ((name: (string & {}), value: any) => void);
14
14
  help: () => void;
15
15
  [key: string]: any;
16
16
  }
@@ -53,6 +53,24 @@ export function useScriptDatabuddyAnalytics(_options) {
53
53
  return null;
54
54
  }
55
55
  return window.db || window.databuddy || null;
56
+ },
57
+ // The SDK finds config by searching for a <script> with src containing
58
+ // "/databuddy.js". When first-party bundling rewrites the src to
59
+ // /_scripts/<hash>.js, the lookup fails. Set window.databuddyConfig
60
+ // so the SDK picks up the config regardless of script src.
61
+ clientInit: import.meta.server ? void 0 : () => {
62
+ const cfg = { clientId: options.clientId };
63
+ if (options?.apiUrl)
64
+ cfg.apiUrl = options.apiUrl;
65
+ if (options?.disabled)
66
+ cfg.disabled = options.disabled;
67
+ if (options?.trackScreenViews)
68
+ cfg.trackScreenViews = options.trackScreenViews;
69
+ if (options?.trackPerformance)
70
+ cfg.trackPerformance = options.trackPerformance;
71
+ if (options?.trackSessions)
72
+ cfg.trackSessions = options.trackSessions;
73
+ window.databuddyConfig = cfg;
56
74
  }
57
75
  }
58
76
  };
@@ -12,14 +12,15 @@ export interface FathomAnalyticsApi {
12
12
  isTrackingEnabled: () => boolean;
13
13
  send: (type: string, data: unknown) => void;
14
14
  setSite: (siteId: string) => void;
15
- sideId: string;
15
+ siteId: string;
16
16
  trackPageview: (ctx?: {
17
17
  url: string;
18
18
  referrer?: string;
19
19
  }) => void;
20
20
  trackGoal: (goalId: string, cents: number) => void;
21
- trackEvent: (eventName: string, value: {
22
- _value: number;
21
+ trackEvent: (eventName: string, value?: {
22
+ _value?: number;
23
+ _site_id?: string;
23
24
  }) => void;
24
25
  }
25
26
  declare global {
@@ -5,7 +5,6 @@ export function useScriptFathomAnalytics(_options) {
5
5
  return useRegistryScript("fathomAnalytics", (options) => ({
6
6
  scriptInput: {
7
7
  src: "https://cdn.usefathom.com/script.js",
8
- // can't be bundled
9
8
  // append the data attr's
10
9
  ...Object.entries(options).filter(([key]) => ["site", "spa", "auto", "canonical", "honorDnt"].includes(key)).reduce((acc, [_key, value]) => {
11
10
  const key = _key === "honourDnt" ? "honor-dnt" : _key;
@@ -38,7 +38,7 @@ export interface EventParameters extends GtagCustomParams {
38
38
  }>;
39
39
  [key: string]: any;
40
40
  }
41
- export type DefaultEventName = 'add_payment_info' | 'add_shipping_info' | 'add_to_cart' | 'add_to_wishlist' | 'begin_checkout' | 'purchase' | 'refund' | 'remove_from_cart' | 'select_item' | 'select_promotion' | 'view_cart' | 'view_item' | 'view_item_list' | 'view_promotion' | 'login' | 'sign_up' | 'search' | 'page_view' | 'screen_view' | string;
41
+ export type DefaultEventName = 'add_payment_info' | 'add_shipping_info' | 'add_to_cart' | 'add_to_wishlist' | 'begin_checkout' | 'purchase' | 'refund' | 'remove_from_cart' | 'select_item' | 'select_promotion' | 'view_cart' | 'view_item' | 'view_item_list' | 'view_promotion' | 'login' | 'sign_up' | 'search' | 'page_view' | 'screen_view' | (string & {});
42
42
  export interface GTag {
43
43
  (command: 'js', value: Date): void;
44
44
  (command: 'config', targetId: string, configParams?: ConfigParams): void;
@@ -24,7 +24,7 @@ export function useScriptGoogleRecaptcha(_options) {
24
24
  const w = window;
25
25
  w.grecaptcha = w.grecaptcha || {};
26
26
  const readyFn = function(cb) {
27
- (w.___grecaptcha_cfg = w.___grecaptcha_cfg || {}).fns = (w.___grecaptcha_cfg.fns || []).concat([cb]);
27
+ (w.___grecaptcha_cfg = w.___grecaptcha_cfg || {}).fns = [...w.___grecaptcha_cfg.fns || [], ...[cb]];
28
28
  };
29
29
  w.grecaptcha.ready = w.grecaptcha.ready || readyFn;
30
30
  if (options?.enterprise) {
@@ -41,7 +41,7 @@ export function useScriptGoogleTagManager(options) {
41
41
  if (opts.defaultConsent)
42
42
  gtag("consent", "default", opts.defaultConsent);
43
43
  window[dataLayerName].push({
44
- "gtm.start": (/* @__PURE__ */ new Date()).getTime(),
44
+ "gtm.start": Date.now(),
45
45
  "event": "gtm.js"
46
46
  });
47
47
  }
@@ -2,7 +2,7 @@ import type { RegistryScriptInput } from '#nuxt-scripts/types';
2
2
  import { HotjarOptions } from './schemas.js';
3
3
  export { HotjarOptions };
4
4
  export interface HotjarApi {
5
- hj: ((event: 'identify', userId: string, attributes?: Record<string, any>) => void) & ((event: 'stateChange', path: string) => void) & ((event: 'event', eventName: string) => void) & ((event: string, arg?: string) => void) & ((...params: any[]) => void) & {
5
+ hj: ((event: 'identify', userId: string, attributes?: Record<string, any>) => void) & ((event: 'stateChange', path: string) => void) & ((event: 'vPageView', path: string) => void) & ((event: 'event', eventName: string) => void) & ((event: (string & {}), ...args: any[]) => void) & {
6
6
  q: any[];
7
7
  };
8
8
  }
@@ -1,6 +1,7 @@
1
1
  import { InstagramEmbedOptions } from "./schemas.js";
2
2
  export { InstagramEmbedOptions };
3
+ const INSTAGRAM_SHORTCODE_RE = /instagram\.com\/(?:p|reel|tv)\/([^/?]+)/;
3
4
  export function extractInstagramShortcode(url) {
4
- const match = url.match(/instagram\.com\/(?:p|reel|tv)\/([^/?]+)/);
5
+ const match = url.match(INSTAGRAM_SHORTCODE_RE);
5
6
  return match?.[1];
6
7
  }
@@ -4,7 +4,7 @@ import { IntercomOptions } from './schemas.js';
4
4
  export { IntercomOptions };
5
5
  export type IntercomInput = RegistryScriptInput<typeof IntercomOptions, true, false, false>;
6
6
  export interface IntercomApi {
7
- Intercom: ((event: 'boot', data?: InferInput<typeof IntercomOptions>) => void) & ((event: 'shutdown') => void) & ((event: 'update', options?: InferInput<typeof IntercomOptions>) => void) & ((event: 'hide') => void) & ((event: 'show') => void) & ((event: 'showSpace', spaceName: 'home' | 'messages' | 'help' | 'news' | 'tasks' | 'tickets' | string) => void) & ((event: 'showMessages') => void) & ((event: 'showNewMessage', content?: string) => void) & ((event: 'onHide', fn: () => void) => void) & ((event: 'onShow', fn: () => void) => void) & ((event: 'onUnreadCountChange', fn: () => void) => void) & ((event: 'trackEvent', eventName: string, metadata?: Record<string, any>) => void) & ((event: 'getVisitorId') => Promise<string>) & ((event: 'startTour', tourId: string | number) => void) & ((event: 'showArticle', articleId: string | number) => void) & ((event: 'showNews', newsItemId: string | number) => void) & ((event: 'startSurvey', surveyId: string | number) => void) & ((event: 'startChecklist', checklistId: string | number) => void) & ((event: 'showTicket', ticketId: string | number) => void) & ((event: 'showConversation', conversationId: string | number) => void) & ((event: 'onUserEmailSupplied', fn: () => void) => void) & ((event: string, ...params: any[]) => void);
7
+ Intercom: ((event: 'boot', data?: InferInput<typeof IntercomOptions>) => void) & ((event: 'shutdown') => void) & ((event: 'update', options?: InferInput<typeof IntercomOptions>) => void) & ((event: 'hide') => void) & ((event: 'show') => void) & ((event: 'showSpace', spaceName: 'home' | 'messages' | 'help' | 'news' | 'tasks' | 'tickets' | (string & {})) => void) & ((event: 'showMessages') => void) & ((event: 'showNewMessage', content?: string) => void) & ((event: 'onHide', fn: () => void) => void) & ((event: 'onShow', fn: () => void) => void) & ((event: 'onUnreadCountChange', fn: () => void) => void) & ((event: 'trackEvent', eventName: string, metadata?: Record<string, any>) => void) & ((event: 'getVisitorId') => Promise<string>) & ((event: 'startTour', tourId: string | number) => void) & ((event: 'showArticle', articleId: string | number) => void) & ((event: 'showNews', newsItemId: string | number) => void) & ((event: 'startSurvey', surveyId: string | number) => void) & ((event: 'startChecklist', checklistId: string | number) => void) & ((event: 'showTicket', ticketId: string | number) => void) & ((event: 'showConversation', conversationId: string | number) => void) & ((event: 'onUserEmailSupplied', fn: () => void) => void) & ((event: (string & {}), ...params: any[]) => void);
8
8
  }
9
9
  declare global {
10
10
  interface Window extends IntercomApi {
@@ -15,7 +15,7 @@ interface EventObjectProperties {
15
15
  num_items?: number;
16
16
  predicted_ltv?: number;
17
17
  search_string?: string;
18
- status?: 'completed' | 'updated' | 'viewed' | 'added_to_cart' | 'removed_from_cart' | string;
18
+ status?: 'completed' | 'updated' | 'viewed' | 'added_to_cart' | 'removed_from_cart' | (string & {});
19
19
  value?: number;
20
20
  [key: string]: any;
21
21
  }
@@ -1,6 +1,7 @@
1
1
  import type { RegistryScriptInput } from '#nuxt-scripts/types';
2
2
  import { RedditPixelOptions } from './schemas.js';
3
- type RdtFns = ((event: 'init', id: string) => void) & ((event: 'track', eventName: string) => void);
3
+ type StandardEvents = 'PageVisit' | 'ViewContent' | 'Search' | 'AddToCart' | 'AddToWishlist' | 'Purchase' | 'Lead' | 'SignUp';
4
+ type RdtFns = ((event: 'init', id: string) => void) & ((event: 'track', eventName: StandardEvents | (string & {}), properties?: Record<string, any>) => void);
4
5
  export interface RedditPixelApi {
5
6
  rdt: RdtFns & {
6
7
  sendEvent: (rdt: RedditPixelApi['rdt'], args: unknown[]) => void;
@@ -39,7 +39,7 @@ export function useScriptRybbitAnalytics(_options) {
39
39
  return useRegistryScript("rybbitAnalytics", (options) => {
40
40
  return {
41
41
  scriptInput: {
42
- "src": "https://app.rybbit.io/api/script.js",
42
+ "src": options?.analyticsHost ? `${options.analyticsHost}/script.js` : "https://app.rybbit.io/api/script.js",
43
43
  "data-site-id": String(options?.siteId),
44
44
  "data-auto-track-pageview": options?.autoTrackPageview,
45
45
  "data-track-spa": options?.trackSpa,
@@ -673,6 +673,12 @@ export declare const RybbitAnalyticsOptions: import("valibot").ObjectSchema<{
673
673
  * API key for authenticated tracking.
674
674
  */
675
675
  readonly apiKey: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
676
+ /**
677
+ * Override the analytics host URL. When first-party mode is enabled, this is
678
+ * auto-injected to route through the proxy. The SDK derives its API endpoint
679
+ * from the script src, so this changes the script src to `${analyticsHost}/script.js`.
680
+ */
681
+ readonly analyticsHost: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
676
682
  }, undefined>;
677
683
  export declare const SegmentOptions: import("valibot").ObjectSchema<{
678
684
  /**
@@ -670,7 +670,13 @@ export const RybbitAnalyticsOptions = object({
670
670
  /**
671
671
  * API key for authenticated tracking.
672
672
  */
673
- apiKey: optional(string())
673
+ apiKey: optional(string()),
674
+ /**
675
+ * Override the analytics host URL. When first-party mode is enabled, this is
676
+ * auto-injected to route through the proxy. The SDK derives its API endpoint
677
+ * from the script src, so this changes the script src to `${analyticsHost}/script.js`.
678
+ */
679
+ analyticsHost: optional(string())
674
680
  });
675
681
  export const SegmentOptions = object({
676
682
  /**
@@ -23,7 +23,7 @@ interface EventObjectProperties {
23
23
  [key: string]: any;
24
24
  }
25
25
  type InitObjectProperties = InferInput<typeof InitObjectPropertiesSchema>;
26
- type SnapTrFns = ((event: 'track', eventName: StandardEvents | '', data?: EventObjectProperties) => void) & ((event: 'init', id: string, data?: Record<string, any>) => void) & ((event: 'init', id: string, data?: InitObjectProperties) => void) & ((event: string, ...params: any[]) => void);
26
+ type SnapTrFns = ((event: 'track', eventName: StandardEvents | (string & {}), data?: EventObjectProperties) => void) & ((event: 'init', id: string, data?: Record<string, any>) => void) & ((event: 'init', id: string, data?: InitObjectProperties) => void) & ((event: (string & {}), ...params: any[]) => void);
27
27
  export interface SnapPixelApi {
28
28
  snaptr: SnapTrFns & {
29
29
  push: SnapTrFns;
@@ -23,7 +23,7 @@ interface IdentifyProperties {
23
23
  phone_number?: string;
24
24
  external_id?: string;
25
25
  }
26
- type TtqFns = ((cmd: 'track', event: StandardEvents | string, properties?: EventProperties) => void) & ((cmd: 'page') => void) & ((cmd: 'identify', properties: IdentifyProperties) => void) & ((cmd: string, ...args: any[]) => void);
26
+ type TtqFns = ((cmd: 'track', event: StandardEvents | (string & {}), properties?: EventProperties) => void) & ((cmd: 'page') => void) & ((cmd: 'identify', properties: IdentifyProperties) => void) & ((cmd: (string & {}), ...args: any[]) => void);
27
27
  export interface TikTokPixelApi {
28
28
  ttq: TtqFns & {
29
29
  push: TtqFns;
@@ -16,7 +16,7 @@ interface EventObjectProperties {
16
16
  phone_number?: string | null;
17
17
  contents: ContentProperties[];
18
18
  }
19
- type TwqFns = ((event: 'event', eventId: string, data?: EventObjectProperties) => void) & ((event: 'config', id: string) => void) & ((event: string, ...params: any[]) => void);
19
+ type TwqFns = ((event: 'event', eventId: string, data?: EventObjectProperties) => void) & ((event: 'config', id: string) => void) & ((event: (string & {}), ...params: any[]) => void);
20
20
  export interface XPixelApi {
21
21
  twq: TwqFns & {
22
22
  loaded: boolean;
@@ -27,7 +27,7 @@ export default defineEventHandler(async (event) => {
27
27
  const encoder = new TextEncoder();
28
28
  const data = encoder.encode(email.trim().toLowerCase());
29
29
  const hashBuffer = await crypto.subtle.digest("SHA-256", data);
30
- hash = Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
30
+ hash = Array.from(new Uint8Array(hashBuffer), (b) => b.toString(16).padStart(2, "0")).join("");
31
31
  }
32
32
  if (!hash) {
33
33
  throw createError({
@@ -1,8 +1,9 @@
1
1
  import { createError, defineEventHandler, getQuery, setHeader } from "h3";
2
2
  import { $fetch } from "ofetch";
3
+ const AMP_RE = /&amp;/g;
3
4
  export default defineEventHandler(async (event) => {
4
5
  const query = getQuery(event);
5
- const url = query.url?.replace(/&amp;/g, "&");
6
+ const url = query.url?.replace(AMP_RE, "&");
6
7
  if (!url) {
7
8
  throw createError({
8
9
  statusCode: 400,
@@ -1,8 +1,9 @@
1
1
  import { createError, defineEventHandler, getQuery, setHeader } from "h3";
2
2
  import { $fetch } from "ofetch";
3
+ const AMP_RE = /&amp;/g;
3
4
  export default defineEventHandler(async (event) => {
4
5
  const query = getQuery(event);
5
- const url = query.url?.replace(/&amp;/g, "&");
6
+ const url = query.url?.replace(AMP_RE, "&");
6
7
  if (!url) {
7
8
  throw createError({
8
9
  statusCode: 400,
@@ -1,5 +1,16 @@
1
1
  import { createError, defineEventHandler, getQuery, setHeader } from "h3";
2
2
  import { $fetch } from "ofetch";
3
+ const LINK_RE = /<link[^>]+rel=["']stylesheet["'][^>]+href=["']([^"']+)["'][^>]*>/gi;
4
+ const LINK_RE_2 = /<link[^>]+href=["']([^"']+)["'][^>]+rel=["']stylesheet["'][^>]*>/gi;
5
+ const RSRC_RE = /url\(\/rsrc\.php([^)]+)\)/g;
6
+ const SCRIPT_RE = /<script[\s\S]*?<\/script>/gi;
7
+ const STYLESHEET_RE = /<link[^>]+rel=["']stylesheet["'][^>]*>/gi;
8
+ const CSS_RE = /<link[^>]+href=["'][^"']+\.css[^"']*["'][^>]*>/gi;
9
+ const NOSCRIPT_RE = /<noscript>[\s\S]*?<\/noscript>/gi;
10
+ const SCONTENT_RE = /https:\/\/scontent[^"'\s),]+\.cdninstagram\.com[^"'\s),]+/g;
11
+ const STATIC_CDN_RE = /https:\/\/static\.cdninstagram\.com[^"'\s),]+/g;
12
+ const LOOKASIDE_RE = /https:\/\/lookaside\.instagram\.com[^"'\s),]+/g;
13
+ const AMP_RE = /&amp;/g;
3
14
  export default defineEventHandler(async (event) => {
4
15
  const query = getQuery(event);
5
16
  const postUrl = query.url;
@@ -41,14 +52,12 @@ export default defineEventHandler(async (event) => {
41
52
  });
42
53
  });
43
54
  const cssUrls = [];
44
- const linkRegex = /<link[^>]+rel=["']stylesheet["'][^>]+href=["']([^"']+)["'][^>]*>/gi;
45
55
  let match;
46
- while ((match = linkRegex.exec(html)) !== null) {
56
+ while ((match = LINK_RE.exec(html)) !== null) {
47
57
  if (match[1])
48
58
  cssUrls.push(match[1]);
49
59
  }
50
- const linkRegex2 = /<link[^>]+href=["']([^"']+)["'][^>]+rel=["']stylesheet["'][^>]*>/gi;
51
- while ((match = linkRegex2.exec(html)) !== null) {
60
+ while ((match = LINK_RE_2.exec(html)) !== null) {
52
61
  if (match[1])
53
62
  cssUrls.push(match[1]);
54
63
  }
@@ -61,7 +70,7 @@ export default defineEventHandler(async (event) => {
61
70
  );
62
71
  let combinedCss = cssContents.join("\n");
63
72
  combinedCss = combinedCss.replace(
64
- /url\(\/rsrc\.php([^)]+)\)/g,
73
+ RSRC_RE,
65
74
  (_m, path) => `url(/api/_scripts/instagram-embed-asset?url=${encodeURIComponent(`https://static.cdninstagram.com/rsrc.php${path}`)})`
66
75
  );
67
76
  const baseStyles = `
@@ -70,15 +79,15 @@ export default defineEventHandler(async (event) => {
70
79
  .Embed { opacity: 1 !important; visibility: visible !important; }
71
80
  .EmbeddedMedia, .EmbeddedMediaImage { display: block !important; visibility: visible !important; }
72
81
  `;
73
- let rewrittenHtml = html.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<link[^>]+rel=["']stylesheet["'][^>]*>/gi, "").replace(/<link[^>]+href=["'][^"']+\.css[^"']*["'][^>]*>/gi, "").replace(/<noscript>[\s\S]*?<\/noscript>/gi, "").replace(
74
- /https:\/\/scontent[^"'\s),]+\.cdninstagram\.com[^"'\s),]+/g,
75
- (m) => `/api/_scripts/instagram-embed-image?url=${encodeURIComponent(m.replace(/&amp;/g, "&"))}`
82
+ let rewrittenHtml = html.replace(SCRIPT_RE, "").replace(STYLESHEET_RE, "").replace(CSS_RE, "").replace(NOSCRIPT_RE, "").replace(
83
+ SCONTENT_RE,
84
+ (m) => `/api/_scripts/instagram-embed-image?url=${encodeURIComponent(m.replace(AMP_RE, "&"))}`
76
85
  ).replace(
77
- /https:\/\/static\.cdninstagram\.com[^"'\s),]+/g,
78
- (m) => `/api/_scripts/instagram-embed-asset?url=${encodeURIComponent(m.replace(/&amp;/g, "&"))}`
86
+ STATIC_CDN_RE,
87
+ (m) => `/api/_scripts/instagram-embed-asset?url=${encodeURIComponent(m.replace(AMP_RE, "&"))}`
79
88
  ).replace(
80
- /https:\/\/lookaside\.instagram\.com[^"'\s),]+/g,
81
- (m) => `/api/_scripts/instagram-embed-image?url=${encodeURIComponent(m.replace(/&amp;/g, "&"))}`
89
+ LOOKASIDE_RE,
90
+ (m) => `/api/_scripts/instagram-embed-image?url=${encodeURIComponent(m.replace(AMP_RE, "&"))}`
82
91
  );
83
92
  rewrittenHtml = rewrittenHtml.replace(
84
93
  "</head>",
@@ -10,6 +10,19 @@ import {
10
10
  SENSITIVE_HEADERS,
11
11
  stripPayloadFingerprinting
12
12
  } from "./utils/privacy.js";
13
+ const COMPRESSION_RE = /gzip|deflate|br|compress|base64/i;
14
+ const ROUTE_WILDCARD_RE = /\/\*\*$/;
15
+ const CLIENT_HINT_VERSION_RE = /;v="(\d+)\.[^"]*"/g;
16
+ const SKIP_RESPONSE_HEADERS = /* @__PURE__ */ new Set(["set-cookie", "transfer-encoding", "content-encoding", "content-length"]);
17
+ let sortedRoutesCache;
18
+ function getSortedRoutes(routes) {
19
+ const key = JSON.stringify(routes);
20
+ if (sortedRoutesCache?.key === key)
21
+ return sortedRoutesCache.sorted;
22
+ const sorted = Object.entries(routes).sort((a, b) => b[0].length - a[0].length);
23
+ sortedRoutesCache = { key, sorted };
24
+ return sorted;
25
+ }
13
26
  function stripQueryFingerprinting(query, privacy) {
14
27
  const stripped = stripPayloadFingerprinting(query, privacy);
15
28
  const params = new URLSearchParams();
@@ -18,11 +31,10 @@ function stripQueryFingerprinting(query, privacy) {
18
31
  params.set(key, typeof value === "object" ? JSON.stringify(value) : String(value));
19
32
  }
20
33
  }
21
- return params.toString();
34
+ return { queryString: params.toString(), stripped };
22
35
  }
23
36
  export default defineEventHandler(async (event) => {
24
37
  const config = useRuntimeConfig();
25
- const nitro = useNitroApp();
26
38
  const proxyConfig = config["nuxt-scripts-proxy"];
27
39
  if (!proxyConfig) {
28
40
  throw createError({
@@ -39,11 +51,10 @@ export default defineEventHandler(async (event) => {
39
51
  let targetBase;
40
52
  let matchedPrefix;
41
53
  let matchedRoutePattern;
42
- const sortedRoutes = Object.entries(routes).sort((a, b) => b[0].length - a[0].length);
43
- for (const [routePattern, target] of sortedRoutes) {
44
- const prefix = routePattern.replace(/\/\*\*$/, "");
54
+ for (const [routePattern, target] of getSortedRoutes(routes)) {
55
+ const prefix = routePattern.replace(ROUTE_WILDCARD_RE, "");
45
56
  if (path.startsWith(prefix)) {
46
- targetBase = target.replace(/\/\*\*$/, "");
57
+ targetBase = target.replace(ROUTE_WILDCARD_RE, "");
47
58
  matchedPrefix = prefix;
48
59
  matchedRoutePattern = routePattern;
49
60
  log("[proxy] Matched:", prefix, "->", targetBase);
@@ -66,22 +77,24 @@ export default defineEventHandler(async (event) => {
66
77
  const privacy = globalPrivacy !== void 0 ? mergePrivacy(perScriptResolved, globalPrivacy) : perScriptResolved;
67
78
  const anyPrivacy = privacy.ip || privacy.userAgent || privacy.language || privacy.screen || privacy.timezone || privacy.hardware;
68
79
  const originalHeaders = getHeaders(event);
80
+ const originalQuery = getQuery(event);
69
81
  const contentType = originalHeaders["content-type"] || "";
70
- const compressionParam = new URL(event.path, "http://localhost").searchParams.get("compression");
82
+ const compressionParam = originalQuery.compression || "";
71
83
  const isBinaryBody = Boolean(
72
- originalHeaders["content-encoding"] || contentType.includes("octet-stream") || compressionParam && /gzip|deflate|br|compress|base64/i.test(compressionParam)
84
+ originalHeaders["content-encoding"] || contentType.includes("octet-stream") || compressionParam && COMPRESSION_RE.test(compressionParam)
73
85
  );
74
86
  let targetPath = path.slice(matchedPrefix.length);
75
87
  if (targetPath && !targetPath.startsWith("/")) {
76
88
  targetPath = `/${targetPath}`;
77
89
  }
78
90
  let targetUrl = targetBase + targetPath;
91
+ let strippedQueryRecord;
79
92
  if (anyPrivacy) {
80
- const query = getQuery(event);
81
- if (Object.keys(query).length > 0) {
82
- const strippedQuery = stripQueryFingerprinting(query, privacy);
93
+ if (Object.keys(originalQuery).length > 0) {
94
+ const { queryString, stripped } = stripQueryFingerprinting(originalQuery, privacy);
95
+ strippedQueryRecord = stripped;
83
96
  const basePath = targetUrl.split("?")[0] || targetUrl;
84
- targetUrl = strippedQuery ? `${basePath}?${strippedQuery}` : basePath;
97
+ targetUrl = queryString ? `${basePath}?${queryString}` : basePath;
85
98
  }
86
99
  }
87
100
  const headers = {};
@@ -89,6 +102,8 @@ export default defineEventHandler(async (event) => {
89
102
  if (!value)
90
103
  continue;
91
104
  const lowerKey = key.toLowerCase();
105
+ if (lowerKey === "host")
106
+ continue;
92
107
  if (SENSITIVE_HEADERS.includes(lowerKey))
93
108
  continue;
94
109
  if (lowerKey === "content-length") {
@@ -112,7 +127,7 @@ export default defineEventHandler(async (event) => {
112
127
  continue;
113
128
  }
114
129
  if (lowerKey === "sec-ch-ua" || lowerKey === "sec-ch-ua-full-version-list") {
115
- headers[lowerKey] = privacy.hardware ? value.replace(/;v="(\d+)\.[^"]*"/g, ';v="$1"') : value;
130
+ headers[lowerKey] = privacy.hardware ? value.replace(CLIENT_HINT_VERSION_RE, ';v="$1"') : value;
116
131
  continue;
117
132
  }
118
133
  if (lowerKey === "sec-ch-ua-platform-version" || lowerKey === "sec-ch-ua-arch" || lowerKey === "sec-ch-ua-model" || lowerKey === "sec-ch-ua-bitness") {
@@ -139,7 +154,6 @@ export default defineEventHandler(async (event) => {
139
154
  let rawBody;
140
155
  let passthroughBody = false;
141
156
  const method = event.method?.toUpperCase();
142
- const originalQuery = getQuery(event);
143
157
  const isWriteMethod = method === "POST" || method === "PUT" || method === "PATCH";
144
158
  if (isWriteMethod) {
145
159
  if (isBinaryBody || !anyPrivacy) {
@@ -192,6 +206,7 @@ export default defineEventHandler(async (event) => {
192
206
  }
193
207
  }
194
208
  }
209
+ const nitro = useNitroApp();
195
210
  await nitro.hooks.callHook("nuxt-scripts:proxy", {
196
211
  timestamp: Date.now(),
197
212
  path: event.path,
@@ -206,7 +221,7 @@ export default defineEventHandler(async (event) => {
206
221
  },
207
222
  stripped: {
208
223
  headers,
209
- query: anyPrivacy ? stripPayloadFingerprinting(originalQuery, privacy) : originalQuery,
224
+ query: strippedQueryRecord ?? originalQuery,
210
225
  body: passthroughBody ? "<passthrough>" : body ?? null
211
226
  }
212
227
  });
@@ -233,23 +248,18 @@ export default defineEventHandler(async (event) => {
233
248
  });
234
249
  } catch (err) {
235
250
  clearTimeout(timeoutId);
236
- log("[proxy] Fetch error:", err instanceof Error ? err.message : err);
237
- if (path.includes("/collect") || path.includes("/tr") || path.includes("/events")) {
238
- event.node.res.statusCode = 204;
239
- return "";
240
- }
241
- const isTimeout = err instanceof Error && (err.message.includes("aborted") || err.message.includes("timeout"));
251
+ log("[proxy] Upstream error:", err);
242
252
  throw createError({
243
- statusCode: isTimeout ? 504 : 502,
244
- statusMessage: isTimeout ? "Upstream timeout" : "Bad Gateway",
245
- message: "Failed to reach upstream"
253
+ statusCode: 502,
254
+ statusMessage: "Bad Gateway",
255
+ message: `Proxy upstream request failed: ${targetUrl}`
246
256
  });
257
+ } finally {
258
+ clearTimeout(timeoutId);
247
259
  }
248
- clearTimeout(timeoutId);
249
260
  log("[proxy] Response:", response.status, response.statusText);
250
- const skipHeaders = ["set-cookie", "transfer-encoding", "content-encoding", "content-length"];
251
261
  response.headers.forEach((value, key) => {
252
- if (!skipHeaders.includes(key.toLowerCase())) {
262
+ if (!SKIP_RESPONSE_HEADERS.has(key.toLowerCase())) {
253
263
  setResponseHeader(event, key, value);
254
264
  }
255
265
  });