@shware/analytics 8.15.1 → 9.0.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 (100) hide show
  1. package/README.md +28 -4
  2. package/dist/attribution/classify.cjs +17 -5
  3. package/dist/attribution/classify.cjs.map +1 -1
  4. package/dist/attribution/classify.d.cts +2 -1
  5. package/dist/attribution/classify.d.cts.map +1 -1
  6. package/dist/attribution/classify.d.mts +2 -1
  7. package/dist/attribution/classify.d.mts.map +1 -1
  8. package/dist/attribution/classify.mjs +17 -5
  9. package/dist/attribution/classify.mjs.map +1 -1
  10. package/dist/attribution/vocabulary.cjs +99 -19
  11. package/dist/attribution/vocabulary.cjs.map +1 -1
  12. package/dist/attribution/vocabulary.d.cts +15 -4
  13. package/dist/attribution/vocabulary.d.cts.map +1 -1
  14. package/dist/attribution/vocabulary.d.mts +15 -4
  15. package/dist/attribution/vocabulary.d.mts.map +1 -1
  16. package/dist/attribution/vocabulary.mjs +99 -19
  17. package/dist/attribution/vocabulary.mjs.map +1 -1
  18. package/dist/click-id/index.cjs +24 -6
  19. package/dist/click-id/index.cjs.map +1 -1
  20. package/dist/click-id/index.d.cts +14 -3
  21. package/dist/click-id/index.d.cts.map +1 -1
  22. package/dist/click-id/index.d.mts +14 -3
  23. package/dist/click-id/index.d.mts.map +1 -1
  24. package/dist/click-id/index.mjs +23 -7
  25. package/dist/click-id/index.mjs.map +1 -1
  26. package/dist/schema/index.cjs +27 -9
  27. package/dist/schema/index.cjs.map +1 -1
  28. package/dist/schema/index.d.cts +126 -54
  29. package/dist/schema/index.d.cts.map +1 -1
  30. package/dist/schema/index.d.mts +126 -54
  31. package/dist/schema/index.d.mts.map +1 -1
  32. package/dist/schema/index.mjs +27 -9
  33. package/dist/schema/index.mjs.map +1 -1
  34. package/dist/server/click-ids.cjs +93 -0
  35. package/dist/server/click-ids.cjs.map +1 -0
  36. package/dist/server/click-ids.d.cts +40 -0
  37. package/dist/server/click-ids.d.cts.map +1 -0
  38. package/dist/server/click-ids.d.mts +40 -0
  39. package/dist/server/click-ids.d.mts.map +1 -0
  40. package/dist/server/click-ids.mjs +85 -0
  41. package/dist/server/click-ids.mjs.map +1 -0
  42. package/dist/server/google-data-manager.cjs +2 -1
  43. package/dist/server/google-data-manager.cjs.map +1 -1
  44. package/dist/server/google-data-manager.d.cts.map +1 -1
  45. package/dist/server/google-data-manager.d.mts.map +1 -1
  46. package/dist/server/google-data-manager.mjs +2 -1
  47. package/dist/server/google-data-manager.mjs.map +1 -1
  48. package/dist/server/linkedin-conversions-api.cjs +9 -4
  49. package/dist/server/linkedin-conversions-api.cjs.map +1 -1
  50. package/dist/server/linkedin-conversions-api.d.cts.map +1 -1
  51. package/dist/server/linkedin-conversions-api.d.mts.map +1 -1
  52. package/dist/server/linkedin-conversions-api.mjs +9 -4
  53. package/dist/server/linkedin-conversions-api.mjs.map +1 -1
  54. package/dist/server/meta-capi.cjs +5 -4
  55. package/dist/server/meta-capi.cjs.map +1 -1
  56. package/dist/server/meta-capi.mjs +5 -4
  57. package/dist/server/meta-capi.mjs.map +1 -1
  58. package/dist/server/meta-conversions-api.cjs +5 -4
  59. package/dist/server/meta-conversions-api.cjs.map +1 -1
  60. package/dist/server/meta-conversions-api.d.cts.map +1 -1
  61. package/dist/server/meta-conversions-api.d.mts.map +1 -1
  62. package/dist/server/meta-conversions-api.mjs +5 -4
  63. package/dist/server/meta-conversions-api.mjs.map +1 -1
  64. package/dist/server/microsoft-conversions-api.cjs +3 -1
  65. package/dist/server/microsoft-conversions-api.cjs.map +1 -1
  66. package/dist/server/microsoft-conversions-api.d.cts.map +1 -1
  67. package/dist/server/microsoft-conversions-api.d.mts.map +1 -1
  68. package/dist/server/microsoft-conversions-api.mjs +3 -1
  69. package/dist/server/microsoft-conversions-api.mjs.map +1 -1
  70. package/dist/server/openai-conversions-api.cjs +33 -10
  71. package/dist/server/openai-conversions-api.cjs.map +1 -1
  72. package/dist/server/openai-conversions-api.d.cts +19 -8
  73. package/dist/server/openai-conversions-api.d.cts.map +1 -1
  74. package/dist/server/openai-conversions-api.d.mts +19 -8
  75. package/dist/server/openai-conversions-api.d.mts.map +1 -1
  76. package/dist/server/openai-conversions-api.mjs +33 -10
  77. package/dist/server/openai-conversions-api.mjs.map +1 -1
  78. package/dist/server/reddit-conversions-api.cjs +3 -2
  79. package/dist/server/reddit-conversions-api.cjs.map +1 -1
  80. package/dist/server/reddit-conversions-api.d.cts.map +1 -1
  81. package/dist/server/reddit-conversions-api.d.mts.map +1 -1
  82. package/dist/server/reddit-conversions-api.mjs +3 -2
  83. package/dist/server/reddit-conversions-api.mjs.map +1 -1
  84. package/dist/track/types.d.cts +50 -16
  85. package/dist/track/types.d.cts.map +1 -1
  86. package/dist/track/types.d.mts +50 -16
  87. package/dist/track/types.d.mts.map +1 -1
  88. package/dist/web/index.cjs +19 -11
  89. package/dist/web/index.cjs.map +1 -1
  90. package/dist/web/index.d.cts.map +1 -1
  91. package/dist/web/index.d.mts.map +1 -1
  92. package/dist/web/index.mjs +19 -11
  93. package/dist/web/index.mjs.map +1 -1
  94. package/dist/web/page-key.cjs +4 -2
  95. package/dist/web/page-key.cjs.map +1 -1
  96. package/dist/web/page-key.d.cts.map +1 -1
  97. package/dist/web/page-key.d.mts.map +1 -1
  98. package/dist/web/page-key.mjs +4 -2
  99. package/dist/web/page-key.mjs.map +1 -1
  100. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { IGNORED_EVENTS } from "../third-parties/ignored-events.mjs";
2
2
  import { getFirst } from "../utils/field.mjs";
3
3
  import { resolveActionSource } from "./action-source.mjs";
4
+ import { redditClickId, redditUuid } from "./click-ids.mjs";
4
5
  import { mapRDTEvent, mapServerStandardEvent } from "../track/rdt.mjs";
5
6
  import { fetch } from "@shware/utils";
6
7
  //#region src/server/reddit-conversions-api.ts
