shopkit-analytics 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -100
- package/dist/adapters/index.d.mts +2 -1
- package/dist/adapters/index.d.ts +2 -1
- package/dist/adapters/index.js +230 -64
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/index.mjs +3 -1
- package/dist/chunk-4RDPDMGW.mjs +68 -0
- package/dist/chunk-4RDPDMGW.mjs.map +1 -0
- package/dist/chunk-NC25KOAF.mjs +156 -0
- package/dist/chunk-NC25KOAF.mjs.map +1 -0
- package/dist/chunk-NGPUKV7E.mjs +46 -0
- package/dist/chunk-NGPUKV7E.mjs.map +1 -0
- package/dist/{chunk-U3UOXFS4.mjs → chunk-NJQ2MOM2.mjs} +206 -116
- package/dist/chunk-NJQ2MOM2.mjs.map +1 -0
- package/dist/chunk-NKDB4KX2.mjs +2 -0
- package/dist/chunk-NKDB4KX2.mjs.map +1 -0
- package/dist/{chunk-BNV3EVHH.mjs → chunk-QCS5UARA.mjs} +2 -2
- package/dist/events/index.js +218 -54
- package/dist/events/index.js.map +1 -1
- package/dist/events/index.mjs +9 -7
- package/dist/experiment/index.d.mts +25 -0
- package/dist/experiment/index.d.ts +25 -0
- package/dist/experiment/index.js +74 -0
- package/dist/experiment/index.js.map +1 -0
- package/dist/experiment/index.mjs +15 -0
- package/dist/experiment/index.mjs.map +1 -0
- package/dist/{index-DS9OI5Mz.d.ts → index-D_8w5bL_.d.ts} +13 -0
- package/dist/{index-Bym1_EAp.d.mts → index-th6sBtE3.d.mts} +13 -0
- package/dist/index.d.mts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +400 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +30 -7
- package/dist/index.mjs.map +1 -1
- package/dist/services/index.d.mts +51 -0
- package/dist/services/index.d.ts +51 -0
- package/dist/services/index.js +180 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/index.mjs +11 -0
- package/dist/services/index.mjs.map +1 -0
- package/dist/types-C__2IBCj.d.mts +7 -0
- package/dist/types-C__2IBCj.d.ts +7 -0
- package/dist/utils/index.d.mts +19 -0
- package/dist/utils/index.d.ts +19 -0
- package/dist/utils/index.js +93 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/index.mjs +12 -0
- package/dist/utils/index.mjs.map +1 -0
- package/package.json +19 -1
- package/templates/nextjs/README.md +206 -0
- package/templates/nextjs/api-events-route.ts +62 -0
- package/dist/chunk-U3UOXFS4.mjs.map +0 -1
- /package/dist/{chunk-BNV3EVHH.mjs.map → chunk-QCS5UARA.mjs.map} +0 -0
package/dist/adapters/index.mjs
CHANGED
|
@@ -8,7 +8,9 @@ import {
|
|
|
8
8
|
PixelAdapter,
|
|
9
9
|
PostHogAdapter,
|
|
10
10
|
ShopifyAdapter
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-NJQ2MOM2.mjs";
|
|
12
|
+
import "../chunk-NGPUKV7E.mjs";
|
|
13
|
+
import "../chunk-4RDPDMGW.mjs";
|
|
12
14
|
import "../chunk-3NR2AKE4.mjs";
|
|
13
15
|
export {
|
|
14
16
|
BaseAdapter,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/utils/event-id.ts
|
|
4
|
+
function generateEventId(eventType) {
|
|
5
|
+
const timestamp = Date.now();
|
|
6
|
+
const randomString = Math.random().toString(36).substring(2, 8);
|
|
7
|
+
return `${timestamp}_${randomString}_${eventType}`;
|
|
8
|
+
}
|
|
9
|
+
function getBrowserInfo() {
|
|
10
|
+
if (typeof window === "undefined") {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
const userAgent = navigator.userAgent;
|
|
14
|
+
const fbc = getFacebookClickId();
|
|
15
|
+
const fbp = getFacebookBrowserId();
|
|
16
|
+
return {
|
|
17
|
+
clientUserAgent: userAgent,
|
|
18
|
+
fbc,
|
|
19
|
+
fbp
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function getFacebookClickId() {
|
|
23
|
+
if (typeof window === "undefined") {
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
27
|
+
const fbclid = urlParams.get("fbclid");
|
|
28
|
+
if (fbclid) {
|
|
29
|
+
return `fb.1.${Date.now()}.${fbclid}`;
|
|
30
|
+
}
|
|
31
|
+
const cookies = document.cookie.split(";");
|
|
32
|
+
for (const cookie of cookies) {
|
|
33
|
+
const [name, value] = cookie.trim().split("=");
|
|
34
|
+
if (name === "_fbc") {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
function getFacebookBrowserId() {
|
|
41
|
+
if (typeof window === "undefined") {
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
const cookies = document.cookie.split(";");
|
|
45
|
+
for (const cookie of cookies) {
|
|
46
|
+
const [name, value] = cookie.trim().split("=");
|
|
47
|
+
if (name === "_fbp") {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
function getClientIpAddress(request) {
|
|
54
|
+
if (!request) {
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
57
|
+
const forwarded = request.headers.get("x-forwarded-for");
|
|
58
|
+
const realIp = request.headers.get("x-real-ip");
|
|
59
|
+
const cfConnectingIp = request.headers.get("cf-connecting-ip");
|
|
60
|
+
return forwarded?.split(",")[0] || realIp || cfConnectingIp || void 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
generateEventId,
|
|
65
|
+
getBrowserInfo,
|
|
66
|
+
getClientIpAddress
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=chunk-4RDPDMGW.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/event-id.ts"],"sourcesContent":["/**\n * Generate a unique event ID for deduplication\n * Format: timestamp_randomString_eventType\n */\nexport function generateEventId(eventType: string): string {\n const timestamp = Date.now();\n const randomString = Math.random().toString(36).substring(2, 8);\n return `${timestamp}_${randomString}_${eventType}`;\n}\n\n/**\n * Extract browser information for CAPI user data\n */\nexport function getBrowserInfo(): {\n clientUserAgent?: string;\n fbc?: string;\n fbp?: string;\n} {\n if (typeof window === \"undefined\") {\n return {};\n }\n\n const userAgent = navigator.userAgent;\n\n // Get Facebook click ID from URL or cookies\n const fbc = getFacebookClickId();\n const fbp = getFacebookBrowserId();\n\n return {\n clientUserAgent: userAgent,\n fbc,\n fbp,\n };\n}\n\n/**\n * Get Facebook click ID (fbc) from URL parameters or cookies\n */\nfunction getFacebookClickId(): string | undefined {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n // Check URL parameters first\n const urlParams = new URLSearchParams(window.location.search);\n const fbclid = urlParams.get(\"fbclid\");\n\n if (fbclid) {\n return `fb.1.${Date.now()}.${fbclid}`;\n }\n\n // Check cookies\n const cookies = document.cookie.split(\";\");\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split(\"=\");\n if (name === \"_fbc\") {\n return value;\n }\n }\n\n return undefined;\n}\n\n/**\n * Get Facebook browser ID (fbp) from cookies\n */\nfunction getFacebookBrowserId(): string | undefined {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n const cookies = document.cookie.split(\";\");\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split(\"=\");\n if (name === \"_fbp\") {\n return value;\n }\n }\n\n return undefined;\n}\n\n/**\n * Get client IP address (this will be handled server-side)\n */\nexport function getClientIpAddress(request?: Request): string | undefined {\n if (!request) {\n return undefined;\n }\n\n // Try different headers for IP address\n const forwarded = request.headers.get(\"x-forwarded-for\");\n const realIp = request.headers.get(\"x-real-ip\");\n const cfConnectingIp = request.headers.get(\"cf-connecting-ip\");\n\n return forwarded?.split(\",\")[0] || realIp || cfConnectingIp || undefined;\n}\n"],"mappings":";;;AAIO,SAAS,gBAAgB,WAA2B;AACzD,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,eAAe,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC;AAC9D,SAAO,GAAG,SAAS,IAAI,YAAY,IAAI,SAAS;AAClD;AAKO,SAAS,iBAId;AACA,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,YAAY,UAAU;AAG5B,QAAM,MAAM,mBAAmB;AAC/B,QAAM,MAAM,qBAAqB;AAEjC,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACF;AAKA,SAAS,qBAAyC;AAChD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,IAAI,gBAAgB,OAAO,SAAS,MAAM;AAC5D,QAAM,SAAS,UAAU,IAAI,QAAQ;AAErC,MAAI,QAAQ;AACV,WAAO,QAAQ,KAAK,IAAI,CAAC,IAAI,MAAM;AAAA,EACrC;AAGA,QAAM,UAAU,SAAS,OAAO,MAAM,GAAG;AACzC,aAAW,UAAU,SAAS;AAC5B,UAAM,CAAC,MAAM,KAAK,IAAI,OAAO,KAAK,EAAE,MAAM,GAAG;AAC7C,QAAI,SAAS,QAAQ;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,uBAA2C;AAClD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,SAAS,OAAO,MAAM,GAAG;AACzC,aAAW,UAAU,SAAS;AAC5B,UAAM,CAAC,MAAM,KAAK,IAAI,OAAO,KAAK,EAAE,MAAM,GAAG;AAC7C,QAAI,SAAS,QAAQ;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,mBAAmB,SAAuC;AACxE,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,QAAQ,QAAQ,IAAI,iBAAiB;AACvD,QAAM,SAAS,QAAQ,QAAQ,IAAI,WAAW;AAC9C,QAAM,iBAAiB,QAAQ,QAAQ,IAAI,kBAAkB;AAE7D,SAAO,WAAW,MAAM,GAAG,EAAE,CAAC,KAAK,UAAU,kBAAkB;AACjE;","names":[]}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/services/facebook-capi.ts
|
|
4
|
+
var FacebookCAPIService = class {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.baseUrl = "https://graph.facebook.com/v18.0";
|
|
7
|
+
this.config = config;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Send events to Facebook CAPI
|
|
11
|
+
*/
|
|
12
|
+
async sendEvents(events, userInfo) {
|
|
13
|
+
if (!this.config.accessToken || !this.config.pixelId) {
|
|
14
|
+
console.warn("Facebook CAPI: Missing access token or pixel ID");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const supportedEvents = events.filter(
|
|
18
|
+
(event) => this.isSupportedEvent(event.type)
|
|
19
|
+
);
|
|
20
|
+
if (supportedEvents.length === 0) {
|
|
21
|
+
console.log("Facebook CAPI: No supported events to send");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const capiEvents = supportedEvents.map(
|
|
25
|
+
(event) => this.convertToFacebookEvent(event, userInfo)
|
|
26
|
+
);
|
|
27
|
+
const payload = {
|
|
28
|
+
data: capiEvents,
|
|
29
|
+
test_event_code: this.config.testEventCode
|
|
30
|
+
};
|
|
31
|
+
try {
|
|
32
|
+
const response = await fetch(
|
|
33
|
+
`${this.baseUrl}/${this.config.pixelId}/events?access_token=${this.config.accessToken}`,
|
|
34
|
+
{
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/json"
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify(payload)
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
const errorData = await response.json();
|
|
44
|
+
console.error("Facebook CAPI Error:", errorData);
|
|
45
|
+
throw new Error(`Facebook CAPI request failed: ${response.status}`);
|
|
46
|
+
}
|
|
47
|
+
const result = await response.json();
|
|
48
|
+
console.log("Facebook CAPI: Events sent successfully", {
|
|
49
|
+
events_received: result.events_received,
|
|
50
|
+
messages: result.messages
|
|
51
|
+
});
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error("Facebook CAPI: Failed to send events", error);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if event type is supported (matches PixelAdapter implementation)
|
|
59
|
+
*/
|
|
60
|
+
isSupportedEvent(eventType) {
|
|
61
|
+
return [
|
|
62
|
+
"page_view" /* PAGE_VIEW */,
|
|
63
|
+
"product_view" /* PRODUCT_VIEW */,
|
|
64
|
+
"add_to_cart" /* ADD_TO_CART */,
|
|
65
|
+
"search" /* SEARCH */
|
|
66
|
+
].includes(eventType);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Convert internal event to Facebook CAPI event format
|
|
70
|
+
* Only handles events implemented in PixelAdapter
|
|
71
|
+
*/
|
|
72
|
+
convertToFacebookEvent(event, userInfo) {
|
|
73
|
+
const baseEvent = {
|
|
74
|
+
event_name: this.mapEventName(event.type),
|
|
75
|
+
event_time: Math.floor((event.timestamp || Date.now()) / 1e3),
|
|
76
|
+
event_id: event.eventId,
|
|
77
|
+
action_source: "website",
|
|
78
|
+
user_data: userInfo ? {
|
|
79
|
+
client_ip_address: userInfo.clientIpAddress,
|
|
80
|
+
client_user_agent: userInfo.clientUserAgent,
|
|
81
|
+
fbc: userInfo.fbc,
|
|
82
|
+
fbp: userInfo.fbp
|
|
83
|
+
} : void 0
|
|
84
|
+
};
|
|
85
|
+
switch (event.type) {
|
|
86
|
+
case "page_view" /* PAGE_VIEW */:
|
|
87
|
+
baseEvent.custom_data = {};
|
|
88
|
+
break;
|
|
89
|
+
case "product_view" /* PRODUCT_VIEW */:
|
|
90
|
+
const productEvent = event;
|
|
91
|
+
baseEvent.custom_data = {
|
|
92
|
+
content_type: "product_group",
|
|
93
|
+
content_ids: [productEvent.productId],
|
|
94
|
+
content_name: productEvent.productName,
|
|
95
|
+
content_category: productEvent.event_category,
|
|
96
|
+
value: productEvent.price,
|
|
97
|
+
currency: productEvent.currency || "INR"
|
|
98
|
+
};
|
|
99
|
+
break;
|
|
100
|
+
case "add_to_cart" /* ADD_TO_CART */:
|
|
101
|
+
const cartEvent = event;
|
|
102
|
+
baseEvent.custom_data = {
|
|
103
|
+
content_type: "product_group",
|
|
104
|
+
content_ids: [cartEvent.productId],
|
|
105
|
+
content_name: cartEvent.productName,
|
|
106
|
+
value: cartEvent.price,
|
|
107
|
+
currency: cartEvent.currency || "INR"
|
|
108
|
+
};
|
|
109
|
+
break;
|
|
110
|
+
case "search" /* SEARCH */:
|
|
111
|
+
const searchEvent = event;
|
|
112
|
+
baseEvent.custom_data = {
|
|
113
|
+
search_string: searchEvent.searchTerm,
|
|
114
|
+
content_category: "product",
|
|
115
|
+
content_ids: searchEvent.content_ids || []
|
|
116
|
+
};
|
|
117
|
+
break;
|
|
118
|
+
default:
|
|
119
|
+
baseEvent.custom_data = {};
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
return baseEvent;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Map internal event types to Facebook event names (matching PixelAdapter)
|
|
126
|
+
*/
|
|
127
|
+
mapEventName(eventType) {
|
|
128
|
+
const eventMap = {
|
|
129
|
+
["page_view" /* PAGE_VIEW */]: "PageView",
|
|
130
|
+
["product_view" /* PRODUCT_VIEW */]: "ViewContent",
|
|
131
|
+
["add_to_cart" /* ADD_TO_CART */]: "AddToCart",
|
|
132
|
+
["search" /* SEARCH */]: "Search"
|
|
133
|
+
};
|
|
134
|
+
return eventMap[eventType] || "CustomEvent";
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
function createFacebookCAPIService(config) {
|
|
138
|
+
const accessToken = config?.accessToken || process.env.FACEBOOK_CAPI_ACCESS_TOKEN;
|
|
139
|
+
const pixelId = config?.pixelId || process.env.NEXT_PUBLIC_PIXEL_ID;
|
|
140
|
+
const testEventCode = config?.testEventCode || process.env.FACEBOOK_TEST_EVENT_CODE;
|
|
141
|
+
if (!accessToken || !pixelId) {
|
|
142
|
+
console.warn("Facebook CAPI: Missing access token or pixel ID");
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
return new FacebookCAPIService({
|
|
146
|
+
accessToken,
|
|
147
|
+
pixelId,
|
|
148
|
+
testEventCode
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export {
|
|
153
|
+
FacebookCAPIService,
|
|
154
|
+
createFacebookCAPIService
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=chunk-NC25KOAF.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/services/facebook-capi.ts"],"sourcesContent":["import {\n TEvent,\n EventType,\n type IAddToCartEvent,\n type IProductViewEvent,\n type ISearchEvent,\n} from \"../types\";\n\n/**\n * Facebook CAPI Configuration\n */\nexport interface FacebookCAPIConfig {\n accessToken: string;\n pixelId: string;\n testEventCode?: string;\n}\n\n/**\n * Facebook CAPI Event Data Structure\n */\ninterface FacebookCAPIEvent {\n event_name: string;\n event_time: number;\n event_id?: string;\n user_data?: {\n client_ip_address?: string;\n client_user_agent?: string;\n fbc?: string;\n fbp?: string;\n };\n custom_data?: {\n currency?: string;\n value?: number;\n content_ids?: string[];\n content_type?: string;\n content_name?: string;\n content_category?: string;\n search_string?: string;\n [key: string]: any;\n };\n action_source: string;\n}\n\n/**\n * Facebook CAPI Service for server-side event tracking\n * Only handles events that are implemented in PixelAdapter\n */\nexport class FacebookCAPIService {\n private config: FacebookCAPIConfig;\n private baseUrl = \"https://graph.facebook.com/v18.0\";\n\n constructor(config: FacebookCAPIConfig) {\n this.config = config;\n }\n\n /**\n * Send events to Facebook CAPI\n */\n public async sendEvents(\n events: TEvent[],\n userInfo?: {\n clientIpAddress?: string;\n clientUserAgent?: string;\n fbc?: string;\n fbp?: string;\n }\n ): Promise<void> {\n if (!this.config.accessToken || !this.config.pixelId) {\n console.warn(\"Facebook CAPI: Missing access token or pixel ID\");\n return;\n }\n\n // Filter events to only supported ones\n const supportedEvents = events.filter((event) =>\n this.isSupportedEvent(event.type)\n );\n\n if (supportedEvents.length === 0) {\n console.log(\"Facebook CAPI: No supported events to send\");\n return;\n }\n\n const capiEvents = supportedEvents.map((event) =>\n this.convertToFacebookEvent(event, userInfo)\n );\n\n const payload = {\n data: capiEvents,\n test_event_code: this.config.testEventCode,\n };\n\n try {\n const response = await fetch(\n `${this.baseUrl}/${this.config.pixelId}/events?access_token=${this.config.accessToken}`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n }\n );\n\n if (!response.ok) {\n const errorData = await response.json();\n console.error(\"Facebook CAPI Error:\", errorData);\n throw new Error(`Facebook CAPI request failed: ${response.status}`);\n }\n\n const result = await response.json();\n console.log(\"Facebook CAPI: Events sent successfully\", {\n events_received: result.events_received,\n messages: result.messages,\n });\n } catch (error) {\n console.error(\"Facebook CAPI: Failed to send events\", error);\n throw error;\n }\n }\n\n /**\n * Check if event type is supported (matches PixelAdapter implementation)\n */\n private isSupportedEvent(eventType: EventType): boolean {\n return [\n EventType.PAGE_VIEW,\n EventType.PRODUCT_VIEW,\n EventType.ADD_TO_CART,\n EventType.SEARCH,\n ].includes(eventType);\n }\n\n /**\n * Convert internal event to Facebook CAPI event format\n * Only handles events implemented in PixelAdapter\n */\n private convertToFacebookEvent(\n event: TEvent,\n userInfo?: {\n clientIpAddress?: string;\n clientUserAgent?: string;\n fbc?: string;\n fbp?: string;\n }\n ): FacebookCAPIEvent {\n const baseEvent: FacebookCAPIEvent = {\n event_name: this.mapEventName(event.type),\n event_time: Math.floor((event.timestamp || Date.now()) / 1000),\n event_id: event.eventId,\n action_source: \"website\",\n user_data: userInfo\n ? {\n client_ip_address: userInfo.clientIpAddress,\n client_user_agent: userInfo.clientUserAgent,\n fbc: userInfo.fbc,\n fbp: userInfo.fbp,\n }\n : undefined,\n };\n\n // Add custom data based on event type (matching PixelAdapter logic)\n switch (event.type) {\n case EventType.PAGE_VIEW:\n baseEvent.custom_data = {};\n break;\n\n case EventType.PRODUCT_VIEW:\n const productEvent = event as IProductViewEvent;\n baseEvent.custom_data = {\n content_type: \"product_group\",\n content_ids: [productEvent.productId],\n content_name: productEvent.productName,\n content_category: productEvent.event_category,\n value: productEvent.price,\n currency: productEvent.currency || \"INR\",\n };\n break;\n\n case EventType.ADD_TO_CART:\n const cartEvent = event as IAddToCartEvent;\n baseEvent.custom_data = {\n content_type: \"product_group\",\n content_ids: [cartEvent.productId],\n content_name: cartEvent.productName,\n value: cartEvent.price,\n currency: cartEvent.currency || \"INR\",\n };\n break;\n\n case EventType.SEARCH:\n const searchEvent = event as ISearchEvent;\n baseEvent.custom_data = {\n search_string: searchEvent.searchTerm,\n content_category: \"product\",\n content_ids: searchEvent.content_ids || [],\n };\n break;\n\n default:\n baseEvent.custom_data = {};\n break;\n }\n\n return baseEvent;\n }\n\n /**\n * Map internal event types to Facebook event names (matching PixelAdapter)\n */\n private mapEventName(eventType: EventType): string {\n const eventMap: Record<EventType, string> = {\n [EventType.PAGE_VIEW]: \"PageView\",\n [EventType.PRODUCT_VIEW]: \"ViewContent\",\n [EventType.ADD_TO_CART]: \"AddToCart\",\n [EventType.SEARCH]: \"Search\",\n } as Record<EventType, string>;\n\n return eventMap[eventType] || \"CustomEvent\";\n }\n}\n\n/**\n * Create Facebook CAPI service instance\n */\nexport function createFacebookCAPIService(config?: {\n accessToken: string;\n pixelId: string;\n testEventCode?: string;\n}): FacebookCAPIService | null {\n const accessToken =\n config?.accessToken || process.env.FACEBOOK_CAPI_ACCESS_TOKEN;\n const pixelId = config?.pixelId || process.env.NEXT_PUBLIC_PIXEL_ID;\n const testEventCode =\n config?.testEventCode || process.env.FACEBOOK_TEST_EVENT_CODE;\n\n if (!accessToken || !pixelId) {\n console.warn(\"Facebook CAPI: Missing access token or pixel ID\");\n return null;\n }\n\n return new FacebookCAPIService({\n accessToken,\n pixelId,\n testEventCode,\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/experiment/constants.ts
|
|
4
|
+
var PRIMA_EXPERIMENT_COOKIES = {
|
|
5
|
+
HOME: "_prima_pr_ab_home",
|
|
6
|
+
COLLECTION: "_prima_pr_ab_collection",
|
|
7
|
+
PRODUCT: "_prima_pr_ab_product"
|
|
8
|
+
};
|
|
9
|
+
var PRIMA_EXPERIMENT_COOKIE_NAMES = Object.values(
|
|
10
|
+
PRIMA_EXPERIMENT_COOKIES
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
// src/experiment/experiment-tracker.ts
|
|
14
|
+
function getCookie(name) {
|
|
15
|
+
if (typeof document === "undefined") return null;
|
|
16
|
+
const value = `; ${document.cookie}`;
|
|
17
|
+
const parts = value.split(`; ${name}=`);
|
|
18
|
+
if (parts.length === 2) {
|
|
19
|
+
return parts.pop()?.split(";").shift() || null;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
function getExperimentParams() {
|
|
24
|
+
return {
|
|
25
|
+
[PRIMA_EXPERIMENT_COOKIES.HOME]: getCookie(PRIMA_EXPERIMENT_COOKIES.HOME),
|
|
26
|
+
[PRIMA_EXPERIMENT_COOKIES.COLLECTION]: getCookie(
|
|
27
|
+
PRIMA_EXPERIMENT_COOKIES.COLLECTION
|
|
28
|
+
),
|
|
29
|
+
[PRIMA_EXPERIMENT_COOKIES.PRODUCT]: getCookie(
|
|
30
|
+
PRIMA_EXPERIMENT_COOKIES.PRODUCT
|
|
31
|
+
)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function hasExperimentData() {
|
|
35
|
+
return PRIMA_EXPERIMENT_COOKIE_NAMES.some(
|
|
36
|
+
(cookieName) => getCookie(cookieName) !== null
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
PRIMA_EXPERIMENT_COOKIES,
|
|
42
|
+
PRIMA_EXPERIMENT_COOKIE_NAMES,
|
|
43
|
+
getExperimentParams,
|
|
44
|
+
hasExperimentData
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=chunk-NGPUKV7E.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/experiment/constants.ts","../src/experiment/experiment-tracker.ts"],"sourcesContent":["/**\n * Prima PR A/B test experiment cookie names\n */\nexport const PRIMA_EXPERIMENT_COOKIES = {\n HOME: \"_prima_pr_ab_home\",\n COLLECTION: \"_prima_pr_ab_collection\",\n PRODUCT: \"_prima_pr_ab_product\",\n} as const;\n\n/**\n * Array of all Prima experiment cookie names for iteration\n */\nexport const PRIMA_EXPERIMENT_COOKIE_NAMES = Object.values(\n PRIMA_EXPERIMENT_COOKIES\n);\n","import type { ExperimentData } from \"./types\";\nimport {\n PRIMA_EXPERIMENT_COOKIES,\n PRIMA_EXPERIMENT_COOKIE_NAMES,\n} from \"./constants\";\n\n/**\n * Get cookie value by name\n */\nfunction getCookie(name: string): string | null {\n if (typeof document === \"undefined\") return null;\n\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n if (parts.length === 2) {\n return parts.pop()?.split(\";\").shift() || null;\n }\n return null;\n}\n\n/**\n * Get experiment parameters from cookies\n */\nexport function getExperimentParams(): ExperimentData {\n return {\n [PRIMA_EXPERIMENT_COOKIES.HOME]: getCookie(PRIMA_EXPERIMENT_COOKIES.HOME),\n [PRIMA_EXPERIMENT_COOKIES.COLLECTION]: getCookie(\n PRIMA_EXPERIMENT_COOKIES.COLLECTION\n ),\n [PRIMA_EXPERIMENT_COOKIES.PRODUCT]: getCookie(\n PRIMA_EXPERIMENT_COOKIES.PRODUCT\n ),\n };\n}\n\n/**\n * Check if any experiment data exists\n */\nexport function hasExperimentData(): boolean {\n return PRIMA_EXPERIMENT_COOKIE_NAMES.some(\n (cookieName) => getCookie(cookieName) !== null\n );\n}\n"],"mappings":";;;AAGO,IAAM,2BAA2B;AAAA,EACtC,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,SAAS;AACX;AAKO,IAAM,gCAAgC,OAAO;AAAA,EAClD;AACF;;;ACLA,SAAS,UAAU,MAA6B;AAC9C,MAAI,OAAO,aAAa,YAAa,QAAO;AAE5C,QAAM,QAAQ,KAAK,SAAS,MAAM;AAClC,QAAM,QAAQ,MAAM,MAAM,KAAK,IAAI,GAAG;AACtC,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,MAAM,IAAI,GAAG,MAAM,GAAG,EAAE,MAAM,KAAK;AAAA,EAC5C;AACA,SAAO;AACT;AAKO,SAAS,sBAAsC;AACpD,SAAO;AAAA,IACL,CAAC,yBAAyB,IAAI,GAAG,UAAU,yBAAyB,IAAI;AAAA,IACxE,CAAC,yBAAyB,UAAU,GAAG;AAAA,MACrC,yBAAyB;AAAA,IAC3B;AAAA,IACA,CAAC,yBAAyB,OAAO,GAAG;AAAA,MAClC,yBAAyB;AAAA,IAC3B;AAAA,EACF;AACF;AAKO,SAAS,oBAA6B;AAC3C,SAAO,8BAA8B;AAAA,IACnC,CAAC,eAAe,UAAU,UAAU,MAAM;AAAA,EAC5C;AACF;","names":[]}
|