@shware/analytics 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.cjs +2 -0
- package/dist/_virtual/_rolldown/runtime.mjs +24 -0
- package/dist/hooks/use-outbound-click-analytics.cjs +2 -2
- package/dist/hooks/use-outbound-click-analytics.cjs.map +1 -1
- package/dist/hooks/use-outbound-click-analytics.mjs +2 -2
- package/dist/hooks/use-outbound-click-analytics.mjs.map +1 -1
- package/dist/index.cjs +0 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/native/fingerprint.cjs +3 -3
- package/dist/native/fingerprint.cjs.map +1 -1
- package/dist/native/fingerprint.mjs +3 -3
- package/dist/native/fingerprint.mjs.map +1 -1
- package/dist/native/firebase.cjs.map +1 -1
- package/dist/native/firebase.mjs.map +1 -1
- package/dist/native/index.cjs +1 -1
- package/dist/native/index.mjs +1 -1
- package/dist/native/setup.cjs +3 -5
- package/dist/native/setup.cjs.map +1 -1
- package/dist/native/setup.mjs +3 -5
- package/dist/native/setup.mjs.map +1 -1
- package/dist/next/index.cjs +1 -1
- package/dist/next/index.mjs +1 -1
- package/dist/node_modules/.pnpm/bowser@2.14.1/node_modules/bowser/es5.cjs +1725 -0
- package/dist/node_modules/.pnpm/bowser@2.14.1/node_modules/bowser/es5.cjs.map +1 -0
- package/dist/node_modules/.pnpm/bowser@2.14.1/node_modules/bowser/es5.mjs +1722 -0
- package/dist/node_modules/.pnpm/bowser@2.14.1/node_modules/bowser/es5.mjs.map +1 -0
- package/dist/react-router/index.cjs +2 -2
- package/dist/react-router/index.mjs +2 -2
- package/dist/schema/index.cjs +0 -14
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +1 -150
- package/dist/schema/index.d.cts.map +1 -1
- package/dist/schema/index.d.mts +1 -150
- package/dist/schema/index.d.mts.map +1 -1
- package/dist/schema/index.mjs +2 -15
- package/dist/schema/index.mjs.map +1 -1
- package/dist/server/linkedin-conversions-api.cjs +1 -1
- package/dist/server/linkedin-conversions-api.cjs.map +1 -1
- package/dist/server/linkedin-conversions-api.mjs +1 -1
- package/dist/server/linkedin-conversions-api.mjs.map +1 -1
- package/dist/server/meta-conversions-api.cjs +4 -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 +4 -4
- package/dist/server/meta-conversions-api.mjs.map +1 -1
- package/dist/server/openai-conversions-api.cjs +1 -1
- package/dist/server/openai-conversions-api.cjs.map +1 -1
- package/dist/server/openai-conversions-api.mjs +1 -1
- package/dist/server/openai-conversions-api.mjs.map +1 -1
- package/dist/server/reddit-conversions-api.cjs +3 -3
- package/dist/server/reddit-conversions-api.cjs.map +1 -1
- package/dist/server/reddit-conversions-api.mjs +3 -3
- package/dist/server/reddit-conversions-api.mjs.map +1 -1
- package/dist/setup/session.cjs.map +1 -1
- package/dist/setup/session.mjs.map +1 -1
- package/dist/tanstack/analytics.cjs +1 -1
- package/dist/tanstack/analytics.mjs +1 -1
- package/dist/third-parties/google-analytics.cjs.map +1 -1
- package/dist/third-parties/google-analytics.d.cts +4 -1
- package/dist/third-parties/google-analytics.d.cts.map +1 -1
- package/dist/third-parties/google-analytics.d.mts +4 -1
- package/dist/third-parties/google-analytics.d.mts.map +1 -1
- package/dist/third-parties/google-analytics.mjs.map +1 -1
- package/dist/third-parties/linkedin-insight-tag.cjs.map +1 -1
- package/dist/third-parties/linkedin-insight-tag.d.cts +4 -1
- package/dist/third-parties/linkedin-insight-tag.d.cts.map +1 -1
- package/dist/third-parties/linkedin-insight-tag.d.mts +4 -1
- package/dist/third-parties/linkedin-insight-tag.d.mts.map +1 -1
- package/dist/third-parties/linkedin-insight-tag.mjs.map +1 -1
- package/dist/third-parties/meta-pixel.cjs.map +1 -1
- package/dist/third-parties/meta-pixel.d.cts +4 -1
- package/dist/third-parties/meta-pixel.d.cts.map +1 -1
- package/dist/third-parties/meta-pixel.d.mts +4 -1
- package/dist/third-parties/meta-pixel.d.mts.map +1 -1
- package/dist/third-parties/meta-pixel.mjs.map +1 -1
- package/dist/third-parties/openai-pixel.cjs +2 -1
- package/dist/third-parties/openai-pixel.cjs.map +1 -1
- package/dist/third-parties/openai-pixel.d.cts +4 -1
- package/dist/third-parties/openai-pixel.d.cts.map +1 -1
- package/dist/third-parties/openai-pixel.d.mts +4 -1
- package/dist/third-parties/openai-pixel.d.mts.map +1 -1
- package/dist/third-parties/openai-pixel.mjs +2 -1
- package/dist/third-parties/openai-pixel.mjs.map +1 -1
- package/dist/third-parties/reddit-pixel.cjs.map +1 -1
- package/dist/third-parties/reddit-pixel.d.cts +4 -1
- package/dist/third-parties/reddit-pixel.d.cts.map +1 -1
- package/dist/third-parties/reddit-pixel.d.mts +4 -1
- package/dist/third-parties/reddit-pixel.d.mts.map +1 -1
- package/dist/third-parties/reddit-pixel.mjs.map +1 -1
- package/dist/track/index.cjs +1 -1
- package/dist/track/index.cjs.map +1 -1
- package/dist/track/index.d.cts.map +1 -1
- package/dist/track/index.d.mts.map +1 -1
- package/dist/track/index.mjs +1 -1
- package/dist/track/index.mjs.map +1 -1
- package/dist/track/oaiq.cjs.map +1 -1
- package/dist/track/oaiq.d.cts +1 -1
- package/dist/track/oaiq.d.cts.map +1 -1
- package/dist/track/oaiq.d.mts +1 -1
- package/dist/track/oaiq.d.mts.map +1 -1
- package/dist/track/oaiq.mjs.map +1 -1
- package/dist/track/rdt.cjs +3 -4
- package/dist/track/rdt.cjs.map +1 -1
- package/dist/track/rdt.mjs +3 -4
- package/dist/track/rdt.mjs.map +1 -1
- package/dist/track/types.d.cts +0 -4
- package/dist/track/types.d.cts.map +1 -1
- package/dist/track/types.d.mts +0 -4
- package/dist/track/types.d.mts.map +1 -1
- package/dist/web/index.cjs +4 -4
- 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 +5 -3
- package/dist/web/index.mjs.map +1 -1
- package/package.json +16 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-pixel.cjs","names":["NON_AD_EVENTS","mapOAIEvent","getFirst"],"sources":["../../src/third-parties/openai-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { NON_AD_EVENTS, type OAIQ, type OAIQUser, mapOAIEvent } from '../track/oaiq';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n
|
|
1
|
+
{"version":3,"file":"openai-pixel.cjs","names":["NON_AD_EVENTS","mapOAIEvent","getFirst"],"sources":["../../src/third-parties/openai-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { NON_AD_EVENTS, type OAIQ, type OAIQUser, mapOAIEvent } from '../track/oaiq';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the OpenAI pixel script has loaded. */\n oaiq?: OAIQ['oaiq'];\n }\n}\n\n/** Drop `undefined` fields so the SDK only receives populated values. */\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nfunction clean(value: unknown): any {\n return JSON.parse(JSON.stringify(value));\n}\n\n/**\n * Forward an internal track event to the OpenAI measurement pixel.\n * `eventId` is reused as the OpenAI `event_id` so browser events deduplicate against the\n * Conversions API. https://developers.openai.com/ads/measurement-pixel\n */\nexport function sendOpenAIEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n) {\n if (typeof window === 'undefined' || !window.oaiq) {\n console.warn('oaiq has not been initialized');\n return;\n }\n if (NON_AD_EVENTS.includes(name)) return;\n if (window.location.host.includes('127.0.0.1')) return;\n if (window.location.host.includes('localhost')) return;\n\n const { type, data } = mapOAIEvent(name, properties);\n if (type === 'custom') {\n window.oaiq('measure', 'custom', clean(data), { event_id: eventId, custom_event_name: name });\n } else {\n window.oaiq('measure', type, clean(data), { event_id: eventId });\n }\n}\n\n/** SHA-256 hex digest, lowercase — the format OpenAI expects for hashed identity fields. */\nasync function sha256(value: string): Promise<string> {\n const bytes = new TextEncoder().encode(value);\n const digest = await crypto.subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(digest))\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Re-initialize the pixel with hashed user identity for better conversion matching. Email and\n * external id are hashed client-side; geographic fields are sent raw. Hashing is asynchronous,\n * so the `init` call is deferred until the digests resolve.\n */\nexport function setOpenAIUser(pixelId: string) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (typeof window === 'undefined' || !window.oaiq) {\n console.warn('oaiq has not been initialized');\n return;\n }\n // Capture the narrowed reference so the deferred `init` closure keeps it non-optional.\n const oaiq = window.oaiq;\n\n const email = getFirst(user_data?.email)?.trim().toLowerCase();\n const address = getFirst(user_data?.address);\n\n const base: OAIQUser = {\n country: address?.country?.trim().toUpperCase(),\n city: address?.city?.trim().toLowerCase(),\n zip_code: address?.postal_code,\n };\n\n const init = (hashed: Partial<OAIQUser>) => {\n oaiq('init', { pixelId, user: clean({ ...base, ...hashed }) });\n };\n\n Promise.all([email ? sha256(email) : undefined, user_id ? sha256(user_id) : undefined])\n .then(([email_sha256, external_id_sha256]) => init({ email_sha256, external_id_sha256 }))\n .catch(() => init({}));\n };\n}\n"],"mappings":";;;;;AAcA,SAAS,MAAM,OAAqB;CAClC,OAAO,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AACzC;;;;;;AAOA,SAAgB,gBACd,MACA,YACA,SACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,MAAM;EACjD,QAAQ,KAAK,+BAA+B;EAC5C;CACF;CACA,IAAIA,mBAAAA,cAAc,SAAS,IAAI,GAAG;CAClC,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,EAAE,MAAM,SAASC,mBAAAA,YAAY,MAAM,UAAU;CACnD,IAAI,SAAS,UACX,OAAO,KAAK,WAAW,UAAU,MAAM,IAAI,GAAG;EAAE,UAAU;EAAS,mBAAmB;CAAK,CAAC;MAE5F,OAAO,KAAK,WAAW,MAAM,MAAM,IAAI,GAAG,EAAE,UAAU,QAAQ,CAAC;AAEnE;;AAGA,eAAe,OAAO,OAAgC;CACpD,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK;CAC5C,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;CAC1D,OAAO,MAAM,KAAK,IAAI,WAAW,MAAM,CAAC,CAAC,CACtC,KAAK,SAAS,KAAK,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CACjD,KAAK,EAAE;AACZ;;;;;;AAOA,SAAgB,cAAc,SAAiB;CAC7C,QAAQ,EAAE,SAAS,gBAAkC;EACnD,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,MAAM;GACjD,QAAQ,KAAK,+BAA+B;GAC5C;EACF;EAEA,MAAM,OAAO,OAAO;EAEpB,MAAM,QAAQC,oBAAAA,SAAS,WAAW,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY;EAC7D,MAAM,UAAUA,oBAAAA,SAAS,WAAW,OAAO;EAE3C,MAAM,OAAiB;GACrB,SAAS,SAAS,SAAS,KAAK,CAAC,CAAC,YAAY;GAC9C,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,YAAY;GACxC,UAAU,SAAS;EACrB;EAEA,MAAM,QAAQ,WAA8B;GAC1C,KAAK,QAAQ;IAAE;IAAS,MAAM,MAAM;KAAE,GAAG;KAAM,GAAG;IAAO,CAAC;GAAE,CAAC;EAC/D;EAEA,QAAQ,IAAI,CAAC,QAAQ,OAAO,KAAK,IAAI,KAAA,GAAW,UAAU,OAAO,OAAO,IAAI,KAAA,CAAS,CAAC,CAAC,CACpF,MAAM,CAAC,cAAc,wBAAwB,KAAK;GAAE;GAAc;EAAmB,CAAC,CAAC,CAAC,CACxF,YAAY,KAAK,CAAC,CAAC,CAAC;CACzB;AACF"}
|
|
@@ -3,7 +3,10 @@ import { EventName, TrackName, TrackProperties } from "../track/types.cjs";
|
|
|
3
3
|
import { OAIQ } from "../track/oaiq.cjs";
|
|
4
4
|
//#region src/third-parties/openai-pixel.d.ts
|
|
5
5
|
declare global {
|
|
6
|
-
interface Window
|
|
6
|
+
interface Window {
|
|
7
|
+
/** Undefined until the OpenAI pixel script has loaded. */
|
|
8
|
+
oaiq?: OAIQ['oaiq'];
|
|
9
|
+
}
|
|
7
10
|
}
|
|
8
11
|
/**
|
|
9
12
|
* Forward an internal track event to the OpenAI measurement pixel.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-pixel.d.cts","names":[],"sources":["../../src/third-parties/openai-pixel.ts"],"mappings":";;;;QAKQ;
|
|
1
|
+
{"version":3,"file":"openai-pixel.d.cts","names":[],"sources":["../../src/third-parties/openai-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,OAAO;;;;;;;;iBAeK,gBAAgB,UAAU,WACxC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;;;;;;iBAgCc,cAAc,qBAAe,SAAA,aACX"}
|
|
@@ -3,7 +3,10 @@ import { EventName, TrackName, TrackProperties } from "../track/types.mjs";
|
|
|
3
3
|
import { OAIQ } from "../track/oaiq.mjs";
|
|
4
4
|
//#region src/third-parties/openai-pixel.d.ts
|
|
5
5
|
declare global {
|
|
6
|
-
interface Window
|
|
6
|
+
interface Window {
|
|
7
|
+
/** Undefined until the OpenAI pixel script has loaded. */
|
|
8
|
+
oaiq?: OAIQ['oaiq'];
|
|
9
|
+
}
|
|
7
10
|
}
|
|
8
11
|
/**
|
|
9
12
|
* Forward an internal track event to the OpenAI measurement pixel.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-pixel.d.mts","names":[],"sources":["../../src/third-parties/openai-pixel.ts"],"mappings":";;;;QAKQ;
|
|
1
|
+
{"version":3,"file":"openai-pixel.d.mts","names":[],"sources":["../../src/third-parties/openai-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,OAAO;;;;;;;;iBAeK,gBAAgB,UAAU,WACxC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;;;;;;iBAgCc,cAAc,qBAAe,SAAA,aACX"}
|
|
@@ -42,6 +42,7 @@ function setOpenAIUser(pixelId) {
|
|
|
42
42
|
console.warn("oaiq has not been initialized");
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
|
+
const oaiq = window.oaiq;
|
|
45
46
|
const email = getFirst(user_data?.email)?.trim().toLowerCase();
|
|
46
47
|
const address = getFirst(user_data?.address);
|
|
47
48
|
const base = {
|
|
@@ -50,7 +51,7 @@ function setOpenAIUser(pixelId) {
|
|
|
50
51
|
zip_code: address?.postal_code
|
|
51
52
|
};
|
|
52
53
|
const init = (hashed) => {
|
|
53
|
-
|
|
54
|
+
oaiq("init", {
|
|
54
55
|
pixelId,
|
|
55
56
|
user: clean({
|
|
56
57
|
...base,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-pixel.mjs","names":[],"sources":["../../src/third-parties/openai-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { NON_AD_EVENTS, type OAIQ, type OAIQUser, mapOAIEvent } from '../track/oaiq';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n
|
|
1
|
+
{"version":3,"file":"openai-pixel.mjs","names":[],"sources":["../../src/third-parties/openai-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { NON_AD_EVENTS, type OAIQ, type OAIQUser, mapOAIEvent } from '../track/oaiq';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the OpenAI pixel script has loaded. */\n oaiq?: OAIQ['oaiq'];\n }\n}\n\n/** Drop `undefined` fields so the SDK only receives populated values. */\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nfunction clean(value: unknown): any {\n return JSON.parse(JSON.stringify(value));\n}\n\n/**\n * Forward an internal track event to the OpenAI measurement pixel.\n * `eventId` is reused as the OpenAI `event_id` so browser events deduplicate against the\n * Conversions API. https://developers.openai.com/ads/measurement-pixel\n */\nexport function sendOpenAIEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n) {\n if (typeof window === 'undefined' || !window.oaiq) {\n console.warn('oaiq has not been initialized');\n return;\n }\n if (NON_AD_EVENTS.includes(name)) return;\n if (window.location.host.includes('127.0.0.1')) return;\n if (window.location.host.includes('localhost')) return;\n\n const { type, data } = mapOAIEvent(name, properties);\n if (type === 'custom') {\n window.oaiq('measure', 'custom', clean(data), { event_id: eventId, custom_event_name: name });\n } else {\n window.oaiq('measure', type, clean(data), { event_id: eventId });\n }\n}\n\n/** SHA-256 hex digest, lowercase — the format OpenAI expects for hashed identity fields. */\nasync function sha256(value: string): Promise<string> {\n const bytes = new TextEncoder().encode(value);\n const digest = await crypto.subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(digest))\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Re-initialize the pixel with hashed user identity for better conversion matching. Email and\n * external id are hashed client-side; geographic fields are sent raw. Hashing is asynchronous,\n * so the `init` call is deferred until the digests resolve.\n */\nexport function setOpenAIUser(pixelId: string) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (typeof window === 'undefined' || !window.oaiq) {\n console.warn('oaiq has not been initialized');\n return;\n }\n // Capture the narrowed reference so the deferred `init` closure keeps it non-optional.\n const oaiq = window.oaiq;\n\n const email = getFirst(user_data?.email)?.trim().toLowerCase();\n const address = getFirst(user_data?.address);\n\n const base: OAIQUser = {\n country: address?.country?.trim().toUpperCase(),\n city: address?.city?.trim().toLowerCase(),\n zip_code: address?.postal_code,\n };\n\n const init = (hashed: Partial<OAIQUser>) => {\n oaiq('init', { pixelId, user: clean({ ...base, ...hashed }) });\n };\n\n Promise.all([email ? sha256(email) : undefined, user_id ? sha256(user_id) : undefined])\n .then(([email_sha256, external_id_sha256]) => init({ email_sha256, external_id_sha256 }))\n .catch(() => init({}));\n };\n}\n"],"mappings":";;;;AAcA,SAAS,MAAM,OAAqB;CAClC,OAAO,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AACzC;;;;;;AAOA,SAAgB,gBACd,MACA,YACA,SACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,MAAM;EACjD,QAAQ,KAAK,+BAA+B;EAC5C;CACF;CACA,IAAI,cAAc,SAAS,IAAI,GAAG;CAClC,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,EAAE,MAAM,SAAS,YAAY,MAAM,UAAU;CACnD,IAAI,SAAS,UACX,OAAO,KAAK,WAAW,UAAU,MAAM,IAAI,GAAG;EAAE,UAAU;EAAS,mBAAmB;CAAK,CAAC;MAE5F,OAAO,KAAK,WAAW,MAAM,MAAM,IAAI,GAAG,EAAE,UAAU,QAAQ,CAAC;AAEnE;;AAGA,eAAe,OAAO,OAAgC;CACpD,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK;CAC5C,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;CAC1D,OAAO,MAAM,KAAK,IAAI,WAAW,MAAM,CAAC,CAAC,CACtC,KAAK,SAAS,KAAK,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CACjD,KAAK,EAAE;AACZ;;;;;;AAOA,SAAgB,cAAc,SAAiB;CAC7C,QAAQ,EAAE,SAAS,gBAAkC;EACnD,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,MAAM;GACjD,QAAQ,KAAK,+BAA+B;GAC5C;EACF;EAEA,MAAM,OAAO,OAAO;EAEpB,MAAM,QAAQ,SAAS,WAAW,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY;EAC7D,MAAM,UAAU,SAAS,WAAW,OAAO;EAE3C,MAAM,OAAiB;GACrB,SAAS,SAAS,SAAS,KAAK,CAAC,CAAC,YAAY;GAC9C,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,YAAY;GACxC,UAAU,SAAS;EACrB;EAEA,MAAM,QAAQ,WAA8B;GAC1C,KAAK,QAAQ;IAAE;IAAS,MAAM,MAAM;KAAE,GAAG;KAAM,GAAG;IAAO,CAAC;GAAE,CAAC;EAC/D;EAEA,QAAQ,IAAI,CAAC,QAAQ,OAAO,KAAK,IAAI,KAAA,GAAW,UAAU,OAAO,OAAO,IAAI,KAAA,CAAS,CAAC,CAAC,CACpF,MAAM,CAAC,cAAc,wBAAwB,KAAK;GAAE;GAAc;EAAmB,CAAC,CAAC,CAAC,CACxF,YAAY,KAAK,CAAC,CAAC,CAAC;CACzB;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reddit-pixel.cjs","names":["mapRDTEvent","getFirst"],"sources":["../../src/third-parties/reddit-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type PixelId, type RDT, mapRDTEvent } from '../track/rdt';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n
|
|
1
|
+
{"version":3,"file":"reddit-pixel.cjs","names":["mapRDTEvent","getFirst"],"sources":["../../src/third-parties/reddit-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type PixelId, type RDT, mapRDTEvent } from '../track/rdt';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Reddit Pixel script has loaded. */\n rdt?: RDT['rdt'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendRedditEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n) {\n if (typeof window === 'undefined' || !window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\n if (metrics.includes(name)) return;\n if (window.location.host.includes('127.0.0.1')) return;\n if (window.location.host.includes('localhost')) return;\n\n const [type, params] = mapRDTEvent(name, properties, eventId);\n if (type === 'Custom') {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n } else {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n }\n}\n\nexport function setRedditUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (!window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\n\n window.rdt('init', pixelId, {\n email: getFirst(user_data?.email),\n phoneNumber: getFirst(user_data?.phone_number),\n externalId: user_id,\n });\n };\n}\n"],"mappings":";;;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,gBACd,MACA,YACA,SACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,CAAC,MAAM,UAAUA,kBAAAA,YAAY,MAAM,YAAY,OAAO;CAC5D,IAAI,SAAS,UACX,OAAO,IAAI,SAAS,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC,CAAC;MAE5D,OAAO,IAAI,SAAS,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC,CAAC;AAEhE;AAEA,SAAgB,cAAc,SAAkB;CAC9C,QAAQ,EAAE,SAAS,gBAAkC;EACnD,IAAI,CAAC,OAAO,KAAK;GACf,QAAQ,KAAK,8BAA8B;GAC3C;EACF;EAEA,OAAO,IAAI,QAAQ,SAAS;GAC1B,OAAOC,oBAAAA,SAAS,WAAW,KAAK;GAChC,aAAaA,oBAAAA,SAAS,WAAW,YAAY;GAC7C,YAAY;EACd,CAAC;CACH;AACF"}
|
|
@@ -3,7 +3,10 @@ import { EventName, TrackName, TrackProperties } from "../track/types.cjs";
|
|
|
3
3
|
import { PixelId, RDT } from "../track/rdt.cjs";
|
|
4
4
|
//#region src/third-parties/reddit-pixel.d.ts
|
|
5
5
|
declare global {
|
|
6
|
-
interface Window
|
|
6
|
+
interface Window {
|
|
7
|
+
/** Undefined until the Reddit Pixel script has loaded. */
|
|
8
|
+
rdt?: RDT['rdt'];
|
|
9
|
+
}
|
|
7
10
|
}
|
|
8
11
|
declare function sendRedditEvent<T extends EventName>(name: TrackName<T>, properties?: TrackProperties<T>, eventId?: string): void;
|
|
9
12
|
declare function setRedditUser(pixelId: PixelId): ({ user_id, user_data }: UpdateVisitorDTO) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reddit-pixel.d.cts","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"mappings":";;;;QAKQ;
|
|
1
|
+
{"version":3,"file":"reddit-pixel.d.cts","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,gBAAgB,UAAU,WACxC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAkBc,cAAc,SAAS,aAAO,SAAA,aACZ"}
|
|
@@ -3,7 +3,10 @@ import { EventName, TrackName, TrackProperties } from "../track/types.mjs";
|
|
|
3
3
|
import { PixelId, RDT } from "../track/rdt.mjs";
|
|
4
4
|
//#region src/third-parties/reddit-pixel.d.ts
|
|
5
5
|
declare global {
|
|
6
|
-
interface Window
|
|
6
|
+
interface Window {
|
|
7
|
+
/** Undefined until the Reddit Pixel script has loaded. */
|
|
8
|
+
rdt?: RDT['rdt'];
|
|
9
|
+
}
|
|
7
10
|
}
|
|
8
11
|
declare function sendRedditEvent<T extends EventName>(name: TrackName<T>, properties?: TrackProperties<T>, eventId?: string): void;
|
|
9
12
|
declare function setRedditUser(pixelId: PixelId): ({ user_id, user_data }: UpdateVisitorDTO) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reddit-pixel.d.mts","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"mappings":";;;;QAKQ;
|
|
1
|
+
{"version":3,"file":"reddit-pixel.d.mts","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,gBAAgB,UAAU,WACxC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAkBc,cAAc,SAAS,aAAO,SAAA,aACZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reddit-pixel.mjs","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type PixelId, type RDT, mapRDTEvent } from '../track/rdt';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n
|
|
1
|
+
{"version":3,"file":"reddit-pixel.mjs","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type PixelId, type RDT, mapRDTEvent } from '../track/rdt';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Reddit Pixel script has loaded. */\n rdt?: RDT['rdt'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendRedditEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n) {\n if (typeof window === 'undefined' || !window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\n if (metrics.includes(name)) return;\n if (window.location.host.includes('127.0.0.1')) return;\n if (window.location.host.includes('localhost')) return;\n\n const [type, params] = mapRDTEvent(name, properties, eventId);\n if (type === 'Custom') {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n } else {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n }\n}\n\nexport function setRedditUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (!window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\n\n window.rdt('init', pixelId, {\n email: getFirst(user_data?.email),\n phoneNumber: getFirst(user_data?.phone_number),\n externalId: user_id,\n });\n };\n}\n"],"mappings":";;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,gBACd,MACA,YACA,SACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,CAAC,MAAM,UAAU,YAAY,MAAM,YAAY,OAAO;CAC5D,IAAI,SAAS,UACX,OAAO,IAAI,SAAS,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC,CAAC;MAE5D,OAAO,IAAI,SAAS,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC,CAAC;AAEhE;AAEA,SAAgB,cAAc,SAAkB;CAC9C,QAAQ,EAAE,SAAS,gBAAkC;EACnD,IAAI,CAAC,OAAO,KAAK;GACf,QAAQ,KAAK,8BAA8B;GAC3C;EACF;EAEA,OAAO,IAAI,QAAQ,SAAS;GAC1B,OAAO,SAAS,WAAW,KAAK;GAChC,aAAa,SAAS,WAAW,YAAY;GAC7C,YAAY;EACd,CAAC;CACH;AACF"}
|
package/dist/track/index.cjs
CHANGED
|
@@ -55,7 +55,7 @@ async function sendEvents(events) {
|
|
|
55
55
|
const eventId = data[index].id;
|
|
56
56
|
options.onSucceed?.({ id: eventId });
|
|
57
57
|
index++;
|
|
58
|
-
if (!
|
|
58
|
+
if (!options.enableThirdPartyTracking || require_third_parties_ignored_events.IGNORED_EVENTS.includes(name)) continue;
|
|
59
59
|
require_setup_index.config.thirdPartyTrackers.forEach((tracker) => tracker(name, properties, eventId));
|
|
60
60
|
}
|
|
61
61
|
} catch (e) {
|
package/dist/track/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["TokenBucket","session","config","getVisitor","IGNORED_EVENTS","cache"],"sources":["../../src/track/index.ts"],"sourcesContent":["import { TokenBucket, fetch } from '@shware/utils';\nimport type { CreateTrackEventDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport { session } from '../setup/session';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { getVisitor } from '../visitor/index';\nimport type { EventName, TrackEventResponse, TrackName, TrackProperties } from './types';\n\nexport interface TrackOptions {\n enableThirdPartyTracking?: boolean;\n onSucceed?: (response?: TrackEventResponse[number]) => void;\n onError?: (error: unknown) => void;\n}\n\nconst defaultOptions: TrackOptions = { enableThirdPartyTracking: true };\nconst tokenBucket = new TokenBucket({ rate: 1, capacity: 20, requested: 2 });\n\ntype Item = {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n name: TrackName<any>;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n properties: TrackProperties<any>;\n timestamp: string;\n options: TrackOptions;\n};\n\nasync function sendEvents(events: Item[]) {\n try {\n if (events.length === 0) return;\n\n if (session.isExpired()) {\n session.refresh();\n events.unshift({\n name: 'session_start',\n properties: {},\n options: { enableThirdPartyTracking: false },\n timestamp: new Date().toISOString(),\n });\n } else {\n session.updateLastActiveTime();\n }\n\n await tokenBucket.removeTokens();\n\n const tags = await config.getTags();\n const visitor_id = (await getVisitor()).id;\n\n const dto: CreateTrackEventDTO = events.map((event) => ({\n name: event.name,\n properties: event.properties,\n tags,\n visitor_id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: event.timestamp,\n }));\n\n const response = await fetch(`${config.endpoint}/events`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send track event: ${response.status} ${await response.text()}`);\n }\n\n const data = (await response.json()) as TrackEventResponse;\n\n let index = 0;\n while (events.length > 0) {\n const event = events.shift();\n if (!event) {\n index++;\n continue;\n }\n const { options, name, properties } = event;\n const eventId = data[index].id;\n options.onSucceed?.({ id: eventId });\n index++;\n if (
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["TokenBucket","session","config","getVisitor","IGNORED_EVENTS","cache"],"sources":["../../src/track/index.ts"],"sourcesContent":["import { TokenBucket, fetch } from '@shware/utils';\nimport type { CreateTrackEventDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport { session } from '../setup/session';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { getVisitor } from '../visitor/index';\nimport type { EventName, TrackEventResponse, TrackName, TrackProperties } from './types';\n\nexport interface TrackOptions {\n enableThirdPartyTracking?: boolean;\n onSucceed?: (response?: TrackEventResponse[number]) => void;\n onError?: (error: unknown) => void;\n}\n\nconst defaultOptions: TrackOptions = { enableThirdPartyTracking: true };\nconst tokenBucket = new TokenBucket({ rate: 1, capacity: 20, requested: 2 });\n\ntype Item = {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n name: TrackName<any>;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n properties: TrackProperties<any>;\n timestamp: string;\n options: TrackOptions;\n};\n\nasync function sendEvents(events: Item[]) {\n try {\n if (events.length === 0) return;\n\n if (session.isExpired()) {\n session.refresh();\n events.unshift({\n name: 'session_start',\n properties: {},\n options: { enableThirdPartyTracking: false },\n timestamp: new Date().toISOString(),\n });\n } else {\n session.updateLastActiveTime();\n }\n\n await tokenBucket.removeTokens();\n\n const tags = await config.getTags();\n const visitor_id = (await getVisitor()).id;\n\n const dto: CreateTrackEventDTO = events.map((event) => ({\n name: event.name,\n properties: event.properties,\n tags,\n visitor_id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: event.timestamp,\n }));\n\n const response = await fetch(`${config.endpoint}/events`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send track event: ${response.status} ${await response.text()}`);\n }\n\n const data = (await response.json()) as TrackEventResponse;\n\n let index = 0;\n while (events.length > 0) {\n const event = events.shift();\n if (!event) {\n index++;\n continue;\n }\n const { options, name, properties } = event;\n const eventId = data[index].id;\n options.onSucceed?.({ id: eventId });\n index++;\n if (!options.enableThirdPartyTracking || IGNORED_EVENTS.includes(name)) {\n continue;\n }\n config.thirdPartyTrackers.forEach((tracker) => tracker(name, properties, eventId));\n }\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n events.forEach((event) => event.options.onError?.(e));\n }\n}\n\nconst batch = 10;\nconst delay = 2000;\nconst list: Item[] = [];\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\nexport function track<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n list.push({ name, properties, options, timestamp: new Date().toISOString() });\n if (list.length >= batch) {\n const copy = [...list];\n list.length = 0;\n void sendEvents(copy);\n return;\n }\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n const copy = [...list];\n list.length = 0;\n void sendEvents(copy);\n }, delay);\n}\n\nexport async function trackAsync<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n await sendEvents([{ name, properties, options, timestamp: new Date().toISOString() }]);\n}\n\nexport function sendBeacon<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (!cache.tags || !cache.visitor) return;\n session.updateLastActiveTime();\n\n const dto: CreateTrackEventDTO = [\n {\n name,\n properties,\n tags: cache.tags,\n visitor_id: cache.visitor.id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: new Date().toISOString(),\n },\n ];\n const blob = new Blob([JSON.stringify(dto)], { type: 'application/json' });\n const success = navigator.sendBeacon(`${config.endpoint}/events`, blob);\n if (success) return;\n console.warn('Failed to send beacon', name, properties);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/track/index.ts"],"mappings":";;UAQiB;EACf;EACA,aAAa,WAAW;EACxB,WAAW;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/track/index.ts"],"mappings":";;UAQiB;EACf;EACA,aAAa,WAAW;EACxB,WAAW;;iBAuFG,MAAM,UAAU,YAAY,WAC1C,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B,UAAS;iBAkBW,WAAW,UAAU,YAAY,WACrD,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B,UAAS,eAA6B;iBAKxB,WAAW,UAAU,YAAY,WAC/C,MAAM,UAAU,IAChB,aAAa,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/track/index.ts"],"mappings":";;UAQiB;EACf;EACA,aAAa,WAAW;EACxB,WAAW;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/track/index.ts"],"mappings":";;UAQiB;EACf;EACA,aAAa,WAAW;EACxB,WAAW;;iBAuFG,MAAM,UAAU,YAAY,WAC1C,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B,UAAS;iBAkBW,WAAW,UAAU,YAAY,WACrD,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B,UAAS,eAA6B;iBAKxB,WAAW,UAAU,YAAY,WAC/C,MAAM,UAAU,IAChB,aAAa,gBAAgB"}
|
package/dist/track/index.mjs
CHANGED
|
@@ -54,7 +54,7 @@ async function sendEvents(events) {
|
|
|
54
54
|
const eventId = data[index].id;
|
|
55
55
|
options.onSucceed?.({ id: eventId });
|
|
56
56
|
index++;
|
|
57
|
-
if (!
|
|
57
|
+
if (!options.enableThirdPartyTracking || IGNORED_EVENTS.includes(name)) continue;
|
|
58
58
|
config.thirdPartyTrackers.forEach((tracker) => tracker(name, properties, eventId));
|
|
59
59
|
}
|
|
60
60
|
} catch (e) {
|
package/dist/track/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/track/index.ts"],"sourcesContent":["import { TokenBucket, fetch } from '@shware/utils';\nimport type { CreateTrackEventDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport { session } from '../setup/session';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { getVisitor } from '../visitor/index';\nimport type { EventName, TrackEventResponse, TrackName, TrackProperties } from './types';\n\nexport interface TrackOptions {\n enableThirdPartyTracking?: boolean;\n onSucceed?: (response?: TrackEventResponse[number]) => void;\n onError?: (error: unknown) => void;\n}\n\nconst defaultOptions: TrackOptions = { enableThirdPartyTracking: true };\nconst tokenBucket = new TokenBucket({ rate: 1, capacity: 20, requested: 2 });\n\ntype Item = {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n name: TrackName<any>;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n properties: TrackProperties<any>;\n timestamp: string;\n options: TrackOptions;\n};\n\nasync function sendEvents(events: Item[]) {\n try {\n if (events.length === 0) return;\n\n if (session.isExpired()) {\n session.refresh();\n events.unshift({\n name: 'session_start',\n properties: {},\n options: { enableThirdPartyTracking: false },\n timestamp: new Date().toISOString(),\n });\n } else {\n session.updateLastActiveTime();\n }\n\n await tokenBucket.removeTokens();\n\n const tags = await config.getTags();\n const visitor_id = (await getVisitor()).id;\n\n const dto: CreateTrackEventDTO = events.map((event) => ({\n name: event.name,\n properties: event.properties,\n tags,\n visitor_id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: event.timestamp,\n }));\n\n const response = await fetch(`${config.endpoint}/events`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send track event: ${response.status} ${await response.text()}`);\n }\n\n const data = (await response.json()) as TrackEventResponse;\n\n let index = 0;\n while (events.length > 0) {\n const event = events.shift();\n if (!event) {\n index++;\n continue;\n }\n const { options, name, properties } = event;\n const eventId = data[index].id;\n options.onSucceed?.({ id: eventId });\n index++;\n if (
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/track/index.ts"],"sourcesContent":["import { TokenBucket, fetch } from '@shware/utils';\nimport type { CreateTrackEventDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport { session } from '../setup/session';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { getVisitor } from '../visitor/index';\nimport type { EventName, TrackEventResponse, TrackName, TrackProperties } from './types';\n\nexport interface TrackOptions {\n enableThirdPartyTracking?: boolean;\n onSucceed?: (response?: TrackEventResponse[number]) => void;\n onError?: (error: unknown) => void;\n}\n\nconst defaultOptions: TrackOptions = { enableThirdPartyTracking: true };\nconst tokenBucket = new TokenBucket({ rate: 1, capacity: 20, requested: 2 });\n\ntype Item = {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n name: TrackName<any>;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n properties: TrackProperties<any>;\n timestamp: string;\n options: TrackOptions;\n};\n\nasync function sendEvents(events: Item[]) {\n try {\n if (events.length === 0) return;\n\n if (session.isExpired()) {\n session.refresh();\n events.unshift({\n name: 'session_start',\n properties: {},\n options: { enableThirdPartyTracking: false },\n timestamp: new Date().toISOString(),\n });\n } else {\n session.updateLastActiveTime();\n }\n\n await tokenBucket.removeTokens();\n\n const tags = await config.getTags();\n const visitor_id = (await getVisitor()).id;\n\n const dto: CreateTrackEventDTO = events.map((event) => ({\n name: event.name,\n properties: event.properties,\n tags,\n visitor_id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: event.timestamp,\n }));\n\n const response = await fetch(`${config.endpoint}/events`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send track event: ${response.status} ${await response.text()}`);\n }\n\n const data = (await response.json()) as TrackEventResponse;\n\n let index = 0;\n while (events.length > 0) {\n const event = events.shift();\n if (!event) {\n index++;\n continue;\n }\n const { options, name, properties } = event;\n const eventId = data[index].id;\n options.onSucceed?.({ id: eventId });\n index++;\n if (!options.enableThirdPartyTracking || IGNORED_EVENTS.includes(name)) {\n continue;\n }\n config.thirdPartyTrackers.forEach((tracker) => tracker(name, properties, eventId));\n }\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n events.forEach((event) => event.options.onError?.(e));\n }\n}\n\nconst batch = 10;\nconst delay = 2000;\nconst list: Item[] = [];\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\nexport function track<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n list.push({ name, properties, options, timestamp: new Date().toISOString() });\n if (list.length >= batch) {\n const copy = [...list];\n list.length = 0;\n void sendEvents(copy);\n return;\n }\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n const copy = [...list];\n list.length = 0;\n void sendEvents(copy);\n }, delay);\n}\n\nexport async function trackAsync<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n await sendEvents([{ name, properties, options, timestamp: new Date().toISOString() }]);\n}\n\nexport function sendBeacon<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (!cache.tags || !cache.visitor) return;\n session.updateLastActiveTime();\n\n const dto: CreateTrackEventDTO = [\n {\n name,\n properties,\n tags: cache.tags,\n visitor_id: cache.visitor.id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: new Date().toISOString(),\n },\n ];\n const blob = new Blob([JSON.stringify(dto)], { type: 'application/json' });\n const success = navigator.sendBeacon(`${config.endpoint}/events`, blob);\n if (success) return;\n console.warn('Failed to send beacon', name, properties);\n}\n"],"mappings":"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"}
|
package/dist/track/oaiq.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oaiq.cjs","names":[],"sources":["../../src/track/oaiq.ts"],"sourcesContent":["import type { Item } from './gtag';\nimport type { EventName, TrackName, TrackProperties } from './types';\n\nexport const NON_AD_EVENTS = [\n // metrics\n 'CLS',\n 'FCP',\n 'FID',\n 'INP',\n 'LCP',\n 'TTFB',\n // promotions\n 'view_promotion',\n 'select_promotion',\n];\n\n/**\n * Content item shared by `contents` and `plan_enrollment` events.\n * https://developers.openai.com/ads/supported-events\n */\nexport type ContentItem = {\n id?: string;\n name?: string;\n content_type?: string;\n quantity?: number;\n /** Per-item monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n amount?: number;\n currency?: string;\n};\n\nexport type ContentsData = {\n type: 'contents';\n /** Monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type CustomerActionData = {\n type: 'customer_action';\n amount?: number;\n currency?: string;\n};\n\nexport type PlanEnrollmentData = {\n type: 'plan_enrollment';\n plan_id?: string;\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type CustomEventData = {\n type: 'custom';\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type EventData = ContentsData | CustomerActionData | PlanEnrollmentData | CustomEventData;\n\n/**\n * Standard event names and the `data` shape each one expects.\n * https://developers.openai.com/ads/supported-events\n */\nexport type StandardEvents = {\n appointment_scheduled: CustomerActionData;\n checkout_started: ContentsData;\n contents_viewed: ContentsData;\n items_added: ContentsData;\n lead_created: CustomerActionData;\n order_created: ContentsData;\n page_viewed: ContentsData;\n registration_completed: CustomerActionData;\n subscription_created: PlanEnrollmentData;\n trial_started: PlanEnrollmentData;\n};\n\nexport type StandardEvent = keyof StandardEvents;\n\n/**\n * Identity fields passed to `oaiq(\"init\", ...)` for conversion matching. Email and external id\n * must be pre-hashed as lowercase 64-char SHA-256 hex strings; the rest are sent as raw values.\n * https://developers.openai.com/ads/measurement-pixel\n */\nexport type OAIQUser = {\n email_sha256?: string;\n external_id_sha256?: string;\n /** Two-letter ISO 3166-1 country code (e.g. \"US\"). */\n country?: string;\n /** Lowercased, max 128 characters. */\n city?: string;\n /** Max 32 characters. */\n zip_code?: string;\n};\n\nexport type InitConfig = {\n pixelId: string;\n /** Log SDK activity to the browser console. */\n debug?: boolean;\n user?: OAIQUser;\n};\n\n/**\n * Fourth argument of `oaiq(\"measure\", ...)`. Required for custom events (carries\n * `custom_event_name`); optional for standard events.\n */\nexport type MeasureOptions = {\n /** Shared with the Conversions API to deduplicate the same conversion across browser and server. */\n event_id?: string;\n /** Required for custom events; 1-64 chars of letters, numbers, underscores, or dashes. */\n custom_event_name?: string;\n /** When true, opts the event out of user-level personalization. */\n opt_out?: boolean;\n};\n\nexport interface OAIQ {\n oaiq(command: 'init', config: InitConfig): void;\n oaiq<T extends StandardEvent>(\n command: 'measure',\n event: T,\n data: StandardEvents[T],\n options?: MeasureOptions\n ): void;\n oaiq(\n command: 'measure',\n event: 'custom',\n data: CustomEventData,\n options: MeasureOptions & { custom_event_name: string }\n ): void;\n}\n\n/**\n * Currencies whose minor unit has 0 or 3 decimal places; everything else uses 2.\n * Follows Stripe's zero-decimal convention (e.g., MGA is treated as 0, ISK is included),\n * which can differ from strict ISO 4217 exponents.\n * https://docs.stripe.com/currencies#zero-decimal\n */\nconst ZERO_DECIMAL_CURRENCIES = new Set([\n 'BIF',\n 'CLP',\n 'DJF',\n 'GNF',\n 'ISK',\n 'JPY',\n 'KMF',\n 'KRW',\n 'MGA',\n 'PYG',\n 'RWF',\n 'UGX',\n 'VND',\n 'VUV',\n 'XAF',\n 'XOF',\n 'XPF',\n]);\nconst THREE_DECIMAL_CURRENCIES = new Set(['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND']);\n\n/** Convert a major-unit amount (e.g., 129.99) into ISO 4217 minor units (e.g., 12,999). */\nexport function toMinorUnits(value?: number, currency?: string): number | undefined {\n if (value === undefined || value === null || Number.isNaN(value)) return undefined;\n const code = currency?.toUpperCase();\n const exponent =\n code && ZERO_DECIMAL_CURRENCIES.has(code)\n ? 0\n : code && THREE_DECIMAL_CURRENCIES.has(code)\n ? 3\n : 2;\n return Math.round(value * 10 ** exponent);\n}\n\nexport function mapContents(items?: Item[], currency?: string): ContentItem[] | undefined {\n if (!items || items.length === 0) return undefined;\n const code = currency?.toUpperCase();\n return items.map((item) => ({\n id: item.item_id,\n name: item.item_name,\n content_type: item.item_category,\n quantity: item.quantity,\n amount: toMinorUnits(item.price, currency),\n currency: item.price !== undefined ? code : undefined,\n }));\n}\n\n/** Safely read a property off loosely typed track properties without widening to `any`. */\nfunction prop(properties: unknown, key: string): unknown {\n return typeof properties === 'object' && properties !== null\n ? (properties as Record<string, unknown>)[key]\n : undefined;\n}\n\nfunction readValue(properties: unknown): number | undefined {\n const value = prop(properties, 'value');\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction readCurrency(properties: unknown): string | undefined {\n const currency = prop(properties, 'currency');\n return typeof currency === 'string' ? currency : undefined;\n}\n\nfunction readItems(properties: unknown): Item[] | undefined {\n const items = prop(properties, 'items');\n return Array.isArray(items) ? (items as Item[]) : undefined;\n}\n\nfunction contentsData(properties: unknown): ContentsData {\n const currency = readCurrency(properties);\n return {\n type: 'contents',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(readItems(properties), currency),\n };\n}\n\nfunction customerActionData(properties: unknown): CustomerActionData {\n const currency = readCurrency(properties);\n return {\n type: 'customer_action',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n };\n}\n\nfunction planEnrollmentData(properties: unknown): PlanEnrollmentData {\n const currency = readCurrency(properties);\n const items = readItems(properties);\n return {\n type: 'plan_enrollment',\n plan_id: items?.[0]?.item_id,\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(items, currency),\n };\n}\n\nexport type MappedOAIEvent = {\n type: StandardEvent | 'custom';\n data: EventData;\n};\n\n/** Map an internal track event onto an OpenAI standard (or custom) conversion event. */\nexport function mapOAIEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n): MappedOAIEvent {\n switch (name) {\n case 'page_view':\n return { type: 'page_viewed', data: contentsData(properties) };\n case 'view_item':\n case 'view_item_list':\n return { type: 'contents_viewed', data: contentsData(properties) };\n case 'begin_checkout':\n return { type: 'checkout_started', data: contentsData(properties) };\n case 'add_to_cart':\n return { type: 'items_added', data: contentsData(properties) };\n case 'purchase':\n return { type: 'order_created', data: contentsData(properties) };\n case 'generate_lead':\n case 'qualify_lead':\n return { type: 'lead_created', data: customerActionData(properties) };\n case 'sign_up':\n case 'login':\n return { type: 'registration_completed', data: customerActionData(properties) };\n case 'schedule':\n return { type: 'appointment_scheduled', data: customerActionData(properties) };\n case 'subscribe':\n return { type: 'subscription_created', data: planEnrollmentData(properties) };\n case 'trial_begin':\n return { type: 'trial_started', data: planEnrollmentData(properties) };\n default: {\n const currency = readCurrency(properties);\n return {\n type: 'custom',\n data: {\n type: 'custom',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(readItems(properties), currency),\n },\n };\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"oaiq.cjs","names":[],"sources":["../../src/track/oaiq.ts"],"sourcesContent":["import type { Item } from './gtag';\nimport type { EventName, TrackName, TrackProperties } from './types';\n\nexport const NON_AD_EVENTS = [\n // metrics\n 'CLS',\n 'FCP',\n 'FID',\n 'INP',\n 'LCP',\n 'TTFB',\n // promotions\n 'view_promotion',\n 'select_promotion',\n];\n\n/**\n * Content item shared by `contents` and `plan_enrollment` events.\n * https://developers.openai.com/ads/supported-events\n */\nexport type ContentItem = {\n id?: string;\n name?: string;\n content_type?: string;\n quantity?: number;\n /** Per-item monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n amount?: number;\n currency?: string;\n};\n\nexport type ContentsData = {\n type: 'contents';\n /** Monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type CustomerActionData = {\n type: 'customer_action';\n amount?: number;\n currency?: string;\n};\n\nexport type PlanEnrollmentData = {\n type: 'plan_enrollment';\n plan_id?: string;\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type CustomEventData = {\n type: 'custom';\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type EventData = ContentsData | CustomerActionData | PlanEnrollmentData | CustomEventData;\n\n/**\n * Standard event names and the `data` shape each one expects.\n * https://developers.openai.com/ads/supported-events\n */\nexport type StandardEvents = {\n appointment_scheduled: CustomerActionData;\n checkout_started: ContentsData;\n contents_viewed: ContentsData;\n items_added: ContentsData;\n lead_created: CustomerActionData;\n order_created: ContentsData;\n page_viewed: ContentsData;\n registration_completed: CustomerActionData;\n subscription_created: PlanEnrollmentData;\n trial_started: PlanEnrollmentData;\n};\n\nexport type StandardEvent = keyof StandardEvents;\n\n/**\n * Identity fields passed to `oaiq(\"init\", ...)` for conversion matching. Email and external id\n * must be pre-hashed as lowercase 64-char SHA-256 hex strings; the rest are sent as raw values.\n * https://developers.openai.com/ads/measurement-pixel\n */\nexport type OAIQUser = {\n email_sha256?: string;\n external_id_sha256?: string;\n /** Two-letter ISO 3166-1 country code (e.g. \"US\"). */\n country?: string;\n /** Lowercased, max 128 characters. */\n city?: string;\n /** Max 32 characters. */\n zip_code?: string;\n};\n\nexport type InitConfig = {\n pixelId: string;\n /** Log SDK activity to the browser console. */\n debug?: boolean;\n user?: OAIQUser;\n};\n\n/**\n * Fourth argument of `oaiq(\"measure\", ...)`. Required for custom events (carries\n * `custom_event_name`); optional for standard events.\n */\nexport type MeasureOptions = {\n /** Shared with the Conversions API to deduplicate the same conversion across browser and server. */\n event_id?: string;\n /** Required for custom events; 1-64 chars of letters, numbers, underscores, or dashes. */\n custom_event_name?: string;\n /** When true, opts the event out of user-level personalization. */\n opt_out?: boolean;\n};\n\nexport interface OAIQ {\n oaiq(command: 'init', config: InitConfig): void;\n oaiq<T extends StandardEvent>(\n command: 'measure',\n event: T,\n data: StandardEvents[T],\n options?: MeasureOptions\n ): void;\n oaiq(\n command: 'measure',\n event: 'custom',\n data: CustomEventData,\n options: MeasureOptions & { custom_event_name: string }\n ): void;\n}\n\n/**\n * Currencies whose minor unit has 0 or 3 decimal places; everything else uses 2.\n * Follows Stripe's zero-decimal convention (e.g., MGA is treated as 0, ISK is included),\n * which can differ from strict ISO 4217 exponents.\n * https://docs.stripe.com/currencies#zero-decimal\n */\nconst ZERO_DECIMAL_CURRENCIES = new Set([\n 'BIF',\n 'CLP',\n 'DJF',\n 'GNF',\n 'ISK',\n 'JPY',\n 'KMF',\n 'KRW',\n 'MGA',\n 'PYG',\n 'RWF',\n 'UGX',\n 'VND',\n 'VUV',\n 'XAF',\n 'XOF',\n 'XPF',\n]);\nconst THREE_DECIMAL_CURRENCIES = new Set(['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND']);\n\n/** Convert a major-unit amount (e.g., 129.99) into ISO 4217 minor units (e.g., 12,999). */\nexport function toMinorUnits(value?: number | null, currency?: string): number | undefined {\n if (value === undefined || value === null || Number.isNaN(value)) return undefined;\n const code = currency?.toUpperCase();\n const exponent =\n code && ZERO_DECIMAL_CURRENCIES.has(code)\n ? 0\n : code && THREE_DECIMAL_CURRENCIES.has(code)\n ? 3\n : 2;\n return Math.round(value * 10 ** exponent);\n}\n\nexport function mapContents(items?: Item[], currency?: string): ContentItem[] | undefined {\n if (!items || items.length === 0) return undefined;\n const code = currency?.toUpperCase();\n return items.map((item) => ({\n id: item.item_id,\n name: item.item_name,\n content_type: item.item_category,\n quantity: item.quantity,\n amount: toMinorUnits(item.price, currency),\n currency: item.price !== undefined ? code : undefined,\n }));\n}\n\n/** Safely read a property off loosely typed track properties without widening to `any`. */\nfunction prop(properties: unknown, key: string): unknown {\n return typeof properties === 'object' && properties !== null\n ? (properties as Record<string, unknown>)[key]\n : undefined;\n}\n\nfunction readValue(properties: unknown): number | undefined {\n const value = prop(properties, 'value');\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction readCurrency(properties: unknown): string | undefined {\n const currency = prop(properties, 'currency');\n return typeof currency === 'string' ? currency : undefined;\n}\n\nfunction readItems(properties: unknown): Item[] | undefined {\n const items = prop(properties, 'items');\n return Array.isArray(items) ? (items as Item[]) : undefined;\n}\n\nfunction contentsData(properties: unknown): ContentsData {\n const currency = readCurrency(properties);\n return {\n type: 'contents',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(readItems(properties), currency),\n };\n}\n\nfunction customerActionData(properties: unknown): CustomerActionData {\n const currency = readCurrency(properties);\n return {\n type: 'customer_action',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n };\n}\n\nfunction planEnrollmentData(properties: unknown): PlanEnrollmentData {\n const currency = readCurrency(properties);\n const items = readItems(properties);\n return {\n type: 'plan_enrollment',\n plan_id: items?.[0]?.item_id,\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(items, currency),\n };\n}\n\nexport type MappedOAIEvent = {\n type: StandardEvent | 'custom';\n data: EventData;\n};\n\n/** Map an internal track event onto an OpenAI standard (or custom) conversion event. */\nexport function mapOAIEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n): MappedOAIEvent {\n switch (name) {\n case 'page_view':\n return { type: 'page_viewed', data: contentsData(properties) };\n case 'view_item':\n case 'view_item_list':\n return { type: 'contents_viewed', data: contentsData(properties) };\n case 'begin_checkout':\n return { type: 'checkout_started', data: contentsData(properties) };\n case 'add_to_cart':\n return { type: 'items_added', data: contentsData(properties) };\n case 'purchase':\n return { type: 'order_created', data: contentsData(properties) };\n case 'generate_lead':\n case 'qualify_lead':\n return { type: 'lead_created', data: customerActionData(properties) };\n case 'sign_up':\n case 'login':\n return { type: 'registration_completed', data: customerActionData(properties) };\n case 'schedule':\n return { type: 'appointment_scheduled', data: customerActionData(properties) };\n case 'subscribe':\n return { type: 'subscription_created', data: planEnrollmentData(properties) };\n case 'trial_begin':\n return { type: 'trial_started', data: planEnrollmentData(properties) };\n default: {\n const currency = readCurrency(properties);\n return {\n type: 'custom',\n data: {\n type: 'custom',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(readItems(properties), currency),\n },\n };\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/track/oaiq.d.cts
CHANGED
|
@@ -99,7 +99,7 @@ interface OAIQ {
|
|
|
99
99
|
}): void;
|
|
100
100
|
}
|
|
101
101
|
/** Convert a major-unit amount (e.g., 129.99) into ISO 4217 minor units (e.g., 12,999). */
|
|
102
|
-
declare function toMinorUnits(value?: number, currency?: string): number | undefined;
|
|
102
|
+
declare function toMinorUnits(value?: number | null, currency?: string): number | undefined;
|
|
103
103
|
declare function mapContents(items?: Item[], currency?: string): ContentItem[] | undefined;
|
|
104
104
|
type MappedOAIEvent = {
|
|
105
105
|
type: StandardEvent | 'custom';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oaiq.d.cts","names":[],"sources":["../../src/track/oaiq.ts"],"mappings":";;;cAGa;;;;;KAiBD;EACV;EACA;EACA;EACA;;EAEA;EACA;;KAGU;EACV;;EAEA;EACA;EACA,WAAW;;KAGD;EACV;EACA;EACA;;KAGU;EACV;EACA;EACA;EACA;EACA,WAAW;;KAGD;EACV;EACA;EACA;EACA,WAAW;;KAGD,YAAY,eAAe,qBAAqB,qBAAqB;;;;;KAMrE;EACV,uBAAuB;EACvB,kBAAkB;EAClB,iBAAiB;EACjB,aAAa;EACb,cAAc;EACd,eAAe;EACf,aAAa;EACb,wBAAwB;EACxB,sBAAsB;EACtB,eAAe;;KAGL,sBAAsB;;;;;;KAOtB;EACV;EACA;;EAEA;;EAEA;;EAEA;;KAGU;EACV;;EAEA;EACA,OAAO;;;;;;KAOG;;EAEV;;EAEA;;EAEA;;UAGe;EACf,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,UAAU,eACb,oBACA,OAAO,GACP,MAAM,eAAe,IACrB,UAAU;EAEZ,KACE,oBACA,iBACA,MAAM,iBACN,SAAS;IAAmB;;;;iBAgChB,aAAa,
|
|
1
|
+
{"version":3,"file":"oaiq.d.cts","names":[],"sources":["../../src/track/oaiq.ts"],"mappings":";;;cAGa;;;;;KAiBD;EACV;EACA;EACA;EACA;;EAEA;EACA;;KAGU;EACV;;EAEA;EACA;EACA,WAAW;;KAGD;EACV;EACA;EACA;;KAGU;EACV;EACA;EACA;EACA;EACA,WAAW;;KAGD;EACV;EACA;EACA;EACA,WAAW;;KAGD,YAAY,eAAe,qBAAqB,qBAAqB;;;;;KAMrE;EACV,uBAAuB;EACvB,kBAAkB;EAClB,iBAAiB;EACjB,aAAa;EACb,cAAc;EACd,eAAe;EACf,aAAa;EACb,wBAAwB;EACxB,sBAAsB;EACtB,eAAe;;KAGL,sBAAsB;;;;;;KAOtB;EACV;EACA;;EAEA;;EAEA;;EAEA;;KAGU;EACV;;EAEA;EACA,OAAO;;;;;;KAOG;;EAEV;;EAEA;;EAEA;;UAGe;EACf,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,UAAU,eACb,oBACA,OAAO,GACP,MAAM,eAAe,IACrB,UAAU;EAEZ,KACE,oBACA,iBACA,MAAM,iBACN,SAAS;IAAmB;;;;iBAgChB,aAAa,uBAAuB;iBAYpC,YAAY,QAAQ,QAAQ,oBAAoB;KAkEpD;EACV,MAAM;EACN,MAAM;;;iBAIQ,YAAY,UAAU,WACpC,MAAM,UAAU,IAChB,aAAa,gBAAgB,KAC5B"}
|
package/dist/track/oaiq.d.mts
CHANGED
|
@@ -99,7 +99,7 @@ interface OAIQ {
|
|
|
99
99
|
}): void;
|
|
100
100
|
}
|
|
101
101
|
/** Convert a major-unit amount (e.g., 129.99) into ISO 4217 minor units (e.g., 12,999). */
|
|
102
|
-
declare function toMinorUnits(value?: number, currency?: string): number | undefined;
|
|
102
|
+
declare function toMinorUnits(value?: number | null, currency?: string): number | undefined;
|
|
103
103
|
declare function mapContents(items?: Item[], currency?: string): ContentItem[] | undefined;
|
|
104
104
|
type MappedOAIEvent = {
|
|
105
105
|
type: StandardEvent | 'custom';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oaiq.d.mts","names":[],"sources":["../../src/track/oaiq.ts"],"mappings":";;;cAGa;;;;;KAiBD;EACV;EACA;EACA;EACA;;EAEA;EACA;;KAGU;EACV;;EAEA;EACA;EACA,WAAW;;KAGD;EACV;EACA;EACA;;KAGU;EACV;EACA;EACA;EACA;EACA,WAAW;;KAGD;EACV;EACA;EACA;EACA,WAAW;;KAGD,YAAY,eAAe,qBAAqB,qBAAqB;;;;;KAMrE;EACV,uBAAuB;EACvB,kBAAkB;EAClB,iBAAiB;EACjB,aAAa;EACb,cAAc;EACd,eAAe;EACf,aAAa;EACb,wBAAwB;EACxB,sBAAsB;EACtB,eAAe;;KAGL,sBAAsB;;;;;;KAOtB;EACV;EACA;;EAEA;;EAEA;;EAEA;;KAGU;EACV;;EAEA;EACA,OAAO;;;;;;KAOG;;EAEV;;EAEA;;EAEA;;UAGe;EACf,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,UAAU,eACb,oBACA,OAAO,GACP,MAAM,eAAe,IACrB,UAAU;EAEZ,KACE,oBACA,iBACA,MAAM,iBACN,SAAS;IAAmB;;;;iBAgChB,aAAa,
|
|
1
|
+
{"version":3,"file":"oaiq.d.mts","names":[],"sources":["../../src/track/oaiq.ts"],"mappings":";;;cAGa;;;;;KAiBD;EACV;EACA;EACA;EACA;;EAEA;EACA;;KAGU;EACV;;EAEA;EACA;EACA,WAAW;;KAGD;EACV;EACA;EACA;;KAGU;EACV;EACA;EACA;EACA;EACA,WAAW;;KAGD;EACV;EACA;EACA;EACA,WAAW;;KAGD,YAAY,eAAe,qBAAqB,qBAAqB;;;;;KAMrE;EACV,uBAAuB;EACvB,kBAAkB;EAClB,iBAAiB;EACjB,aAAa;EACb,cAAc;EACd,eAAe;EACf,aAAa;EACb,wBAAwB;EACxB,sBAAsB;EACtB,eAAe;;KAGL,sBAAsB;;;;;;KAOtB;EACV;EACA;;EAEA;;EAEA;;EAEA;;KAGU;EACV;;EAEA;EACA,OAAO;;;;;;KAOG;;EAEV;;EAEA;;EAEA;;UAGe;EACf,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,UAAU,eACb,oBACA,OAAO,GACP,MAAM,eAAe,IACrB,UAAU;EAEZ,KACE,oBACA,iBACA,MAAM,iBACN,SAAS;IAAmB;;;;iBAgChB,aAAa,uBAAuB;iBAYpC,YAAY,QAAQ,QAAQ,oBAAoB;KAkEpD;EACV,MAAM;EACN,MAAM;;;iBAIQ,YAAY,UAAU,WACpC,MAAM,UAAU,IAChB,aAAa,gBAAgB,KAC5B"}
|
package/dist/track/oaiq.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oaiq.mjs","names":[],"sources":["../../src/track/oaiq.ts"],"sourcesContent":["import type { Item } from './gtag';\nimport type { EventName, TrackName, TrackProperties } from './types';\n\nexport const NON_AD_EVENTS = [\n // metrics\n 'CLS',\n 'FCP',\n 'FID',\n 'INP',\n 'LCP',\n 'TTFB',\n // promotions\n 'view_promotion',\n 'select_promotion',\n];\n\n/**\n * Content item shared by `contents` and `plan_enrollment` events.\n * https://developers.openai.com/ads/supported-events\n */\nexport type ContentItem = {\n id?: string;\n name?: string;\n content_type?: string;\n quantity?: number;\n /** Per-item monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n amount?: number;\n currency?: string;\n};\n\nexport type ContentsData = {\n type: 'contents';\n /** Monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type CustomerActionData = {\n type: 'customer_action';\n amount?: number;\n currency?: string;\n};\n\nexport type PlanEnrollmentData = {\n type: 'plan_enrollment';\n plan_id?: string;\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type CustomEventData = {\n type: 'custom';\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type EventData = ContentsData | CustomerActionData | PlanEnrollmentData | CustomEventData;\n\n/**\n * Standard event names and the `data` shape each one expects.\n * https://developers.openai.com/ads/supported-events\n */\nexport type StandardEvents = {\n appointment_scheduled: CustomerActionData;\n checkout_started: ContentsData;\n contents_viewed: ContentsData;\n items_added: ContentsData;\n lead_created: CustomerActionData;\n order_created: ContentsData;\n page_viewed: ContentsData;\n registration_completed: CustomerActionData;\n subscription_created: PlanEnrollmentData;\n trial_started: PlanEnrollmentData;\n};\n\nexport type StandardEvent = keyof StandardEvents;\n\n/**\n * Identity fields passed to `oaiq(\"init\", ...)` for conversion matching. Email and external id\n * must be pre-hashed as lowercase 64-char SHA-256 hex strings; the rest are sent as raw values.\n * https://developers.openai.com/ads/measurement-pixel\n */\nexport type OAIQUser = {\n email_sha256?: string;\n external_id_sha256?: string;\n /** Two-letter ISO 3166-1 country code (e.g. \"US\"). */\n country?: string;\n /** Lowercased, max 128 characters. */\n city?: string;\n /** Max 32 characters. */\n zip_code?: string;\n};\n\nexport type InitConfig = {\n pixelId: string;\n /** Log SDK activity to the browser console. */\n debug?: boolean;\n user?: OAIQUser;\n};\n\n/**\n * Fourth argument of `oaiq(\"measure\", ...)`. Required for custom events (carries\n * `custom_event_name`); optional for standard events.\n */\nexport type MeasureOptions = {\n /** Shared with the Conversions API to deduplicate the same conversion across browser and server. */\n event_id?: string;\n /** Required for custom events; 1-64 chars of letters, numbers, underscores, or dashes. */\n custom_event_name?: string;\n /** When true, opts the event out of user-level personalization. */\n opt_out?: boolean;\n};\n\nexport interface OAIQ {\n oaiq(command: 'init', config: InitConfig): void;\n oaiq<T extends StandardEvent>(\n command: 'measure',\n event: T,\n data: StandardEvents[T],\n options?: MeasureOptions\n ): void;\n oaiq(\n command: 'measure',\n event: 'custom',\n data: CustomEventData,\n options: MeasureOptions & { custom_event_name: string }\n ): void;\n}\n\n/**\n * Currencies whose minor unit has 0 or 3 decimal places; everything else uses 2.\n * Follows Stripe's zero-decimal convention (e.g., MGA is treated as 0, ISK is included),\n * which can differ from strict ISO 4217 exponents.\n * https://docs.stripe.com/currencies#zero-decimal\n */\nconst ZERO_DECIMAL_CURRENCIES = new Set([\n 'BIF',\n 'CLP',\n 'DJF',\n 'GNF',\n 'ISK',\n 'JPY',\n 'KMF',\n 'KRW',\n 'MGA',\n 'PYG',\n 'RWF',\n 'UGX',\n 'VND',\n 'VUV',\n 'XAF',\n 'XOF',\n 'XPF',\n]);\nconst THREE_DECIMAL_CURRENCIES = new Set(['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND']);\n\n/** Convert a major-unit amount (e.g., 129.99) into ISO 4217 minor units (e.g., 12,999). */\nexport function toMinorUnits(value?: number, currency?: string): number | undefined {\n if (value === undefined || value === null || Number.isNaN(value)) return undefined;\n const code = currency?.toUpperCase();\n const exponent =\n code && ZERO_DECIMAL_CURRENCIES.has(code)\n ? 0\n : code && THREE_DECIMAL_CURRENCIES.has(code)\n ? 3\n : 2;\n return Math.round(value * 10 ** exponent);\n}\n\nexport function mapContents(items?: Item[], currency?: string): ContentItem[] | undefined {\n if (!items || items.length === 0) return undefined;\n const code = currency?.toUpperCase();\n return items.map((item) => ({\n id: item.item_id,\n name: item.item_name,\n content_type: item.item_category,\n quantity: item.quantity,\n amount: toMinorUnits(item.price, currency),\n currency: item.price !== undefined ? code : undefined,\n }));\n}\n\n/** Safely read a property off loosely typed track properties without widening to `any`. */\nfunction prop(properties: unknown, key: string): unknown {\n return typeof properties === 'object' && properties !== null\n ? (properties as Record<string, unknown>)[key]\n : undefined;\n}\n\nfunction readValue(properties: unknown): number | undefined {\n const value = prop(properties, 'value');\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction readCurrency(properties: unknown): string | undefined {\n const currency = prop(properties, 'currency');\n return typeof currency === 'string' ? currency : undefined;\n}\n\nfunction readItems(properties: unknown): Item[] | undefined {\n const items = prop(properties, 'items');\n return Array.isArray(items) ? (items as Item[]) : undefined;\n}\n\nfunction contentsData(properties: unknown): ContentsData {\n const currency = readCurrency(properties);\n return {\n type: 'contents',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(readItems(properties), currency),\n };\n}\n\nfunction customerActionData(properties: unknown): CustomerActionData {\n const currency = readCurrency(properties);\n return {\n type: 'customer_action',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n };\n}\n\nfunction planEnrollmentData(properties: unknown): PlanEnrollmentData {\n const currency = readCurrency(properties);\n const items = readItems(properties);\n return {\n type: 'plan_enrollment',\n plan_id: items?.[0]?.item_id,\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(items, currency),\n };\n}\n\nexport type MappedOAIEvent = {\n type: StandardEvent | 'custom';\n data: EventData;\n};\n\n/** Map an internal track event onto an OpenAI standard (or custom) conversion event. */\nexport function mapOAIEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n): MappedOAIEvent {\n switch (name) {\n case 'page_view':\n return { type: 'page_viewed', data: contentsData(properties) };\n case 'view_item':\n case 'view_item_list':\n return { type: 'contents_viewed', data: contentsData(properties) };\n case 'begin_checkout':\n return { type: 'checkout_started', data: contentsData(properties) };\n case 'add_to_cart':\n return { type: 'items_added', data: contentsData(properties) };\n case 'purchase':\n return { type: 'order_created', data: contentsData(properties) };\n case 'generate_lead':\n case 'qualify_lead':\n return { type: 'lead_created', data: customerActionData(properties) };\n case 'sign_up':\n case 'login':\n return { type: 'registration_completed', data: customerActionData(properties) };\n case 'schedule':\n return { type: 'appointment_scheduled', data: customerActionData(properties) };\n case 'subscribe':\n return { type: 'subscription_created', data: planEnrollmentData(properties) };\n case 'trial_begin':\n return { type: 'trial_started', data: planEnrollmentData(properties) };\n default: {\n const currency = readCurrency(properties);\n return {\n type: 'custom',\n data: {\n type: 'custom',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(readItems(properties), currency),\n },\n };\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"oaiq.mjs","names":[],"sources":["../../src/track/oaiq.ts"],"sourcesContent":["import type { Item } from './gtag';\nimport type { EventName, TrackName, TrackProperties } from './types';\n\nexport const NON_AD_EVENTS = [\n // metrics\n 'CLS',\n 'FCP',\n 'FID',\n 'INP',\n 'LCP',\n 'TTFB',\n // promotions\n 'view_promotion',\n 'select_promotion',\n];\n\n/**\n * Content item shared by `contents` and `plan_enrollment` events.\n * https://developers.openai.com/ads/supported-events\n */\nexport type ContentItem = {\n id?: string;\n name?: string;\n content_type?: string;\n quantity?: number;\n /** Per-item monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n amount?: number;\n currency?: string;\n};\n\nexport type ContentsData = {\n type: 'contents';\n /** Monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type CustomerActionData = {\n type: 'customer_action';\n amount?: number;\n currency?: string;\n};\n\nexport type PlanEnrollmentData = {\n type: 'plan_enrollment';\n plan_id?: string;\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type CustomEventData = {\n type: 'custom';\n amount?: number;\n currency?: string;\n contents?: ContentItem[];\n};\n\nexport type EventData = ContentsData | CustomerActionData | PlanEnrollmentData | CustomEventData;\n\n/**\n * Standard event names and the `data` shape each one expects.\n * https://developers.openai.com/ads/supported-events\n */\nexport type StandardEvents = {\n appointment_scheduled: CustomerActionData;\n checkout_started: ContentsData;\n contents_viewed: ContentsData;\n items_added: ContentsData;\n lead_created: CustomerActionData;\n order_created: ContentsData;\n page_viewed: ContentsData;\n registration_completed: CustomerActionData;\n subscription_created: PlanEnrollmentData;\n trial_started: PlanEnrollmentData;\n};\n\nexport type StandardEvent = keyof StandardEvents;\n\n/**\n * Identity fields passed to `oaiq(\"init\", ...)` for conversion matching. Email and external id\n * must be pre-hashed as lowercase 64-char SHA-256 hex strings; the rest are sent as raw values.\n * https://developers.openai.com/ads/measurement-pixel\n */\nexport type OAIQUser = {\n email_sha256?: string;\n external_id_sha256?: string;\n /** Two-letter ISO 3166-1 country code (e.g. \"US\"). */\n country?: string;\n /** Lowercased, max 128 characters. */\n city?: string;\n /** Max 32 characters. */\n zip_code?: string;\n};\n\nexport type InitConfig = {\n pixelId: string;\n /** Log SDK activity to the browser console. */\n debug?: boolean;\n user?: OAIQUser;\n};\n\n/**\n * Fourth argument of `oaiq(\"measure\", ...)`. Required for custom events (carries\n * `custom_event_name`); optional for standard events.\n */\nexport type MeasureOptions = {\n /** Shared with the Conversions API to deduplicate the same conversion across browser and server. */\n event_id?: string;\n /** Required for custom events; 1-64 chars of letters, numbers, underscores, or dashes. */\n custom_event_name?: string;\n /** When true, opts the event out of user-level personalization. */\n opt_out?: boolean;\n};\n\nexport interface OAIQ {\n oaiq(command: 'init', config: InitConfig): void;\n oaiq<T extends StandardEvent>(\n command: 'measure',\n event: T,\n data: StandardEvents[T],\n options?: MeasureOptions\n ): void;\n oaiq(\n command: 'measure',\n event: 'custom',\n data: CustomEventData,\n options: MeasureOptions & { custom_event_name: string }\n ): void;\n}\n\n/**\n * Currencies whose minor unit has 0 or 3 decimal places; everything else uses 2.\n * Follows Stripe's zero-decimal convention (e.g., MGA is treated as 0, ISK is included),\n * which can differ from strict ISO 4217 exponents.\n * https://docs.stripe.com/currencies#zero-decimal\n */\nconst ZERO_DECIMAL_CURRENCIES = new Set([\n 'BIF',\n 'CLP',\n 'DJF',\n 'GNF',\n 'ISK',\n 'JPY',\n 'KMF',\n 'KRW',\n 'MGA',\n 'PYG',\n 'RWF',\n 'UGX',\n 'VND',\n 'VUV',\n 'XAF',\n 'XOF',\n 'XPF',\n]);\nconst THREE_DECIMAL_CURRENCIES = new Set(['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND']);\n\n/** Convert a major-unit amount (e.g., 129.99) into ISO 4217 minor units (e.g., 12,999). */\nexport function toMinorUnits(value?: number | null, currency?: string): number | undefined {\n if (value === undefined || value === null || Number.isNaN(value)) return undefined;\n const code = currency?.toUpperCase();\n const exponent =\n code && ZERO_DECIMAL_CURRENCIES.has(code)\n ? 0\n : code && THREE_DECIMAL_CURRENCIES.has(code)\n ? 3\n : 2;\n return Math.round(value * 10 ** exponent);\n}\n\nexport function mapContents(items?: Item[], currency?: string): ContentItem[] | undefined {\n if (!items || items.length === 0) return undefined;\n const code = currency?.toUpperCase();\n return items.map((item) => ({\n id: item.item_id,\n name: item.item_name,\n content_type: item.item_category,\n quantity: item.quantity,\n amount: toMinorUnits(item.price, currency),\n currency: item.price !== undefined ? code : undefined,\n }));\n}\n\n/** Safely read a property off loosely typed track properties without widening to `any`. */\nfunction prop(properties: unknown, key: string): unknown {\n return typeof properties === 'object' && properties !== null\n ? (properties as Record<string, unknown>)[key]\n : undefined;\n}\n\nfunction readValue(properties: unknown): number | undefined {\n const value = prop(properties, 'value');\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction readCurrency(properties: unknown): string | undefined {\n const currency = prop(properties, 'currency');\n return typeof currency === 'string' ? currency : undefined;\n}\n\nfunction readItems(properties: unknown): Item[] | undefined {\n const items = prop(properties, 'items');\n return Array.isArray(items) ? (items as Item[]) : undefined;\n}\n\nfunction contentsData(properties: unknown): ContentsData {\n const currency = readCurrency(properties);\n return {\n type: 'contents',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(readItems(properties), currency),\n };\n}\n\nfunction customerActionData(properties: unknown): CustomerActionData {\n const currency = readCurrency(properties);\n return {\n type: 'customer_action',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n };\n}\n\nfunction planEnrollmentData(properties: unknown): PlanEnrollmentData {\n const currency = readCurrency(properties);\n const items = readItems(properties);\n return {\n type: 'plan_enrollment',\n plan_id: items?.[0]?.item_id,\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(items, currency),\n };\n}\n\nexport type MappedOAIEvent = {\n type: StandardEvent | 'custom';\n data: EventData;\n};\n\n/** Map an internal track event onto an OpenAI standard (or custom) conversion event. */\nexport function mapOAIEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n): MappedOAIEvent {\n switch (name) {\n case 'page_view':\n return { type: 'page_viewed', data: contentsData(properties) };\n case 'view_item':\n case 'view_item_list':\n return { type: 'contents_viewed', data: contentsData(properties) };\n case 'begin_checkout':\n return { type: 'checkout_started', data: contentsData(properties) };\n case 'add_to_cart':\n return { type: 'items_added', data: contentsData(properties) };\n case 'purchase':\n return { type: 'order_created', data: contentsData(properties) };\n case 'generate_lead':\n case 'qualify_lead':\n return { type: 'lead_created', data: customerActionData(properties) };\n case 'sign_up':\n case 'login':\n return { type: 'registration_completed', data: customerActionData(properties) };\n case 'schedule':\n return { type: 'appointment_scheduled', data: customerActionData(properties) };\n case 'subscribe':\n return { type: 'subscription_created', data: planEnrollmentData(properties) };\n case 'trial_begin':\n return { type: 'trial_started', data: planEnrollmentData(properties) };\n default: {\n const currency = readCurrency(properties);\n return {\n type: 'custom',\n data: {\n type: 'custom',\n amount: toMinorUnits(readValue(properties), currency),\n currency: currency?.toUpperCase(),\n contents: mapContents(readItems(properties), currency),\n },\n };\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/track/rdt.cjs
CHANGED
|
@@ -18,7 +18,7 @@ function mapRDTEvent(name, properties, eventId) {
|
|
|
18
18
|
conversionId: eventId,
|
|
19
19
|
value: p?.value,
|
|
20
20
|
currency: p?.currency.toUpperCase(),
|
|
21
|
-
itemCount: p?.items
|
|
21
|
+
itemCount: p?.items.reduce((acc, i) => acc + (i.quantity ?? 1), 0),
|
|
22
22
|
products: mapItems(p?.items)
|
|
23
23
|
}];
|
|
24
24
|
} else if (name === "add_to_wishlist") {
|
|
@@ -27,7 +27,7 @@ function mapRDTEvent(name, properties, eventId) {
|
|
|
27
27
|
conversionId: eventId,
|
|
28
28
|
value: p?.value,
|
|
29
29
|
currency: p?.currency.toUpperCase(),
|
|
30
|
-
itemCount: p?.items
|
|
30
|
+
itemCount: p?.items.reduce((acc, i) => acc + (i.quantity ?? 1), 0),
|
|
31
31
|
products: mapItems(p?.items)
|
|
32
32
|
}];
|
|
33
33
|
} else if (name === "purchase") {
|
|
@@ -62,8 +62,7 @@ function mapServerStandardEvent(name) {
|
|
|
62
62
|
if (name === "AddToWishlist") return "ADD_TO_WISHLIST";
|
|
63
63
|
if (name === "Purchase") return "PURCHASE";
|
|
64
64
|
if (name === "Lead") return "LEAD";
|
|
65
|
-
|
|
66
|
-
throw new Error(`Unsupported standard event: ${String(name)}`);
|
|
65
|
+
return "SIGN_UP";
|
|
67
66
|
}
|
|
68
67
|
//#endregion
|
|
69
68
|
exports.mapItems = mapItems;
|
package/dist/track/rdt.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rdt.cjs","names":[],"sources":["../../src/track/rdt.ts"],"sourcesContent":["import type { Item } from './gtag';\nimport type { EventName, TrackName, TrackProperties } from './types';\n\n/** https://business.reddithelp.com/s/article/about-event-metadata */\nexport type Product = {\n /**\n * (Required) Product ID: Either the SKU or GTIN, which represents the variant ID, not the\n * parent ID. If there are no variants, pass the assigned ID for that item.\n */\n id: string;\n\n /** (Optional) Product Category: The group the product belongs to. */\n name?: string;\n\n /** (Optional) Product Name: The title of the product. */\n category?: string;\n};\n\n/**\n * https://business.reddithelp.com/s/article/supported-conversion-events#supported-conversion-events\n * https://business.reddithelp.com/s/article/about-event-metadata\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport type StandardEvents = {\n PageVisit: {\n conversionId?: string;\n products?: Product[];\n };\n ViewContent: {\n conversionId?: string;\n products?: Product[];\n };\n Search: {\n conversionId?: string;\n products?: Product[];\n };\n AddToCart: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n AddToWishlist: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n Purchase: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n Lead: {\n value?: number;\n currency?: string;\n conversionId?: string;\n products?: Product[];\n };\n SignUp: {\n value?: number;\n currency?: string;\n conversionId?: string;\n products?: Product[];\n };\n};\n\nexport type PixelId = `a2_${string}`;\n\nexport type MatchKeys = {\n email?: string;\n phoneNumber?: string;\n externalId?: string;\n idfa?: string;\n aaid?: string;\n};\n\nexport type CustomEventParams<T extends string = string> = {\n customEventName: T;\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n};\n\nexport interface RDT {\n rdt(event: 'init', pixelId: PixelId, matchKeys?: MatchKeys): void;\n\n rdt<T extends keyof StandardEvents>(event: 'track', type: T, params?: StandardEvents[T]): void;\n\n rdt(event: 'track', type: 'Custom', params: CustomEventParams): void;\n}\n\ntype Mapped<F extends keyof StandardEvents> = [F, StandardEvents[F]];\ntype Missed<F extends string> = ['Custom', CustomEventParams<F>];\n\nexport function mapItems(items?: Item[]): undefined | Product[] {\n if (!items || items.length === 0) return undefined;\n return items.map((item) => ({\n id: item.item_id,\n name: item.item_name,\n category: item.item_category,\n }));\n}\n\nexport function mapRDTEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n): Mapped<keyof StandardEvents> | Missed<TrackName<T>> {\n // standard events\n if (name === 'page_view') {\n return ['PageVisit', { conversionId: eventId }];\n } else if (name === 'view_item') {\n return ['ViewContent', { conversionId: eventId }];\n } else if (name === 'search') {\n return ['Search', { conversionId: eventId }];\n } else if (name === 'add_to_cart') {\n const p = properties as TrackProperties<'add_to_cart'> | undefined;\n return [\n 'AddToCart',\n {\n conversionId: eventId,\n value: p?.value,\n currency: p?.currency.toUpperCase(),\n itemCount: p?.items
|
|
1
|
+
{"version":3,"file":"rdt.cjs","names":[],"sources":["../../src/track/rdt.ts"],"sourcesContent":["import type { Item } from './gtag';\nimport type { EventName, TrackName, TrackProperties } from './types';\n\n/** https://business.reddithelp.com/s/article/about-event-metadata */\nexport type Product = {\n /**\n * (Required) Product ID: Either the SKU or GTIN, which represents the variant ID, not the\n * parent ID. If there are no variants, pass the assigned ID for that item.\n */\n id: string;\n\n /** (Optional) Product Category: The group the product belongs to. */\n name?: string;\n\n /** (Optional) Product Name: The title of the product. */\n category?: string;\n};\n\n/**\n * https://business.reddithelp.com/s/article/supported-conversion-events#supported-conversion-events\n * https://business.reddithelp.com/s/article/about-event-metadata\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport type StandardEvents = {\n PageVisit: {\n conversionId?: string;\n products?: Product[];\n };\n ViewContent: {\n conversionId?: string;\n products?: Product[];\n };\n Search: {\n conversionId?: string;\n products?: Product[];\n };\n AddToCart: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n AddToWishlist: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n Purchase: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n Lead: {\n value?: number;\n currency?: string;\n conversionId?: string;\n products?: Product[];\n };\n SignUp: {\n value?: number;\n currency?: string;\n conversionId?: string;\n products?: Product[];\n };\n};\n\nexport type PixelId = `a2_${string}`;\n\nexport type MatchKeys = {\n email?: string;\n phoneNumber?: string;\n externalId?: string;\n idfa?: string;\n aaid?: string;\n};\n\nexport type CustomEventParams<T extends string = string> = {\n customEventName: T;\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n};\n\nexport interface RDT {\n rdt(event: 'init', pixelId: PixelId, matchKeys?: MatchKeys): void;\n\n rdt<T extends keyof StandardEvents>(event: 'track', type: T, params?: StandardEvents[T]): void;\n\n rdt(event: 'track', type: 'Custom', params: CustomEventParams): void;\n}\n\ntype Mapped<F extends keyof StandardEvents> = [F, StandardEvents[F]];\ntype Missed<F extends string> = ['Custom', CustomEventParams<F>];\n\nexport function mapItems(items?: Item[]): undefined | Product[] {\n if (!items || items.length === 0) return undefined;\n return items.map((item) => ({\n id: item.item_id,\n name: item.item_name,\n category: item.item_category,\n }));\n}\n\nexport function mapRDTEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n): Mapped<keyof StandardEvents> | Missed<TrackName<T>> {\n // standard events\n if (name === 'page_view') {\n return ['PageVisit', { conversionId: eventId }];\n } else if (name === 'view_item') {\n return ['ViewContent', { conversionId: eventId }];\n } else if (name === 'search') {\n return ['Search', { conversionId: eventId }];\n } else if (name === 'add_to_cart') {\n const p = properties as TrackProperties<'add_to_cart'> | undefined;\n return [\n 'AddToCart',\n {\n conversionId: eventId,\n value: p?.value,\n currency: p?.currency.toUpperCase(),\n itemCount: p?.items.reduce((acc, i) => acc + (i.quantity ?? 1), 0),\n products: mapItems(p?.items),\n },\n ];\n } else if (name === 'add_to_wishlist') {\n const p = properties as TrackProperties<'add_to_wishlist'> | undefined;\n return [\n 'AddToWishlist',\n {\n conversionId: eventId,\n value: p?.value,\n currency: p?.currency.toUpperCase(),\n itemCount: p?.items.reduce((acc, i) => acc + (i.quantity ?? 1), 0),\n products: mapItems(p?.items),\n },\n ];\n } else if (name === 'purchase') {\n const p = properties as TrackProperties<'purchase'> | undefined;\n return [\n 'Purchase',\n {\n conversionId: eventId,\n value: p?.value,\n currency: p?.currency.toUpperCase(),\n itemCount: p?.items?.reduce((acc, i) => acc + (i.quantity ?? 1), 0),\n products: mapItems(p?.items),\n },\n ];\n } else if (name === 'generate_lead') {\n const p = properties as TrackProperties<'generate_lead'> | undefined;\n return [\n 'Lead',\n { conversionId: eventId, value: p?.value, currency: p?.currency.toUpperCase() },\n ];\n } else if (name === 'sign_up' || name === 'login') {\n return ['SignUp', { conversionId: eventId }];\n } else {\n // custom event\n return [\n 'Custom',\n {\n customEventName: name,\n conversionId: eventId,\n value:\n properties && 'value' in properties && typeof properties.value === 'number'\n ? properties.value\n : undefined,\n currency:\n properties && 'currency' in properties && typeof properties.currency === 'string'\n ? properties.currency.toUpperCase()\n : undefined,\n },\n ];\n }\n}\n\nexport type ServerStandardEvent =\n | 'PAGE_VISIT'\n | 'VIEW_CONTENT'\n | 'SEARCH'\n | 'ADD_TO_CART'\n | 'ADD_TO_WISHLIST'\n | 'PURCHASE'\n | 'LEAD'\n | 'SIGN_UP';\n\nexport function mapServerStandardEvent(name: keyof StandardEvents): ServerStandardEvent {\n if (name === 'PageVisit') return 'PAGE_VISIT';\n if (name === 'ViewContent') return 'VIEW_CONTENT';\n if (name === 'Search') return 'SEARCH';\n if (name === 'AddToCart') return 'ADD_TO_CART';\n if (name === 'AddToWishlist') return 'ADD_TO_WISHLIST';\n if (name === 'Purchase') return 'PURCHASE';\n if (name === 'Lead') return 'LEAD';\n // `name` is narrowed to 'SignUp' here, so the mapping is exhaustive\n return 'SIGN_UP';\n}\n"],"mappings":";;AAqGA,SAAgB,SAAS,OAAuC;CAC9D,IAAI,CAAC,SAAS,MAAM,WAAW,GAAG,OAAO,KAAA;CACzC,OAAO,MAAM,KAAK,UAAU;EAC1B,IAAI,KAAK;EACT,MAAM,KAAK;EACX,UAAU,KAAK;CACjB,EAAE;AACJ;AAEA,SAAgB,YACd,MACA,YACA,SACqD;CAErD,IAAI,SAAS,aACX,OAAO,CAAC,aAAa,EAAE,cAAc,QAAQ,CAAC;MACzC,IAAI,SAAS,aAClB,OAAO,CAAC,eAAe,EAAE,cAAc,QAAQ,CAAC;MAC3C,IAAI,SAAS,UAClB,OAAO,CAAC,UAAU,EAAE,cAAc,QAAQ,CAAC;MACtC,IAAI,SAAS,eAAe;EACjC,MAAM,IAAI;EACV,OAAO,CACL,aACA;GACE,cAAc;GACd,OAAO,GAAG;GACV,UAAU,GAAG,SAAS,YAAY;GAClC,WAAW,GAAG,MAAM,QAAQ,KAAK,MAAM,OAAO,EAAE,YAAY,IAAI,CAAC;GACjE,UAAU,SAAS,GAAG,KAAK;EAC7B,CACF;CACF,OAAO,IAAI,SAAS,mBAAmB;EACrC,MAAM,IAAI;EACV,OAAO,CACL,iBACA;GACE,cAAc;GACd,OAAO,GAAG;GACV,UAAU,GAAG,SAAS,YAAY;GAClC,WAAW,GAAG,MAAM,QAAQ,KAAK,MAAM,OAAO,EAAE,YAAY,IAAI,CAAC;GACjE,UAAU,SAAS,GAAG,KAAK;EAC7B,CACF;CACF,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,IAAI;EACV,OAAO,CACL,YACA;GACE,cAAc;GACd,OAAO,GAAG;GACV,UAAU,GAAG,SAAS,YAAY;GAClC,WAAW,GAAG,OAAO,QAAQ,KAAK,MAAM,OAAO,EAAE,YAAY,IAAI,CAAC;GAClE,UAAU,SAAS,GAAG,KAAK;EAC7B,CACF;CACF,OAAO,IAAI,SAAS,iBAAiB;EACnC,MAAM,IAAI;EACV,OAAO,CACL,QACA;GAAE,cAAc;GAAS,OAAO,GAAG;GAAO,UAAU,GAAG,SAAS,YAAY;EAAE,CAChF;CACF,OAAO,IAAI,SAAS,aAAa,SAAS,SACxC,OAAO,CAAC,UAAU,EAAE,cAAc,QAAQ,CAAC;MAG3C,OAAO,CACL,UACA;EACE,iBAAiB;EACjB,cAAc;EACd,OACE,cAAc,WAAW,cAAc,OAAO,WAAW,UAAU,WAC/D,WAAW,QACX,KAAA;EACN,UACE,cAAc,cAAc,cAAc,OAAO,WAAW,aAAa,WACrE,WAAW,SAAS,YAAY,IAChC,KAAA;CACR,CACF;AAEJ;AAYA,SAAgB,uBAAuB,MAAiD;CACtF,IAAI,SAAS,aAAa,OAAO;CACjC,IAAI,SAAS,eAAe,OAAO;CACnC,IAAI,SAAS,UAAU,OAAO;CAC9B,IAAI,SAAS,aAAa,OAAO;CACjC,IAAI,SAAS,iBAAiB,OAAO;CACrC,IAAI,SAAS,YAAY,OAAO;CAChC,IAAI,SAAS,QAAQ,OAAO;CAE5B,OAAO;AACT"}
|
package/dist/track/rdt.mjs
CHANGED
|
@@ -17,7 +17,7 @@ function mapRDTEvent(name, properties, eventId) {
|
|
|
17
17
|
conversionId: eventId,
|
|
18
18
|
value: p?.value,
|
|
19
19
|
currency: p?.currency.toUpperCase(),
|
|
20
|
-
itemCount: p?.items
|
|
20
|
+
itemCount: p?.items.reduce((acc, i) => acc + (i.quantity ?? 1), 0),
|
|
21
21
|
products: mapItems(p?.items)
|
|
22
22
|
}];
|
|
23
23
|
} else if (name === "add_to_wishlist") {
|
|
@@ -26,7 +26,7 @@ function mapRDTEvent(name, properties, eventId) {
|
|
|
26
26
|
conversionId: eventId,
|
|
27
27
|
value: p?.value,
|
|
28
28
|
currency: p?.currency.toUpperCase(),
|
|
29
|
-
itemCount: p?.items
|
|
29
|
+
itemCount: p?.items.reduce((acc, i) => acc + (i.quantity ?? 1), 0),
|
|
30
30
|
products: mapItems(p?.items)
|
|
31
31
|
}];
|
|
32
32
|
} else if (name === "purchase") {
|
|
@@ -61,8 +61,7 @@ function mapServerStandardEvent(name) {
|
|
|
61
61
|
if (name === "AddToWishlist") return "ADD_TO_WISHLIST";
|
|
62
62
|
if (name === "Purchase") return "PURCHASE";
|
|
63
63
|
if (name === "Lead") return "LEAD";
|
|
64
|
-
|
|
65
|
-
throw new Error(`Unsupported standard event: ${String(name)}`);
|
|
64
|
+
return "SIGN_UP";
|
|
66
65
|
}
|
|
67
66
|
//#endregion
|
|
68
67
|
export { mapItems, mapRDTEvent, mapServerStandardEvent };
|
package/dist/track/rdt.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rdt.mjs","names":[],"sources":["../../src/track/rdt.ts"],"sourcesContent":["import type { Item } from './gtag';\nimport type { EventName, TrackName, TrackProperties } from './types';\n\n/** https://business.reddithelp.com/s/article/about-event-metadata */\nexport type Product = {\n /**\n * (Required) Product ID: Either the SKU or GTIN, which represents the variant ID, not the\n * parent ID. If there are no variants, pass the assigned ID for that item.\n */\n id: string;\n\n /** (Optional) Product Category: The group the product belongs to. */\n name?: string;\n\n /** (Optional) Product Name: The title of the product. */\n category?: string;\n};\n\n/**\n * https://business.reddithelp.com/s/article/supported-conversion-events#supported-conversion-events\n * https://business.reddithelp.com/s/article/about-event-metadata\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport type StandardEvents = {\n PageVisit: {\n conversionId?: string;\n products?: Product[];\n };\n ViewContent: {\n conversionId?: string;\n products?: Product[];\n };\n Search: {\n conversionId?: string;\n products?: Product[];\n };\n AddToCart: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n AddToWishlist: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n Purchase: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n Lead: {\n value?: number;\n currency?: string;\n conversionId?: string;\n products?: Product[];\n };\n SignUp: {\n value?: number;\n currency?: string;\n conversionId?: string;\n products?: Product[];\n };\n};\n\nexport type PixelId = `a2_${string}`;\n\nexport type MatchKeys = {\n email?: string;\n phoneNumber?: string;\n externalId?: string;\n idfa?: string;\n aaid?: string;\n};\n\nexport type CustomEventParams<T extends string = string> = {\n customEventName: T;\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n};\n\nexport interface RDT {\n rdt(event: 'init', pixelId: PixelId, matchKeys?: MatchKeys): void;\n\n rdt<T extends keyof StandardEvents>(event: 'track', type: T, params?: StandardEvents[T]): void;\n\n rdt(event: 'track', type: 'Custom', params: CustomEventParams): void;\n}\n\ntype Mapped<F extends keyof StandardEvents> = [F, StandardEvents[F]];\ntype Missed<F extends string> = ['Custom', CustomEventParams<F>];\n\nexport function mapItems(items?: Item[]): undefined | Product[] {\n if (!items || items.length === 0) return undefined;\n return items.map((item) => ({\n id: item.item_id,\n name: item.item_name,\n category: item.item_category,\n }));\n}\n\nexport function mapRDTEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n): Mapped<keyof StandardEvents> | Missed<TrackName<T>> {\n // standard events\n if (name === 'page_view') {\n return ['PageVisit', { conversionId: eventId }];\n } else if (name === 'view_item') {\n return ['ViewContent', { conversionId: eventId }];\n } else if (name === 'search') {\n return ['Search', { conversionId: eventId }];\n } else if (name === 'add_to_cart') {\n const p = properties as TrackProperties<'add_to_cart'> | undefined;\n return [\n 'AddToCart',\n {\n conversionId: eventId,\n value: p?.value,\n currency: p?.currency.toUpperCase(),\n itemCount: p?.items
|
|
1
|
+
{"version":3,"file":"rdt.mjs","names":[],"sources":["../../src/track/rdt.ts"],"sourcesContent":["import type { Item } from './gtag';\nimport type { EventName, TrackName, TrackProperties } from './types';\n\n/** https://business.reddithelp.com/s/article/about-event-metadata */\nexport type Product = {\n /**\n * (Required) Product ID: Either the SKU or GTIN, which represents the variant ID, not the\n * parent ID. If there are no variants, pass the assigned ID for that item.\n */\n id: string;\n\n /** (Optional) Product Category: The group the product belongs to. */\n name?: string;\n\n /** (Optional) Product Name: The title of the product. */\n category?: string;\n};\n\n/**\n * https://business.reddithelp.com/s/article/supported-conversion-events#supported-conversion-events\n * https://business.reddithelp.com/s/article/about-event-metadata\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport type StandardEvents = {\n PageVisit: {\n conversionId?: string;\n products?: Product[];\n };\n ViewContent: {\n conversionId?: string;\n products?: Product[];\n };\n Search: {\n conversionId?: string;\n products?: Product[];\n };\n AddToCart: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n AddToWishlist: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n Purchase: {\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n };\n Lead: {\n value?: number;\n currency?: string;\n conversionId?: string;\n products?: Product[];\n };\n SignUp: {\n value?: number;\n currency?: string;\n conversionId?: string;\n products?: Product[];\n };\n};\n\nexport type PixelId = `a2_${string}`;\n\nexport type MatchKeys = {\n email?: string;\n phoneNumber?: string;\n externalId?: string;\n idfa?: string;\n aaid?: string;\n};\n\nexport type CustomEventParams<T extends string = string> = {\n customEventName: T;\n value?: number;\n currency?: string;\n itemCount?: number;\n conversionId?: string;\n products?: Product[];\n};\n\nexport interface RDT {\n rdt(event: 'init', pixelId: PixelId, matchKeys?: MatchKeys): void;\n\n rdt<T extends keyof StandardEvents>(event: 'track', type: T, params?: StandardEvents[T]): void;\n\n rdt(event: 'track', type: 'Custom', params: CustomEventParams): void;\n}\n\ntype Mapped<F extends keyof StandardEvents> = [F, StandardEvents[F]];\ntype Missed<F extends string> = ['Custom', CustomEventParams<F>];\n\nexport function mapItems(items?: Item[]): undefined | Product[] {\n if (!items || items.length === 0) return undefined;\n return items.map((item) => ({\n id: item.item_id,\n name: item.item_name,\n category: item.item_category,\n }));\n}\n\nexport function mapRDTEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n): Mapped<keyof StandardEvents> | Missed<TrackName<T>> {\n // standard events\n if (name === 'page_view') {\n return ['PageVisit', { conversionId: eventId }];\n } else if (name === 'view_item') {\n return ['ViewContent', { conversionId: eventId }];\n } else if (name === 'search') {\n return ['Search', { conversionId: eventId }];\n } else if (name === 'add_to_cart') {\n const p = properties as TrackProperties<'add_to_cart'> | undefined;\n return [\n 'AddToCart',\n {\n conversionId: eventId,\n value: p?.value,\n currency: p?.currency.toUpperCase(),\n itemCount: p?.items.reduce((acc, i) => acc + (i.quantity ?? 1), 0),\n products: mapItems(p?.items),\n },\n ];\n } else if (name === 'add_to_wishlist') {\n const p = properties as TrackProperties<'add_to_wishlist'> | undefined;\n return [\n 'AddToWishlist',\n {\n conversionId: eventId,\n value: p?.value,\n currency: p?.currency.toUpperCase(),\n itemCount: p?.items.reduce((acc, i) => acc + (i.quantity ?? 1), 0),\n products: mapItems(p?.items),\n },\n ];\n } else if (name === 'purchase') {\n const p = properties as TrackProperties<'purchase'> | undefined;\n return [\n 'Purchase',\n {\n conversionId: eventId,\n value: p?.value,\n currency: p?.currency.toUpperCase(),\n itemCount: p?.items?.reduce((acc, i) => acc + (i.quantity ?? 1), 0),\n products: mapItems(p?.items),\n },\n ];\n } else if (name === 'generate_lead') {\n const p = properties as TrackProperties<'generate_lead'> | undefined;\n return [\n 'Lead',\n { conversionId: eventId, value: p?.value, currency: p?.currency.toUpperCase() },\n ];\n } else if (name === 'sign_up' || name === 'login') {\n return ['SignUp', { conversionId: eventId }];\n } else {\n // custom event\n return [\n 'Custom',\n {\n customEventName: name,\n conversionId: eventId,\n value:\n properties && 'value' in properties && typeof properties.value === 'number'\n ? properties.value\n : undefined,\n currency:\n properties && 'currency' in properties && typeof properties.currency === 'string'\n ? properties.currency.toUpperCase()\n : undefined,\n },\n ];\n }\n}\n\nexport type ServerStandardEvent =\n | 'PAGE_VISIT'\n | 'VIEW_CONTENT'\n | 'SEARCH'\n | 'ADD_TO_CART'\n | 'ADD_TO_WISHLIST'\n | 'PURCHASE'\n | 'LEAD'\n | 'SIGN_UP';\n\nexport function mapServerStandardEvent(name: keyof StandardEvents): ServerStandardEvent {\n if (name === 'PageVisit') return 'PAGE_VISIT';\n if (name === 'ViewContent') return 'VIEW_CONTENT';\n if (name === 'Search') return 'SEARCH';\n if (name === 'AddToCart') return 'ADD_TO_CART';\n if (name === 'AddToWishlist') return 'ADD_TO_WISHLIST';\n if (name === 'Purchase') return 'PURCHASE';\n if (name === 'Lead') return 'LEAD';\n // `name` is narrowed to 'SignUp' here, so the mapping is exhaustive\n return 'SIGN_UP';\n}\n"],"mappings":";AAqGA,SAAgB,SAAS,OAAuC;CAC9D,IAAI,CAAC,SAAS,MAAM,WAAW,GAAG,OAAO,KAAA;CACzC,OAAO,MAAM,KAAK,UAAU;EAC1B,IAAI,KAAK;EACT,MAAM,KAAK;EACX,UAAU,KAAK;CACjB,EAAE;AACJ;AAEA,SAAgB,YACd,MACA,YACA,SACqD;CAErD,IAAI,SAAS,aACX,OAAO,CAAC,aAAa,EAAE,cAAc,QAAQ,CAAC;MACzC,IAAI,SAAS,aAClB,OAAO,CAAC,eAAe,EAAE,cAAc,QAAQ,CAAC;MAC3C,IAAI,SAAS,UAClB,OAAO,CAAC,UAAU,EAAE,cAAc,QAAQ,CAAC;MACtC,IAAI,SAAS,eAAe;EACjC,MAAM,IAAI;EACV,OAAO,CACL,aACA;GACE,cAAc;GACd,OAAO,GAAG;GACV,UAAU,GAAG,SAAS,YAAY;GAClC,WAAW,GAAG,MAAM,QAAQ,KAAK,MAAM,OAAO,EAAE,YAAY,IAAI,CAAC;GACjE,UAAU,SAAS,GAAG,KAAK;EAC7B,CACF;CACF,OAAO,IAAI,SAAS,mBAAmB;EACrC,MAAM,IAAI;EACV,OAAO,CACL,iBACA;GACE,cAAc;GACd,OAAO,GAAG;GACV,UAAU,GAAG,SAAS,YAAY;GAClC,WAAW,GAAG,MAAM,QAAQ,KAAK,MAAM,OAAO,EAAE,YAAY,IAAI,CAAC;GACjE,UAAU,SAAS,GAAG,KAAK;EAC7B,CACF;CACF,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,IAAI;EACV,OAAO,CACL,YACA;GACE,cAAc;GACd,OAAO,GAAG;GACV,UAAU,GAAG,SAAS,YAAY;GAClC,WAAW,GAAG,OAAO,QAAQ,KAAK,MAAM,OAAO,EAAE,YAAY,IAAI,CAAC;GAClE,UAAU,SAAS,GAAG,KAAK;EAC7B,CACF;CACF,OAAO,IAAI,SAAS,iBAAiB;EACnC,MAAM,IAAI;EACV,OAAO,CACL,QACA;GAAE,cAAc;GAAS,OAAO,GAAG;GAAO,UAAU,GAAG,SAAS,YAAY;EAAE,CAChF;CACF,OAAO,IAAI,SAAS,aAAa,SAAS,SACxC,OAAO,CAAC,UAAU,EAAE,cAAc,QAAQ,CAAC;MAG3C,OAAO,CACL,UACA;EACE,iBAAiB;EACjB,cAAc;EACd,OACE,cAAc,WAAW,cAAc,OAAO,WAAW,UAAU,WAC/D,WAAW,QACX,KAAA;EACN,UACE,cAAc,cAAc,cAAc,OAAO,WAAW,aAAa,WACrE,WAAW,SAAS,YAAY,IAChC,KAAA;CACR,CACF;AAEJ;AAYA,SAAgB,uBAAuB,MAAiD;CACtF,IAAI,SAAS,aAAa,OAAO;CACjC,IAAI,SAAS,eAAe,OAAO;CACnC,IAAI,SAAS,UAAU,OAAO;CAC9B,IAAI,SAAS,aAAa,OAAO;CACjC,IAAI,SAAS,iBAAiB,OAAO;CACrC,IAAI,SAAS,YAAY,OAAO;CAChC,IAAI,SAAS,QAAQ,OAAO;CAE5B,OAAO;AACT"}
|