@shware/analytics 8.16.0 → 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.
- package/README.md +28 -4
- package/dist/attribution/classify.cjs +6 -6
- package/dist/attribution/classify.cjs.map +1 -1
- package/dist/attribution/classify.mjs +6 -6
- package/dist/attribution/classify.mjs.map +1 -1
- package/dist/attribution/vocabulary.cjs +3 -4
- package/dist/attribution/vocabulary.cjs.map +1 -1
- package/dist/attribution/vocabulary.d.cts +3 -4
- package/dist/attribution/vocabulary.d.cts.map +1 -1
- package/dist/attribution/vocabulary.d.mts +3 -4
- package/dist/attribution/vocabulary.d.mts.map +1 -1
- package/dist/attribution/vocabulary.mjs +3 -4
- package/dist/attribution/vocabulary.mjs.map +1 -1
- package/dist/click-id/index.cjs +24 -6
- package/dist/click-id/index.cjs.map +1 -1
- package/dist/click-id/index.d.cts +14 -3
- package/dist/click-id/index.d.cts.map +1 -1
- package/dist/click-id/index.d.mts +14 -3
- package/dist/click-id/index.d.mts.map +1 -1
- package/dist/click-id/index.mjs +23 -7
- package/dist/click-id/index.mjs.map +1 -1
- package/dist/schema/index.cjs +25 -9
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +114 -54
- package/dist/schema/index.d.cts.map +1 -1
- package/dist/schema/index.d.mts +114 -54
- package/dist/schema/index.d.mts.map +1 -1
- package/dist/schema/index.mjs +25 -9
- package/dist/schema/index.mjs.map +1 -1
- package/dist/server/click-ids.cjs +93 -0
- package/dist/server/click-ids.cjs.map +1 -0
- package/dist/server/click-ids.d.cts +40 -0
- package/dist/server/click-ids.d.cts.map +1 -0
- package/dist/server/click-ids.d.mts +40 -0
- package/dist/server/click-ids.d.mts.map +1 -0
- package/dist/server/click-ids.mjs +85 -0
- package/dist/server/click-ids.mjs.map +1 -0
- package/dist/server/google-data-manager.cjs +2 -1
- package/dist/server/google-data-manager.cjs.map +1 -1
- package/dist/server/google-data-manager.d.cts.map +1 -1
- package/dist/server/google-data-manager.d.mts.map +1 -1
- package/dist/server/google-data-manager.mjs +2 -1
- package/dist/server/google-data-manager.mjs.map +1 -1
- package/dist/server/linkedin-conversions-api.cjs +9 -4
- package/dist/server/linkedin-conversions-api.cjs.map +1 -1
- package/dist/server/linkedin-conversions-api.d.cts.map +1 -1
- package/dist/server/linkedin-conversions-api.d.mts.map +1 -1
- package/dist/server/linkedin-conversions-api.mjs +9 -4
- package/dist/server/linkedin-conversions-api.mjs.map +1 -1
- package/dist/server/meta-capi.cjs +5 -4
- package/dist/server/meta-capi.cjs.map +1 -1
- package/dist/server/meta-capi.mjs +5 -4
- package/dist/server/meta-capi.mjs.map +1 -1
- package/dist/server/meta-conversions-api.cjs +5 -4
- package/dist/server/meta-conversions-api.cjs.map +1 -1
- package/dist/server/meta-conversions-api.d.cts.map +1 -1
- package/dist/server/meta-conversions-api.d.mts.map +1 -1
- package/dist/server/meta-conversions-api.mjs +5 -4
- package/dist/server/meta-conversions-api.mjs.map +1 -1
- package/dist/server/microsoft-conversions-api.cjs +3 -1
- package/dist/server/microsoft-conversions-api.cjs.map +1 -1
- package/dist/server/microsoft-conversions-api.d.cts.map +1 -1
- package/dist/server/microsoft-conversions-api.d.mts.map +1 -1
- package/dist/server/microsoft-conversions-api.mjs +3 -1
- package/dist/server/microsoft-conversions-api.mjs.map +1 -1
- package/dist/server/openai-conversions-api.cjs +33 -11
- package/dist/server/openai-conversions-api.cjs.map +1 -1
- package/dist/server/openai-conversions-api.d.cts +19 -8
- package/dist/server/openai-conversions-api.d.cts.map +1 -1
- package/dist/server/openai-conversions-api.d.mts +19 -8
- package/dist/server/openai-conversions-api.d.mts.map +1 -1
- package/dist/server/openai-conversions-api.mjs +33 -11
- package/dist/server/openai-conversions-api.mjs.map +1 -1
- package/dist/server/reddit-conversions-api.cjs +3 -2
- package/dist/server/reddit-conversions-api.cjs.map +1 -1
- package/dist/server/reddit-conversions-api.d.cts.map +1 -1
- package/dist/server/reddit-conversions-api.d.mts.map +1 -1
- package/dist/server/reddit-conversions-api.mjs +3 -2
- package/dist/server/reddit-conversions-api.mjs.map +1 -1
- package/dist/track/types.d.cts +48 -16
- package/dist/track/types.d.cts.map +1 -1
- package/dist/track/types.d.mts +48 -16
- package/dist/track/types.d.mts.map +1 -1
- package/dist/web/index.cjs +17 -11
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.d.cts.map +1 -1
- package/dist/web/index.d.mts.map +1 -1
- package/dist/web/index.mjs +17 -11
- package/dist/web/index.mjs.map +1 -1
- 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
|
|
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
|
|
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
|
|
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"}
|
package/dist/track/types.d.cts
CHANGED
|
@@ -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,26 +144,55 @@ export interface AdvertisingInfo {
|
|
|
141
144
|
campaign_id?: string;
|
|
142
145
|
campaign_name?: string;
|
|
143
146
|
placement?: string;
|
|
144
|
-
/**
|
|
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
|
-
|
|
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
|
-
|
|
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
192
|
ScCid?: string;
|
|
158
193
|
ttclid?: string;
|
|
159
194
|
twclid?: string;
|
|
160
|
-
wbraid?: string;
|
|
161
|
-
gbraid?: string;
|
|
162
195
|
yclid?: string;
|
|
163
|
-
oppref?: string;
|
|
164
196
|
epik?: string;
|
|
165
197
|
}
|
|
166
198
|
/**
|
|
@@ -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
|
|
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"}
|
package/dist/track/types.d.mts
CHANGED
|
@@ -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,26 +144,55 @@ export interface AdvertisingInfo {
|
|
|
141
144
|
campaign_id?: string;
|
|
142
145
|
campaign_name?: string;
|
|
143
146
|
placement?: string;
|
|
144
|
-
/**
|
|
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
|
-
|
|
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
|
-
|
|
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
192
|
ScCid?: string;
|
|
158
193
|
ttclid?: string;
|
|
159
194
|
twclid?: string;
|
|
160
|
-
wbraid?: string;
|
|
161
|
-
gbraid?: string;
|
|
162
195
|
yclid?: string;
|
|
163
|
-
oppref?: string;
|
|
164
196
|
epik?: string;
|
|
165
197
|
}
|
|
166
198
|
/**
|
|
@@ -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
|
|
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"}
|
package/dist/web/index.cjs
CHANGED
|
@@ -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,24 +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") ??
|
|
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
|
-
|
|
110
|
-
|
|
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
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,
|
|
121
|
-
oppref: params.get("oppref") ?? void 0,
|
|
122
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,
|
|
123
129
|
utm_source: link?.utm_source ?? params.get("utm_source") ?? void 0,
|
|
124
130
|
utm_medium: link?.utm_medium ?? params.get("utm_medium") ?? void 0,
|
|
125
131
|
utm_campaign: link?.utm_campaign ?? params.get("utm_campaign") ?? void 0,
|
package/dist/web/index.cjs.map
CHANGED
|
@@ -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 // 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 wbraid: params.get('wbraid') ?? parseGcl(parsed._gcl_gb)?.clickId,\n gbraid: params.get('gbraid') ?? undefined,\n yclid: params.get('yclid') ?? undefined,\n // From the URL only, not the `__oppref` / `_epik` cookies the pixels keep: a cookie outlives\n // the click, and a click id here names the visit's channel (`CLICK_ID_CHANNELS`).\n oppref: params.get('oppref') ?? undefined,\n epik: params.get('epik') ?? 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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"}
|
package/dist/web/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/web/index.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/web/index.ts"],"mappings":";;;wBAegB;wBAiDM,WAAO,QAAA;qBA2GhB,SAAS"}
|
package/dist/web/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/web/index.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/web/index.ts"],"mappings":";;;wBAegB;wBAiDM,WAAO,QAAA;qBA2GhB,SAAS"}
|
package/dist/web/index.mjs
CHANGED
|
@@ -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,24 +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") ??
|
|
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
|
-
|
|
109
|
-
|
|
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
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,
|
|
120
|
-
oppref: params.get("oppref") ?? void 0,
|
|
121
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,
|
|
122
128
|
utm_source: link?.utm_source ?? params.get("utm_source") ?? void 0,
|
|
123
129
|
utm_medium: link?.utm_medium ?? params.get("utm_medium") ?? void 0,
|
|
124
130
|
utm_campaign: link?.utm_campaign ?? params.get("utm_campaign") ?? void 0,
|
package/dist/web/index.mjs.map
CHANGED
|
@@ -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 // 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 wbraid: params.get('wbraid') ?? parseGcl(parsed._gcl_gb)?.clickId,\n gbraid: params.get('gbraid') ?? undefined,\n yclid: params.get('yclid') ?? undefined,\n // From the URL only, not the `__oppref` / `_epik` cookies the pixels keep: a cookie outlives\n // the click, and a click id here names the visit's channel (`CLICK_ID_CHANNELS`).\n oppref: params.get('oppref') ?? undefined,\n epik: params.get('epik') ?? 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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"}
|