@walkeros/server-destination-criteo 4.1.2 → 4.1.3-next-1780071196115
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/CHANGELOG.md +15 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/walkerOS.json +5 -5
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @walkeros/server-destination-criteo
|
|
2
2
|
|
|
3
|
+
## 4.1.3-next-1780071196115
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2d64ed2: `getHashServer` now accepts an `algorithm` option (`sha256` default,
|
|
8
|
+
or `md5`), so destinations can request either digest from the shared util
|
|
9
|
+
instead of calling Node crypto directly. Criteo's email hashing composes this
|
|
10
|
+
util for its md5, sha256, and sha256_md5 forms. No behavior change for
|
|
11
|
+
existing SHA-256 callers.
|
|
12
|
+
- Updated dependencies [908d6f0]
|
|
13
|
+
- Updated dependencies [2d64ed2]
|
|
14
|
+
- Updated dependencies [3eb2467]
|
|
15
|
+
- @walkeros/core@4.1.3-next-1780071196115
|
|
16
|
+
- @walkeros/server-core@4.1.3-next-1780071196115
|
|
17
|
+
|
|
3
18
|
## 4.1.2
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -1 +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"),
|
|
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_core=require("@walkeros/server-core"),sha256HexPattern=/^[a-f0-9]{64}$/,md5HexPattern=/^[a-f0-9]{32}$/;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,collector:collector}){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},{collector:collector}):{},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 async function(email){const normalized=email.toLowerCase().trim();if(!normalized)return{};if(sha256HexPattern.test(normalized))return{sha256:normalized};if(md5HexPattern.test(normalized))return{md5:normalized,sha256_md5:await(0,import_server_core.getHashServer)(normalized)};const md5=await(0,import_server_core.getHashServer)(normalized,void 0,{algorithm:"md5"});return{md5:md5,sha256:await(0,import_server_core.getHashServer)(normalized),sha256_md5:await(0,import_server_core.getHashServer)(md5)}}(rawEmail);Object.keys(hashes).length>0&&(identity.email=hashes)}const criteoEvent={event:"string"==typeof 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]};event.source?.url&&(body.full_url=event.source.url),event.source?.referrer&&(body.previous_url=event.source.referrer);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=env?.sendServer||import_server_core.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
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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, collector },\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 }, { collector })\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?.url) body.full_url = event.source.url;\n if (event.source?.referrer) body.previous_url = event.source.referrer;\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.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 CriteoEmailHashes,\n CriteoEvent,\n CriteoIdentity,\n CriteoItem,\n CriteoRequestBody,\n Env,\n PushFn,\n Settings,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { getHashServer, sendServer } from '@walkeros/server-core';\nimport { DEFAULT_URL } from './config';\n\nconst INTEGRATION_VERSION = 'walkeros_criteo_1.0.0';\n\nconst sha256HexPattern = /^[a-f0-9]{64}$/;\nconst md5HexPattern = /^[a-f0-9]{32}$/;\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 hex string\n *\n * Already-hashed input is passed through: a SHA-256 hex only sets `sha256`;\n * an MD5 hex sets `md5` and derives `sha256_md5` from it.\n *\n * https://guides.criteotilt.com/events-api/\n */\nasync function hashEmail(email: string): Promise<CriteoEmailHashes> {\n const normalized = email.toLowerCase().trim();\n if (!normalized) return {};\n\n if (sha256HexPattern.test(normalized)) {\n return { sha256: normalized };\n }\n\n if (md5HexPattern.test(normalized)) {\n return { md5: normalized, sha256_md5: await getHashServer(normalized) };\n }\n\n const md5 = await getHashServer(normalized, undefined, { algorithm: 'md5' });\n return {\n md5,\n sha256: await getHashServer(normalized),\n sha256_md5: await getHashServer(md5),\n };\n}\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, collector },\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 }, { collector })\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?.url) body.full_url = event.source.url;\n if (event.source?.referrer) body.previous_url = event.source.referrer;\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 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":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +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";
|
|
1
|
+
var DEFAULT_URL="https://widget.criteo.com/m/event?version=s2s_v0";import{getMappingValue,isObject}from"@walkeros/core";import{getHashServer,sendServer}from"@walkeros/server-core";var sha256HexPattern=/^[a-f0-9]{64}$/,md5HexPattern=/^[a-f0-9]{32}$/;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,collector:collector}){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},{collector:collector}):{},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 async function(email){const normalized=email.toLowerCase().trim();if(!normalized)return{};if(sha256HexPattern.test(normalized))return{sha256:normalized};if(md5HexPattern.test(normalized))return{md5:normalized,sha256_md5:await getHashServer(normalized)};const md5=await getHashServer(normalized,void 0,{algorithm:"md5"});return{md5:md5,sha256:await getHashServer(normalized),sha256_md5:await getHashServer(md5)}}(rawEmail);Object.keys(hashes).length>0&&(identity.email=hashes)}const criteoEvent={event:"string"==typeof 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]};event.source?.url&&(body.full_url=event.source.url),event.source?.referrer&&(body.previous_url=event.source.referrer);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=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
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +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, collector },\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 }, { collector })\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?.url) body.full_url = event.source.url;\n if (event.source?.referrer) body.previous_url = event.source.referrer;\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":";AAGO,IAAM,cAAc;AAEpB,SAAS,UACd,gBAA+B,CAAC,GAChC,QACQ;AACR,QAAM,WAAY,cAAc,YAAY,CAAC;AAC7C,QAAM,EAAE,WAAW,SAAS,IAAI;AAEhC,MAAI,CAAC,UAAW,QAAO,MAAM,mCAAmC;AAChE,MAAI,CAAC,SAAU,QAAO,MAAM,kCAAkC;AAE9D,QAAM,iBAA2B;AAAA,IAC/B,UAAU;AAAA,IACV,KAAK;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,eAAe,UAAU,eAAe;AACtD;;;ACfA,SAAS,iBAAiB,gBAAgB;AAC1C,SAAS,kBAAkB;;;ACV3B,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAavB,SAAS,QAAQ,OAAuB;AAC7C,SAAO,WAAW,KAAK,EAAE,OAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK;AAC1E;AAEA,IAAM,mBAAmB;AACzB,IAAM,gBAAgB;AAEtB,SAAS,YAAY,OAAwB;AAC3C,SAAO,iBAAiB,KAAK,KAAK;AACpC;AAEA,SAAS,SAAS,OAAwB;AACxC,SAAO,cAAc,KAAK,KAAK;AACjC;AAOA,eAAsB,UAAU,OAA2C;AACzE,QAAM,aAAa,MAAM,YAAY,EAAE,KAAK;AAC5C,MAAI,CAAC,WAAY,QAAO,CAAC;AAGzB,MAAI,YAAY,UAAU,GAAG;AAC3B,WAAO,EAAE,QAAQ,WAAW;AAAA,EAC9B;AAGA,MAAI,SAAS,UAAU,GAAG;AACxB,UAAMA,cAAa,MAAM,cAAc,UAAU;AACjD,WAAO,EAAE,KAAK,YAAY,YAAAA,YAAW;AAAA,EACvC;AAEA,QAAM,MAAM,QAAQ,UAAU;AAC9B,QAAM,SAAS,MAAM,cAAc,UAAU;AAC7C,QAAM,aAAa,MAAM,cAAc,GAAG;AAC1C,SAAO,EAAE,KAAK,QAAQ,WAAW;AACnC;;;ADvCA,IAAM,sBAAsB;AAE5B,SAAS,gBAAgB,OAAoC;AAC3D,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU;AAChD,WAAO,OAAO,KAAK;AACrB,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAoC;AAC3D,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAChE,MAAI,OAAO,UAAU,YAAY,UAAU,IAAI;AAC7C,UAAM,IAAI,OAAO,KAAK;AACtB,QAAI,OAAO,SAAS,CAAC,EAAG,QAAO;AAAA,EACjC;AACA,SAAO;AACT;AAEA,SAAS,eAAe,IAAqB;AAC3C,MAAI,OAAO,OAAO,YAAY,OAAO,SAAS,EAAE,GAAG;AACjD,WAAO,IAAI,KAAK,EAAE,EAAE,YAAY;AAAA,EAClC;AACA,MAAI,OAAO,OAAO,YAAY,GAAI,QAAO;AACzC,UAAO,oBAAI,KAAK,GAAE,YAAY;AAChC;AAEA,SAAS,QAAQ,KAAwC;AACvD,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO;AAChC,QAAM,QAAsB,CAAC;AAC7B,aAAW,SAAS,KAAK;AACvB,QAAI,CAAC,SAAS,KAAK,EAAG;AACtB,UAAM,KAAK,gBAAgB,MAAM,EAAE;AACnC,QAAI,CAAC,GAAI;AACT,UAAM,OAAmB,EAAE,GAAG;AAC9B,UAAM,QAAQ,gBAAgB,MAAM,KAAK;AACzC,QAAI,UAAU,OAAW,MAAK,QAAQ;AACtC,UAAM,WAAW,gBAAgB,MAAM,QAAQ;AAC/C,QAAI,aAAa,OAAW,MAAK,WAAW;AAC5C,UAAM,KAAK,IAAI;AAAA,EACjB;AACA,SAAO,MAAM,SAAS,QAAQ;AAChC;AAEO,IAAM,OAAe,eAC1B,OACA,EAAE,QAAQ,MAAM,MAAM,KAAK,QAAQ,UAAU,GAC7C;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,EACF,IAAI,OAAO;AAEX,QAAM,YAAY,SAAS,IAAI,IAAI,OAAO,CAAC;AAC3C,QAAM,iBAAiB,YACnB,MAAM,gBAAgB,OAAO,EAAE,KAAK,UAAU,GAAG,EAAE,UAAU,CAAC,IAC9D,CAAC;AACL,QAAM,mBAAmB,SAAS,cAAc,IAAI,iBAAiB,CAAC;AAGtE,QAAM,WAA2B,EAAE,aAAa,SAAS;AAEzD,QAAM,eAAe,gBAAgB,iBAAiB,cAAc;AACpE,MAAI,aAAc,UAAS,iBAAiB;AAE5C,QAAM,WAAW,gBAAgB,iBAAiB,KAAK;AACvD,MAAI,UAAU;AACZ,UAAM,SAAS,MAAM,UAAU,QAAQ;AACvC,QAAI,OAAO,KAAK,MAAM,EAAE,SAAS,EAAG,UAAS,QAAQ;AAAA,EACvD;AAGA,QAAM,kBACH,OAAO,MAAM,SAAS,YAAY,KAAK,QAAS,MAAM;AAEzD,QAAM,cAA2B;AAAA,IAC/B,OAAO;AAAA,IACP,WAAW,eAAe,MAAM,SAAS;AAAA,EAC3C;AAEA,QAAM,UAAU,gBAAgB,UAAU,EAAE;AAC5C,MAAI,QAAS,aAAY,KAAK;AAE9B,QAAM,QAAQ,QAAQ,UAAU,IAAI;AACpC,MAAI,MAAO,aAAY,OAAO;AAE9B,QAAM,UAAU,gBAAgB,UAAU,0BAA0B;AACpE,MAAI,QAAS,aAAY,6BAA6B;AAGtD,QAAM,OAA0B;AAAA,IAC9B,SAAS;AAAA,IACT,WAAW;AAAA,IACX,SAAS;AAAA,IACT,IAAI;AAAA,IACJ,QAAQ,CAAC,WAAW;AAAA,EACtB;AAEA,MAAI,MAAM,QAAQ,IAAK,MAAK,WAAW,MAAM,OAAO;AACpD,MAAI,MAAM,QAAQ,SAAU,MAAK,eAAe,MAAM,OAAO;AAE7D,QAAM,oBAAoB;AAAA,IACxB,iBAAiB;AAAA,EACnB;AACA,MAAI,kBAAmB,MAAK,sBAAsB;AAElD,QAAM,KAAK,gBAAgB,iBAAiB,EAAE;AAC9C,MAAI,GAAI,MAAK,KAAK;AAElB,QAAM,YAAY,gBAAgB,iBAAiB,SAAS;AAC5D,MAAI,UAAW,MAAK,YAAY;AAEhC,MAAI,QAAS,MAAK,UAAU;AAC5B,MAAI,SAAU,MAAK,WAAW;AAE9B,SAAO,MAAM,6BAA6B;AAAA,IACxC;AAAA,IACA,QAAQ;AAAA,IACR,WAAW,YAAY;AAAA,IACvB,SAAS,YAAY;AAAA,EACvB,CAAC;AAED,QAAM,eAAgB,KAAa,cAAc;AACjD,QAAM,SAAS,MAAM,aAAa,KAAK,KAAK,UAAU,IAAI,CAAC;AAE3D,SAAO,MAAM,uBAAuB;AAAA,IAClC,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK;AAAA,EACrC,CAAC;AAED,MAAI,SAAS,MAAM,KAAK,OAAO,OAAO,OAAO;AAC3C,WAAO,MAAM,qBAAqB,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,EAC5D;AACF;;;AEvJA;;;ACOO,IAAM,oBAAiC;AAAA,EAC5C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,OAAO,GAAG;AAC5C,UAAM,SAAS,UAAU,eAAe,MAAM;AAC9C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AACF;AAEA,IAAO,gBAAQ;","names":["sha256_md5"]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/push.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 CriteoEmailHashes,\n CriteoEvent,\n CriteoIdentity,\n CriteoItem,\n CriteoRequestBody,\n Env,\n PushFn,\n Settings,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { getHashServer, sendServer } from '@walkeros/server-core';\nimport { DEFAULT_URL } from './config';\n\nconst INTEGRATION_VERSION = 'walkeros_criteo_1.0.0';\n\nconst sha256HexPattern = /^[a-f0-9]{64}$/;\nconst md5HexPattern = /^[a-f0-9]{32}$/;\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 hex string\n *\n * Already-hashed input is passed through: a SHA-256 hex only sets `sha256`;\n * an MD5 hex sets `md5` and derives `sha256_md5` from it.\n *\n * https://guides.criteotilt.com/events-api/\n */\nasync function hashEmail(email: string): Promise<CriteoEmailHashes> {\n const normalized = email.toLowerCase().trim();\n if (!normalized) return {};\n\n if (sha256HexPattern.test(normalized)) {\n return { sha256: normalized };\n }\n\n if (md5HexPattern.test(normalized)) {\n return { md5: normalized, sha256_md5: await getHashServer(normalized) };\n }\n\n const md5 = await getHashServer(normalized, undefined, { algorithm: 'md5' });\n return {\n md5,\n sha256: await getHashServer(normalized),\n sha256_md5: await getHashServer(md5),\n };\n}\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, collector },\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 }, { collector })\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?.url) body.full_url = event.source.url;\n if (event.source?.referrer) body.previous_url = event.source.referrer;\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 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":[]}
|
package/dist/walkerOS.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$meta": {
|
|
3
3
|
"package": "@walkeros/server-destination-criteo",
|
|
4
|
-
"version": "4.1.
|
|
4
|
+
"version": "4.1.3-next-1780071196115",
|
|
5
5
|
"type": "destination",
|
|
6
6
|
"platform": [
|
|
7
7
|
"server"
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
"consent": {
|
|
128
128
|
"functional": true
|
|
129
129
|
},
|
|
130
|
-
"id": "
|
|
130
|
+
"id": "0f7b909306ec4b64",
|
|
131
131
|
"trigger": "click",
|
|
132
132
|
"entity": "product",
|
|
133
133
|
"action": "add",
|
|
@@ -213,7 +213,7 @@
|
|
|
213
213
|
"consent": {
|
|
214
214
|
"functional": true
|
|
215
215
|
},
|
|
216
|
-
"id": "
|
|
216
|
+
"id": "6eb4376ce1c8f7cf",
|
|
217
217
|
"trigger": "load",
|
|
218
218
|
"entity": "page",
|
|
219
219
|
"action": "view",
|
|
@@ -276,7 +276,7 @@
|
|
|
276
276
|
"consent": {
|
|
277
277
|
"functional": true
|
|
278
278
|
},
|
|
279
|
-
"id": "
|
|
279
|
+
"id": "9e50b6d7e2814609",
|
|
280
280
|
"trigger": "load",
|
|
281
281
|
"entity": "order",
|
|
282
282
|
"action": "complete",
|
|
@@ -360,7 +360,7 @@
|
|
|
360
360
|
"consent": {
|
|
361
361
|
"functional": true
|
|
362
362
|
},
|
|
363
|
-
"id": "
|
|
363
|
+
"id": "4bcb05d231cf6516",
|
|
364
364
|
"trigger": "load",
|
|
365
365
|
"entity": "product",
|
|
366
366
|
"action": "view",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkeros/server-destination-criteo",
|
|
3
3
|
"description": "Criteo Events API server destination for walkerOS",
|
|
4
|
-
"version": "4.1.
|
|
4
|
+
"version": "4.1.3-next-1780071196115",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"update": "npx npm-check-updates -u && npm update"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@walkeros/core": "4.1.
|
|
39
|
-
"@walkeros/server-core": "4.1.
|
|
38
|
+
"@walkeros/core": "4.1.3-next-1780071196115",
|
|
39
|
+
"@walkeros/server-core": "4.1.3-next-1780071196115"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@walkeros/collector": "4.1.
|
|
42
|
+
"@walkeros/collector": "4.1.3-next-1780071196115"
|
|
43
43
|
},
|
|
44
44
|
"repository": {
|
|
45
45
|
"url": "git+https://github.com/elbwalker/walkerOS.git",
|