@@ -9,7 +10,7 @@ function getServerEvent(event, data, actionSource) {
9
10
  const [type, params] = mapRDTEvent(name, properties, id);
10
11
  const source = resolveActionSource(platform, actionSource);
11
12
  return {
12
- click_id: tags.rdt_cid,
13
+ click_id: redditClickId(tags),
13
14
  event_at: new Date(created_at).getTime(),
14
15
  action_source: source === "web" ? "WEBSITE" : source === "app" ? "APP" : "UNKNOWN",
15
16
  type: {
@@ -31,7 +32,7 @@ function getServerEvent(event, data, actionSource) {
31
32
  user_agent: data.user_agent,
32
33
  idfa: platform === "ios" ? tags.advertising_id : void 0,
33
34
  aaid: platform === "android" ? tags.advertising_id : void 0,
34
- uuid: tags.rdt_uuid,
35
+ uuid: redditUuid(tags),
35
36
  screen_dimensions: tags.screen_width && tags.screen_height ? {
36
37
  width: tags.screen_width,
37
38
  height: tags.screen_height
@@ -1 +1 @@
1
- {"version":3,"file":"reddit-conversions-api.mjs","names":[],"sources":["../../src/server/reddit-conversions-api.ts"],"sourcesContent":["import { fetch } from '@shware/utils';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { type ServerStandardEvent, mapRDTEvent, mapServerStandardEvent } from '../track/rdt';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\nimport { getFirst } from '../utils/field';\nimport { type EventActionSource, resolveActionSource } from './action-source';\n\n/**\n * https://ads-api.reddit.com/docs/v3/operations/Post%20Conversion%20Events\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport interface RedditEvent {\n /** Match keys: Share user identifiers to match conversions to a Reddit ad engagement. */\n click_id?: string;\n\n /** Unix epoch timestamp in milliseconds, event_at can't be older than seven days. */\n event_at: number;\n\n action_source: 'WEBSITE' | 'APP' | (string & {});\n\n type: {\n tracking_type: ServerStandardEvent | 'CUSTOM';\n custom_event_name?: string;\n };\n\n /**\n * Event metadata\n * Share as much additional information about your conversion event as you'd like. If you're\n * using the Conversions API with the pixel, conversion_id is required for deduplication.\n */\n metadata?: {\n conversion_id?: string;\n currency?: string; // ISO 4217 3-letter currency code\n item_count?: number;\n value?: number;\n products?: { id: string; name?: string; category?: string }[];\n };\n\n user?: {\n email?: string;\n external_id?: string;\n ip_address?: string;\n phone_number?: string;\n user_agent?: string;\n\n /** The Identifier for Advertisers (IDFA) of the user's Apple device. */\n idfa?: string;\n\n /** The Android Advertising ID (AAID) of the user's Android device. */\n aaid?: string;\n /**\n * The value from the first-party Pixel _rdt_uuid cookie on your domain. Note that it is in\n * the {timestamp}.{uuid} format. You may use the full value or just the UUID portion.\n * Example: 1684189007728.7c73f2ae-a433-4d7b-9838-f467da98f48e\n */\n uuid?: string;\n\n screen_dimensions?: { width: number; height: number };\n\n /**\n * A structure of data processing options to specify the processing type for the event\n * https://business.reddithelp.com/s/article/Limited-Data-Use\n */\n data_processing_options?: {\n country: string;\n region: string;\n modes: string[] | ['LDU'];\n };\n };\n}\n\nexport interface CreateRedditEventDTO {\n data: { test_id?: string; events: RedditEvent[] };\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n actionSource?: EventActionSource\n): RedditEvent {\n const { id, name, properties, tags, platform, created_at } = event;\n const [type, params] = mapRDTEvent(name, properties, id);\n // Reddit documents WEBSITE and APP only, so an offline conversion shares the fallback with an\n // undeterminable platform rather than inventing an enum value the API may reject.\n const source = resolveActionSource(platform, actionSource);\n\n return {\n click_id: tags.rdt_cid,\n event_at: new Date(created_at).getTime(),\n action_source: source === 'web' ? 'WEBSITE' : source === 'app' ? 'APP' : 'UNKNOWN',\n type: {\n tracking_type: type === 'Custom' ? 'CUSTOM' : mapServerStandardEvent(type),\n custom_event_name: type === 'Custom' ? params.customEventName : undefined,\n },\n metadata: {\n conversion_id: id,\n currency:\n 'currency' in params && typeof params.currency === 'string'\n ? params.currency.toUpperCase()\n : undefined,\n item_count:\n 'itemCount' in params && typeof params.itemCount === 'number'\n ? params.itemCount\n : undefined,\n value: 'value' in params && typeof params.value === 'number' ? params.value : undefined,\n products:\n 'products' in params && Array.isArray(params.products) && params.products.length > 0\n ? params.products\n : undefined,\n },\n user: {\n email: getFirst(data.email),\n external_id: data.user_id,\n ip_address: data.ip_address,\n phone_number: getFirst(data.phone_number),\n user_agent: data.user_agent,\n idfa: platform === 'ios' ? tags.advertising_id : undefined,\n aaid: platform === 'android' ? tags.advertising_id : undefined,\n uuid: tags.rdt_uuid,\n screen_dimensions:\n tags.screen_width && tags.screen_height\n ? { width: tags.screen_width, height: tags.screen_height }\n : undefined,\n },\n };\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n testId?: string,\n actionSource?: EventActionSource\n) {\n const dto: CreateRedditEventDTO = {\n data: {\n test_id: testId,\n events: events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, actionSource)),\n },\n };\n\n if (dto.data.events.length === 0) return;\n\n try {\n const response = await fetch(\n `https://ads-api.reddit.com/api/v3/pixels/${pixelId}/conversion_events`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n body: JSON.stringify(dto),\n }\n );\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send Reddit conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send Reddit conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;AA2EA,SAAgB,eAEd,OACA,MACA,cACa;CACb,MAAM,EAAE,IAAI,MAAM,YAAY,MAAM,UAAU,eAAe;CAC7D,MAAM,CAAC,MAAM,UAAU,YAAY,MAAM,YAAY,EAAE;CAGvD,MAAM,SAAS,oBAAoB,UAAU,YAAY;CAEzD,OAAO;EACL,UAAU,KAAK;EACf,UAAU,IAAI,KAAK,UAAU,CAAC,CAAC,QAAQ;EACvC,eAAe,WAAW,QAAQ,YAAY,WAAW,QAAQ,QAAQ;EACzE,MAAM;GACJ,eAAe,SAAS,WAAW,WAAW,uBAAuB,IAAI;GACzE,mBAAmB,SAAS,WAAW,OAAO,kBAAkB,KAAA;EAClE;EACA,UAAU;GACR,eAAe;GACf,UACE,cAAc,UAAU,OAAO,OAAO,aAAa,WAC/C,OAAO,SAAS,YAAY,IAC5B,KAAA;GACN,YACE,eAAe,UAAU,OAAO,OAAO,cAAc,WACjD,OAAO,YACP,KAAA;GACN,OAAO,WAAW,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;GAC9E,UACE,cAAc,UAAU,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,IAC/E,OAAO,WACP,KAAA;EACR;EACA,MAAM;GACJ,OAAO,SAAS,KAAK,KAAK;GAC1B,aAAa,KAAK;GAClB,YAAY,KAAK;GACjB,cAAc,SAAS,KAAK,YAAY;GACxC,YAAY,KAAK;GACjB,MAAM,aAAa,QAAQ,KAAK,iBAAiB,KAAA;GACjD,MAAM,aAAa,YAAY,KAAK,iBAAiB,KAAA;GACrD,MAAM,KAAK;GACX,mBACE,KAAK,gBAAgB,KAAK,gBACtB;IAAE,OAAO,KAAK;IAAc,QAAQ,KAAK;GAAc,IACvD,KAAA;EACR;CACF;AACF;AAEA,eAAsB,WACpB,aACA,SAEA,QACA,OAAyB,CAAC,GAC1B,QACA,cACA;CACA,MAAM,MAA4B,EAChC,MAAM;EACJ,SAAS;EACT,QAAQ,OACL,QAAQ,UAAU,CAAC,eAAe,SAAS,MAAM,IAAI,CAAC,CAAC,CACvD,KAAK,UAAU,eAAe,OAAO,MAAM,YAAY,CAAC;CAC7D,EACF;CAEA,IAAI,IAAI,KAAK,OAAO,WAAW,GAAG;CAElC,IAAI;EACF,MAAM,WAAW,MAAM,MACrB,4CAA4C,QAAQ,qBACpD;GACE,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,QAAQ;IACR,eAAe,UAAU;GAC3B;GACA,MAAM,KAAK,UAAU,GAAG;EAC1B,CACF;EACA,IAAI,SAAS,IAAI;EACjB,MAAM,EAAE,WAAW;EACnB,MAAM,UAAU,MAAM,SAAS,KAAK;EACpC,QAAQ,MAAM,6CAA6C,OAAO,UAAU,SAAS;CACvF,SAAS,OAAO;EACd,QAAQ,MAAM,oDAAoD,KAAK;CACzE;AACF"}
1
+ {"version":3,"file":"reddit-conversions-api.mjs","names":[],"sources":["../../src/server/reddit-conversions-api.ts"],"sourcesContent":["import { fetch } from '@shware/utils';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { type ServerStandardEvent, mapRDTEvent, mapServerStandardEvent } from '../track/rdt';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\nimport { getFirst } from '../utils/field';\nimport { type EventActionSource, resolveActionSource } from './action-source';\nimport { redditClickId, redditUuid } from './click-ids';\n\n/**\n * https://ads-api.reddit.com/docs/v3/operations/Post%20Conversion%20Events\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport interface RedditEvent {\n /** Match keys: Share user identifiers to match conversions to a Reddit ad engagement. */\n click_id?: string;\n\n /** Unix epoch timestamp in milliseconds, event_at can't be older than seven days. */\n event_at: number;\n\n action_source: 'WEBSITE' | 'APP' | (string & {});\n\n type: {\n tracking_type: ServerStandardEvent | 'CUSTOM';\n custom_event_name?: string;\n };\n\n /**\n * Event metadata\n * Share as much additional information about your conversion event as you'd like. If you're\n * using the Conversions API with the pixel, conversion_id is required for deduplication.\n */\n metadata?: {\n conversion_id?: string;\n currency?: string; // ISO 4217 3-letter currency code\n item_count?: number;\n value?: number;\n products?: { id: string; name?: string; category?: string }[];\n };\n\n user?: {\n email?: string;\n external_id?: string;\n ip_address?: string;\n phone_number?: string;\n user_agent?: string;\n\n /** The Identifier for Advertisers (IDFA) of the user's Apple device. */\n idfa?: string;\n\n /** The Android Advertising ID (AAID) of the user's Android device. */\n aaid?: string;\n /**\n * The value from the first-party Pixel _rdt_uuid cookie on your domain. Note that it is in\n * the {timestamp}.{uuid} format. You may use the full value or just the UUID portion.\n * Example: 1684189007728.7c73f2ae-a433-4d7b-9838-f467da98f48e\n */\n uuid?: string;\n\n screen_dimensions?: { width: number; height: number };\n\n /**\n * A structure of data processing options to specify the processing type for the event\n * https://business.reddithelp.com/s/article/Limited-Data-Use\n */\n data_processing_options?: {\n country: string;\n region: string;\n modes: string[] | ['LDU'];\n };\n };\n}\n\nexport interface CreateRedditEventDTO {\n data: { test_id?: string; events: RedditEvent[] };\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n actionSource?: EventActionSource\n): RedditEvent {\n const { id, name, properties, tags, platform, created_at } = event;\n const [type, params] = mapRDTEvent(name, properties, id);\n // Reddit documents WEBSITE and APP only, so an offline conversion shares the fallback with an\n // undeterminable platform rather than inventing an enum value the API may reject.\n const source = resolveActionSource(platform, actionSource);\n\n return {\n click_id: redditClickId(tags),\n event_at: new Date(created_at).getTime(),\n action_source: source === 'web' ? 'WEBSITE' : source === 'app' ? 'APP' : 'UNKNOWN',\n type: {\n tracking_type: type === 'Custom' ? 'CUSTOM' : mapServerStandardEvent(type),\n custom_event_name: type === 'Custom' ? params.customEventName : undefined,\n },\n metadata: {\n conversion_id: id,\n currency:\n 'currency' in params && typeof params.currency === 'string'\n ? params.currency.toUpperCase()\n : undefined,\n item_count:\n 'itemCount' in params && typeof params.itemCount === 'number'\n ? params.itemCount\n : undefined,\n value: 'value' in params && typeof params.value === 'number' ? params.value : undefined,\n products:\n 'products' in params && Array.isArray(params.products) && params.products.length > 0\n ? params.products\n : undefined,\n },\n user: {\n email: getFirst(data.email),\n external_id: data.user_id,\n ip_address: data.ip_address,\n phone_number: getFirst(data.phone_number),\n user_agent: data.user_agent,\n idfa: platform === 'ios' ? tags.advertising_id : undefined,\n aaid: platform === 'android' ? tags.advertising_id : undefined,\n uuid: redditUuid(tags),\n screen_dimensions:\n tags.screen_width && tags.screen_height\n ? { width: tags.screen_width, height: tags.screen_height }\n : undefined,\n },\n };\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n testId?: string,\n actionSource?: EventActionSource\n) {\n const dto: CreateRedditEventDTO = {\n data: {\n test_id: testId,\n events: events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, actionSource)),\n },\n };\n\n if (dto.data.events.length === 0) return;\n\n try {\n const response = await fetch(\n `https://ads-api.reddit.com/api/v3/pixels/${pixelId}/conversion_events`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n body: JSON.stringify(dto),\n }\n );\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send Reddit conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send Reddit conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;;AA4EA,SAAgB,eAEd,OACA,MACA,cACa;CACb,MAAM,EAAE,IAAI,MAAM,YAAY,MAAM,UAAU,eAAe;CAC7D,MAAM,CAAC,MAAM,UAAU,YAAY,MAAM,YAAY,EAAE;CAGvD,MAAM,SAAS,oBAAoB,UAAU,YAAY;CAEzD,OAAO;EACL,UAAU,cAAc,IAAI;EAC5B,UAAU,IAAI,KAAK,UAAU,CAAC,CAAC,QAAQ;EACvC,eAAe,WAAW,QAAQ,YAAY,WAAW,QAAQ,QAAQ;EACzE,MAAM;GACJ,eAAe,SAAS,WAAW,WAAW,uBAAuB,IAAI;GACzE,mBAAmB,SAAS,WAAW,OAAO,kBAAkB,KAAA;EAClE;EACA,UAAU;GACR,eAAe;GACf,UACE,cAAc,UAAU,OAAO,OAAO,aAAa,WAC/C,OAAO,SAAS,YAAY,IAC5B,KAAA;GACN,YACE,eAAe,UAAU,OAAO,OAAO,cAAc,WACjD,OAAO,YACP,KAAA;GACN,OAAO,WAAW,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;GAC9E,UACE,cAAc,UAAU,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,IAC/E,OAAO,WACP,KAAA;EACR;EACA,MAAM;GACJ,OAAO,SAAS,KAAK,KAAK;GAC1B,aAAa,KAAK;GAClB,YAAY,KAAK;GACjB,cAAc,SAAS,KAAK,YAAY;GACxC,YAAY,KAAK;GACjB,MAAM,aAAa,QAAQ,KAAK,iBAAiB,KAAA;GACjD,MAAM,aAAa,YAAY,KAAK,iBAAiB,KAAA;GACrD,MAAM,WAAW,IAAI;GACrB,mBACE,KAAK,gBAAgB,KAAK,gBACtB;IAAE,OAAO,KAAK;IAAc,QAAQ,KAAK;GAAc,IACvD,KAAA;EACR;CACF;AACF;AAEA,eAAsB,WACpB,aACA,SAEA,QACA,OAAyB,CAAC,GAC1B,QACA,cACA;CACA,MAAM,MAA4B,EAChC,MAAM;EACJ,SAAS;EACT,QAAQ,OACL,QAAQ,UAAU,CAAC,eAAe,SAAS,MAAM,IAAI,CAAC,CAAC,CACvD,KAAK,UAAU,eAAe,OAAO,MAAM,YAAY,CAAC;CAC7D,EACF;CAEA,IAAI,IAAI,KAAK,OAAO,WAAW,GAAG;CAElC,IAAI;EACF,MAAM,WAAW,MAAM,MACrB,4CAA4C,QAAQ,qBACpD;GACE,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,QAAQ;IACR,eAAe,UAAU;GAC3B;GACA,MAAM,KAAK,UAAU,GAAG;EAC1B,CACF;EACA,IAAI,SAAS,IAAI;EACjB,MAAM,EAAE,WAAW;EACnB,MAAM,UAAU,MAAM,SAAS,KAAK;EACpC,QAAQ,MAAM,6CAA6C,OAAO,UAAU,SAAS;CACvF,SAAS,OAAO;EACd,QAAQ,MAAM,oDAAoD,KAAK;CACzE;AACF"}
@@ -124,15 +124,18 @@ export interface PageInfo {
124
124
  */
125
125
  source_url?: string;
126
126
  }
127
+ /**
128
+ * Ad click ids and the ad platforms' first-party cookies, each under the name of where it was
129
+ * read: a URL parameter keeps the parameter's own name (`fbclid`, `gclid`, `ScCid` — jsonb keys
130
+ * are case-sensitive, so in SQL that is `tags->>'ScCid'`), a cookie keeps the cookie's name and
131
+ * so starts with an underscore (`_fbc`, `_gcl_aw`, `__oppref`). One source per key, never a
132
+ * fallback from one to the other, so a value always says where it came from.
133
+ *
134
+ * The URL parameters are this page's click and name the visit's channel (`CLICK_ID_CHANNELS`);
135
+ * the cookies outlive the click and only ever feed the conversion senders, which take the URL
136
+ * parameter first and the cookie when the page carries none (`server/click-ids`).
137
+ */
127
138
  export interface AdvertisingInfo {
128
- /**
129
- * Meta pixel fields
130
- * ref: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters#fbc
131
- * Stored in the _fbc/_fbp browser cookie under your domain
132
- * ref: https://www.facebook.com/business/help/2360940870872492?checkpoint_src=any
133
- */
134
- fbc?: string;
135
- fbp?: string;
136
139
  fbclid?: string;
137
140
  ad_id?: string;
138
141
  ad_name?: string;
@@ -141,25 +144,56 @@ export interface AdvertisingInfo {
141
144
  campaign_id?: string;
142
145
  campaign_name?: string;
143
146
  placement?: string;
144
- /** Google Analytics fields */
147
+ /**
148
+ * Meta click id cookie, `fb.<subdomainIndex>.<creationTime>.<fbclid>`, set server-side by
149
+ * `resolveClickIdCookies`.
150
+ * ref: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc
151
+ */
152
+ _fbc?: string;
153
+ /** Meta browser id cookie, `fb.<subdomainIndex>.<creationTime>.<random>`, set by the pixel. */
154
+ _fbp?: string;
155
+ /** @deprecated Renamed to `_fbc` in 9.0.0; still read from clients on an older version. */
156
+ fbc?: string;
157
+ /** @deprecated Renamed to `_fbp` in 9.0.0; still read from clients on an older version. */
158
+ fbp?: string;
145
159
  gclid?: string;
146
160
  gclsrc?: string;
147
161
  gad_source?: string;
148
162
  gad_campaignid?: string;
149
- /** Reddit Ads fields */
163
+ wbraid?: string;
164
+ gbraid?: string;
165
+ dclid?: string;
166
+ /** gtag's click cookie, `GCL.<seconds>.<gclid>`; see `parseGcl`. */
167
+ _gcl_aw?: string;
168
+ /** gtag's web-to-app click cookie, `GCL.<seconds>.<wbraid>`; see `parseGcl`. */
169
+ _gcl_gb?: string;
170
+ msclkid?: string;
171
+ /** The UET tag's click cookie, `_uet<msclkid>`; see `parseUetMsclkid`. */
172
+ _uetmsclkid?: string;
150
173
  rdt_cid?: string;
174
+ /** Reddit click id cookie, set server-side by `resolveClickIdCookies`. */
175
+ _rdt_cid?: string;
176
+ /** The Reddit pixel's browser id cookie, `<timestamp>.<uuid>`. */
177
+ _rdt_uuid?: string;
178
+ /** @deprecated Renamed to `_rdt_uuid` in 9.0.0; still read from clients on an older version. */
151
179
  rdt_uuid?: string;
152
- /** LinkedIn Ads fields: get click id from url params or first-party cookie */
153
180
  li_fat_id?: string;
154
- dclid?: string;
181
+ /**
182
+ * The Insight Tag's click cookie. The cookie itself is named `li_fat_id`, like the URL
183
+ * parameter; the underscore is ours, to keep the two apart.
184
+ */
185
+ _li_fat_id?: string;
186
+ oppref?: string;
187
+ /** The pixel's copy of the last `oppref`, kept 30 days. */
188
+ __oppref?: string;
189
+ /** The pixel's browser reference, a random id kept 365 days. */
190
+ __obref?: string;
155
191
  ko_click_id?: string;
156
- msclkid?: string;
157
- sccid?: string;
192
+ ScCid?: string;
158
193
  ttclid?: string;
159
194
  twclid?: string;
160
- wbraid?: string;
161
- gbraid?: string;
162
195
  yclid?: string;
196
+ epik?: string;
163
197
  }
164
198
  /**
165
199
  * UTM campaign parameters.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":["GAUserProvidedData"],"sources":["../../src/track/types.ts"],"mappings":";;YAEY;YACA,YAAY;YAEZ,UAAU,UAAU,YAAY,aAAa,gBAAgB,iBACrE,IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+Ba;;;;;;;KAQZ,oBAAoB,KAAK,gBAAgB,wBAC1C,sBAAsB;YAGd,gBAAgB,UAAU,YAAY,aAAa,gBAAgB,iBAC3E,eAAe,KAAK,oBAAoB,KACxC,gBAAgB,wBACd,sBAAsB,KACtB,OAAO,mBAAmB;YAEpB;YACA;iBAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe,yBAAyBA;EACxC;EACA;EACA;EACA;EACA;IAAa;IAAc;IAAe;;EAE1C;EACA;;YAGU,qBAAqB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAGe;EACf;EACA;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;iBAGe;;EAEf;EACA;;iBAGe;EACf;EACA;EACA;;;;;;;;;;iBAWe;EACf;EACA;EACA;;;;;;;EAOA;;;;;;EAMA;;iBAGe;;;;;;;EAOf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;;EAEA;EACA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;iBAQe;;EAEf;;;;;;;;;;;;EAqCA;;;;;;EAuDA;;EAMA;;EAEA;;EAEA;;EAEA;;EAUA;;EAEA;;iBAGe,kBACP,cAAc,YAAY,SAAS,iBAAiB,UAAU,iBAAiB;EACvF;GACC;;iBAGc,WAAW,UAAU,YAAY;EAChD;EACA,MAAM,UAAU;EAChB,MAAM;EACN;EACA;EACA,UAAU;EACV,aAAa;EACb,aAAa,gBAAgB;EAC7B;;YAGU;;EAEV"}
1
+ {"version":3,"file":"types.d.cts","names":["GAUserProvidedData"],"sources":["../../src/track/types.ts"],"mappings":";;YAEY;YACA,YAAY;YAEZ,UAAU,UAAU,YAAY,aAAa,gBAAgB,iBACrE,IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+Ba;;;;;;;KAQZ,oBAAoB,KAAK,gBAAgB,wBAC1C,sBAAsB;YAGd,gBAAgB,UAAU,YAAY,aAAa,gBAAgB,iBAC3E,eAAe,KAAK,oBAAoB,KACxC,gBAAgB,wBACd,sBAAsB,KACtB,OAAO,mBAAmB;YAEpB;YACA;iBAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe,yBAAyBA;EACxC;EACA;EACA;EACA;EACA;IAAa;IAAc;IAAe;;EAE1C;EACA;;YAGU,qBAAqB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAGe;EACf;EACA;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;iBAGe;;EAEf;EACA;;iBAGe;EACf;EACA;EACA;;;;;;;;;;iBAWe;EACf;EACA;EACA;;;;;;;EAOA;;;;;;EAMA;;;;;;;;;;;;;iBAce;EAEf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;EAMA;;EAEA;;EAEA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;EAEA;EAEA;;EAEA;EAEA;;EAEA;;EAEA;;EAEA;EAEA;;;;;EAKA;EAEA;;EAEA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;;;;;;;iBAQe;;EAEf;;;;;;;;;;;;EAqCA;;;;;;EAuDA;;EAMA;;EAEA;;EAEA;;EAEA;;EAUA;;EAEA;;iBAGe,kBACP,cAAc,YAAY,SAAS,iBAAiB,UAAU,iBAAiB;EACvF;GACC;;iBAGc,WAAW,UAAU,YAAY;EAChD;EACA,MAAM,UAAU;EAChB,MAAM;EACN;EACA;EACA,UAAU;EACV,aAAa;EACb,aAAa,gBAAgB;EAC7B;;YAGU;;EAEV"}
@@ -124,15 +124,18 @@ export interface PageInfo {
124
124
  */
125
125
  source_url?: string;
126
126
  }
127
+ /**
128
+ * Ad click ids and the ad platforms' first-party cookies, each under the name of where it was
129
+ * read: a URL parameter keeps the parameter's own name (`fbclid`, `gclid`, `ScCid` — jsonb keys
130
+ * are case-sensitive, so in SQL that is `tags->>'ScCid'`), a cookie keeps the cookie's name and
131
+ * so starts with an underscore (`_fbc`, `_gcl_aw`, `__oppref`). One source per key, never a
132
+ * fallback from one to the other, so a value always says where it came from.
133
+ *
134
+ * The URL parameters are this page's click and name the visit's channel (`CLICK_ID_CHANNELS`);
135
+ * the cookies outlive the click and only ever feed the conversion senders, which take the URL
136
+ * parameter first and the cookie when the page carries none (`server/click-ids`).
137
+ */
127
138
  export interface AdvertisingInfo {
128
- /**
129
- * Meta pixel fields
130
- * ref: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters#fbc
131
- * Stored in the _fbc/_fbp browser cookie under your domain
132
- * ref: https://www.facebook.com/business/help/2360940870872492?checkpoint_src=any
133
- */
134
- fbc?: string;
135
- fbp?: string;
136
139
  fbclid?: string;
137
140
  ad_id?: string;
138
141
  ad_name?: string;
@@ -141,25 +144,56 @@ export interface AdvertisingInfo {
141
144
  campaign_id?: string;
142
145
  campaign_name?: string;
143
146
  placement?: string;
144
- /** Google Analytics fields */
147
+ /**
148
+ * Meta click id cookie, `fb.<subdomainIndex>.<creationTime>.<fbclid>`, set server-side by
149
+ * `resolveClickIdCookies`.
150
+ * ref: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc
151
+ */
152
+ _fbc?: string;
153
+ /** Meta browser id cookie, `fb.<subdomainIndex>.<creationTime>.<random>`, set by the pixel. */
154
+ _fbp?: string;
155
+ /** @deprecated Renamed to `_fbc` in 9.0.0; still read from clients on an older version. */
156
+ fbc?: string;
157
+ /** @deprecated Renamed to `_fbp` in 9.0.0; still read from clients on an older version. */
158
+ fbp?: string;
145
159
  gclid?: string;
146
160
  gclsrc?: string;
147
161
  gad_source?: string;
148
162
  gad_campaignid?: string;
149
- /** Reddit Ads fields */
163
+ wbraid?: string;
164
+ gbraid?: string;
165
+ dclid?: string;
166
+ /** gtag's click cookie, `GCL.<seconds>.<gclid>`; see `parseGcl`. */
167
+ _gcl_aw?: string;
168
+ /** gtag's web-to-app click cookie, `GCL.<seconds>.<wbraid>`; see `parseGcl`. */
169
+ _gcl_gb?: string;
170
+ msclkid?: string;
171
+ /** The UET tag's click cookie, `_uet<msclkid>`; see `parseUetMsclkid`. */
172
+ _uetmsclkid?: string;
150
173
  rdt_cid?: string;
174
+ /** Reddit click id cookie, set server-side by `resolveClickIdCookies`. */
175
+ _rdt_cid?: string;
176
+ /** The Reddit pixel's browser id cookie, `<timestamp>.<uuid>`. */
177
+ _rdt_uuid?: string;
178
+ /** @deprecated Renamed to `_rdt_uuid` in 9.0.0; still read from clients on an older version. */
151
179
  rdt_uuid?: string;
152
- /** LinkedIn Ads fields: get click id from url params or first-party cookie */
153
180
  li_fat_id?: string;
154
- dclid?: string;
181
+ /**
182
+ * The Insight Tag's click cookie. The cookie itself is named `li_fat_id`, like the URL
183
+ * parameter; the underscore is ours, to keep the two apart.
184
+ */
185
+ _li_fat_id?: string;
186
+ oppref?: string;
187
+ /** The pixel's copy of the last `oppref`, kept 30 days. */
188
+ __oppref?: string;
189
+ /** The pixel's browser reference, a random id kept 365 days. */
190
+ __obref?: string;
155
191
  ko_click_id?: string;
156
- msclkid?: string;
157
- sccid?: string;
192
+ ScCid?: string;
158
193
  ttclid?: string;
159
194
  twclid?: string;
160
- wbraid?: string;
161
- gbraid?: string;
162
195
  yclid?: string;
196
+ epik?: string;
163
197
  }
164
198
  /**
165
199
  * UTM campaign parameters.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":["GAUserProvidedData"],"sources":["../../src/track/types.ts"],"mappings":";;YAEY;YACA,YAAY;YAEZ,UAAU,UAAU,YAAY,aAAa,gBAAgB,iBACrE,IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+Ba;;;;;;;KAQZ,oBAAoB,KAAK,gBAAgB,wBAC1C,sBAAsB;YAGd,gBAAgB,UAAU,YAAY,aAAa,gBAAgB,iBAC3E,eAAe,KAAK,oBAAoB,KACxC,gBAAgB,wBACd,sBAAsB,KACtB,OAAO,mBAAmB;YAEpB;YACA;iBAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe,yBAAyBA;EACxC;EACA;EACA;EACA;EACA;IAAa;IAAc;IAAe;;EAE1C;EACA;;YAGU,qBAAqB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAGe;EACf;EACA;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;iBAGe;;EAEf;EACA;;iBAGe;EACf;EACA;EACA;;;;;;;;;;iBAWe;EACf;EACA;EACA;;;;;;;EAOA;;;;;;EAMA;;iBAGe;;;;;;;EAOf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;;EAEA;EACA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;iBAQe;;EAEf;;;;;;;;;;;;EAqCA;;;;;;EAuDA;;EAMA;;EAEA;;EAEA;;EAEA;;EAUA;;EAEA;;iBAGe,kBACP,cAAc,YAAY,SAAS,iBAAiB,UAAU,iBAAiB;EACvF;GACC;;iBAGc,WAAW,UAAU,YAAY;EAChD;EACA,MAAM,UAAU;EAChB,MAAM;EACN;EACA;EACA,UAAU;EACV,aAAa;EACb,aAAa,gBAAgB;EAC7B;;YAGU;;EAEV"}
1
+ {"version":3,"file":"types.d.mts","names":["GAUserProvidedData"],"sources":["../../src/track/types.ts"],"mappings":";;YAEY;YACA,YAAY;YAEZ,UAAU,UAAU,YAAY,aAAa,gBAAgB,iBACrE,IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+Ba;;;;;;;KAQZ,oBAAoB,KAAK,gBAAgB,wBAC1C,sBAAsB;YAGd,gBAAgB,UAAU,YAAY,aAAa,gBAAgB,iBAC3E,eAAe,KAAK,oBAAoB,KACxC,gBAAgB,wBACd,sBAAsB,KACtB,OAAO,mBAAmB;YAEpB;YACA;iBAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe,yBAAyBA;EACxC;EACA;EACA;EACA;EACA;IAAa;IAAc;IAAe;;EAE1C;EACA;;YAGU,qBAAqB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAGe;EACf;EACA;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;iBAGe;;EAEf;EACA;;iBAGe;EACf;EACA;EACA;;;;;;;;;;iBAWe;EACf;EACA;EACA;;;;;;;EAOA;;;;;;EAMA;;;;;;;;;;;;;iBAce;EAEf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;EAMA;;EAEA;;EAEA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;EAEA;EAEA;;EAEA;EAEA;;EAEA;;EAEA;;EAEA;EAEA;;;;;EAKA;EAEA;;EAEA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;;;;;;;iBAQe;;EAEf;;;;;;;;;;;;EAqCA;;;;;;EAuDA;;EAMA;;EAEA;;EAEA;;EAEA;;EAUA;;EAEA;;iBAGe,kBACP,cAAc,YAAY,SAAS,iBAAiB,UAAU,iBAAiB;EACvF;GACC;;iBAGc,WAAW,UAAU,YAAY;EAChD;EACA,MAAM,UAAU;EAChB,MAAM;EACN;EACA;EACA,UAAU;EACV,aAAa;EACb,aAAa,gBAAgB;EAC7B;;YAGU;;EAEV"}
@@ -3,7 +3,6 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
3
3
  const require_setup_index = require("../setup/index.cjs");
4
4
  const require_constants_storage = require("../constants/storage.cjs");
5
5
  const require_link_index = require("../link/index.cjs");
6
- const require_click_id_index = require("../click-id/index.cjs");
7
6
  const require_web_page_key = require("./page-key.cjs");
8
7
  const require_es5$1 = require("../node_modules/.pnpm/bowser@2.14.1/node_modules/bowser/es5.cjs");
9
8
  let uuid = require("uuid");
@@ -92,8 +91,6 @@ async function getTags() {
92
91
  page_referrer,
93
92
  page_title,
94
93
  page_load_id,
95
- fbc: parsed._fbc ?? void 0,
96
- fbp: parsed._fbp,
97
94
  fbclid: params.get("fbclid") ?? void 0,
98
95
  ad_id: params.get("ad_id") ?? void 0,
99
96
  ad_name: params.get("ad_name") ?? void 0,
@@ -102,22 +99,33 @@ async function getTags() {
102
99
  campaign_id: params.get("campaign_id") ?? void 0,
103
100
  campaign_name: params.get("campaign_name") ?? void 0,
104
101
  placement: params.get("placement") ?? void 0,
105
- gclid: params.get("gclid") ?? require_click_id_index.parseGcl(parsed._gcl_aw)?.clickId,
102
+ gclid: params.get("gclid") ?? void 0,
106
103
  gclsrc: params.get("gclsrc") ?? void 0,
107
104
  gad_source: params.get("gad_source") ?? void 0,
108
105
  gad_campaignid: params.get("gad_campaignid") ?? void 0,
109
- rdt_cid: params.get("rdt_cid") ?? parsed._rdt_cid ?? void 0,
110
- rdt_uuid: parsed._rdt_uuid,
111
- li_fat_id: params.get("li_fat_id") ?? parsed.li_fat_id ?? void 0,
106
+ wbraid: params.get("wbraid") ?? void 0,
107
+ gbraid: params.get("gbraid") ?? void 0,
112
108
  dclid: params.get("dclid") ?? void 0,
109
+ msclkid: params.get("msclkid") ?? void 0,
110
+ rdt_cid: params.get("rdt_cid") ?? void 0,
111
+ li_fat_id: params.get("li_fat_id") ?? void 0,
112
+ oppref: params.get("oppref") ?? void 0,
113
113
  ko_click_id: params.get("ko_click_id") ?? void 0,
114
- msclkid: params.get("msclkid") ?? require_click_id_index.parseUetMsclkid(parsed._uetmsclkid),
115
- sccid: params.get("sccid") ?? void 0,
114
+ ScCid: params.get("ScCid") ?? void 0,
116
115
  ttclid: params.get("ttclid") ?? void 0,
117
116
  twclid: params.get("twclid") ?? void 0,
118
- wbraid: params.get("wbraid") ?? require_click_id_index.parseGcl(parsed._gcl_gb)?.clickId,
119
- gbraid: params.get("gbraid") ?? void 0,
120
117
  yclid: params.get("yclid") ?? void 0,
118
+ epik: params.get("epik") ?? void 0,
119
+ _fbc: parsed._fbc || void 0,
120
+ _fbp: parsed._fbp || void 0,
121
+ _gcl_aw: parsed._gcl_aw || void 0,
122
+ _gcl_gb: parsed._gcl_gb || void 0,
123
+ _uetmsclkid: parsed._uetmsclkid || void 0,
124
+ _rdt_cid: parsed._rdt_cid || void 0,
125
+ _rdt_uuid: parsed._rdt_uuid || void 0,
126
+ _li_fat_id: parsed.li_fat_id || void 0,
127
+ __oppref: parsed.__oppref || void 0,
128
+ __obref: parsed.__obref || void 0,
121
129
  utm_source: link?.utm_source ?? params.get("utm_source") ?? void 0,
122
130
  utm_medium: link?.utm_medium ?? params.get("utm_medium") ?? void 0,
123
131
  utm_campaign: link?.utm_campaign ?? params.get("utm_campaign") ?? void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["uuidv4","config","keys","getLink","getPageKey","Bowser","parseCookie","parseGcl","parseUetMsclkid"],"sources":["../../src/web/index.ts"],"sourcesContent":["import Bowser from 'bowser';\nimport { parseCookie } from 'cookie';\nimport { v4 as uuidv4 } from 'uuid';\nimport { parseGcl, parseUetMsclkid } from '../click-id/index';\nimport { keys } from '../constants/storage';\nimport { type Link, getLink } from '../link/index';\nimport { type Storage, cache, config } from '../setup/index';\nimport type { TrackTags } from '../track/types';\nimport { getPageKey } from './page-key';\n\n// lib.dom types `crypto.randomUUID` as always present, but it is missing in insecure contexts\n// and older browsers, so probe it before use.\nfunction randomUUID(): string {\n return (crypto as Partial<Crypto>).randomUUID ? crypto.randomUUID() : uuidv4();\n}\n\nexport function getDeviceId() {\n const cached = config.storage.getItem(keys.device_id);\n if (cached) return cached;\n const id = randomUUID();\n config.storage.setItem(keys.device_id, id);\n return id;\n}\n\n/**\n * The current page load, keyed by the page it was loaded at. A module variable and nothing more\n * persistent: the id must die with the page (a reload is a new page load, and storage would\n * carry it over — or, shared across tabs, let two pages overwrite each other's).\n *\n * Keyed by `getPageKey` because that is what the SDK's own `page_view` fires on (see\n * `useWebAnalytics`): the id exists to link an event to the `page_view` of the page it happened\n * on, so it must rotate exactly when a `page_view` is sent — path or query change, yes; hash\n * change or tracking-parameter cleanup, no.\n */\nlet pageLoad: { page: string; id: string } | undefined;\n\nfunction getPageLoadId(page: string): string {\n if (pageLoad?.page !== page) pageLoad = { page, id: randomUUID() };\n return pageLoad.id;\n}\n\nconst links = new Map<string, Promise<Link | null>>();\n\n/**\n * `getTags` runs once per event now, and the link a `?s=` id points at cannot change while the\n * page is open, so an uncached lookup would put an identical request on the wire for every\n * event the page sends.\n */\nfunction getCachedLink(id: string) {\n const cached = links.get(id);\n if (cached) return cached;\n const link = getLink(id).then((result) => {\n // A lookup that came back empty must not stick for the lifetime of the page. `getLink`\n // answers null for a network failure as well as for a link that does not exist, and losing\n // the link's utm params for every later event costs more than repeating a rare request.\n if (!result) links.delete(id);\n return result;\n });\n links.set(id, link);\n return link;\n}\n\n/** The user agent cannot change while the page is open, so it is parsed once. */\nlet parser: ReturnType<typeof Bowser.getParser> | undefined;\n\nexport async function getTags() {\n // Read the page before the first await: `getTags` runs when the event happens, and a single\n // page app can navigate while the link lookup below is still in flight.\n const page_location = window.location.href;\n const page_load_id = getPageLoadId(getPageKey(window.location.pathname, window.location.search));\n const page_referrer = document.referrer || undefined;\n const page_title = document.title;\n\n parser ??= Bowser.getParser(window.navigator.userAgent);\n const params = new URLSearchParams(window.location.search);\n const os = parser.getOS();\n const browser = parser.getBrowser();\n const platform = parser.getPlatform();\n const parsed = parseCookie(document.cookie);\n\n const linkId = params.get('s');\n const link = linkId ? await getCachedLink(linkId) : null;\n\n const tags: TrackTags = {\n os: `${os.name} ${os.version}`,\n os_name: os.name,\n os_version: os.version,\n browser: `${browser.name} ${browser.version}`,\n browser_name: browser.name,\n browser_version: browser.version,\n device: platform.model,\n device_id: getDeviceId(),\n device_type: platform.type,\n device_vendor: platform.vendor,\n device_pixel_ratio: window.devicePixelRatio,\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n screen_resolution: `${window.screen.width}x${window.screen.height}`,\n webdriver: navigator.webdriver || undefined,\n release: config.release,\n language: navigator.language,\n time_zone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n page_location,\n page_referrer,\n page_title,\n page_load_id,\n // Meta Ads — _fbc is set server-side (see @shware/analytics/server resolveClickIdCookies)\n fbc: parsed._fbc ?? undefined,\n fbp: parsed._fbp,\n fbclid: params.get('fbclid') ?? undefined,\n ad_id: params.get('ad_id') ?? undefined,\n ad_name: params.get('ad_name') ?? undefined,\n adset_id: params.get('adset_id') ?? undefined,\n adset_name: params.get('adset_name') ?? undefined,\n campaign_id: params.get('campaign_id') ?? undefined,\n campaign_name: params.get('campaign_name') ?? undefined,\n placement: params.get('placement') ?? undefined,\n // Google Ads — _gcl_aw/_gcl_gb are written by gtag and kept alive server-side (see\n // @shware/analytics/server resolveClickIdCookies); the URL wins, the cookie carries the\n // click id to every later page of the visit and to returning visits.\n gclid: params.get('gclid') ?? parseGcl(parsed._gcl_aw)?.clickId,\n gclsrc: params.get('gclsrc') ?? undefined,\n gad_source: params.get('gad_source') ?? undefined,\n gad_campaignid: params.get('gad_campaignid') ?? undefined,\n // Reddit Ads — _rdt_cid is set server-side (see @shware/analytics/server resolveClickIdCookies)\n rdt_cid: params.get('rdt_cid') ?? parsed._rdt_cid ?? undefined,\n rdt_uuid: parsed._rdt_uuid,\n // LinkedIn Ads: get click id from url params or first-party cookie\n li_fat_id: params.get('li_fat_id') ?? parsed.li_fat_id ?? undefined,\n // click ids\n dclid: params.get('dclid') ?? undefined,\n ko_click_id: params.get('ko_click_id') ?? undefined,\n // Microsoft Ads — _uetmsclkid is written by the UET tag and kept alive server-side (see\n // @shware/analytics/server resolveClickIdCookies); the URL wins, the cookie carries the\n // click id to every later page of the visit and to returning visits.\n msclkid: params.get('msclkid') ?? parseUetMsclkid(parsed._uetmsclkid),\n sccid: params.get('sccid') ?? undefined,\n ttclid: params.get('ttclid') ?? undefined,\n twclid: params.get('twclid') ?? undefined,\n wbraid: params.get('wbraid') ?? parseGcl(parsed._gcl_gb)?.clickId,\n gbraid: params.get('gbraid') ?? undefined,\n yclid: params.get('yclid') ?? undefined,\n // utm params\n utm_source: link?.utm_source ?? params.get('utm_source') ?? undefined,\n utm_medium: link?.utm_medium ?? params.get('utm_medium') ?? undefined,\n utm_campaign: link?.utm_campaign ?? params.get('utm_campaign') ?? undefined,\n utm_term: link?.utm_term ?? params.get('utm_term') ?? undefined,\n utm_content: link?.utm_content ?? params.get('utm_content') ?? undefined,\n utm_id: link?.utm_id ?? params.get('utm_id') ?? undefined,\n utm_source_platform:\n link?.utm_source_platform ?? params.get('utm_source_platform') ?? undefined,\n utm_creative_format:\n link?.utm_creative_format ?? params.get('utm_creative_format') ?? undefined,\n utm_marketing_tactic:\n link?.utm_marketing_tactic ?? params.get('utm_marketing_tactic') ?? undefined,\n };\n\n cache.tags = tags;\n return tags;\n}\n\nconst map = new Map<string, string>();\n\nexport const storage: Storage = {\n getItem: (key) => {\n try {\n return localStorage.getItem(key);\n } catch {\n console.error('localStorage is not available');\n return map.get(key) ?? null;\n }\n },\n setItem: (key, value) => {\n try {\n localStorage.setItem(key, value);\n } catch {\n console.error('localStorage is not available');\n map.set(key, value);\n }\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["uuidv4","config","keys","getLink","getPageKey","Bowser","parseCookie"],"sources":["../../src/web/index.ts"],"sourcesContent":["import Bowser from 'bowser';\nimport { parseCookie } from 'cookie';\nimport { v4 as uuidv4 } from 'uuid';\nimport { keys } from '../constants/storage';\nimport { type Link, getLink } from '../link/index';\nimport { type Storage, cache, config } from '../setup/index';\nimport type { TrackTags } from '../track/types';\nimport { getPageKey } from './page-key';\n\n// lib.dom types `crypto.randomUUID` as always present, but it is missing in insecure contexts\n// and older browsers, so probe it before use.\nfunction randomUUID(): string {\n return (crypto as Partial<Crypto>).randomUUID ? crypto.randomUUID() : uuidv4();\n}\n\nexport function getDeviceId() {\n const cached = config.storage.getItem(keys.device_id);\n if (cached) return cached;\n const id = randomUUID();\n config.storage.setItem(keys.device_id, id);\n return id;\n}\n\n/**\n * The current page load, keyed by the page it was loaded at. A module variable and nothing more\n * persistent: the id must die with the page (a reload is a new page load, and storage would\n * carry it over — or, shared across tabs, let two pages overwrite each other's).\n *\n * Keyed by `getPageKey` because that is what the SDK's own `page_view` fires on (see\n * `useWebAnalytics`): the id exists to link an event to the `page_view` of the page it happened\n * on, so it must rotate exactly when a `page_view` is sent — path or query change, yes; hash\n * change or tracking-parameter cleanup, no.\n */\nlet pageLoad: { page: string; id: string } | undefined;\n\nfunction getPageLoadId(page: string): string {\n if (pageLoad?.page !== page) pageLoad = { page, id: randomUUID() };\n return pageLoad.id;\n}\n\nconst links = new Map<string, Promise<Link | null>>();\n\n/**\n * `getTags` runs once per event now, and the link a `?s=` id points at cannot change while the\n * page is open, so an uncached lookup would put an identical request on the wire for every\n * event the page sends.\n */\nfunction getCachedLink(id: string) {\n const cached = links.get(id);\n if (cached) return cached;\n const link = getLink(id).then((result) => {\n // A lookup that came back empty must not stick for the lifetime of the page. `getLink`\n // answers null for a network failure as well as for a link that does not exist, and losing\n // the link's utm params for every later event costs more than repeating a rare request.\n if (!result) links.delete(id);\n return result;\n });\n links.set(id, link);\n return link;\n}\n\n/** The user agent cannot change while the page is open, so it is parsed once. */\nlet parser: ReturnType<typeof Bowser.getParser> | undefined;\n\nexport async function getTags() {\n // Read the page before the first await: `getTags` runs when the event happens, and a single\n // page app can navigate while the link lookup below is still in flight.\n const page_location = window.location.href;\n const page_load_id = getPageLoadId(getPageKey(window.location.pathname, window.location.search));\n const page_referrer = document.referrer || undefined;\n const page_title = document.title;\n\n parser ??= Bowser.getParser(window.navigator.userAgent);\n const params = new URLSearchParams(window.location.search);\n const os = parser.getOS();\n const browser = parser.getBrowser();\n const platform = parser.getPlatform();\n const parsed = parseCookie(document.cookie);\n\n const linkId = params.get('s');\n const link = linkId ? await getCachedLink(linkId) : null;\n\n const tags: TrackTags = {\n os: `${os.name} ${os.version}`,\n os_name: os.name,\n os_version: os.version,\n browser: `${browser.name} ${browser.version}`,\n browser_name: browser.name,\n browser_version: browser.version,\n device: platform.model,\n device_id: getDeviceId(),\n device_type: platform.type,\n device_vendor: platform.vendor,\n device_pixel_ratio: window.devicePixelRatio,\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n screen_resolution: `${window.screen.width}x${window.screen.height}`,\n webdriver: navigator.webdriver || undefined,\n release: config.release,\n language: navigator.language,\n time_zone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n page_location,\n page_referrer,\n page_title,\n page_load_id,\n // Ad click ids from the URL, each under its parameter's name: this page's click, which\n // names the visit's channel (`CLICK_ID_CHANNELS`). Never filled from a cookie — a cookie\n // outlives the click; the cookies go below under their own names.\n fbclid: params.get('fbclid') ?? undefined,\n ad_id: params.get('ad_id') ?? undefined,\n ad_name: params.get('ad_name') ?? undefined,\n adset_id: params.get('adset_id') ?? undefined,\n adset_name: params.get('adset_name') ?? undefined,\n campaign_id: params.get('campaign_id') ?? undefined,\n campaign_name: params.get('campaign_name') ?? undefined,\n placement: params.get('placement') ?? undefined,\n gclid: params.get('gclid') ?? undefined,\n gclsrc: params.get('gclsrc') ?? undefined,\n gad_source: params.get('gad_source') ?? undefined,\n gad_campaignid: params.get('gad_campaignid') ?? undefined,\n wbraid: params.get('wbraid') ?? undefined,\n gbraid: params.get('gbraid') ?? undefined,\n dclid: params.get('dclid') ?? undefined,\n msclkid: params.get('msclkid') ?? undefined,\n rdt_cid: params.get('rdt_cid') ?? undefined,\n li_fat_id: params.get('li_fat_id') ?? undefined,\n oppref: params.get('oppref') ?? undefined,\n ko_click_id: params.get('ko_click_id') ?? undefined,\n // Snapchat appends `ScCid`, and URL parameters are case-sensitive.\n ScCid: params.get('ScCid') ?? undefined,\n ttclid: params.get('ttclid') ?? undefined,\n twclid: params.get('twclid') ?? undefined,\n yclid: params.get('yclid') ?? undefined,\n epik: params.get('epik') ?? undefined,\n // The ad platforms' first-party cookies, raw and under the cookie's own name, for the\n // conversion senders only: they carry the click to the later pages and visits where the\n // URL no longer does. `_fbc`, `_rdt_cid`, `_gcl_*` and `_uetmsclkid` are kept alive\n // server-side (see @shware/analytics/server resolveClickIdCookies); the rest are the pixels'.\n _fbc: parsed._fbc || undefined,\n _fbp: parsed._fbp || undefined,\n _gcl_aw: parsed._gcl_aw || undefined,\n _gcl_gb: parsed._gcl_gb || undefined,\n _uetmsclkid: parsed._uetmsclkid || undefined,\n _rdt_cid: parsed._rdt_cid || undefined,\n _rdt_uuid: parsed._rdt_uuid || undefined,\n // The Insight Tag's cookie is itself named `li_fat_id`; renamed so it cannot pass for the\n // URL parameter.\n _li_fat_id: parsed.li_fat_id || undefined,\n __oppref: parsed.__oppref || undefined,\n __obref: parsed.__obref || undefined,\n // utm params\n utm_source: link?.utm_source ?? params.get('utm_source') ?? undefined,\n utm_medium: link?.utm_medium ?? params.get('utm_medium') ?? undefined,\n utm_campaign: link?.utm_campaign ?? params.get('utm_campaign') ?? undefined,\n utm_term: link?.utm_term ?? params.get('utm_term') ?? undefined,\n utm_content: link?.utm_content ?? params.get('utm_content') ?? undefined,\n utm_id: link?.utm_id ?? params.get('utm_id') ?? undefined,\n utm_source_platform:\n link?.utm_source_platform ?? params.get('utm_source_platform') ?? undefined,\n utm_creative_format:\n link?.utm_creative_format ?? params.get('utm_creative_format') ?? undefined,\n utm_marketing_tactic:\n link?.utm_marketing_tactic ?? params.get('utm_marketing_tactic') ?? undefined,\n };\n\n cache.tags = tags;\n return tags;\n}\n\nconst map = new Map<string, string>();\n\nexport const storage: Storage = {\n getItem: (key) => {\n try {\n return localStorage.getItem(key);\n } catch {\n console.error('localStorage is not available');\n return map.get(key) ?? null;\n }\n },\n setItem: (key, value) => {\n try {\n localStorage.setItem(key, value);\n } catch {\n console.error('localStorage is not available');\n map.set(key, value);\n }\n },\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/web/index.ts"],"mappings":";;;wBAgBgB;wBAiDM,WAAO,QAAA;qBAkGhB,SAAS"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/web/index.ts"],"mappings":";;;wBAegB;wBAiDM,WAAO,QAAA;qBA2GhB,SAAS"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/web/index.ts"],"mappings":";;;wBAgBgB;wBAiDM,WAAO,QAAA;qBAkGhB,SAAS"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/web/index.ts"],"mappings":";;;wBAegB;wBAiDM,WAAO,QAAA;qBA2GhB,SAAS"}
@@ -2,7 +2,6 @@ import { __toESM } from "../_virtual/_rolldown/runtime.mjs";
2
2
  import { cache, config } from "../setup/index.mjs";
3
3
  import { keys } from "../constants/storage.mjs";
4
4
  import { getLink } from "../link/index.mjs";
5
- import { parseGcl, parseUetMsclkid } from "../click-id/index.mjs";
6
5
  import { getPageKey } from "./page-key.mjs";
7
6
  import { require_es5 } from "../node_modules/.pnpm/bowser@2.14.1/node_modules/bowser/es5.mjs";
8
7
  import { v4 } from "uuid";
@@ -91,8 +90,6 @@ async function getTags() {
91
90
  page_referrer,
92
91
  page_title,
93
92
  page_load_id,
94
- fbc: parsed._fbc ?? void 0,
95
- fbp: parsed._fbp,
96
93
  fbclid: params.get("fbclid") ?? void 0,
97
94
  ad_id: params.get("ad_id") ?? void 0,
98
95
  ad_name: params.get("ad_name") ?? void 0,
@@ -101,22 +98,33 @@ async function getTags() {
101
98
  campaign_id: params.get("campaign_id") ?? void 0,
102
99
  campaign_name: params.get("campaign_name") ?? void 0,
103
100
  placement: params.get("placement") ?? void 0,
104
- gclid: params.get("gclid") ?? parseGcl(parsed._gcl_aw)?.clickId,
101
+ gclid: params.get("gclid") ?? void 0,
105
102
  gclsrc: params.get("gclsrc") ?? void 0,
106
103
  gad_source: params.get("gad_source") ?? void 0,
107
104
  gad_campaignid: params.get("gad_campaignid") ?? void 0,
108
- rdt_cid: params.get("rdt_cid") ?? parsed._rdt_cid ?? void 0,
109
- rdt_uuid: parsed._rdt_uuid,
110
- li_fat_id: params.get("li_fat_id") ?? parsed.li_fat_id ?? void 0,
105
+ wbraid: params.get("wbraid") ?? void 0,
106
+ gbraid: params.get("gbraid") ?? void 0,
111
107
  dclid: params.get("dclid") ?? void 0,
108
+ msclkid: params.get("msclkid") ?? void 0,
109
+ rdt_cid: params.get("rdt_cid") ?? void 0,
110
+ li_fat_id: params.get("li_fat_id") ?? void 0,
111
+ oppref: params.get("oppref") ?? void 0,
112
112
  ko_click_id: params.get("ko_click_id") ?? void 0,
113
- msclkid: params.get("msclkid") ?? parseUetMsclkid(parsed._uetmsclkid),
114
- sccid: params.get("sccid") ?? void 0,
113
+ ScCid: params.get("ScCid") ?? void 0,
115
114
  ttclid: params.get("ttclid") ?? void 0,
116
115
  twclid: params.get("twclid") ?? void 0,
117
- wbraid: params.get("wbraid") ?? parseGcl(parsed._gcl_gb)?.clickId,
118
- gbraid: params.get("gbraid") ?? void 0,
119
116
  yclid: params.get("yclid") ?? void 0,
117
+ epik: params.get("epik") ?? void 0,
118
+ _fbc: parsed._fbc || void 0,
119
+ _fbp: parsed._fbp || void 0,
120
+ _gcl_aw: parsed._gcl_aw || void 0,
121
+ _gcl_gb: parsed._gcl_gb || void 0,
122
+ _uetmsclkid: parsed._uetmsclkid || void 0,
123
+ _rdt_cid: parsed._rdt_cid || void 0,
124
+ _rdt_uuid: parsed._rdt_uuid || void 0,
125
+ _li_fat_id: parsed.li_fat_id || void 0,
126
+ __oppref: parsed.__oppref || void 0,
127
+ __obref: parsed.__obref || void 0,
120
128
  utm_source: link?.utm_source ?? params.get("utm_source") ?? void 0,
121
129
  utm_medium: link?.utm_medium ?? params.get("utm_medium") ?? void 0,
122
130
  utm_campaign: link?.utm_campaign ?? params.get("utm_campaign") ?? void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["uuidv4","Bowser"],"sources":["../../src/web/index.ts"],"sourcesContent":["import Bowser from 'bowser';\nimport { parseCookie } from 'cookie';\nimport { v4 as uuidv4 } from 'uuid';\nimport { parseGcl, parseUetMsclkid } from '../click-id/index';\nimport { keys } from '../constants/storage';\nimport { type Link, getLink } from '../link/index';\nimport { type Storage, cache, config } from '../setup/index';\nimport type { TrackTags } from '../track/types';\nimport { getPageKey } from './page-key';\n\n// lib.dom types `crypto.randomUUID` as always present, but it is missing in insecure contexts\n// and older browsers, so probe it before use.\nfunction randomUUID(): string {\n return (crypto as Partial<Crypto>).randomUUID ? crypto.randomUUID() : uuidv4();\n}\n\nexport function getDeviceId() {\n const cached = config.storage.getItem(keys.device_id);\n if (cached) return cached;\n const id = randomUUID();\n config.storage.setItem(keys.device_id, id);\n return id;\n}\n\n/**\n * The current page load, keyed by the page it was loaded at. A module variable and nothing more\n * persistent: the id must die with the page (a reload is a new page load, and storage would\n * carry it over — or, shared across tabs, let two pages overwrite each other's).\n *\n * Keyed by `getPageKey` because that is what the SDK's own `page_view` fires on (see\n * `useWebAnalytics`): the id exists to link an event to the `page_view` of the page it happened\n * on, so it must rotate exactly when a `page_view` is sent — path or query change, yes; hash\n * change or tracking-parameter cleanup, no.\n */\nlet pageLoad: { page: string; id: string } | undefined;\n\nfunction getPageLoadId(page: string): string {\n if (pageLoad?.page !== page) pageLoad = { page, id: randomUUID() };\n return pageLoad.id;\n}\n\nconst links = new Map<string, Promise<Link | null>>();\n\n/**\n * `getTags` runs once per event now, and the link a `?s=` id points at cannot change while the\n * page is open, so an uncached lookup would put an identical request on the wire for every\n * event the page sends.\n */\nfunction getCachedLink(id: string) {\n const cached = links.get(id);\n if (cached) return cached;\n const link = getLink(id).then((result) => {\n // A lookup that came back empty must not stick for the lifetime of the page. `getLink`\n // answers null for a network failure as well as for a link that does not exist, and losing\n // the link's utm params for every later event costs more than repeating a rare request.\n if (!result) links.delete(id);\n return result;\n });\n links.set(id, link);\n return link;\n}\n\n/** The user agent cannot change while the page is open, so it is parsed once. */\nlet parser: ReturnType<typeof Bowser.getParser> | undefined;\n\nexport async function getTags() {\n // Read the page before the first await: `getTags` runs when the event happens, and a single\n // page app can navigate while the link lookup below is still in flight.\n const page_location = window.location.href;\n const page_load_id = getPageLoadId(getPageKey(window.location.pathname, window.location.search));\n const page_referrer = document.referrer || undefined;\n const page_title = document.title;\n\n parser ??= Bowser.getParser(window.navigator.userAgent);\n const params = new URLSearchParams(window.location.search);\n const os = parser.getOS();\n const browser = parser.getBrowser();\n const platform = parser.getPlatform();\n const parsed = parseCookie(document.cookie);\n\n const linkId = params.get('s');\n const link = linkId ? await getCachedLink(linkId) : null;\n\n const tags: TrackTags = {\n os: `${os.name} ${os.version}`,\n os_name: os.name,\n os_version: os.version,\n browser: `${browser.name} ${browser.version}`,\n browser_name: browser.name,\n browser_version: browser.version,\n device: platform.model,\n device_id: getDeviceId(),\n device_type: platform.type,\n device_vendor: platform.vendor,\n device_pixel_ratio: window.devicePixelRatio,\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n screen_resolution: `${window.screen.width}x${window.screen.height}`,\n webdriver: navigator.webdriver || undefined,\n release: config.release,\n language: navigator.language,\n time_zone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n page_location,\n page_referrer,\n page_title,\n page_load_id,\n // Meta Ads — _fbc is set server-side (see @shware/analytics/server resolveClickIdCookies)\n fbc: parsed._fbc ?? undefined,\n fbp: parsed._fbp,\n fbclid: params.get('fbclid') ?? undefined,\n ad_id: params.get('ad_id') ?? undefined,\n ad_name: params.get('ad_name') ?? undefined,\n adset_id: params.get('adset_id') ?? undefined,\n adset_name: params.get('adset_name') ?? undefined,\n campaign_id: params.get('campaign_id') ?? undefined,\n campaign_name: params.get('campaign_name') ?? undefined,\n placement: params.get('placement') ?? undefined,\n // Google Ads — _gcl_aw/_gcl_gb are written by gtag and kept alive server-side (see\n // @shware/analytics/server resolveClickIdCookies); the URL wins, the cookie carries the\n // click id to every later page of the visit and to returning visits.\n gclid: params.get('gclid') ?? parseGcl(parsed._gcl_aw)?.clickId,\n gclsrc: params.get('gclsrc') ?? undefined,\n gad_source: params.get('gad_source') ?? undefined,\n gad_campaignid: params.get('gad_campaignid') ?? undefined,\n // Reddit Ads — _rdt_cid is set server-side (see @shware/analytics/server resolveClickIdCookies)\n rdt_cid: params.get('rdt_cid') ?? parsed._rdt_cid ?? undefined,\n rdt_uuid: parsed._rdt_uuid,\n // LinkedIn Ads: get click id from url params or first-party cookie\n li_fat_id: params.get('li_fat_id') ?? parsed.li_fat_id ?? undefined,\n // click ids\n dclid: params.get('dclid') ?? undefined,\n ko_click_id: params.get('ko_click_id') ?? undefined,\n // Microsoft Ads — _uetmsclkid is written by the UET tag and kept alive server-side (see\n // @shware/analytics/server resolveClickIdCookies); the URL wins, the cookie carries the\n // click id to every later page of the visit and to returning visits.\n msclkid: params.get('msclkid') ?? parseUetMsclkid(parsed._uetmsclkid),\n sccid: params.get('sccid') ?? undefined,\n ttclid: params.get('ttclid') ?? undefined,\n twclid: params.get('twclid') ?? undefined,\n wbraid: params.get('wbraid') ?? parseGcl(parsed._gcl_gb)?.clickId,\n gbraid: params.get('gbraid') ?? undefined,\n yclid: params.get('yclid') ?? undefined,\n // utm params\n utm_source: link?.utm_source ?? params.get('utm_source') ?? undefined,\n utm_medium: link?.utm_medium ?? params.get('utm_medium') ?? undefined,\n utm_campaign: link?.utm_campaign ?? params.get('utm_campaign') ?? undefined,\n utm_term: link?.utm_term ?? params.get('utm_term') ?? undefined,\n utm_content: link?.utm_content ?? params.get('utm_content') ?? undefined,\n utm_id: link?.utm_id ?? params.get('utm_id') ?? undefined,\n utm_source_platform:\n link?.utm_source_platform ?? params.get('utm_source_platform') ?? undefined,\n utm_creative_format:\n link?.utm_creative_format ?? params.get('utm_creative_format') ?? undefined,\n utm_marketing_tactic:\n link?.utm_marketing_tactic ?? params.get('utm_marketing_tactic') ?? undefined,\n };\n\n cache.tags = tags;\n return tags;\n}\n\nconst map = new Map<string, string>();\n\nexport const storage: Storage = {\n getItem: (key) => {\n try {\n return localStorage.getItem(key);\n } catch {\n console.error('localStorage is not available');\n return map.get(key) ?? null;\n }\n },\n setItem: (key, value) => {\n try {\n localStorage.setItem(key, value);\n } catch {\n console.error('localStorage is not available');\n map.set(key, value);\n }\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["uuidv4","Bowser"],"sources":["../../src/web/index.ts"],"sourcesContent":["import Bowser from 'bowser';\nimport { parseCookie } from 'cookie';\nimport { v4 as uuidv4 } from 'uuid';\nimport { keys } from '../constants/storage';\nimport { type Link, getLink } from '../link/index';\nimport { type Storage, cache, config } from '../setup/index';\nimport type { TrackTags } from '../track/types';\nimport { getPageKey } from './page-key';\n\n// lib.dom types `crypto.randomUUID` as always present, but it is missing in insecure contexts\n// and older browsers, so probe it before use.\nfunction randomUUID(): string {\n return (crypto as Partial<Crypto>).randomUUID ? crypto.randomUUID() : uuidv4();\n}\n\nexport function getDeviceId() {\n const cached = config.storage.getItem(keys.device_id);\n if (cached) return cached;\n const id = randomUUID();\n config.storage.setItem(keys.device_id, id);\n return id;\n}\n\n/**\n * The current page load, keyed by the page it was loaded at. A module variable and nothing more\n * persistent: the id must die with the page (a reload is a new page load, and storage would\n * carry it over — or, shared across tabs, let two pages overwrite each other's).\n *\n * Keyed by `getPageKey` because that is what the SDK's own `page_view` fires on (see\n * `useWebAnalytics`): the id exists to link an event to the `page_view` of the page it happened\n * on, so it must rotate exactly when a `page_view` is sent — path or query change, yes; hash\n * change or tracking-parameter cleanup, no.\n */\nlet pageLoad: { page: string; id: string } | undefined;\n\nfunction getPageLoadId(page: string): string {\n if (pageLoad?.page !== page) pageLoad = { page, id: randomUUID() };\n return pageLoad.id;\n}\n\nconst links = new Map<string, Promise<Link | null>>();\n\n/**\n * `getTags` runs once per event now, and the link a `?s=` id points at cannot change while the\n * page is open, so an uncached lookup would put an identical request on the wire for every\n * event the page sends.\n */\nfunction getCachedLink(id: string) {\n const cached = links.get(id);\n if (cached) return cached;\n const link = getLink(id).then((result) => {\n // A lookup that came back empty must not stick for the lifetime of the page. `getLink`\n // answers null for a network failure as well as for a link that does not exist, and losing\n // the link's utm params for every later event costs more than repeating a rare request.\n if (!result) links.delete(id);\n return result;\n });\n links.set(id, link);\n return link;\n}\n\n/** The user agent cannot change while the page is open, so it is parsed once. */\nlet parser: ReturnType<typeof Bowser.getParser> | undefined;\n\nexport async function getTags() {\n // Read the page before the first await: `getTags` runs when the event happens, and a single\n // page app can navigate while the link lookup below is still in flight.\n const page_location = window.location.href;\n const page_load_id = getPageLoadId(getPageKey(window.location.pathname, window.location.search));\n const page_referrer = document.referrer || undefined;\n const page_title = document.title;\n\n parser ??= Bowser.getParser(window.navigator.userAgent);\n const params = new URLSearchParams(window.location.search);\n const os = parser.getOS();\n const browser = parser.getBrowser();\n const platform = parser.getPlatform();\n const parsed = parseCookie(document.cookie);\n\n const linkId = params.get('s');\n const link = linkId ? await getCachedLink(linkId) : null;\n\n const tags: TrackTags = {\n os: `${os.name} ${os.version}`,\n os_name: os.name,\n os_version: os.version,\n browser: `${browser.name} ${browser.version}`,\n browser_name: browser.name,\n browser_version: browser.version,\n device: platform.model,\n device_id: getDeviceId(),\n device_type: platform.type,\n device_vendor: platform.vendor,\n device_pixel_ratio: window.devicePixelRatio,\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n screen_resolution: `${window.screen.width}x${window.screen.height}`,\n webdriver: navigator.webdriver || undefined,\n release: config.release,\n language: navigator.language,\n time_zone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n page_location,\n page_referrer,\n page_title,\n page_load_id,\n // Ad click ids from the URL, each under its parameter's name: this page's click, which\n // names the visit's channel (`CLICK_ID_CHANNELS`). Never filled from a cookie — a cookie\n // outlives the click; the cookies go below under their own names.\n fbclid: params.get('fbclid') ?? undefined,\n ad_id: params.get('ad_id') ?? undefined,\n ad_name: params.get('ad_name') ?? undefined,\n adset_id: params.get('adset_id') ?? undefined,\n adset_name: params.get('adset_name') ?? undefined,\n campaign_id: params.get('campaign_id') ?? undefined,\n campaign_name: params.get('campaign_name') ?? undefined,\n placement: params.get('placement') ?? undefined,\n gclid: params.get('gclid') ?? undefined,\n gclsrc: params.get('gclsrc') ?? undefined,\n gad_source: params.get('gad_source') ?? undefined,\n gad_campaignid: params.get('gad_campaignid') ?? undefined,\n wbraid: params.get('wbraid') ?? undefined,\n gbraid: params.get('gbraid') ?? undefined,\n dclid: params.get('dclid') ?? undefined,\n msclkid: params.get('msclkid') ?? undefined,\n rdt_cid: params.get('rdt_cid') ?? undefined,\n li_fat_id: params.get('li_fat_id') ?? undefined,\n oppref: params.get('oppref') ?? undefined,\n ko_click_id: params.get('ko_click_id') ?? undefined,\n // Snapchat appends `ScCid`, and URL parameters are case-sensitive.\n ScCid: params.get('ScCid') ?? undefined,\n ttclid: params.get('ttclid') ?? undefined,\n twclid: params.get('twclid') ?? undefined,\n yclid: params.get('yclid') ?? undefined,\n epik: params.get('epik') ?? undefined,\n // The ad platforms' first-party cookies, raw and under the cookie's own name, for the\n // conversion senders only: they carry the click to the later pages and visits where the\n // URL no longer does. `_fbc`, `_rdt_cid`, `_gcl_*` and `_uetmsclkid` are kept alive\n // server-side (see @shware/analytics/server resolveClickIdCookies); the rest are the pixels'.\n _fbc: parsed._fbc || undefined,\n _fbp: parsed._fbp || undefined,\n _gcl_aw: parsed._gcl_aw || undefined,\n _gcl_gb: parsed._gcl_gb || undefined,\n _uetmsclkid: parsed._uetmsclkid || undefined,\n _rdt_cid: parsed._rdt_cid || undefined,\n _rdt_uuid: parsed._rdt_uuid || undefined,\n // The Insight Tag's cookie is itself named `li_fat_id`; renamed so it cannot pass for the\n // URL parameter.\n _li_fat_id: parsed.li_fat_id || undefined,\n __oppref: parsed.__oppref || undefined,\n __obref: parsed.__obref || undefined,\n // utm params\n utm_source: link?.utm_source ?? params.get('utm_source') ?? undefined,\n utm_medium: link?.utm_medium ?? params.get('utm_medium') ?? undefined,\n utm_campaign: link?.utm_campaign ?? params.get('utm_campaign') ?? undefined,\n utm_term: link?.utm_term ?? params.get('utm_term') ?? undefined,\n utm_content: link?.utm_content ?? params.get('utm_content') ?? undefined,\n utm_id: link?.utm_id ?? params.get('utm_id') ?? undefined,\n utm_source_platform:\n link?.utm_source_platform ?? params.get('utm_source_platform') ?? undefined,\n utm_creative_format:\n link?.utm_creative_format ?? params.get('utm_creative_format') ?? undefined,\n utm_marketing_tactic:\n link?.utm_marketing_tactic ?? params.get('utm_marketing_tactic') ?? undefined,\n };\n\n cache.tags = tags;\n return tags;\n}\n\nconst map = new Map<string, string>();\n\nexport const storage: Storage = {\n getItem: (key) => {\n try {\n return localStorage.getItem(key);\n } catch {\n console.error('localStorage is not available');\n return map.get(key) ?? null;\n }\n },\n setItem: (key, value) => {\n try {\n localStorage.setItem(key, value);\n } catch {\n console.error('localStorage is not available');\n map.set(key, value);\n }\n },\n};\n"],"mappings":"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"}
@@ -29,9 +29,11 @@ const TRACKING_PARAMS = /* @__PURE__ */ new Set([
29
29
  "li_fat_id",
30
30
  "ttclid",
31
31
  "twclid",
32
- "sccid",
32
+ "ScCid",
33
33
  "ko_click_id",
34
- "yclid"
34
+ "yclid",
35
+ "oppref",
36
+ "epik"
35
37
  ]);
36
38
  function isTrackingParam(name) {
37
39
  return name.startsWith("utm_") || TRACKING_PARAMS.has(name);
@@ -1 +1 @@
1
- {"version":3,"file":"page-key.cjs","names":[],"sources":["../../src/web/page-key.ts"],"sourcesContent":["/**\n * What makes two URLs \"the same page\" for page views and the page load id.\n *\n * Path plus query, in line with GA4's enhanced measurement (a history change with a new path\n * or query is a page view), Next.js's documented pattern (`usePathname` + `useSearchParams`)\n * and PostHog's `history_change`: `?page=2` and `?q=shoes` are different pages to a funnel.\n * The hash is not part of it — an in-page anchor is not a navigation, and GA4 ignores\n * fragment-only changes by default too.\n *\n * Tracking parameters are stripped before comparing. A landing page commonly cleans `utm_*`\n * and the ad click ids out of its URL with `replaceState` once they are captured; keyed on the\n * raw query, that cleanup would count as a second page view of the landing page. (GA4 has this\n * quirk; the usual advice is to strip before comparing.) The parameters are the ones `getTags`\n * captures — nothing a page's own state lives in.\n */\n\nconst TRACKING_PARAMS = new Set([\n 'fbclid',\n 'gclid',\n 'gclsrc',\n 'gad_source',\n 'gad_campaignid',\n 'gbraid',\n 'wbraid',\n 'dclid',\n 'msclkid',\n 'rdt_cid',\n 'li_fat_id',\n 'ttclid',\n 'twclid',\n 'sccid',\n 'ko_click_id',\n 'yclid',\n]);\n\nfunction isTrackingParam(name: string): boolean {\n return name.startsWith('utm_') || TRACKING_PARAMS.has(name);\n}\n\n/**\n * `pathname` plus the query with tracking parameters removed and the rest sorted, so two URLs\n * that differ only in tracking decoration or parameter order map to one key.\n */\nexport function getPageKey(pathname: string, search = ''): string {\n const params = new URLSearchParams(search);\n for (const name of Array.from(params.keys())) {\n if (isTrackingParam(name)) params.delete(name);\n }\n params.sort();\n const query = params.toString();\n return query ? `${pathname}?${query}` : pathname;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAgBA,MAAM,kCAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,gBAAgB,MAAuB;CAC9C,OAAO,KAAK,WAAW,MAAM,KAAK,gBAAgB,IAAI,IAAI;AAC5D;;;;;AAMA,SAAgB,WAAW,UAAkB,SAAS,IAAY;CAChE,MAAM,SAAS,IAAI,gBAAgB,MAAM;CACzC,KAAK,MAAM,QAAQ,MAAM,KAAK,OAAO,KAAK,CAAC,GACzC,IAAI,gBAAgB,IAAI,GAAG,OAAO,OAAO,IAAI;CAE/C,OAAO,KAAK;CACZ,MAAM,QAAQ,OAAO,SAAS;CAC9B,OAAO,QAAQ,GAAG,SAAS,GAAG,UAAU;AAC1C"}
1
+ {"version":3,"file":"page-key.cjs","names":[],"sources":["../../src/web/page-key.ts"],"sourcesContent":["/**\n * What makes two URLs \"the same page\" for page views and the page load id.\n *\n * Path plus query, in line with GA4's enhanced measurement (a history change with a new path\n * or query is a page view), Next.js's documented pattern (`usePathname` + `useSearchParams`)\n * and PostHog's `history_change`: `?page=2` and `?q=shoes` are different pages to a funnel.\n * The hash is not part of it — an in-page anchor is not a navigation, and GA4 ignores\n * fragment-only changes by default too.\n *\n * Tracking parameters are stripped before comparing. A landing page commonly cleans `utm_*`\n * and the ad click ids out of its URL with `replaceState` once they are captured; keyed on the\n * raw query, that cleanup would count as a second page view of the landing page. (GA4 has this\n * quirk; the usual advice is to strip before comparing.) The parameters are the ones `getTags`\n * captures — nothing a page's own state lives in.\n */\n\nconst TRACKING_PARAMS = new Set([\n 'fbclid',\n 'gclid',\n 'gclsrc',\n 'gad_source',\n 'gad_campaignid',\n 'gbraid',\n 'wbraid',\n 'dclid',\n 'msclkid',\n 'rdt_cid',\n 'li_fat_id',\n 'ttclid',\n 'twclid',\n 'ScCid',\n 'ko_click_id',\n 'yclid',\n 'oppref',\n 'epik',\n]);\n\nfunction isTrackingParam(name: string): boolean {\n return name.startsWith('utm_') || TRACKING_PARAMS.has(name);\n}\n\n/**\n * `pathname` plus the query with tracking parameters removed and the rest sorted, so two URLs\n * that differ only in tracking decoration or parameter order map to one key.\n */\nexport function getPageKey(pathname: string, search = ''): string {\n const params = new URLSearchParams(search);\n for (const name of Array.from(params.keys())) {\n if (isTrackingParam(name)) params.delete(name);\n }\n params.sort();\n const query = params.toString();\n return query ? `${pathname}?${query}` : pathname;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAgBA,MAAM,kCAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,gBAAgB,MAAuB;CAC9C,OAAO,KAAK,WAAW,MAAM,KAAK,gBAAgB,IAAI,IAAI;AAC5D;;;;;AAMA,SAAgB,WAAW,UAAkB,SAAS,IAAY;CAChE,MAAM,SAAS,IAAI,gBAAgB,MAAM;CACzC,KAAK,MAAM,QAAQ,MAAM,KAAK,OAAO,KAAK,CAAC,GACzC,IAAI,gBAAgB,IAAI,GAAG,OAAO,OAAO,IAAI;CAE/C,OAAO,KAAK;CACZ,MAAM,QAAQ,OAAO,SAAS;CAC9B,OAAO,QAAQ,GAAG,SAAS,GAAG,UAAU;AAC1C"}
@@ -1 +1 @@
1
- {"version":3,"file":"page-key.d.cts","names":[],"sources":["../../src/web/page-key.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;wBA2CgB,WAAW,kBAAkB"}
1
+ {"version":3,"file":"page-key.d.cts","names":[],"sources":["../../src/web/page-key.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;wBA6CgB,WAAW,kBAAkB"}
@@ -1 +1 @@
1
- {"version":3,"file":"page-key.d.mts","names":[],"sources":["../../src/web/page-key.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;wBA2CgB,WAAW,kBAAkB"}
1
+ {"version":3,"file":"page-key.d.mts","names":[],"sources":["../../src/web/page-key.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;wBA6CgB,WAAW,kBAAkB"}
@@ -28,9 +28,11 @@ const TRACKING_PARAMS = /* @__PURE__ */ new Set([
28
28
  "li_fat_id",
29
29
  "ttclid",
30
30
  "twclid",
31
- "sccid",
31
+ "ScCid",
32
32
  "ko_click_id",
33
- "yclid"
33
+ "yclid",
34
+ "oppref",
35
+ "epik"
34
36
  ]);
35
37
  function isTrackingParam(name) {
36
38
  return name.startsWith("utm_") || TRACKING_PARAMS.has(name);
@@ -1 +1 @@
1
- {"version":3,"file":"page-key.mjs","names":[],"sources":["../../src/web/page-key.ts"],"sourcesContent":["/**\n * What makes two URLs \"the same page\" for page views and the page load id.\n *\n * Path plus query, in line with GA4's enhanced measurement (a history change with a new path\n * or query is a page view), Next.js's documented pattern (`usePathname` + `useSearchParams`)\n * and PostHog's `history_change`: `?page=2` and `?q=shoes` are different pages to a funnel.\n * The hash is not part of it — an in-page anchor is not a navigation, and GA4 ignores\n * fragment-only changes by default too.\n *\n * Tracking parameters are stripped before comparing. A landing page commonly cleans `utm_*`\n * and the ad click ids out of its URL with `replaceState` once they are captured; keyed on the\n * raw query, that cleanup would count as a second page view of the landing page. (GA4 has this\n * quirk; the usual advice is to strip before comparing.) The parameters are the ones `getTags`\n * captures — nothing a page's own state lives in.\n */\n\nconst TRACKING_PARAMS = new Set([\n 'fbclid',\n 'gclid',\n 'gclsrc',\n 'gad_source',\n 'gad_campaignid',\n 'gbraid',\n 'wbraid',\n 'dclid',\n 'msclkid',\n 'rdt_cid',\n 'li_fat_id',\n 'ttclid',\n 'twclid',\n 'sccid',\n 'ko_click_id',\n 'yclid',\n]);\n\nfunction isTrackingParam(name: string): boolean {\n return name.startsWith('utm_') || TRACKING_PARAMS.has(name);\n}\n\n/**\n * `pathname` plus the query with tracking parameters removed and the rest sorted, so two URLs\n * that differ only in tracking decoration or parameter order map to one key.\n */\nexport function getPageKey(pathname: string, search = ''): string {\n const params = new URLSearchParams(search);\n for (const name of Array.from(params.keys())) {\n if (isTrackingParam(name)) params.delete(name);\n }\n params.sort();\n const query = params.toString();\n return query ? `${pathname}?${query}` : pathname;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAM,kCAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,gBAAgB,MAAuB;CAC9C,OAAO,KAAK,WAAW,MAAM,KAAK,gBAAgB,IAAI,IAAI;AAC5D;;;;;AAMA,SAAgB,WAAW,UAAkB,SAAS,IAAY;CAChE,MAAM,SAAS,IAAI,gBAAgB,MAAM;CACzC,KAAK,MAAM,QAAQ,MAAM,KAAK,OAAO,KAAK,CAAC,GACzC,IAAI,gBAAgB,IAAI,GAAG,OAAO,OAAO,IAAI;CAE/C,OAAO,KAAK;CACZ,MAAM,QAAQ,OAAO,SAAS;CAC9B,OAAO,QAAQ,GAAG,SAAS,GAAG,UAAU;AAC1C"}
1
+ {"version":3,"file":"page-key.mjs","names":[],"sources":["../../src/web/page-key.ts"],"sourcesContent":["/**\n * What makes two URLs \"the same page\" for page views and the page load id.\n *\n * Path plus query, in line with GA4's enhanced measurement (a history change with a new path\n * or query is a page view), Next.js's documented pattern (`usePathname` + `useSearchParams`)\n * and PostHog's `history_change`: `?page=2` and `?q=shoes` are different pages to a funnel.\n * The hash is not part of it — an in-page anchor is not a navigation, and GA4 ignores\n * fragment-only changes by default too.\n *\n * Tracking parameters are stripped before comparing. A landing page commonly cleans `utm_*`\n * and the ad click ids out of its URL with `replaceState` once they are captured; keyed on the\n * raw query, that cleanup would count as a second page view of the landing page. (GA4 has this\n * quirk; the usual advice is to strip before comparing.) The parameters are the ones `getTags`\n * captures — nothing a page's own state lives in.\n */\n\nconst TRACKING_PARAMS = new Set([\n 'fbclid',\n 'gclid',\n 'gclsrc',\n 'gad_source',\n 'gad_campaignid',\n 'gbraid',\n 'wbraid',\n 'dclid',\n 'msclkid',\n 'rdt_cid',\n 'li_fat_id',\n 'ttclid',\n 'twclid',\n 'ScCid',\n 'ko_click_id',\n 'yclid',\n 'oppref',\n 'epik',\n]);\n\nfunction isTrackingParam(name: string): boolean {\n return name.startsWith('utm_') || TRACKING_PARAMS.has(name);\n}\n\n/**\n * `pathname` plus the query with tracking parameters removed and the rest sorted, so two URLs\n * that differ only in tracking decoration or parameter order map to one key.\n */\nexport function getPageKey(pathname: string, search = ''): string {\n const params = new URLSearchParams(search);\n for (const name of Array.from(params.keys())) {\n if (isTrackingParam(name)) params.delete(name);\n }\n params.sort();\n const query = params.toString();\n return query ? `${pathname}?${query}` : pathname;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAM,kCAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,gBAAgB,MAAuB;CAC9C,OAAO,KAAK,WAAW,MAAM,KAAK,gBAAgB,IAAI,IAAI;AAC5D;;;;;AAMA,SAAgB,WAAW,UAAkB,SAAS,IAAY;CAChE,MAAM,SAAS,IAAI,gBAAgB,MAAM;CACzC,KAAK,MAAM,QAAQ,MAAM,KAAK,OAAO,KAAK,CAAC,GACzC,IAAI,gBAAgB,IAAI,GAAG,OAAO,OAAO,IAAI;CAE/C,OAAO,KAAK;CACZ,MAAM,QAAQ,OAAO,SAAS;CAC9B,OAAO,QAAQ,GAAG,SAAS,GAAG,UAAU;AAC1C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shware/analytics",
3
- "version": "8.15.1",
3
+ "version": "9.0.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",