@walkeros/server-destination-criteo 3.4.0-next-1776749829492

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.
@@ -0,0 +1,120 @@
1
+ import { Mapping as Mapping$1, Destination as Destination$1 } from '@walkeros/core';
2
+ import { DestinationServer, sendServer } from '@walkeros/server-core';
3
+
4
+ interface Settings {
5
+ /** Criteo Partner ID (numeric string, provided by Criteo) */
6
+ partnerId: string;
7
+ /** Caller ID for user mapping (provided by Criteo) */
8
+ callerId: string;
9
+ /** Site type: `d` (desktop), `m` (mobile web), `t` (tablet). Default `d`. */
10
+ siteType?: SiteType;
11
+ /** ISO 3166-1 alpha-2 country code */
12
+ country?: string;
13
+ /** 2-letter language code */
14
+ language?: string;
15
+ /** API endpoint override (default: https://widget.criteo.com/m/event?version=s2s_v0) */
16
+ url?: string;
17
+ /** Mapping for identity fields (mapped_user_id, email, retailer_visitor_id) */
18
+ user_data?: Mapping$1.Map;
19
+ }
20
+ type InitSettings = Partial<Settings>;
21
+ interface Mapping {
22
+ }
23
+ interface Env extends DestinationServer.Env {
24
+ sendServer?: typeof sendServer;
25
+ }
26
+ type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings>;
27
+ interface Destination extends DestinationServer.Destination<Types> {
28
+ init: DestinationServer.InitFn<Types>;
29
+ }
30
+ type Config = {
31
+ settings: Settings;
32
+ } & DestinationServer.Config<Types>;
33
+ type InitFn = DestinationServer.InitFn<Types>;
34
+ type PushFn = DestinationServer.PushFn<Types>;
35
+ type PartialConfig = DestinationServer.PartialConfig<Types>;
36
+ type PushEvents = DestinationServer.PushEvents<Mapping>;
37
+ type Rule = Mapping$1.Rule<Mapping>;
38
+ type Rules = Mapping$1.Rules<Rule>;
39
+ /** Site type: desktop / mobile web / tablet */
40
+ type SiteType = 'd' | 'm' | 't';
41
+ /**
42
+ * Criteo Events API (S2S v0)
43
+ * https://guides.criteotilt.com/events-api/
44
+ */
45
+ interface CriteoRequestBody {
46
+ /** Integration version identifier (e.g. `walkeros_criteo_1.0.0`) */
47
+ version: string;
48
+ site_type?: SiteType;
49
+ /** Criteo Partner ID */
50
+ account: string;
51
+ id: CriteoIdentity;
52
+ ip?: string;
53
+ full_url?: string;
54
+ previous_url?: string;
55
+ useragent?: string;
56
+ retailer_visitor_id?: string;
57
+ country?: string;
58
+ language?: string;
59
+ events: CriteoEvent[];
60
+ }
61
+ interface CriteoIdentity {
62
+ /** GUM ID */
63
+ mapped_user_id?: string;
64
+ /** Caller ID (provided by Criteo) */
65
+ mapping_key: string;
66
+ email?: CriteoEmailHashes;
67
+ }
68
+ interface CriteoEmailHashes {
69
+ raw?: string;
70
+ md5?: string;
71
+ sha256?: string;
72
+ sha256_md5?: string;
73
+ }
74
+ interface CriteoEvent {
75
+ event: CriteoEventName;
76
+ /** ISO 8601 timestamp */
77
+ timestamp?: string;
78
+ /** Transaction ID or event-level ID */
79
+ id?: string;
80
+ item?: CriteoItem[];
81
+ deduplication_page_view_id?: string;
82
+ }
83
+ interface CriteoItem {
84
+ id: string;
85
+ price?: number;
86
+ quantity?: number;
87
+ }
88
+ /**
89
+ * Standard Criteo Events API event names.
90
+ * Custom event names are also accepted as plain strings.
91
+ */
92
+ type CriteoEventName = 'viewHome' | 'viewPage' | 'viewItem' | 'viewList' | 'addToCart' | 'viewBasket' | 'beginCheckout' | 'trackTransaction' | 'addPaymentInfo' | 'login' | (string & {});
93
+
94
+ type index_Config = Config;
95
+ type index_CriteoEmailHashes = CriteoEmailHashes;
96
+ type index_CriteoEvent = CriteoEvent;
97
+ type index_CriteoEventName = CriteoEventName;
98
+ type index_CriteoIdentity = CriteoIdentity;
99
+ type index_CriteoItem = CriteoItem;
100
+ type index_CriteoRequestBody = CriteoRequestBody;
101
+ type index_Destination = Destination;
102
+ type index_Env = Env;
103
+ type index_InitFn = InitFn;
104
+ type index_InitSettings = InitSettings;
105
+ type index_Mapping = Mapping;
106
+ type index_PartialConfig = PartialConfig;
107
+ type index_PushEvents = PushEvents;
108
+ type index_PushFn = PushFn;
109
+ type index_Rule = Rule;
110
+ type index_Rules = Rules;
111
+ type index_Settings = Settings;
112
+ type index_SiteType = SiteType;
113
+ type index_Types = Types;
114
+ declare namespace index {
115
+ export type { index_Config as Config, index_CriteoEmailHashes as CriteoEmailHashes, index_CriteoEvent as CriteoEvent, index_CriteoEventName as CriteoEventName, index_CriteoIdentity as CriteoIdentity, index_CriteoItem as CriteoItem, index_CriteoRequestBody as CriteoRequestBody, index_Destination as Destination, index_Env as Env, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PushEvents as PushEvents, index_PushFn as PushFn, index_Rule as Rule, index_Rules as Rules, index_Settings as Settings, index_SiteType as SiteType, index_Types as Types };
116
+ }
117
+
118
+ declare const destinationCriteo: Destination;
119
+
120
+ export { index as DestinationCriteo, destinationCriteo as default, destinationCriteo };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationCriteo:()=>types_exports,default:()=>index_default,destinationCriteo:()=>destinationCriteo}),module.exports=(mod=index_exports,((to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to})(__defProp({},"__esModule",{value:!0}),mod));var DEFAULT_URL="https://widget.criteo.com/m/event?version=s2s_v0";var import_core=require("@walkeros/core"),import_server_core2=require("@walkeros/server-core"),import_crypto=require("crypto"),import_server_core=require("@walkeros/server-core");var sha256HexPattern=/^[a-f0-9]{64}$/,md5HexPattern=/^[a-f0-9]{32}$/;async function hashEmail(email){const normalized=email.toLowerCase().trim();if(!normalized)return{};if(value=normalized,sha256HexPattern.test(value))return{sha256:normalized};var value;if(function(value){return md5HexPattern.test(value)}(normalized)){return{md5:normalized,sha256_md5:await(0,import_server_core.getHashServer)(normalized)}}const md5=function(value){return(0,import_crypto.createHash)("md5").update(value.toLowerCase().trim()).digest("hex")}(normalized);return{md5:md5,sha256:await(0,import_server_core.getHashServer)(normalized),sha256_md5:await(0,import_server_core.getHashServer)(md5)}}function toStringOrUndef(value){if(null!=value)return"string"==typeof value?value:"number"==typeof value||"boolean"==typeof value?String(value):void 0}function toNumberOrUndef(value){if("number"==typeof value&&Number.isFinite(value))return value;if("string"==typeof value&&""!==value){const n=Number(value);if(Number.isFinite(n))return n}}var push=async function(event,{config:config,rule:rule,data:data,env:env,logger:logger}){var _a,_b;const{partnerId:partnerId,callerId:callerId,siteType:siteType="d",country:country,language:language,url:url=DEFAULT_URL,user_data:user_data}=config.settings,eventData=(0,import_core.isObject)(data)?data:{},userDataCustom=user_data?await(0,import_core.getMappingValue)(event,{map:user_data}):{},resolvedUserData=(0,import_core.isObject)(userDataCustom)?userDataCustom:{},identity={mapping_key:callerId},mappedUserId=toStringOrUndef(resolvedUserData.mapped_user_id);mappedUserId&&(identity.mapped_user_id=mappedUserId);const rawEmail=toStringOrUndef(resolvedUserData.email);if(rawEmail){const hashes=await hashEmail(rawEmail);Object.keys(hashes).length>0&&(identity.email=hashes)}const criteoEvent={event:"string"==typeof(null==rule?void 0:rule.name)&&rule.name||event.name,timestamp:(ts=event.timestamp,"number"==typeof ts&&Number.isFinite(ts)?new Date(ts).toISOString():"string"==typeof ts&&ts?ts:(new Date).toISOString())};var ts;const eventId=toStringOrUndef(eventData.id);eventId&&(criteoEvent.id=eventId);const items=function(raw){if(!Array.isArray(raw))return;const items=[];for(const entry of raw){if(!(0,import_core.isObject)(entry))continue;const id=toStringOrUndef(entry.id);if(!id)continue;const item={id:id},price=toNumberOrUndef(entry.price);void 0!==price&&(item.price=price);const quantity=toNumberOrUndef(entry.quantity);void 0!==quantity&&(item.quantity=quantity),items.push(item)}return items.length?items:void 0}(eventData.item);items&&(criteoEvent.item=items);const dedupId=toStringOrUndef(eventData.deduplication_page_view_id);dedupId&&(criteoEvent.deduplication_page_view_id=dedupId);const body={version:"walkeros_criteo_1.0.0",site_type:siteType,account:partnerId,id:identity,events:[criteoEvent]};(null==(_a=event.source)?void 0:_a.id)&&(body.full_url=event.source.id),(null==(_b=event.source)?void 0:_b.previous_id)&&(body.previous_url=event.source.previous_id);const retailerVisitorId=toStringOrUndef(resolvedUserData.retailer_visitor_id);retailerVisitorId&&(body.retailer_visitor_id=retailerVisitorId);const ip=toStringOrUndef(resolvedUserData.ip);ip&&(body.ip=ip);const useragent=toStringOrUndef(resolvedUserData.useragent);useragent&&(body.useragent=useragent),country&&(body.country=country),language&&(body.language=language),logger.debug("Calling Criteo Events API",{url:url,method:"POST",eventName:criteoEvent.event,eventId:criteoEvent.id});const sendServerFn=(null==env?void 0:env.sendServer)||import_server_core2.sendServer,result=await sendServerFn(url,JSON.stringify(body));logger.debug("Criteo API response",{ok:!(0,import_core.isObject)(result)||result.ok}),(0,import_core.isObject)(result)&&!1===result.ok&&logger.throw(`Criteo API error: ${JSON.stringify(result)}`)},types_exports={},destinationCriteo={type:"criteo",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{partnerId:partnerId,callerId:callerId}=settings;partnerId||logger.throw("Config settings partnerId missing"),callerId||logger.throw("Config settings callerId missing");const settingsConfig={siteType:"d",url:DEFAULT_URL,...settings,partnerId:partnerId,callerId:callerId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await push(event,context)},index_default=destinationCriteo;//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/hash.ts","../src/types/index.ts"],"sourcesContent":["import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationCriteo from './types';\n\nexport const destinationCriteo: Destination = {\n type: 'criteo',\n\n config: {},\n\n async init({ config: partialConfig, logger }) {\n const config = getConfig(partialConfig, logger);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationCriteo;\n","import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport const DEFAULT_URL = 'https://widget.criteo.com/m/event?version=s2s_v0';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { partnerId, callerId } = settings;\n\n if (!partnerId) logger.throw('Config settings partnerId missing');\n if (!callerId) logger.throw('Config settings callerId missing');\n\n const settingsConfig: Settings = {\n siteType: 'd',\n url: DEFAULT_URL,\n ...settings,\n partnerId,\n callerId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n CriteoEvent,\n CriteoIdentity,\n CriteoItem,\n CriteoRequestBody,\n Env,\n PushFn,\n Settings,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEmail } from './hash';\nimport { DEFAULT_URL } from './config';\n\nconst INTEGRATION_VERSION = 'walkeros_criteo_1.0.0';\n\nfunction toStringOrUndef(value: unknown): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value);\n return undefined;\n}\n\nfunction toNumberOrUndef(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value !== '') {\n const n = Number(value);\n if (Number.isFinite(n)) return n;\n }\n return undefined;\n}\n\nfunction toIsoTimestamp(ts: unknown): string {\n if (typeof ts === 'number' && Number.isFinite(ts)) {\n return new Date(ts).toISOString();\n }\n if (typeof ts === 'string' && ts) return ts;\n return new Date().toISOString();\n}\n\nfunction toItems(raw: unknown): CriteoItem[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const items: CriteoItem[] = [];\n for (const entry of raw) {\n if (!isObject(entry)) continue;\n const id = toStringOrUndef(entry.id);\n if (!id) continue;\n const item: CriteoItem = { id };\n const price = toNumberOrUndef(entry.price);\n if (price !== undefined) item.price = price;\n const quantity = toNumberOrUndef(entry.quantity);\n if (quantity !== undefined) item.quantity = quantity;\n items.push(item);\n }\n return items.length ? items : undefined;\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, env, logger },\n) {\n const {\n partnerId,\n callerId,\n siteType = 'd',\n country,\n language,\n url = DEFAULT_URL,\n user_data,\n } = config.settings as Settings;\n\n const eventData = isObject(data) ? data : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data })\n : {};\n const resolvedUserData = isObject(userDataCustom) ? userDataCustom : {};\n\n // Build identity block\n const identity: CriteoIdentity = { mapping_key: callerId };\n\n const mappedUserId = toStringOrUndef(resolvedUserData.mapped_user_id);\n if (mappedUserId) identity.mapped_user_id = mappedUserId;\n\n const rawEmail = toStringOrUndef(resolvedUserData.email);\n if (rawEmail) {\n const hashes = await hashEmail(rawEmail);\n if (Object.keys(hashes).length > 0) identity.email = hashes;\n }\n\n // Build event object\n const criteoEventName =\n (typeof rule?.name === 'string' && rule.name) || event.name;\n\n const criteoEvent: CriteoEvent = {\n event: criteoEventName,\n timestamp: toIsoTimestamp(event.timestamp),\n };\n\n const eventId = toStringOrUndef(eventData.id);\n if (eventId) criteoEvent.id = eventId;\n\n const items = toItems(eventData.item);\n if (items) criteoEvent.item = items;\n\n const dedupId = toStringOrUndef(eventData.deduplication_page_view_id);\n if (dedupId) criteoEvent.deduplication_page_view_id = dedupId;\n\n // Build request body\n const body: CriteoRequestBody = {\n version: INTEGRATION_VERSION,\n site_type: siteType,\n account: partnerId,\n id: identity,\n events: [criteoEvent],\n };\n\n if (event.source?.id) body.full_url = event.source.id;\n if (event.source?.previous_id) body.previous_url = event.source.previous_id;\n\n const retailerVisitorId = toStringOrUndef(\n resolvedUserData.retailer_visitor_id,\n );\n if (retailerVisitorId) body.retailer_visitor_id = retailerVisitorId;\n\n const ip = toStringOrUndef(resolvedUserData.ip);\n if (ip) body.ip = ip;\n\n const useragent = toStringOrUndef(resolvedUserData.useragent);\n if (useragent) body.useragent = useragent;\n\n if (country) body.country = country;\n if (language) body.language = language;\n\n logger.debug('Calling Criteo Events API', {\n url,\n method: 'POST',\n eventName: criteoEvent.event,\n eventId: criteoEvent.id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(url, JSON.stringify(body));\n\n logger.debug('Criteo API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Criteo API error: ${JSON.stringify(result)}`);\n }\n};\n","import { createHash } from 'crypto';\nimport { getHashServer } from '@walkeros/server-core';\nimport type { CriteoEmailHashes } from './types';\n\n/**\n * Criteo Events API expects email in three hashed forms:\n * - md5: MD5 of lowercased/trimmed email\n * - sha256: SHA-256 of lowercased/trimmed email\n * - sha256_md5: SHA-256 of the MD5 hash (hex string)\n *\n * https://guides.criteotilt.com/events-api/\n */\n\n/** MD5 hex digest of the lowercased/trimmed input */\nexport function hashMD5(value: string): string {\n return createHash('md5').update(value.toLowerCase().trim()).digest('hex');\n}\n\nconst sha256HexPattern = /^[a-f0-9]{64}$/;\nconst md5HexPattern = /^[a-f0-9]{32}$/;\n\nfunction isSha256Hex(value: string): boolean {\n return sha256HexPattern.test(value);\n}\n\nfunction isMd5Hex(value: string): boolean {\n return md5HexPattern.test(value);\n}\n\n/**\n * Hash an email address into Criteo's three expected forms.\n * If the input already looks like a SHA-256 hex string, it is not re-hashed.\n * If the input looks like an MD5 hex string, it is used directly as md5.\n */\nexport async function hashEmail(email: string): Promise<CriteoEmailHashes> {\n const normalized = email.toLowerCase().trim();\n if (!normalized) return {};\n\n // Already SHA-256 hashed — can't derive md5 from it, only pass through.\n if (isSha256Hex(normalized)) {\n return { sha256: normalized };\n }\n\n // Already MD5 hashed — derive sha256_md5 from it, can't derive sha256.\n if (isMd5Hex(normalized)) {\n const sha256_md5 = await getHashServer(normalized);\n return { md5: normalized, sha256_md5 };\n }\n\n const md5 = hashMD5(normalized);\n const sha256 = await getHashServer(normalized);\n const sha256_md5 = await getHashServer(md5);\n return { md5, sha256, sha256_md5 };\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n /** Criteo Partner ID (numeric string, provided by Criteo) */\n partnerId: string;\n /** Caller ID for user mapping (provided by Criteo) */\n callerId: string;\n /** Site type: `d` (desktop), `m` (mobile web), `t` (tablet). Default `d`. */\n siteType?: SiteType;\n /** ISO 3166-1 alpha-2 country code */\n country?: string;\n /** 2-letter language code */\n language?: string;\n /** API endpoint override (default: https://widget.criteo.com/m/event?version=s2s_v0) */\n url?: string;\n /** Mapping for identity fields (mapped_user_id, email, retailer_visitor_id) */\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n sendServer?: typeof sendServer;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n/** Site type: desktop / mobile web / tablet */\nexport type SiteType = 'd' | 'm' | 't';\n\n/**\n * Criteo Events API (S2S v0)\n * https://guides.criteotilt.com/events-api/\n */\nexport interface CriteoRequestBody {\n /** Integration version identifier (e.g. `walkeros_criteo_1.0.0`) */\n version: string;\n site_type?: SiteType;\n /** Criteo Partner ID */\n account: string;\n id: CriteoIdentity;\n ip?: string;\n full_url?: string;\n previous_url?: string;\n useragent?: string;\n retailer_visitor_id?: string;\n country?: string;\n language?: string;\n events: CriteoEvent[];\n}\n\nexport interface CriteoIdentity {\n /** GUM ID */\n mapped_user_id?: string;\n /** Caller ID (provided by Criteo) */\n mapping_key: string;\n email?: CriteoEmailHashes;\n}\n\nexport interface CriteoEmailHashes {\n raw?: string;\n md5?: string;\n sha256?: string;\n sha256_md5?: string;\n}\n\nexport interface CriteoEvent {\n event: CriteoEventName;\n /** ISO 8601 timestamp */\n timestamp?: string;\n /** Transaction ID or event-level ID */\n id?: string;\n item?: CriteoItem[];\n deduplication_page_view_id?: string;\n}\n\nexport interface CriteoItem {\n id: string;\n price?: number;\n quantity?: number;\n}\n\n/**\n * Standard Criteo Events API event names.\n * Custom event names are also accepted as plain strings.\n */\nexport type CriteoEventName =\n | 'viewHome'\n | 'viewPage'\n | 'viewItem'\n | 'viewList'\n | 'addToCart'\n | 'viewBasket'\n | 'beginCheckout'\n | 'trackTransaction'\n | 'addPaymentInfo'\n | 'login'\n | (string & {});\n"],"mappings":"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","names":["import_server_core","sha256_md5"]}
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ var DEFAULT_URL="https://widget.criteo.com/m/event?version=s2s_v0";import{getMappingValue,isObject}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{createHash}from"crypto";import{getHashServer}from"@walkeros/server-core";var sha256HexPattern=/^[a-f0-9]{64}$/,md5HexPattern=/^[a-f0-9]{32}$/;async function hashEmail(email){const normalized=email.toLowerCase().trim();if(!normalized)return{};if(value=normalized,sha256HexPattern.test(value))return{sha256:normalized};var value;if(function(value){return md5HexPattern.test(value)}(normalized)){return{md5:normalized,sha256_md5:await getHashServer(normalized)}}const md5=function(value){return createHash("md5").update(value.toLowerCase().trim()).digest("hex")}(normalized);return{md5:md5,sha256:await getHashServer(normalized),sha256_md5:await getHashServer(md5)}}function toStringOrUndef(value){if(null!=value)return"string"==typeof value?value:"number"==typeof value||"boolean"==typeof value?String(value):void 0}function toNumberOrUndef(value){if("number"==typeof value&&Number.isFinite(value))return value;if("string"==typeof value&&""!==value){const n=Number(value);if(Number.isFinite(n))return n}}var push=async function(event,{config:config,rule:rule,data:data,env:env,logger:logger}){var _a,_b;const{partnerId:partnerId,callerId:callerId,siteType:siteType="d",country:country,language:language,url:url=DEFAULT_URL,user_data:user_data}=config.settings,eventData=isObject(data)?data:{},userDataCustom=user_data?await getMappingValue(event,{map:user_data}):{},resolvedUserData=isObject(userDataCustom)?userDataCustom:{},identity={mapping_key:callerId},mappedUserId=toStringOrUndef(resolvedUserData.mapped_user_id);mappedUserId&&(identity.mapped_user_id=mappedUserId);const rawEmail=toStringOrUndef(resolvedUserData.email);if(rawEmail){const hashes=await hashEmail(rawEmail);Object.keys(hashes).length>0&&(identity.email=hashes)}const criteoEvent={event:"string"==typeof(null==rule?void 0:rule.name)&&rule.name||event.name,timestamp:(ts=event.timestamp,"number"==typeof ts&&Number.isFinite(ts)?new Date(ts).toISOString():"string"==typeof ts&&ts?ts:(new Date).toISOString())};var ts;const eventId=toStringOrUndef(eventData.id);eventId&&(criteoEvent.id=eventId);const items=function(raw){if(!Array.isArray(raw))return;const items=[];for(const entry of raw){if(!isObject(entry))continue;const id=toStringOrUndef(entry.id);if(!id)continue;const item={id:id},price=toNumberOrUndef(entry.price);void 0!==price&&(item.price=price);const quantity=toNumberOrUndef(entry.quantity);void 0!==quantity&&(item.quantity=quantity),items.push(item)}return items.length?items:void 0}(eventData.item);items&&(criteoEvent.item=items);const dedupId=toStringOrUndef(eventData.deduplication_page_view_id);dedupId&&(criteoEvent.deduplication_page_view_id=dedupId);const body={version:"walkeros_criteo_1.0.0",site_type:siteType,account:partnerId,id:identity,events:[criteoEvent]};(null==(_a=event.source)?void 0:_a.id)&&(body.full_url=event.source.id),(null==(_b=event.source)?void 0:_b.previous_id)&&(body.previous_url=event.source.previous_id);const retailerVisitorId=toStringOrUndef(resolvedUserData.retailer_visitor_id);retailerVisitorId&&(body.retailer_visitor_id=retailerVisitorId);const ip=toStringOrUndef(resolvedUserData.ip);ip&&(body.ip=ip);const useragent=toStringOrUndef(resolvedUserData.useragent);useragent&&(body.useragent=useragent),country&&(body.country=country),language&&(body.language=language),logger.debug("Calling Criteo Events API",{url:url,method:"POST",eventName:criteoEvent.event,eventId:criteoEvent.id});const sendServerFn=(null==env?void 0:env.sendServer)||sendServer,result=await sendServerFn(url,JSON.stringify(body));logger.debug("Criteo API response",{ok:!isObject(result)||result.ok}),isObject(result)&&!1===result.ok&&logger.throw(`Criteo API error: ${JSON.stringify(result)}`)},types_exports={},destinationCriteo={type:"criteo",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{partnerId:partnerId,callerId:callerId}=settings;partnerId||logger.throw("Config settings partnerId missing"),callerId||logger.throw("Config settings callerId missing");const settingsConfig={siteType:"d",url:DEFAULT_URL,...settings,partnerId:partnerId,callerId:callerId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await push(event,context)},index_default=destinationCriteo;export{types_exports as DestinationCriteo,index_default as default,destinationCriteo};//# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/push.ts","../src/hash.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport const DEFAULT_URL = 'https://widget.criteo.com/m/event?version=s2s_v0';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { partnerId, callerId } = settings;\n\n if (!partnerId) logger.throw('Config settings partnerId missing');\n if (!callerId) logger.throw('Config settings callerId missing');\n\n const settingsConfig: Settings = {\n siteType: 'd',\n url: DEFAULT_URL,\n ...settings,\n partnerId,\n callerId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n CriteoEvent,\n CriteoIdentity,\n CriteoItem,\n CriteoRequestBody,\n Env,\n PushFn,\n Settings,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEmail } from './hash';\nimport { DEFAULT_URL } from './config';\n\nconst INTEGRATION_VERSION = 'walkeros_criteo_1.0.0';\n\nfunction toStringOrUndef(value: unknown): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value);\n return undefined;\n}\n\nfunction toNumberOrUndef(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value !== '') {\n const n = Number(value);\n if (Number.isFinite(n)) return n;\n }\n return undefined;\n}\n\nfunction toIsoTimestamp(ts: unknown): string {\n if (typeof ts === 'number' && Number.isFinite(ts)) {\n return new Date(ts).toISOString();\n }\n if (typeof ts === 'string' && ts) return ts;\n return new Date().toISOString();\n}\n\nfunction toItems(raw: unknown): CriteoItem[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const items: CriteoItem[] = [];\n for (const entry of raw) {\n if (!isObject(entry)) continue;\n const id = toStringOrUndef(entry.id);\n if (!id) continue;\n const item: CriteoItem = { id };\n const price = toNumberOrUndef(entry.price);\n if (price !== undefined) item.price = price;\n const quantity = toNumberOrUndef(entry.quantity);\n if (quantity !== undefined) item.quantity = quantity;\n items.push(item);\n }\n return items.length ? items : undefined;\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, env, logger },\n) {\n const {\n partnerId,\n callerId,\n siteType = 'd',\n country,\n language,\n url = DEFAULT_URL,\n user_data,\n } = config.settings as Settings;\n\n const eventData = isObject(data) ? data : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data })\n : {};\n const resolvedUserData = isObject(userDataCustom) ? userDataCustom : {};\n\n // Build identity block\n const identity: CriteoIdentity = { mapping_key: callerId };\n\n const mappedUserId = toStringOrUndef(resolvedUserData.mapped_user_id);\n if (mappedUserId) identity.mapped_user_id = mappedUserId;\n\n const rawEmail = toStringOrUndef(resolvedUserData.email);\n if (rawEmail) {\n const hashes = await hashEmail(rawEmail);\n if (Object.keys(hashes).length > 0) identity.email = hashes;\n }\n\n // Build event object\n const criteoEventName =\n (typeof rule?.name === 'string' && rule.name) || event.name;\n\n const criteoEvent: CriteoEvent = {\n event: criteoEventName,\n timestamp: toIsoTimestamp(event.timestamp),\n };\n\n const eventId = toStringOrUndef(eventData.id);\n if (eventId) criteoEvent.id = eventId;\n\n const items = toItems(eventData.item);\n if (items) criteoEvent.item = items;\n\n const dedupId = toStringOrUndef(eventData.deduplication_page_view_id);\n if (dedupId) criteoEvent.deduplication_page_view_id = dedupId;\n\n // Build request body\n const body: CriteoRequestBody = {\n version: INTEGRATION_VERSION,\n site_type: siteType,\n account: partnerId,\n id: identity,\n events: [criteoEvent],\n };\n\n if (event.source?.id) body.full_url = event.source.id;\n if (event.source?.previous_id) body.previous_url = event.source.previous_id;\n\n const retailerVisitorId = toStringOrUndef(\n resolvedUserData.retailer_visitor_id,\n );\n if (retailerVisitorId) body.retailer_visitor_id = retailerVisitorId;\n\n const ip = toStringOrUndef(resolvedUserData.ip);\n if (ip) body.ip = ip;\n\n const useragent = toStringOrUndef(resolvedUserData.useragent);\n if (useragent) body.useragent = useragent;\n\n if (country) body.country = country;\n if (language) body.language = language;\n\n logger.debug('Calling Criteo Events API', {\n url,\n method: 'POST',\n eventName: criteoEvent.event,\n eventId: criteoEvent.id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(url, JSON.stringify(body));\n\n logger.debug('Criteo API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Criteo API error: ${JSON.stringify(result)}`);\n }\n};\n","import { createHash } from 'crypto';\nimport { getHashServer } from '@walkeros/server-core';\nimport type { CriteoEmailHashes } from './types';\n\n/**\n * Criteo Events API expects email in three hashed forms:\n * - md5: MD5 of lowercased/trimmed email\n * - sha256: SHA-256 of lowercased/trimmed email\n * - sha256_md5: SHA-256 of the MD5 hash (hex string)\n *\n * https://guides.criteotilt.com/events-api/\n */\n\n/** MD5 hex digest of the lowercased/trimmed input */\nexport function hashMD5(value: string): string {\n return createHash('md5').update(value.toLowerCase().trim()).digest('hex');\n}\n\nconst sha256HexPattern = /^[a-f0-9]{64}$/;\nconst md5HexPattern = /^[a-f0-9]{32}$/;\n\nfunction isSha256Hex(value: string): boolean {\n return sha256HexPattern.test(value);\n}\n\nfunction isMd5Hex(value: string): boolean {\n return md5HexPattern.test(value);\n}\n\n/**\n * Hash an email address into Criteo's three expected forms.\n * If the input already looks like a SHA-256 hex string, it is not re-hashed.\n * If the input looks like an MD5 hex string, it is used directly as md5.\n */\nexport async function hashEmail(email: string): Promise<CriteoEmailHashes> {\n const normalized = email.toLowerCase().trim();\n if (!normalized) return {};\n\n // Already SHA-256 hashed — can't derive md5 from it, only pass through.\n if (isSha256Hex(normalized)) {\n return { sha256: normalized };\n }\n\n // Already MD5 hashed — derive sha256_md5 from it, can't derive sha256.\n if (isMd5Hex(normalized)) {\n const sha256_md5 = await getHashServer(normalized);\n return { md5: normalized, sha256_md5 };\n }\n\n const md5 = hashMD5(normalized);\n const sha256 = await getHashServer(normalized);\n const sha256_md5 = await getHashServer(md5);\n return { md5, sha256, sha256_md5 };\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n /** Criteo Partner ID (numeric string, provided by Criteo) */\n partnerId: string;\n /** Caller ID for user mapping (provided by Criteo) */\n callerId: string;\n /** Site type: `d` (desktop), `m` (mobile web), `t` (tablet). Default `d`. */\n siteType?: SiteType;\n /** ISO 3166-1 alpha-2 country code */\n country?: string;\n /** 2-letter language code */\n language?: string;\n /** API endpoint override (default: https://widget.criteo.com/m/event?version=s2s_v0) */\n url?: string;\n /** Mapping for identity fields (mapped_user_id, email, retailer_visitor_id) */\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n sendServer?: typeof sendServer;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n/** Site type: desktop / mobile web / tablet */\nexport type SiteType = 'd' | 'm' | 't';\n\n/**\n * Criteo Events API (S2S v0)\n * https://guides.criteotilt.com/events-api/\n */\nexport interface CriteoRequestBody {\n /** Integration version identifier (e.g. `walkeros_criteo_1.0.0`) */\n version: string;\n site_type?: SiteType;\n /** Criteo Partner ID */\n account: string;\n id: CriteoIdentity;\n ip?: string;\n full_url?: string;\n previous_url?: string;\n useragent?: string;\n retailer_visitor_id?: string;\n country?: string;\n language?: string;\n events: CriteoEvent[];\n}\n\nexport interface CriteoIdentity {\n /** GUM ID */\n mapped_user_id?: string;\n /** Caller ID (provided by Criteo) */\n mapping_key: string;\n email?: CriteoEmailHashes;\n}\n\nexport interface CriteoEmailHashes {\n raw?: string;\n md5?: string;\n sha256?: string;\n sha256_md5?: string;\n}\n\nexport interface CriteoEvent {\n event: CriteoEventName;\n /** ISO 8601 timestamp */\n timestamp?: string;\n /** Transaction ID or event-level ID */\n id?: string;\n item?: CriteoItem[];\n deduplication_page_view_id?: string;\n}\n\nexport interface CriteoItem {\n id: string;\n price?: number;\n quantity?: number;\n}\n\n/**\n * Standard Criteo Events API event names.\n * Custom event names are also accepted as plain strings.\n */\nexport type CriteoEventName =\n | 'viewHome'\n | 'viewPage'\n | 'viewItem'\n | 'viewList'\n | 'addToCart'\n | 'viewBasket'\n | 'beginCheckout'\n | 'trackTransaction'\n | 'addPaymentInfo'\n | 'login'\n | (string & {});\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationCriteo from './types';\n\nexport const destinationCriteo: Destination = {\n type: 'criteo',\n\n config: {},\n\n async init({ config: partialConfig, logger }) {\n const config = getConfig(partialConfig, logger);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationCriteo;\n"],"mappings":"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","names":["sha256_md5"]}
@@ -0,0 +1,427 @@
1
+ {
2
+ "$meta": {
3
+ "package": "@walkeros/server-destination-criteo",
4
+ "version": "3.4.0-next-1776749829492",
5
+ "type": "destination",
6
+ "platform": [
7
+ "server"
8
+ ],
9
+ "docs": "https://www.walkeros.io/docs/destinations/server/criteo",
10
+ "source": "https://github.com/elbwalker/walkerOS/tree/main/packages/server/destinations/criteo/src"
11
+ },
12
+ "schemas": {
13
+ "mapping": {
14
+ "$schema": "http://json-schema.org/draft-07/schema#",
15
+ "type": "object",
16
+ "properties": {},
17
+ "additionalProperties": false
18
+ },
19
+ "settings": {
20
+ "$schema": "http://json-schema.org/draft-07/schema#",
21
+ "type": "object",
22
+ "properties": {
23
+ "partnerId": {
24
+ "type": "string",
25
+ "minLength": 1,
26
+ "description": "Criteo Partner ID (numeric string, provided by Criteo)"
27
+ },
28
+ "callerId": {
29
+ "type": "string",
30
+ "minLength": 1,
31
+ "description": "Caller ID for user mapping (provided by Criteo)"
32
+ },
33
+ "siteType": {
34
+ "type": "string",
35
+ "enum": [
36
+ "d",
37
+ "m",
38
+ "t"
39
+ ],
40
+ "description": "Site type: d (desktop), m (mobile web), t (tablet)"
41
+ },
42
+ "country": {
43
+ "type": "string",
44
+ "minLength": 2,
45
+ "maxLength": 2,
46
+ "description": "ISO 3166-1 alpha-2 country code"
47
+ },
48
+ "language": {
49
+ "type": "string",
50
+ "minLength": 2,
51
+ "maxLength": 2,
52
+ "description": "2-letter language code"
53
+ },
54
+ "url": {
55
+ "type": "string",
56
+ "format": "uri",
57
+ "description": "Custom Events API endpoint (default https://widget.criteo.com/m/event?version=s2s_v0)"
58
+ },
59
+ "user_data": {
60
+ "type": "object",
61
+ "propertyNames": {
62
+ "type": "string"
63
+ },
64
+ "additionalProperties": {
65
+ "type": "string"
66
+ },
67
+ "description": "Mapping for identity fields (like { email: 'user.email', mapped_user_id: 'user.id' })"
68
+ }
69
+ },
70
+ "required": [
71
+ "partnerId",
72
+ "callerId"
73
+ ],
74
+ "additionalProperties": false
75
+ }
76
+ },
77
+ "examples": {
78
+ "env": {
79
+ "push": {
80
+ "sendServer": {
81
+ "$code": "async()=>({ok:!0,data:\"OK\"})"
82
+ }
83
+ },
84
+ "simulation": [
85
+ "sendServer"
86
+ ]
87
+ },
88
+ "step": {
89
+ "addToCart": {
90
+ "in": {
91
+ "name": "product add",
92
+ "data": {
93
+ "id": "SKU-B2",
94
+ "name": "Running Shoes",
95
+ "price": 89.99
96
+ },
97
+ "context": {
98
+ "shopping": [
99
+ "intent",
100
+ 0
101
+ ]
102
+ },
103
+ "globals": {
104
+ "pagegroup": "shop"
105
+ },
106
+ "custom": {
107
+ "completely": "random"
108
+ },
109
+ "user": {
110
+ "id": "us3r",
111
+ "device": "c00k13",
112
+ "session": "s3ss10n"
113
+ },
114
+ "nested": [
115
+ {
116
+ "entity": "product",
117
+ "data": {
118
+ "id": "SKU-B2",
119
+ "name": "Running Shoes",
120
+ "price": 89.99,
121
+ "quantity": 1
122
+ }
123
+ }
124
+ ],
125
+ "consent": {
126
+ "functional": true
127
+ },
128
+ "id": "1700000901000-gr0up-1",
129
+ "trigger": "click",
130
+ "entity": "product",
131
+ "action": "add",
132
+ "timestamp": 1700000901000,
133
+ "timing": 3.14,
134
+ "group": "gr0up",
135
+ "count": 1,
136
+ "version": {
137
+ "source": "3.4.0-next-1776749829492",
138
+ "tagging": 1
139
+ },
140
+ "source": {
141
+ "type": "server",
142
+ "id": "https://shop.example.com/products/running-shoes",
143
+ "previous_id": ""
144
+ }
145
+ },
146
+ "mapping": {
147
+ "name": "addToCart",
148
+ "data": {
149
+ "map": {
150
+ "item": {
151
+ "loop": [
152
+ "nested",
153
+ {
154
+ "condition": {
155
+ "$code": "e=>h(e)&&\"product\"===e.entity"
156
+ },
157
+ "map": {
158
+ "id": "data.id",
159
+ "price": "data.price",
160
+ "quantity": {
161
+ "key": "data.quantity",
162
+ "value": 1
163
+ }
164
+ }
165
+ }
166
+ ]
167
+ }
168
+ }
169
+ }
170
+ },
171
+ "out": [
172
+ [
173
+ "sendServer",
174
+ "https://widget.criteo.com/m/event?version=s2s_v0",
175
+ "{\"version\":\"walkeros_criteo_1.0.0\",\"site_type\":\"d\",\"account\":\"PARTNER_ID\",\"id\":{\"mapping_key\":\"CALLER_ID\"},\"events\":[{\"event\":\"addToCart\",\"timestamp\":\"2023-11-14T22:28:21.000Z\",\"item\":[{\"id\":\"SKU-B2\",\"price\":89.99,\"quantity\":1}]}],\"full_url\":\"https://shop.example.com/products/running-shoes\"}"
176
+ ]
177
+ ]
178
+ },
179
+ "pageView": {
180
+ "in": {
181
+ "name": "page view",
182
+ "data": {
183
+ "domain": "www.example.com",
184
+ "title": "walkerOS documentation",
185
+ "referrer": "https://www.walkeros.io/",
186
+ "search": "?foo=bar",
187
+ "hash": "#hash",
188
+ "id": "/docs/"
189
+ },
190
+ "context": {
191
+ "dev": [
192
+ "test",
193
+ 1
194
+ ]
195
+ },
196
+ "globals": {
197
+ "pagegroup": "docs"
198
+ },
199
+ "custom": {
200
+ "completely": "random"
201
+ },
202
+ "user": {
203
+ "id": "us3r",
204
+ "device": "c00k13",
205
+ "session": "s3ss10n"
206
+ },
207
+ "nested": [
208
+ {
209
+ "entity": "child",
210
+ "data": {
211
+ "is": "subordinated"
212
+ },
213
+ "nested": [],
214
+ "context": {
215
+ "element": [
216
+ "child",
217
+ 0
218
+ ]
219
+ }
220
+ }
221
+ ],
222
+ "consent": {
223
+ "functional": true
224
+ },
225
+ "id": "1700000903000-gr0up-1",
226
+ "trigger": "load",
227
+ "entity": "page",
228
+ "action": "view",
229
+ "timestamp": 1700000903000,
230
+ "timing": 3.14,
231
+ "group": "gr0up",
232
+ "count": 1,
233
+ "version": {
234
+ "source": "3.4.0-next-1776749829492",
235
+ "tagging": 1
236
+ },
237
+ "source": {
238
+ "type": "server",
239
+ "id": "https://example.com/",
240
+ "previous_id": ""
241
+ }
242
+ },
243
+ "mapping": {
244
+ "name": "viewHome"
245
+ },
246
+ "out": [
247
+ [
248
+ "sendServer",
249
+ "https://widget.criteo.com/m/event?version=s2s_v0",
250
+ "{\"version\":\"walkeros_criteo_1.0.0\",\"site_type\":\"d\",\"account\":\"PARTNER_ID\",\"id\":{\"mapping_key\":\"CALLER_ID\"},\"events\":[{\"event\":\"viewHome\",\"timestamp\":\"2023-11-14T22:28:23.000Z\"}],\"full_url\":\"https://example.com/\"}"
251
+ ]
252
+ ]
253
+ },
254
+ "purchase": {
255
+ "in": {
256
+ "name": "order complete",
257
+ "data": {
258
+ "id": "ORD-300",
259
+ "total": 249.99,
260
+ "currency": "EUR"
261
+ },
262
+ "context": {
263
+ "shopping": [
264
+ "complete",
265
+ 0
266
+ ]
267
+ },
268
+ "globals": {
269
+ "pagegroup": "shop"
270
+ },
271
+ "custom": {
272
+ "completely": "random"
273
+ },
274
+ "user": {
275
+ "id": "user-123",
276
+ "device": "device-456"
277
+ },
278
+ "nested": [
279
+ {
280
+ "entity": "product",
281
+ "data": {
282
+ "id": "SKU-A1",
283
+ "name": "Widget Pro",
284
+ "price": 124.99,
285
+ "quantity": 2
286
+ }
287
+ }
288
+ ],
289
+ "consent": {
290
+ "functional": true
291
+ },
292
+ "id": "1700000900000-gr0up-1",
293
+ "trigger": "load",
294
+ "entity": "order",
295
+ "action": "complete",
296
+ "timestamp": 1700000900000,
297
+ "timing": 3.14,
298
+ "group": "gr0up",
299
+ "count": 1,
300
+ "version": {
301
+ "source": "3.4.0-next-1776749829492",
302
+ "tagging": 1
303
+ },
304
+ "source": {
305
+ "type": "server",
306
+ "id": "https://shop.example.com/checkout/complete",
307
+ "previous_id": "https://shop.example.com/cart"
308
+ }
309
+ },
310
+ "mapping": {
311
+ "name": "trackTransaction",
312
+ "data": {
313
+ "map": {
314
+ "id": "data.id",
315
+ "item": {
316
+ "loop": [
317
+ "nested",
318
+ {
319
+ "condition": {
320
+ "$code": "e=>h(e)&&\"product\"===e.entity"
321
+ },
322
+ "map": {
323
+ "id": "data.id",
324
+ "price": "data.price",
325
+ "quantity": {
326
+ "key": "data.quantity",
327
+ "value": 1
328
+ }
329
+ }
330
+ }
331
+ ]
332
+ }
333
+ }
334
+ }
335
+ },
336
+ "out": [
337
+ [
338
+ "sendServer",
339
+ "https://widget.criteo.com/m/event?version=s2s_v0",
340
+ "{\"version\":\"walkeros_criteo_1.0.0\",\"site_type\":\"d\",\"account\":\"PARTNER_ID\",\"id\":{\"mapping_key\":\"CALLER_ID\"},\"events\":[{\"event\":\"trackTransaction\",\"timestamp\":\"2023-11-14T22:28:20.000Z\",\"id\":\"ORD-300\",\"item\":[{\"id\":\"SKU-A1\",\"price\":124.99,\"quantity\":2}]}],\"full_url\":\"https://shop.example.com/checkout/complete\",\"previous_url\":\"https://shop.example.com/cart\"}"
341
+ ]
342
+ ]
343
+ },
344
+ "viewItem": {
345
+ "in": {
346
+ "name": "product view",
347
+ "data": {
348
+ "id": "SKU-C3",
349
+ "name": "Coffee Maker"
350
+ },
351
+ "context": {
352
+ "shopping": [
353
+ "detail",
354
+ 0
355
+ ]
356
+ },
357
+ "globals": {
358
+ "pagegroup": "shop"
359
+ },
360
+ "custom": {
361
+ "completely": "random"
362
+ },
363
+ "user": {
364
+ "id": "us3r",
365
+ "device": "c00k13",
366
+ "session": "s3ss10n"
367
+ },
368
+ "nested": [
369
+ {
370
+ "entity": "product",
371
+ "data": {
372
+ "id": "SKU-C3"
373
+ }
374
+ }
375
+ ],
376
+ "consent": {
377
+ "functional": true
378
+ },
379
+ "id": "1700000902000-gr0up-1",
380
+ "trigger": "load",
381
+ "entity": "product",
382
+ "action": "view",
383
+ "timestamp": 1700000902000,
384
+ "timing": 3.14,
385
+ "group": "gr0up",
386
+ "count": 1,
387
+ "version": {
388
+ "source": "3.4.0-next-1776749829492",
389
+ "tagging": 1
390
+ },
391
+ "source": {
392
+ "type": "server",
393
+ "id": "https://shop.example.com/products/coffee-maker",
394
+ "previous_id": ""
395
+ }
396
+ },
397
+ "mapping": {
398
+ "name": "viewItem",
399
+ "data": {
400
+ "map": {
401
+ "item": {
402
+ "loop": [
403
+ "nested",
404
+ {
405
+ "condition": {
406
+ "$code": "e=>h(e)&&\"product\"===e.entity"
407
+ },
408
+ "map": {
409
+ "id": "data.id"
410
+ }
411
+ }
412
+ ]
413
+ }
414
+ }
415
+ }
416
+ },
417
+ "out": [
418
+ [
419
+ "sendServer",
420
+ "https://widget.criteo.com/m/event?version=s2s_v0",
421
+ "{\"version\":\"walkeros_criteo_1.0.0\",\"site_type\":\"d\",\"account\":\"PARTNER_ID\",\"id\":{\"mapping_key\":\"CALLER_ID\"},\"events\":[{\"event\":\"viewItem\",\"timestamp\":\"2023-11-14T22:28:22.000Z\",\"item\":[{\"id\":\"SKU-C3\"}]}],\"full_url\":\"https://shop.example.com/products/coffee-maker\"}"
422
+ ]
423
+ ]
424
+ }
425
+ }
426
+ }
427
+ }