@walkeros/server-destination-snapchat 3.4.2 → 4.0.0-next-1777882869103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dev.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,i=(e,a)=>{for(var r in a)t(e,r,{get:a[r],enumerable:!0})},s={};i(s,{examples:()=>E,schemas:()=>o}),module.exports=(e=s,((e,i,s,o)=>{if(i&&"object"==typeof i||"function"==typeof i)for(let c of r(i))n.call(e,c)||c===s||t(e,c,{get:()=>i[c],enumerable:!(o=a(i,c))||o.enumerable});return e})(t({},"__esModule",{value:!0}),e));var o={};i(o,{MappingSchema:()=>u,SettingsSchema:()=>p,StandardEventNameSchema:()=>_,mapping:()=>v,settings:()=>l});var c=require("@walkeros/core/dev"),d=require("@walkeros/core/dev"),p=d.z.object({accessToken:d.z.string().min(1).describe("Long-lived Conversions API access token from Snapchat Ads Manager"),pixelId:d.z.string().min(1).describe("Snap Pixel ID"),url:d.z.string().url().describe("Custom Conversions API base URL (default https://tr.snapchat.com/v3/)").optional(),action_source:d.z.enum(["WEB","MOBILE_APP","OFFLINE"]).describe("Event action source (default WEB)").optional(),doNotHash:d.z.array(d.z.string()).describe("User data fields to skip hashing (like ['em', 'ph'])").optional(),user_data:d.z.record(d.z.string(),d.z.string()).describe("Mapping for user data fields (like { em: 'user.email' })").optional(),testMode:d.z.boolean().describe("When true, sends events to /events/validate instead of /events for testing").optional()}),u=require("@walkeros/core/dev").z.object({}),m=require("@walkeros/core/dev"),_=m.z.union([m.z.enum(["PAGE_VIEW","VIEW_CONTENT","ADD_CART","ADD_TO_WISHLIST","START_CHECKOUT","ADD_BILLING","PURCHASE","SIGN_UP","SEARCH","SAVE","SUBSCRIBE","COMPLETE_TUTORIAL","START_TRIAL","AD_CLICK","AD_VIEW","APP_OPEN","LEVEL_COMPLETE","INVITE","LOGIN","SHARE","RESERVE","ACHIEVEMENT_UNLOCKED","SPENT_CREDITS","RATE","LIST_VIEW","CUSTOM_EVENT_1","CUSTOM_EVENT_2","CUSTOM_EVENT_3","CUSTOM_EVENT_4","CUSTOM_EVENT_5"]),m.z.string()]),l=(0,c.zodToSchema)(p),v=(0,c.zodToSchema)(u),E={};i(E,{env:()=>S,step:()=>y});var S={};i(S,{push:()=>h,simulation:()=>g});var h={sendServer:async()=>({ok:!0,data:{status:"OK",request_id:"mock-123"}})},g=["sendServer"],y={};i(y,{addToCart:()=>f,lead:()=>C,pageView:()=>O,purchase:()=>b});var A=require("@walkeros/core"),T="https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t",b={title:"Purchase",description:"A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.",in:(0,A.getEvent)("order complete",{timestamp:17000009e5,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Widget Pro",price:124.99,quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"server",id:"https://shop.example.com/checkout/complete",previous_id:""}}),mapping:{name:"PURCHASE",data:{map:{custom_data:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"},transaction_id:"data.id",contents:{loop:["nested",{condition:e=>(0,A.isObject)(e)&&"product"===e.entity,map:{id:"data.id",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}},user_data:{map:{external_id:"user.id"}}}}},out:[["sendServer",T,JSON.stringify({data:[{event_name:"PURCHASE",event_time:1700000900,action_source:"WEB",event_id:"1700000900000-gr0up-1",user_data:{external_id:"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"},custom_data:{value:249.99,currency:"EUR",transaction_id:"ORD-300",contents:[{id:"SKU-A1",item_price:124.99,quantity:2}]},event_source_url:"https://shop.example.com/checkout/complete"}]})]]},f={title:"Add to cart",description:"A product add is sent to Snapchat as an ADD_CART conversion with value and product details.",in:(0,A.getEvent)("product add",{timestamp:1700000901e3,data:{id:"SKU-B2",name:"Running Shoes",price:89.99,color:"blue"},nested:[{entity:"product",data:{id:"SKU-B2",name:"Running Shoes",price:89.99,quantity:1}}],source:{type:"server",id:"https://shop.example.com/products/running-shoes",previous_id:""}}),mapping:{name:"ADD_CART",data:{map:{custom_data:{map:{value:"data.price",currency:{value:"EUR"},contents:{loop:["nested",{condition:e=>(0,A.isObject)(e)&&"product"===e.entity,map:{id:"data.id",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",T,JSON.stringify({data:[{event_name:"ADD_CART",event_time:1700000901,action_source:"WEB",event_id:"1700000901000-gr0up-1",user_data:{},custom_data:{value:89.99,currency:"EUR",contents:[{id:"SKU-B2",item_price:89.99,quantity:1}]},event_source_url:"https://shop.example.com/products/running-shoes"}]})]]},O={title:"Page view",description:"A page view is forwarded to Snapchat with the event source URL and no extra custom data.",in:(0,A.getEvent)("page view",{timestamp:1700000902e3,source:{type:"server",id:"https://example.com/docs/",previous_id:""}}),mapping:void 0,out:[["sendServer",T,JSON.stringify({data:[{event_name:"page view",event_time:1700000902,action_source:"WEB",event_id:"1700000902000-gr0up-1",user_data:{},custom_data:{},event_source_url:"https://example.com/docs/"}]})]]},C={title:"Sign up",description:"A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.",in:(0,A.getEvent)("form submit",{timestamp:1700000903e3,data:{type:"newsletter"},user:{email:"user@example.com"},source:{type:"server",id:"https://example.com/contact",previous_id:""}}),mapping:{name:"SIGN_UP",data:{map:{user_data:{map:{em:"user.email"}},custom_data:{map:{sign_up_method:{value:"newsletter"}}}}}},out:[["sendServer",T,JSON.stringify({data:[{event_name:"SIGN_UP",event_time:1700000903,action_source:"WEB",event_id:"1700000903000-gr0up-1",user_data:{em:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"},custom_data:{sign_up_method:"newsletter"},event_source_url:"https://example.com/contact"}]})]]};//# sourceMappingURL=dev.js.map
1
+ "use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,s=(e,a)=>{for(var r in a)t(e,r,{get:a[r],enumerable:!0})},o={};s(o,{examples:()=>E,schemas:()=>i}),module.exports=(e=o,((e,s,o,i)=>{if(s&&"object"==typeof s||"function"==typeof s)for(let c of r(s))n.call(e,c)||c===o||t(e,c,{get:()=>s[c],enumerable:!(i=a(s,c))||i.enumerable});return e})(t({},"__esModule",{value:!0}),e));var i={};s(i,{MappingSchema:()=>u,SettingsSchema:()=>p,StandardEventNameSchema:()=>l,mapping:()=>v,settings:()=>_});var c=require("@walkeros/core/dev"),d=require("@walkeros/core/dev"),p=d.z.object({accessToken:d.z.string().min(1).describe("Long-lived Conversions API access token from Snapchat Ads Manager"),pixelId:d.z.string().min(1).describe("Snap Pixel ID"),url:d.z.string().url().describe("Custom Conversions API base URL (default https://tr.snapchat.com/v3/)").optional(),action_source:d.z.enum(["WEB","MOBILE_APP","OFFLINE"]).describe("Event action source (default WEB)").optional(),doNotHash:d.z.array(d.z.string()).describe("User data fields to skip hashing (like ['em', 'ph'])").optional(),user_data:d.z.record(d.z.string(),d.z.string()).describe("Mapping for user data fields (like { em: 'user.email' })").optional(),testMode:d.z.boolean().describe("When true, sends events to /events/validate instead of /events for testing").optional()}),u=require("@walkeros/core/dev").z.object({}),m=require("@walkeros/core/dev"),l=m.z.union([m.z.enum(["PAGE_VIEW","VIEW_CONTENT","ADD_CART","ADD_TO_WISHLIST","START_CHECKOUT","ADD_BILLING","PURCHASE","SIGN_UP","SEARCH","SAVE","SUBSCRIBE","COMPLETE_TUTORIAL","START_TRIAL","AD_CLICK","AD_VIEW","APP_OPEN","LEVEL_COMPLETE","INVITE","LOGIN","SHARE","RESERVE","ACHIEVEMENT_UNLOCKED","SPENT_CREDITS","RATE","LIST_VIEW","CUSTOM_EVENT_1","CUSTOM_EVENT_2","CUSTOM_EVENT_3","CUSTOM_EVENT_4","CUSTOM_EVENT_5"]),m.z.string()]),_=(0,c.zodToSchema)(p),v=(0,c.zodToSchema)(u),E={};s(E,{env:()=>S,step:()=>f});var S={};s(S,{push:()=>h,simulation:()=>b});var h={sendServer:async()=>({ok:!0,data:{status:"OK",request_id:"mock-123"}})},b=["sendServer"],f={};s(f,{addToCart:()=>T,lead:()=>w,pageView:()=>O,purchase:()=>A});var g=require("@walkeros/core"),y="https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t",A={title:"Purchase",description:"A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.",in:(0,g.getEvent)("order complete",{id:"e1f2a3b4c5d60001",timestamp:17000009e5,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Widget Pro",price:124.99,quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/checkout/complete"}}),mapping:{name:"PURCHASE",data:{map:{custom_data:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"},transaction_id:"data.id",contents:{loop:["nested",{condition:e=>(0,g.isObject)(e)&&"product"===e.entity,map:{id:"data.id",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}},user_data:{map:{external_id:"user.id"}}}}},out:[["sendServer",y,JSON.stringify({data:[{event_name:"PURCHASE",event_time:1700000900,action_source:"WEB",event_id:"e1f2a3b4c5d60001",user_data:{external_id:"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"},custom_data:{value:249.99,currency:"EUR",transaction_id:"ORD-300",contents:[{id:"SKU-A1",item_price:124.99,quantity:2}]},event_source_url:"https://shop.example.com/checkout/complete"}]})]]},T={title:"Add to cart",description:"A product add is sent to Snapchat as an ADD_CART conversion with value and product details.",in:(0,g.getEvent)("product add",{id:"e1f2a3b4c5d60002",timestamp:1700000901e3,data:{id:"SKU-B2",name:"Running Shoes",price:89.99,color:"blue"},nested:[{entity:"product",data:{id:"SKU-B2",name:"Running Shoes",price:89.99,quantity:1}}],source:{type:"browser",platform:"web",url:"https://shop.example.com/products/running-shoes"}}),mapping:{name:"ADD_CART",data:{map:{custom_data:{map:{value:"data.price",currency:{value:"EUR"},contents:{loop:["nested",{condition:e=>(0,g.isObject)(e)&&"product"===e.entity,map:{id:"data.id",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",y,JSON.stringify({data:[{event_name:"ADD_CART",event_time:1700000901,action_source:"WEB",event_id:"e1f2a3b4c5d60002",user_data:{},custom_data:{value:89.99,currency:"EUR",contents:[{id:"SKU-B2",item_price:89.99,quantity:1}]},event_source_url:"https://shop.example.com/products/running-shoes"}]})]]},O={title:"Page view",description:"A page view is forwarded to Snapchat with the event source URL and no extra custom data.",in:(0,g.getEvent)("page view",{id:"e1f2a3b4c5d60003",timestamp:1700000902e3,source:{type:"browser",platform:"web",url:"https://example.com/docs/"}}),mapping:void 0,out:[["sendServer",y,JSON.stringify({data:[{event_name:"page view",event_time:1700000902,action_source:"WEB",event_id:"e1f2a3b4c5d60003",user_data:{},custom_data:{},event_source_url:"https://example.com/docs/"}]})]]},w={title:"Sign up",description:"A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.",in:(0,g.getEvent)("form submit",{id:"e1f2a3b4c5d60004",timestamp:1700000903e3,data:{type:"newsletter"},user:{email:"user@example.com"},source:{type:"browser",platform:"web",url:"https://example.com/contact"}}),mapping:{name:"SIGN_UP",data:{map:{user_data:{map:{em:"user.email"}},custom_data:{map:{sign_up_method:{value:"newsletter"}}}}}},out:[["sendServer",y,JSON.stringify({data:[{event_name:"SIGN_UP",event_time:1700000903,action_source:"WEB",event_id:"e1f2a3b4c5d60004",user_data:{em:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"},custom_data:{sign_up_method:"newsletter"},event_source_url:"https://example.com/contact"}]})]]};//# sourceMappingURL=dev.js.map
package/dist/dev.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Long-lived Conversions API access token from Snapchat Ads Manager',\n ),\n pixelId: z.string().min(1).describe('Snap Pixel ID'),\n url: z\n .string()\n .url()\n .describe(\n 'Custom Conversions API base URL (default https://tr.snapchat.com/v3/)',\n )\n .optional(),\n action_source: z\n .enum(['WEB', 'MOBILE_APP', 'OFFLINE'])\n .describe('Event action source (default WEB)')\n .optional(),\n doNotHash: z\n .array(z.string())\n .describe(\"User data fields to skip hashing (like ['em', 'ph'])\")\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\"Mapping for user data fields (like { em: 'user.email' })\")\n .optional(),\n testMode: z\n .boolean()\n .describe(\n 'When true, sends events to /events/validate instead of /events for testing',\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Snapchat Conversions API Mapping Schema\n * Snapchat CAPI has no event-level mapping configuration\n */\nexport const MappingSchema = z.object({});\n\n/**\n * Type inference from MappingSchema\n */\nexport type Mapping = z.infer<typeof MappingSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Standard Snapchat Conversions API event names (UPPERCASE).\n * https://businesshelp.snapchat.com/s/article/capi-parameters\n */\nexport const StandardEventNameSchema = z.union([\n z.enum([\n 'PAGE_VIEW',\n 'VIEW_CONTENT',\n 'ADD_CART',\n 'ADD_TO_WISHLIST',\n 'START_CHECKOUT',\n 'ADD_BILLING',\n 'PURCHASE',\n 'SIGN_UP',\n 'SEARCH',\n 'SAVE',\n 'SUBSCRIBE',\n 'COMPLETE_TUTORIAL',\n 'START_TRIAL',\n 'AD_CLICK',\n 'AD_VIEW',\n 'APP_OPEN',\n 'LEVEL_COMPLETE',\n 'INVITE',\n 'LOGIN',\n 'SHARE',\n 'RESERVE',\n 'ACHIEVEMENT_UNLOCKED',\n 'SPENT_CREDITS',\n 'RATE',\n 'LIST_VIEW',\n 'CUSTOM_EVENT_1',\n 'CUSTOM_EVENT_2',\n 'CUSTOM_EVENT_3',\n 'CUSTOM_EVENT_4',\n 'CUSTOM_EVENT_5',\n ]),\n z.string(), // Allow custom event names\n]);\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for Snapchat Conversions API destination.\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\ntype MockSendServer = (\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n) => Promise<SendResponse>;\n\nconst mockSendServer: MockSendServer = async () => ({\n ok: true,\n data: {\n status: 'OK',\n request_id: 'mock-123',\n },\n});\n\n/**\n * Standard mock environment for push operations.\n *\n * Use this for testing Snapchat Conversions API events without making\n * actual HTTP requests to Snapchat's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * Snapchat Conversions API step examples.\n *\n * At push time, the destination calls `env.sendServer(url, body)` where\n * `url` is `${settings.url}${settings.pixelId}/${path}?access_token=${settings.accessToken}`\n * with `path` = `events` (or `events/validate` when `testMode` is set),\n * and `body` is the JSON-stringified `{ data: [snapchatEvent] }` payload.\n *\n * The test fixture pins `accessToken = 's3cr3t'` and `pixelId = 'p1x3l1d'`,\n * so every endpoint resolves to:\n * https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t\n *\n * Body fields are emitted in the order the destination constructs them\n * (insertion order matters for `JSON.stringify` string equality):\n * 1. event_name\n * 2. event_time (unix seconds; `Math.round(event.timestamp / 1000)`)\n * 3. action_source (default 'WEB')\n * 4. event_id\n * 5. user_data (hashed per Snapchat's PII requirements)\n * 6. custom_data (mapped event data, excluding user_data/custom_data keys)\n * 7. event_source_url (appended last when action_source === 'WEB')\n */\nconst ENDPOINT =\n 'https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t';\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.',\n in: getEvent('order complete', {\n timestamp: 1700000900000,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: { id: 'SKU-A1', name: 'Widget Pro', price: 124.99, quantity: 2 },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'server',\n id: 'https://shop.example.com/checkout/complete',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'PURCHASE',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n transaction_id: 'data.id',\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n user_data: {\n map: {\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'PURCHASE',\n event_time: 1700000900,\n action_source: 'WEB',\n event_id: '1700000900000-gr0up-1',\n user_data: {\n external_id:\n 'fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8',\n },\n custom_data: {\n value: 249.99,\n currency: 'EUR',\n transaction_id: 'ORD-300',\n contents: [{ id: 'SKU-A1', item_price: 124.99, quantity: 2 }],\n },\n event_source_url: 'https://shop.example.com/checkout/complete',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to Snapchat as an ADD_CART conversion with value and product details.',\n in: getEvent('product add', {\n timestamp: 1700000901000,\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n color: 'blue',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n quantity: 1,\n },\n },\n ],\n source: {\n type: 'server',\n id: 'https://shop.example.com/products/running-shoes',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'ADD_CART',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'ADD_CART',\n event_time: 1700000901,\n action_source: 'WEB',\n event_id: '1700000901000-gr0up-1',\n user_data: {},\n custom_data: {\n value: 89.99,\n currency: 'EUR',\n contents: [{ id: 'SKU-B2', item_price: 89.99, quantity: 1 }],\n },\n event_source_url: 'https://shop.example.com/products/running-shoes',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const pageView: Flow.StepExample = {\n title: 'Page view',\n description:\n 'A page view is forwarded to Snapchat with the event source URL and no extra custom data.',\n in: getEvent('page view', {\n timestamp: 1700000902000,\n source: {\n type: 'server',\n id: 'https://example.com/docs/',\n previous_id: '',\n },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'page view',\n event_time: 1700000902,\n action_source: 'WEB',\n event_id: '1700000902000-gr0up-1',\n user_data: {},\n custom_data: {},\n event_source_url: 'https://example.com/docs/',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Sign up',\n description:\n 'A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.',\n in: getEvent('form submit', {\n timestamp: 1700000903000,\n data: { type: 'newsletter' },\n user: { email: 'user@example.com' },\n source: {\n type: 'server',\n id: 'https://example.com/contact',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'SIGN_UP',\n data: {\n map: {\n user_data: {\n map: {\n em: 'user.email',\n },\n },\n custom_data: {\n map: {\n sign_up_method: { value: 'newsletter' },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'SIGN_UP',\n event_time: 1700000903,\n action_source: 'WEB',\n event_id: '1700000903000-gr0up-1',\n user_data: {\n // sha256('user@example.com')\n em: 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n custom_data: {\n sign_up_method: 'newsletter',\n },\n event_source_url: 'https://example.com/contact',\n },\n ],\n }),\n ],\n ],\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,cAA4B;;;ACA5B,iBAAkB;AAEX,IAAM,iBAAiB,aAAE,OAAO;AAAA,EACrC,aAAa,aACV,OAAO,EACP,IAAI,CAAC,EACL;AAAA,IACC;AAAA,EACF;AAAA,EACF,SAAS,aAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,eAAe;AAAA,EACnD,KAAK,aACF,OAAO,EACP,IAAI,EACJ;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,eAAe,aACZ,KAAK,CAAC,OAAO,cAAc,SAAS,CAAC,EACrC,SAAS,mCAAmC,EAC5C,SAAS;AAAA,EACZ,WAAW,aACR,MAAM,aAAE,OAAO,CAAC,EAChB,SAAS,sDAAsD,EAC/D,SAAS;AAAA,EACZ,WAAW,aACR,OAAO,aAAE,OAAO,GAAG,aAAE,OAAO,CAAC,EAC7B,SAAS,0DAA0D,EACnE,SAAS;AAAA,EACZ,UAAU,aACP,QAAQ,EACR;AAAA,IACC;AAAA,EACF,EACC,SAAS;AACd,CAAC;;;ACnCD,IAAAC,cAAkB;AAMX,IAAM,gBAAgB,cAAE,OAAO,CAAC,CAAC;;;ACNxC,IAAAC,cAAkB;AAMX,IAAM,0BAA0B,cAAE,MAAM;AAAA,EAC7C,cAAE,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,cAAE,OAAO;AAAA;AACX,CAAC;;;AH9BM,IAAM,eAAW,yBAAY,cAAc;AAC3C,IAAM,cAAU,yBAAY,aAAa;;;AIXhD;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAiBA,IAAM,iBAAiC,aAAa;AAAA,EAClD,IAAI;AAAA,EACJ,MAAM;AAAA,IACJ,QAAQ;AAAA,IACR,YAAY;AAAA,EACd;AACF;AAQO,IAAM,OAAY;AAAA,EACvB,YAAY;AACd;AAEO,IAAM,aAAa,CAAC,YAAY;;;ACnCvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAmC;AAwBnC,IAAM,WACJ;AAEK,IAAM,WAA6B;AAAA,EACxC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,kBAAkB;AAAA,IAC7B,WAAW;AAAA,IACX,MAAM,EAAE,IAAI,WAAW,OAAO,QAAQ,UAAU,MAAM;AAAA,IACtD,QAAQ;AAAA,MACN;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,EAAE,IAAI,UAAU,MAAM,cAAc,OAAO,QAAQ,UAAU,EAAE;AAAA,MACvE;AAAA,IACF;AAAA,IACA,MAAM,EAAE,IAAI,YAAY,QAAQ,aAAa;AAAA,IAC7C,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,EACF,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,aAAa;AAAA,UACX,KAAK;AAAA,YACH,OAAO;AAAA,YACP,UAAU,EAAE,KAAK,iBAAiB,OAAO,MAAM;AAAA,YAC/C,gBAAgB;AAAA,YAChB,UAAU;AAAA,cACR,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,kBACE,WAAW,CAAC,eACV,sBAAS,MAAM,KAAK,OAAO,WAAW;AAAA,kBACxC,KAAK;AAAA,oBACH,IAAI;AAAA,oBACJ,YAAY;AAAA,oBACZ,UAAU,EAAE,KAAK,iBAAiB,OAAO,EAAE;AAAA,kBAC7C;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,WAAW;AAAA,UACT,KAAK;AAAA,YACH,aAAa;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,UACJ;AAAA,YACE,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,UAAU;AAAA,YACV,WAAW;AAAA,cACT,aACE;AAAA,YACJ;AAAA,YACA,aAAa;AAAA,cACX,OAAO;AAAA,cACP,UAAU;AAAA,cACV,gBAAgB;AAAA,cAChB,UAAU,CAAC,EAAE,IAAI,UAAU,YAAY,QAAQ,UAAU,EAAE,CAAC;AAAA,YAC9D;AAAA,YACA,kBAAkB;AAAA,UACpB;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEO,IAAM,YAA8B;AAAA,EACzC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,eAAe;AAAA,IAC1B,WAAW;AAAA,IACX,MAAM;AAAA,MACJ,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,QAAQ;AAAA,QACR,MAAM;AAAA,UACJ,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,OAAO;AAAA,UACP,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,EACF,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,aAAa;AAAA,UACX,KAAK;AAAA,YACH,OAAO;AAAA,YACP,UAAU,EAAE,OAAO,MAAM;AAAA,YACzB,UAAU;AAAA,cACR,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,kBACE,WAAW,CAAC,eACV,sBAAS,MAAM,KAAK,OAAO,WAAW;AAAA,kBACxC,KAAK;AAAA,oBACH,IAAI;AAAA,oBACJ,YAAY;AAAA,oBACZ,UAAU,EAAE,KAAK,iBAAiB,OAAO,EAAE;AAAA,kBAC7C;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,UACJ;AAAA,YACE,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,UAAU;AAAA,YACV,WAAW,CAAC;AAAA,YACZ,aAAa;AAAA,cACX,OAAO;AAAA,cACP,UAAU;AAAA,cACV,UAAU,CAAC,EAAE,IAAI,UAAU,YAAY,OAAO,UAAU,EAAE,CAAC;AAAA,YAC7D;AAAA,YACA,kBAAkB;AAAA,UACpB;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEO,IAAM,WAA6B;AAAA,EACxC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,aAAa;AAAA,IACxB,WAAW;AAAA,IACX,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,EACF,CAAC;AAAA,EACD,SAAS;AAAA,EACT,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,UACJ;AAAA,YACE,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,UAAU;AAAA,YACV,WAAW,CAAC;AAAA,YACZ,aAAa,CAAC;AAAA,YACd,kBAAkB;AAAA,UACpB;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEO,IAAM,OAAyB;AAAA,EACpC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,eAAe;AAAA,IAC1B,WAAW;AAAA,IACX,MAAM,EAAE,MAAM,aAAa;AAAA,IAC3B,MAAM,EAAE,OAAO,mBAAmB;AAAA,IAClC,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,EACF,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,WAAW;AAAA,UACT,KAAK;AAAA,YACH,IAAI;AAAA,UACN;AAAA,QACF;AAAA,QACA,aAAa;AAAA,UACX,KAAK;AAAA,YACH,gBAAgB,EAAE,OAAO,aAAa;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,UACJ;AAAA,YACE,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,UAAU;AAAA,YACV,WAAW;AAAA;AAAA,cAET,IAAI;AAAA,YACN;AAAA,YACA,aAAa;AAAA,cACX,gBAAgB;AAAA,YAClB;AAAA,YACA,kBAAkB;AAAA,UACpB;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":["import_dev","import_dev","import_dev"]}
1
+ {"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Long-lived Conversions API access token from Snapchat Ads Manager',\n ),\n pixelId: z.string().min(1).describe('Snap Pixel ID'),\n url: z\n .string()\n .url()\n .describe(\n 'Custom Conversions API base URL (default https://tr.snapchat.com/v3/)',\n )\n .optional(),\n action_source: z\n .enum(['WEB', 'MOBILE_APP', 'OFFLINE'])\n .describe('Event action source (default WEB)')\n .optional(),\n doNotHash: z\n .array(z.string())\n .describe(\"User data fields to skip hashing (like ['em', 'ph'])\")\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\"Mapping for user data fields (like { em: 'user.email' })\")\n .optional(),\n testMode: z\n .boolean()\n .describe(\n 'When true, sends events to /events/validate instead of /events for testing',\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Snapchat Conversions API Mapping Schema\n * Snapchat CAPI has no event-level mapping configuration\n */\nexport const MappingSchema = z.object({});\n\n/**\n * Type inference from MappingSchema\n */\nexport type Mapping = z.infer<typeof MappingSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Standard Snapchat Conversions API event names (UPPERCASE).\n * https://businesshelp.snapchat.com/s/article/capi-parameters\n */\nexport const StandardEventNameSchema = z.union([\n z.enum([\n 'PAGE_VIEW',\n 'VIEW_CONTENT',\n 'ADD_CART',\n 'ADD_TO_WISHLIST',\n 'START_CHECKOUT',\n 'ADD_BILLING',\n 'PURCHASE',\n 'SIGN_UP',\n 'SEARCH',\n 'SAVE',\n 'SUBSCRIBE',\n 'COMPLETE_TUTORIAL',\n 'START_TRIAL',\n 'AD_CLICK',\n 'AD_VIEW',\n 'APP_OPEN',\n 'LEVEL_COMPLETE',\n 'INVITE',\n 'LOGIN',\n 'SHARE',\n 'RESERVE',\n 'ACHIEVEMENT_UNLOCKED',\n 'SPENT_CREDITS',\n 'RATE',\n 'LIST_VIEW',\n 'CUSTOM_EVENT_1',\n 'CUSTOM_EVENT_2',\n 'CUSTOM_EVENT_3',\n 'CUSTOM_EVENT_4',\n 'CUSTOM_EVENT_5',\n ]),\n z.string(), // Allow custom event names\n]);\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for Snapchat Conversions API destination.\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\ntype MockSendServer = (\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n) => Promise<SendResponse>;\n\nconst mockSendServer: MockSendServer = async () => ({\n ok: true,\n data: {\n status: 'OK',\n request_id: 'mock-123',\n },\n});\n\n/**\n * Standard mock environment for push operations.\n *\n * Use this for testing Snapchat Conversions API events without making\n * actual HTTP requests to Snapchat's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * Snapchat Conversions API step examples.\n *\n * At push time, the destination calls `env.sendServer(url, body)` where\n * `url` is `${settings.url}${settings.pixelId}/${path}?access_token=${settings.accessToken}`\n * with `path` = `events` (or `events/validate` when `testMode` is set),\n * and `body` is the JSON-stringified `{ data: [snapchatEvent] }` payload.\n *\n * The test fixture pins `accessToken = 's3cr3t'` and `pixelId = 'p1x3l1d'`,\n * so every endpoint resolves to:\n * https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t\n *\n * Body fields are emitted in the order the destination constructs them\n * (insertion order matters for `JSON.stringify` string equality):\n * 1. event_name\n * 2. event_time (unix seconds; `Math.round(event.timestamp / 1000)`)\n * 3. action_source (default 'WEB')\n * 4. event_id\n * 5. user_data (hashed per Snapchat's PII requirements)\n * 6. custom_data (mapped event data, excluding user_data/custom_data keys)\n * 7. event_source_url (appended last when action_source === 'WEB')\n */\nconst ENDPOINT =\n 'https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t';\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'e1f2a3b4c5d60001',\n timestamp: 1700000900000,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: { id: 'SKU-A1', name: 'Widget Pro', price: 124.99, quantity: 2 },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/checkout/complete',\n },\n }),\n mapping: {\n name: 'PURCHASE',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n transaction_id: 'data.id',\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n user_data: {\n map: {\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'PURCHASE',\n event_time: 1700000900,\n action_source: 'WEB',\n event_id: 'e1f2a3b4c5d60001',\n user_data: {\n external_id:\n 'fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8',\n },\n custom_data: {\n value: 249.99,\n currency: 'EUR',\n transaction_id: 'ORD-300',\n contents: [{ id: 'SKU-A1', item_price: 124.99, quantity: 2 }],\n },\n event_source_url: 'https://shop.example.com/checkout/complete',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to Snapchat as an ADD_CART conversion with value and product details.',\n in: getEvent('product add', {\n id: 'e1f2a3b4c5d60002',\n timestamp: 1700000901000,\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n color: 'blue',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n quantity: 1,\n },\n },\n ],\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products/running-shoes',\n },\n }),\n mapping: {\n name: 'ADD_CART',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'ADD_CART',\n event_time: 1700000901,\n action_source: 'WEB',\n event_id: 'e1f2a3b4c5d60002',\n user_data: {},\n custom_data: {\n value: 89.99,\n currency: 'EUR',\n contents: [{ id: 'SKU-B2', item_price: 89.99, quantity: 1 }],\n },\n event_source_url: 'https://shop.example.com/products/running-shoes',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const pageView: Flow.StepExample = {\n title: 'Page view',\n description:\n 'A page view is forwarded to Snapchat with the event source URL and no extra custom data.',\n in: getEvent('page view', {\n id: 'e1f2a3b4c5d60003',\n timestamp: 1700000902000,\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/docs/',\n },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'page view',\n event_time: 1700000902,\n action_source: 'WEB',\n event_id: 'e1f2a3b4c5d60003',\n user_data: {},\n custom_data: {},\n event_source_url: 'https://example.com/docs/',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Sign up',\n description:\n 'A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.',\n in: getEvent('form submit', {\n id: 'e1f2a3b4c5d60004',\n timestamp: 1700000903000,\n data: { type: 'newsletter' },\n user: { email: 'user@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/contact',\n },\n }),\n mapping: {\n name: 'SIGN_UP',\n data: {\n map: {\n user_data: {\n map: {\n em: 'user.email',\n },\n },\n custom_data: {\n map: {\n sign_up_method: { value: 'newsletter' },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'SIGN_UP',\n event_time: 1700000903,\n action_source: 'WEB',\n event_id: 'e1f2a3b4c5d60004',\n user_data: {\n // sha256('user@example.com')\n em: 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n custom_data: {\n sign_up_method: 'newsletter',\n },\n event_source_url: 'https://example.com/contact',\n },\n ],\n }),\n ],\n ],\n};\n"],"mappings":"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","names":["import_dev","import_dev","import_dev"]}
package/dist/dev.mjs CHANGED
@@ -1 +1 @@
1
- var e=Object.defineProperty,t=(t,a)=>{for(var r in a)e(t,r,{get:a[r],enumerable:!0})},a={};t(a,{MappingSchema:()=>o,SettingsSchema:()=>i,StandardEventNameSchema:()=>c,mapping:()=>u,settings:()=>p});import{zodToSchema as r}from"@walkeros/core/dev";import{z as s}from"@walkeros/core/dev";var i=s.object({accessToken:s.string().min(1).describe("Long-lived Conversions API access token from Snapchat Ads Manager"),pixelId:s.string().min(1).describe("Snap Pixel ID"),url:s.string().url().describe("Custom Conversions API base URL (default https://tr.snapchat.com/v3/)").optional(),action_source:s.enum(["WEB","MOBILE_APP","OFFLINE"]).describe("Event action source (default WEB)").optional(),doNotHash:s.array(s.string()).describe("User data fields to skip hashing (like ['em', 'ph'])").optional(),user_data:s.record(s.string(),s.string()).describe("Mapping for user data fields (like { em: 'user.email' })").optional(),testMode:s.boolean().describe("When true, sends events to /events/validate instead of /events for testing").optional()});import{z as n}from"@walkeros/core/dev";var o=n.object({});import{z as d}from"@walkeros/core/dev";var c=d.union([d.enum(["PAGE_VIEW","VIEW_CONTENT","ADD_CART","ADD_TO_WISHLIST","START_CHECKOUT","ADD_BILLING","PURCHASE","SIGN_UP","SEARCH","SAVE","SUBSCRIBE","COMPLETE_TUTORIAL","START_TRIAL","AD_CLICK","AD_VIEW","APP_OPEN","LEVEL_COMPLETE","INVITE","LOGIN","SHARE","RESERVE","ACHIEVEMENT_UNLOCKED","SPENT_CREDITS","RATE","LIST_VIEW","CUSTOM_EVENT_1","CUSTOM_EVENT_2","CUSTOM_EVENT_3","CUSTOM_EVENT_4","CUSTOM_EVENT_5"]),d.string()]),p=r(i),u=r(o),m={};t(m,{env:()=>_,step:()=>E});var _={};t(_,{push:()=>l,simulation:()=>v});var l={sendServer:async()=>({ok:!0,data:{status:"OK",request_id:"mock-123"}})},v=["sendServer"],E={};t(E,{addToCart:()=>T,lead:()=>f,pageView:()=>y,purchase:()=>A});import{getEvent as S,isObject as h}from"@walkeros/core";var g="https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t",A={title:"Purchase",description:"A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.",in:S("order complete",{timestamp:17000009e5,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Widget Pro",price:124.99,quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"server",id:"https://shop.example.com/checkout/complete",previous_id:""}}),mapping:{name:"PURCHASE",data:{map:{custom_data:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"},transaction_id:"data.id",contents:{loop:["nested",{condition:e=>h(e)&&"product"===e.entity,map:{id:"data.id",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}},user_data:{map:{external_id:"user.id"}}}}},out:[["sendServer",g,JSON.stringify({data:[{event_name:"PURCHASE",event_time:1700000900,action_source:"WEB",event_id:"1700000900000-gr0up-1",user_data:{external_id:"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"},custom_data:{value:249.99,currency:"EUR",transaction_id:"ORD-300",contents:[{id:"SKU-A1",item_price:124.99,quantity:2}]},event_source_url:"https://shop.example.com/checkout/complete"}]})]]},T={title:"Add to cart",description:"A product add is sent to Snapchat as an ADD_CART conversion with value and product details.",in:S("product add",{timestamp:1700000901e3,data:{id:"SKU-B2",name:"Running Shoes",price:89.99,color:"blue"},nested:[{entity:"product",data:{id:"SKU-B2",name:"Running Shoes",price:89.99,quantity:1}}],source:{type:"server",id:"https://shop.example.com/products/running-shoes",previous_id:""}}),mapping:{name:"ADD_CART",data:{map:{custom_data:{map:{value:"data.price",currency:{value:"EUR"},contents:{loop:["nested",{condition:e=>h(e)&&"product"===e.entity,map:{id:"data.id",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",g,JSON.stringify({data:[{event_name:"ADD_CART",event_time:1700000901,action_source:"WEB",event_id:"1700000901000-gr0up-1",user_data:{},custom_data:{value:89.99,currency:"EUR",contents:[{id:"SKU-B2",item_price:89.99,quantity:1}]},event_source_url:"https://shop.example.com/products/running-shoes"}]})]]},y={title:"Page view",description:"A page view is forwarded to Snapchat with the event source URL and no extra custom data.",in:S("page view",{timestamp:1700000902e3,source:{type:"server",id:"https://example.com/docs/",previous_id:""}}),mapping:void 0,out:[["sendServer",g,JSON.stringify({data:[{event_name:"page view",event_time:1700000902,action_source:"WEB",event_id:"1700000902000-gr0up-1",user_data:{},custom_data:{},event_source_url:"https://example.com/docs/"}]})]]},f={title:"Sign up",description:"A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.",in:S("form submit",{timestamp:1700000903e3,data:{type:"newsletter"},user:{email:"user@example.com"},source:{type:"server",id:"https://example.com/contact",previous_id:""}}),mapping:{name:"SIGN_UP",data:{map:{user_data:{map:{em:"user.email"}},custom_data:{map:{sign_up_method:{value:"newsletter"}}}}}},out:[["sendServer",g,JSON.stringify({data:[{event_name:"SIGN_UP",event_time:1700000903,action_source:"WEB",event_id:"1700000903000-gr0up-1",user_data:{em:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"},custom_data:{sign_up_method:"newsletter"},event_source_url:"https://example.com/contact"}]})]]};export{m as examples,a as schemas};//# sourceMappingURL=dev.mjs.map
1
+ var e=Object.defineProperty,t=(t,a)=>{for(var r in a)e(t,r,{get:a[r],enumerable:!0})},a={};t(a,{MappingSchema:()=>o,SettingsSchema:()=>s,StandardEventNameSchema:()=>d,mapping:()=>m,settings:()=>p});import{zodToSchema as r}from"@walkeros/core/dev";import{z as n}from"@walkeros/core/dev";var s=n.object({accessToken:n.string().min(1).describe("Long-lived Conversions API access token from Snapchat Ads Manager"),pixelId:n.string().min(1).describe("Snap Pixel ID"),url:n.string().url().describe("Custom Conversions API base URL (default https://tr.snapchat.com/v3/)").optional(),action_source:n.enum(["WEB","MOBILE_APP","OFFLINE"]).describe("Event action source (default WEB)").optional(),doNotHash:n.array(n.string()).describe("User data fields to skip hashing (like ['em', 'ph'])").optional(),user_data:n.record(n.string(),n.string()).describe("Mapping for user data fields (like { em: 'user.email' })").optional(),testMode:n.boolean().describe("When true, sends events to /events/validate instead of /events for testing").optional()});import{z as i}from"@walkeros/core/dev";var o=i.object({});import{z as c}from"@walkeros/core/dev";var d=c.union([c.enum(["PAGE_VIEW","VIEW_CONTENT","ADD_CART","ADD_TO_WISHLIST","START_CHECKOUT","ADD_BILLING","PURCHASE","SIGN_UP","SEARCH","SAVE","SUBSCRIBE","COMPLETE_TUTORIAL","START_TRIAL","AD_CLICK","AD_VIEW","APP_OPEN","LEVEL_COMPLETE","INVITE","LOGIN","SHARE","RESERVE","ACHIEVEMENT_UNLOCKED","SPENT_CREDITS","RATE","LIST_VIEW","CUSTOM_EVENT_1","CUSTOM_EVENT_2","CUSTOM_EVENT_3","CUSTOM_EVENT_4","CUSTOM_EVENT_5"]),c.string()]),p=r(s),m=r(o),u={};t(u,{env:()=>_,step:()=>E});var _={};t(_,{push:()=>l,simulation:()=>v});var l={sendServer:async()=>({ok:!0,data:{status:"OK",request_id:"mock-123"}})},v=["sendServer"],E={};t(E,{addToCart:()=>A,lead:()=>T,pageView:()=>g,purchase:()=>b});import{getEvent as S,isObject as h}from"@walkeros/core";var f="https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t",b={title:"Purchase",description:"A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.",in:S("order complete",{id:"e1f2a3b4c5d60001",timestamp:17000009e5,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Widget Pro",price:124.99,quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/checkout/complete"}}),mapping:{name:"PURCHASE",data:{map:{custom_data:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"},transaction_id:"data.id",contents:{loop:["nested",{condition:e=>h(e)&&"product"===e.entity,map:{id:"data.id",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}},user_data:{map:{external_id:"user.id"}}}}},out:[["sendServer",f,JSON.stringify({data:[{event_name:"PURCHASE",event_time:1700000900,action_source:"WEB",event_id:"e1f2a3b4c5d60001",user_data:{external_id:"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"},custom_data:{value:249.99,currency:"EUR",transaction_id:"ORD-300",contents:[{id:"SKU-A1",item_price:124.99,quantity:2}]},event_source_url:"https://shop.example.com/checkout/complete"}]})]]},A={title:"Add to cart",description:"A product add is sent to Snapchat as an ADD_CART conversion with value and product details.",in:S("product add",{id:"e1f2a3b4c5d60002",timestamp:1700000901e3,data:{id:"SKU-B2",name:"Running Shoes",price:89.99,color:"blue"},nested:[{entity:"product",data:{id:"SKU-B2",name:"Running Shoes",price:89.99,quantity:1}}],source:{type:"browser",platform:"web",url:"https://shop.example.com/products/running-shoes"}}),mapping:{name:"ADD_CART",data:{map:{custom_data:{map:{value:"data.price",currency:{value:"EUR"},contents:{loop:["nested",{condition:e=>h(e)&&"product"===e.entity,map:{id:"data.id",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",f,JSON.stringify({data:[{event_name:"ADD_CART",event_time:1700000901,action_source:"WEB",event_id:"e1f2a3b4c5d60002",user_data:{},custom_data:{value:89.99,currency:"EUR",contents:[{id:"SKU-B2",item_price:89.99,quantity:1}]},event_source_url:"https://shop.example.com/products/running-shoes"}]})]]},g={title:"Page view",description:"A page view is forwarded to Snapchat with the event source URL and no extra custom data.",in:S("page view",{id:"e1f2a3b4c5d60003",timestamp:1700000902e3,source:{type:"browser",platform:"web",url:"https://example.com/docs/"}}),mapping:void 0,out:[["sendServer",f,JSON.stringify({data:[{event_name:"page view",event_time:1700000902,action_source:"WEB",event_id:"e1f2a3b4c5d60003",user_data:{},custom_data:{},event_source_url:"https://example.com/docs/"}]})]]},T={title:"Sign up",description:"A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.",in:S("form submit",{id:"e1f2a3b4c5d60004",timestamp:1700000903e3,data:{type:"newsletter"},user:{email:"user@example.com"},source:{type:"browser",platform:"web",url:"https://example.com/contact"}}),mapping:{name:"SIGN_UP",data:{map:{user_data:{map:{em:"user.email"}},custom_data:{map:{sign_up_method:{value:"newsletter"}}}}}},out:[["sendServer",f,JSON.stringify({data:[{event_name:"SIGN_UP",event_time:1700000903,action_source:"WEB",event_id:"e1f2a3b4c5d60004",user_data:{em:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"},custom_data:{sign_up_method:"newsletter"},event_source_url:"https://example.com/contact"}]})]]};export{u as examples,a as schemas};//# sourceMappingURL=dev.mjs.map
package/dist/dev.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Long-lived Conversions API access token from Snapchat Ads Manager',\n ),\n pixelId: z.string().min(1).describe('Snap Pixel ID'),\n url: z\n .string()\n .url()\n .describe(\n 'Custom Conversions API base URL (default https://tr.snapchat.com/v3/)',\n )\n .optional(),\n action_source: z\n .enum(['WEB', 'MOBILE_APP', 'OFFLINE'])\n .describe('Event action source (default WEB)')\n .optional(),\n doNotHash: z\n .array(z.string())\n .describe(\"User data fields to skip hashing (like ['em', 'ph'])\")\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\"Mapping for user data fields (like { em: 'user.email' })\")\n .optional(),\n testMode: z\n .boolean()\n .describe(\n 'When true, sends events to /events/validate instead of /events for testing',\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Snapchat Conversions API Mapping Schema\n * Snapchat CAPI has no event-level mapping configuration\n */\nexport const MappingSchema = z.object({});\n\n/**\n * Type inference from MappingSchema\n */\nexport type Mapping = z.infer<typeof MappingSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Standard Snapchat Conversions API event names (UPPERCASE).\n * https://businesshelp.snapchat.com/s/article/capi-parameters\n */\nexport const StandardEventNameSchema = z.union([\n z.enum([\n 'PAGE_VIEW',\n 'VIEW_CONTENT',\n 'ADD_CART',\n 'ADD_TO_WISHLIST',\n 'START_CHECKOUT',\n 'ADD_BILLING',\n 'PURCHASE',\n 'SIGN_UP',\n 'SEARCH',\n 'SAVE',\n 'SUBSCRIBE',\n 'COMPLETE_TUTORIAL',\n 'START_TRIAL',\n 'AD_CLICK',\n 'AD_VIEW',\n 'APP_OPEN',\n 'LEVEL_COMPLETE',\n 'INVITE',\n 'LOGIN',\n 'SHARE',\n 'RESERVE',\n 'ACHIEVEMENT_UNLOCKED',\n 'SPENT_CREDITS',\n 'RATE',\n 'LIST_VIEW',\n 'CUSTOM_EVENT_1',\n 'CUSTOM_EVENT_2',\n 'CUSTOM_EVENT_3',\n 'CUSTOM_EVENT_4',\n 'CUSTOM_EVENT_5',\n ]),\n z.string(), // Allow custom event names\n]);\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for Snapchat Conversions API destination.\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\ntype MockSendServer = (\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n) => Promise<SendResponse>;\n\nconst mockSendServer: MockSendServer = async () => ({\n ok: true,\n data: {\n status: 'OK',\n request_id: 'mock-123',\n },\n});\n\n/**\n * Standard mock environment for push operations.\n *\n * Use this for testing Snapchat Conversions API events without making\n * actual HTTP requests to Snapchat's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * Snapchat Conversions API step examples.\n *\n * At push time, the destination calls `env.sendServer(url, body)` where\n * `url` is `${settings.url}${settings.pixelId}/${path}?access_token=${settings.accessToken}`\n * with `path` = `events` (or `events/validate` when `testMode` is set),\n * and `body` is the JSON-stringified `{ data: [snapchatEvent] }` payload.\n *\n * The test fixture pins `accessToken = 's3cr3t'` and `pixelId = 'p1x3l1d'`,\n * so every endpoint resolves to:\n * https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t\n *\n * Body fields are emitted in the order the destination constructs them\n * (insertion order matters for `JSON.stringify` string equality):\n * 1. event_name\n * 2. event_time (unix seconds; `Math.round(event.timestamp / 1000)`)\n * 3. action_source (default 'WEB')\n * 4. event_id\n * 5. user_data (hashed per Snapchat's PII requirements)\n * 6. custom_data (mapped event data, excluding user_data/custom_data keys)\n * 7. event_source_url (appended last when action_source === 'WEB')\n */\nconst ENDPOINT =\n 'https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t';\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.',\n in: getEvent('order complete', {\n timestamp: 1700000900000,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: { id: 'SKU-A1', name: 'Widget Pro', price: 124.99, quantity: 2 },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'server',\n id: 'https://shop.example.com/checkout/complete',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'PURCHASE',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n transaction_id: 'data.id',\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n user_data: {\n map: {\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'PURCHASE',\n event_time: 1700000900,\n action_source: 'WEB',\n event_id: '1700000900000-gr0up-1',\n user_data: {\n external_id:\n 'fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8',\n },\n custom_data: {\n value: 249.99,\n currency: 'EUR',\n transaction_id: 'ORD-300',\n contents: [{ id: 'SKU-A1', item_price: 124.99, quantity: 2 }],\n },\n event_source_url: 'https://shop.example.com/checkout/complete',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to Snapchat as an ADD_CART conversion with value and product details.',\n in: getEvent('product add', {\n timestamp: 1700000901000,\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n color: 'blue',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n quantity: 1,\n },\n },\n ],\n source: {\n type: 'server',\n id: 'https://shop.example.com/products/running-shoes',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'ADD_CART',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'ADD_CART',\n event_time: 1700000901,\n action_source: 'WEB',\n event_id: '1700000901000-gr0up-1',\n user_data: {},\n custom_data: {\n value: 89.99,\n currency: 'EUR',\n contents: [{ id: 'SKU-B2', item_price: 89.99, quantity: 1 }],\n },\n event_source_url: 'https://shop.example.com/products/running-shoes',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const pageView: Flow.StepExample = {\n title: 'Page view',\n description:\n 'A page view is forwarded to Snapchat with the event source URL and no extra custom data.',\n in: getEvent('page view', {\n timestamp: 1700000902000,\n source: {\n type: 'server',\n id: 'https://example.com/docs/',\n previous_id: '',\n },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'page view',\n event_time: 1700000902,\n action_source: 'WEB',\n event_id: '1700000902000-gr0up-1',\n user_data: {},\n custom_data: {},\n event_source_url: 'https://example.com/docs/',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Sign up',\n description:\n 'A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.',\n in: getEvent('form submit', {\n timestamp: 1700000903000,\n data: { type: 'newsletter' },\n user: { email: 'user@example.com' },\n source: {\n type: 'server',\n id: 'https://example.com/contact',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'SIGN_UP',\n data: {\n map: {\n user_data: {\n map: {\n em: 'user.email',\n },\n },\n custom_data: {\n map: {\n sign_up_method: { value: 'newsletter' },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'SIGN_UP',\n event_time: 1700000903,\n action_source: 'WEB',\n event_id: '1700000903000-gr0up-1',\n user_data: {\n // sha256('user@example.com')\n em: 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n custom_data: {\n sign_up_method: 'newsletter',\n },\n event_source_url: 'https://example.com/contact',\n },\n ],\n }),\n ],\n ],\n};\n"],"mappings":"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","names":["z","z"]}
1
+ {"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Long-lived Conversions API access token from Snapchat Ads Manager',\n ),\n pixelId: z.string().min(1).describe('Snap Pixel ID'),\n url: z\n .string()\n .url()\n .describe(\n 'Custom Conversions API base URL (default https://tr.snapchat.com/v3/)',\n )\n .optional(),\n action_source: z\n .enum(['WEB', 'MOBILE_APP', 'OFFLINE'])\n .describe('Event action source (default WEB)')\n .optional(),\n doNotHash: z\n .array(z.string())\n .describe(\"User data fields to skip hashing (like ['em', 'ph'])\")\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\"Mapping for user data fields (like { em: 'user.email' })\")\n .optional(),\n testMode: z\n .boolean()\n .describe(\n 'When true, sends events to /events/validate instead of /events for testing',\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Snapchat Conversions API Mapping Schema\n * Snapchat CAPI has no event-level mapping configuration\n */\nexport const MappingSchema = z.object({});\n\n/**\n * Type inference from MappingSchema\n */\nexport type Mapping = z.infer<typeof MappingSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Standard Snapchat Conversions API event names (UPPERCASE).\n * https://businesshelp.snapchat.com/s/article/capi-parameters\n */\nexport const StandardEventNameSchema = z.union([\n z.enum([\n 'PAGE_VIEW',\n 'VIEW_CONTENT',\n 'ADD_CART',\n 'ADD_TO_WISHLIST',\n 'START_CHECKOUT',\n 'ADD_BILLING',\n 'PURCHASE',\n 'SIGN_UP',\n 'SEARCH',\n 'SAVE',\n 'SUBSCRIBE',\n 'COMPLETE_TUTORIAL',\n 'START_TRIAL',\n 'AD_CLICK',\n 'AD_VIEW',\n 'APP_OPEN',\n 'LEVEL_COMPLETE',\n 'INVITE',\n 'LOGIN',\n 'SHARE',\n 'RESERVE',\n 'ACHIEVEMENT_UNLOCKED',\n 'SPENT_CREDITS',\n 'RATE',\n 'LIST_VIEW',\n 'CUSTOM_EVENT_1',\n 'CUSTOM_EVENT_2',\n 'CUSTOM_EVENT_3',\n 'CUSTOM_EVENT_4',\n 'CUSTOM_EVENT_5',\n ]),\n z.string(), // Allow custom event names\n]);\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for Snapchat Conversions API destination.\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\ntype MockSendServer = (\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n) => Promise<SendResponse>;\n\nconst mockSendServer: MockSendServer = async () => ({\n ok: true,\n data: {\n status: 'OK',\n request_id: 'mock-123',\n },\n});\n\n/**\n * Standard mock environment for push operations.\n *\n * Use this for testing Snapchat Conversions API events without making\n * actual HTTP requests to Snapchat's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * Snapchat Conversions API step examples.\n *\n * At push time, the destination calls `env.sendServer(url, body)` where\n * `url` is `${settings.url}${settings.pixelId}/${path}?access_token=${settings.accessToken}`\n * with `path` = `events` (or `events/validate` when `testMode` is set),\n * and `body` is the JSON-stringified `{ data: [snapchatEvent] }` payload.\n *\n * The test fixture pins `accessToken = 's3cr3t'` and `pixelId = 'p1x3l1d'`,\n * so every endpoint resolves to:\n * https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t\n *\n * Body fields are emitted in the order the destination constructs them\n * (insertion order matters for `JSON.stringify` string equality):\n * 1. event_name\n * 2. event_time (unix seconds; `Math.round(event.timestamp / 1000)`)\n * 3. action_source (default 'WEB')\n * 4. event_id\n * 5. user_data (hashed per Snapchat's PII requirements)\n * 6. custom_data (mapped event data, excluding user_data/custom_data keys)\n * 7. event_source_url (appended last when action_source === 'WEB')\n */\nconst ENDPOINT =\n 'https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t';\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'e1f2a3b4c5d60001',\n timestamp: 1700000900000,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: { id: 'SKU-A1', name: 'Widget Pro', price: 124.99, quantity: 2 },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/checkout/complete',\n },\n }),\n mapping: {\n name: 'PURCHASE',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n transaction_id: 'data.id',\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n user_data: {\n map: {\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'PURCHASE',\n event_time: 1700000900,\n action_source: 'WEB',\n event_id: 'e1f2a3b4c5d60001',\n user_data: {\n external_id:\n 'fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8',\n },\n custom_data: {\n value: 249.99,\n currency: 'EUR',\n transaction_id: 'ORD-300',\n contents: [{ id: 'SKU-A1', item_price: 124.99, quantity: 2 }],\n },\n event_source_url: 'https://shop.example.com/checkout/complete',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to Snapchat as an ADD_CART conversion with value and product details.',\n in: getEvent('product add', {\n id: 'e1f2a3b4c5d60002',\n timestamp: 1700000901000,\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n color: 'blue',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n quantity: 1,\n },\n },\n ],\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products/running-shoes',\n },\n }),\n mapping: {\n name: 'ADD_CART',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'ADD_CART',\n event_time: 1700000901,\n action_source: 'WEB',\n event_id: 'e1f2a3b4c5d60002',\n user_data: {},\n custom_data: {\n value: 89.99,\n currency: 'EUR',\n contents: [{ id: 'SKU-B2', item_price: 89.99, quantity: 1 }],\n },\n event_source_url: 'https://shop.example.com/products/running-shoes',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const pageView: Flow.StepExample = {\n title: 'Page view',\n description:\n 'A page view is forwarded to Snapchat with the event source URL and no extra custom data.',\n in: getEvent('page view', {\n id: 'e1f2a3b4c5d60003',\n timestamp: 1700000902000,\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/docs/',\n },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'page view',\n event_time: 1700000902,\n action_source: 'WEB',\n event_id: 'e1f2a3b4c5d60003',\n user_data: {},\n custom_data: {},\n event_source_url: 'https://example.com/docs/',\n },\n ],\n }),\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Sign up',\n description:\n 'A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.',\n in: getEvent('form submit', {\n id: 'e1f2a3b4c5d60004',\n timestamp: 1700000903000,\n data: { type: 'newsletter' },\n user: { email: 'user@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/contact',\n },\n }),\n mapping: {\n name: 'SIGN_UP',\n data: {\n map: {\n user_data: {\n map: {\n em: 'user.email',\n },\n },\n custom_data: {\n map: {\n sign_up_method: { value: 'newsletter' },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'SIGN_UP',\n event_time: 1700000903,\n action_source: 'WEB',\n event_id: 'e1f2a3b4c5d60004',\n user_data: {\n // sha256('user@example.com')\n em: 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n custom_data: {\n sign_up_method: 'newsletter',\n },\n event_source_url: 'https://example.com/contact',\n },\n ],\n }),\n ],\n ],\n};\n"],"mappings":"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","names":["z","z"]}
@@ -57,6 +57,7 @@ var purchase = {
57
57
  title: "Purchase",
58
58
  description: "A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.",
59
59
  in: (0, import_core.getEvent)("order complete", {
60
+ id: "e1f2a3b4c5d60001",
60
61
  timestamp: 17000009e5,
61
62
  data: { id: "ORD-300", total: 249.99, currency: "EUR" },
62
63
  nested: [
@@ -67,9 +68,9 @@ var purchase = {
67
68
  ],
68
69
  user: { id: "user-123", device: "device-456" },
69
70
  source: {
70
- type: "server",
71
- id: "https://shop.example.com/checkout/complete",
72
- previous_id: ""
71
+ type: "browser",
72
+ platform: "web",
73
+ url: "https://shop.example.com/checkout/complete"
73
74
  }
74
75
  }),
75
76
  mapping: {
@@ -114,7 +115,7 @@ var purchase = {
114
115
  event_name: "PURCHASE",
115
116
  event_time: 1700000900,
116
117
  action_source: "WEB",
117
- event_id: "1700000900000-gr0up-1",
118
+ event_id: "e1f2a3b4c5d60001",
118
119
  user_data: {
119
120
  external_id: "fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"
120
121
  },
@@ -135,6 +136,7 @@ var addToCart = {
135
136
  title: "Add to cart",
136
137
  description: "A product add is sent to Snapchat as an ADD_CART conversion with value and product details.",
137
138
  in: (0, import_core.getEvent)("product add", {
139
+ id: "e1f2a3b4c5d60002",
138
140
  timestamp: 1700000901e3,
139
141
  data: {
140
142
  id: "SKU-B2",
@@ -154,9 +156,9 @@ var addToCart = {
154
156
  }
155
157
  ],
156
158
  source: {
157
- type: "server",
158
- id: "https://shop.example.com/products/running-shoes",
159
- previous_id: ""
159
+ type: "browser",
160
+ platform: "web",
161
+ url: "https://shop.example.com/products/running-shoes"
160
162
  }
161
163
  }),
162
164
  mapping: {
@@ -195,7 +197,7 @@ var addToCart = {
195
197
  event_name: "ADD_CART",
196
198
  event_time: 1700000901,
197
199
  action_source: "WEB",
198
- event_id: "1700000901000-gr0up-1",
200
+ event_id: "e1f2a3b4c5d60002",
199
201
  user_data: {},
200
202
  custom_data: {
201
203
  value: 89.99,
@@ -213,11 +215,12 @@ var pageView = {
213
215
  title: "Page view",
214
216
  description: "A page view is forwarded to Snapchat with the event source URL and no extra custom data.",
215
217
  in: (0, import_core.getEvent)("page view", {
218
+ id: "e1f2a3b4c5d60003",
216
219
  timestamp: 1700000902e3,
217
220
  source: {
218
- type: "server",
219
- id: "https://example.com/docs/",
220
- previous_id: ""
221
+ type: "browser",
222
+ platform: "web",
223
+ url: "https://example.com/docs/"
221
224
  }
222
225
  }),
223
226
  mapping: void 0,
@@ -231,7 +234,7 @@ var pageView = {
231
234
  event_name: "page view",
232
235
  event_time: 1700000902,
233
236
  action_source: "WEB",
234
- event_id: "1700000902000-gr0up-1",
237
+ event_id: "e1f2a3b4c5d60003",
235
238
  user_data: {},
236
239
  custom_data: {},
237
240
  event_source_url: "https://example.com/docs/"
@@ -245,13 +248,14 @@ var lead = {
245
248
  title: "Sign up",
246
249
  description: "A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.",
247
250
  in: (0, import_core.getEvent)("form submit", {
251
+ id: "e1f2a3b4c5d60004",
248
252
  timestamp: 1700000903e3,
249
253
  data: { type: "newsletter" },
250
254
  user: { email: "user@example.com" },
251
255
  source: {
252
- type: "server",
253
- id: "https://example.com/contact",
254
- previous_id: ""
256
+ type: "browser",
257
+ platform: "web",
258
+ url: "https://example.com/contact"
255
259
  }
256
260
  }),
257
261
  mapping: {
@@ -281,7 +285,7 @@ var lead = {
281
285
  event_name: "SIGN_UP",
282
286
  event_time: 1700000903,
283
287
  action_source: "WEB",
284
- event_id: "1700000903000-gr0up-1",
288
+ event_id: "e1f2a3b4c5d60004",
285
289
  user_data: {
286
290
  // sha256('user@example.com')
287
291
  em: "b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"
@@ -36,6 +36,7 @@ var purchase = {
36
36
  title: "Purchase",
37
37
  description: "A completed order is sent to the Snapchat Conversions API as a PURCHASE with value, currency, and contents.",
38
38
  in: getEvent("order complete", {
39
+ id: "e1f2a3b4c5d60001",
39
40
  timestamp: 17000009e5,
40
41
  data: { id: "ORD-300", total: 249.99, currency: "EUR" },
41
42
  nested: [
@@ -46,9 +47,9 @@ var purchase = {
46
47
  ],
47
48
  user: { id: "user-123", device: "device-456" },
48
49
  source: {
49
- type: "server",
50
- id: "https://shop.example.com/checkout/complete",
51
- previous_id: ""
50
+ type: "browser",
51
+ platform: "web",
52
+ url: "https://shop.example.com/checkout/complete"
52
53
  }
53
54
  }),
54
55
  mapping: {
@@ -93,7 +94,7 @@ var purchase = {
93
94
  event_name: "PURCHASE",
94
95
  event_time: 1700000900,
95
96
  action_source: "WEB",
96
- event_id: "1700000900000-gr0up-1",
97
+ event_id: "e1f2a3b4c5d60001",
97
98
  user_data: {
98
99
  external_id: "fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"
99
100
  },
@@ -114,6 +115,7 @@ var addToCart = {
114
115
  title: "Add to cart",
115
116
  description: "A product add is sent to Snapchat as an ADD_CART conversion with value and product details.",
116
117
  in: getEvent("product add", {
118
+ id: "e1f2a3b4c5d60002",
117
119
  timestamp: 1700000901e3,
118
120
  data: {
119
121
  id: "SKU-B2",
@@ -133,9 +135,9 @@ var addToCart = {
133
135
  }
134
136
  ],
135
137
  source: {
136
- type: "server",
137
- id: "https://shop.example.com/products/running-shoes",
138
- previous_id: ""
138
+ type: "browser",
139
+ platform: "web",
140
+ url: "https://shop.example.com/products/running-shoes"
139
141
  }
140
142
  }),
141
143
  mapping: {
@@ -174,7 +176,7 @@ var addToCart = {
174
176
  event_name: "ADD_CART",
175
177
  event_time: 1700000901,
176
178
  action_source: "WEB",
177
- event_id: "1700000901000-gr0up-1",
179
+ event_id: "e1f2a3b4c5d60002",
178
180
  user_data: {},
179
181
  custom_data: {
180
182
  value: 89.99,
@@ -192,11 +194,12 @@ var pageView = {
192
194
  title: "Page view",
193
195
  description: "A page view is forwarded to Snapchat with the event source URL and no extra custom data.",
194
196
  in: getEvent("page view", {
197
+ id: "e1f2a3b4c5d60003",
195
198
  timestamp: 1700000902e3,
196
199
  source: {
197
- type: "server",
198
- id: "https://example.com/docs/",
199
- previous_id: ""
200
+ type: "browser",
201
+ platform: "web",
202
+ url: "https://example.com/docs/"
200
203
  }
201
204
  }),
202
205
  mapping: void 0,
@@ -210,7 +213,7 @@ var pageView = {
210
213
  event_name: "page view",
211
214
  event_time: 1700000902,
212
215
  action_source: "WEB",
213
- event_id: "1700000902000-gr0up-1",
216
+ event_id: "e1f2a3b4c5d60003",
214
217
  user_data: {},
215
218
  custom_data: {},
216
219
  event_source_url: "https://example.com/docs/"
@@ -224,13 +227,14 @@ var lead = {
224
227
  title: "Sign up",
225
228
  description: "A newsletter form submission is sent to Snapchat as a SIGN_UP conversion with a hashed email.",
226
229
  in: getEvent("form submit", {
230
+ id: "e1f2a3b4c5d60004",
227
231
  timestamp: 1700000903e3,
228
232
  data: { type: "newsletter" },
229
233
  user: { email: "user@example.com" },
230
234
  source: {
231
- type: "server",
232
- id: "https://example.com/contact",
233
- previous_id: ""
235
+ type: "browser",
236
+ platform: "web",
237
+ url: "https://example.com/contact"
234
238
  }
235
239
  }),
236
240
  mapping: {
@@ -260,7 +264,7 @@ var lead = {
260
264
  event_name: "SIGN_UP",
261
265
  event_time: 1700000903,
262
266
  action_source: "WEB",
263
- event_id: "1700000903000-gr0up-1",
267
+ event_id: "e1f2a3b4c5d60004",
264
268
  user_data: {
265
269
  // sha256('user@example.com')
266
270
  em: "b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"
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,{DestinationSnapchat:()=>types_exports,default:()=>index_default,destinationSnapchat:()=>destinationSnapchat}),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 import_core=require("@walkeros/core"),import_server_core2=require("@walkeros/server-core"),import_server_core=require("@walkeros/server-core"),keysToHash=["em","ph","fn","ln","db","ge","ct","st","zp","country","external_id"];async function hashUserData(userData,doNotHash=[]){const entries=await Promise.all(Object.entries(userData).map(async([key,value])=>void 0===value?[key,value]:function(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}(key,doNotHash)?[key,await(0,import_server_core.getHashServer)(String(value))]:[key,value]));return Object.fromEntries(entries)}var types_exports={},destinationSnapchat={type:"snapchat",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,pixelId:pixelId}=settings;accessToken||logger.throw("Config settings accessToken missing"),pixelId||logger.throw("Config settings pixelId missing");const settingsConfig={action_source:"WEB",url:"https://tr.snapchat.com/v3/",...settings,accessToken:accessToken,pixelId:pixelId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,collector:collector,env:env,logger:logger}){var _a;const{accessToken:accessToken,pixelId:pixelId,action_source:action_source="WEB",doNotHash:doNotHash,url:url="https://tr.snapchat.com/v3/",user_data:user_data,testMode:testMode}=config.settings,eventData=(0,import_core.isObject)(data)?data:{},configData=config.data?await(0,import_core.getMappingValue)(event,config.data):{},userDataCustom=user_data?await(0,import_core.getMappingValue)(event,{map:user_data}):{},eventMappedUserData=(0,import_core.isObject)(eventData.user_data)?eventData.user_data:{},userData={...(0,import_core.isObject)(configData)&&(0,import_core.isObject)(configData.user_data)?configData.user_data:{},...(0,import_core.isObject)(userDataCustom)?userDataCustom:{},...eventMappedUserData},hashedUserData=await hashUserData(userData,doNotHash),customData={};(0,import_core.isObject)(eventData.custom_data)&&Object.assign(customData,eventData.custom_data);for(const[key,value]of Object.entries(eventData))"user_data"!==key&&"custom_data"!==key&&(customData[key]=value);const snapchatEvent={event_name:event.name,event_time:Math.round((event.timestamp||Date.now())/1e3),action_source:action_source,event_id:event.id,user_data:hashedUserData,custom_data:customData};"WEB"===action_source&&(null==(_a=event.source)?void 0:_a.id)&&(snapchatEvent.event_source_url=event.source.id);const body={data:[snapchatEvent]},endpoint=`${url}${pixelId}/${testMode?"events/validate":"events"}?access_token=${accessToken}`;logger.debug("Calling Snapchat Conversions API",{endpoint:endpoint,method:"POST",eventName:snapchatEvent.event_name,eventId:snapchatEvent.event_id});const sendServerFn=(null==env?void 0:env.sendServer)||import_server_core2.sendServer,result=await sendServerFn(endpoint,JSON.stringify(body));logger.debug("Snapchat API response",{ok:!(0,import_core.isObject)(result)||result.ok}),(0,import_core.isObject)(result)&&!1===result.ok&&logger.throw(`Snapchat API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationSnapchat;//# sourceMappingURL=index.js.map
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,{DestinationSnapchat:()=>types_exports,default:()=>index_default,destinationSnapchat:()=>destinationSnapchat}),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 import_core=require("@walkeros/core"),import_server_core2=require("@walkeros/server-core"),import_server_core=require("@walkeros/server-core"),keysToHash=["em","ph","fn","ln","db","ge","ct","st","zp","country","external_id"];async function hashUserData(userData,doNotHash=[]){const entries=await Promise.all(Object.entries(userData).map(async([key,value])=>void 0===value?[key,value]:function(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}(key,doNotHash)?[key,await(0,import_server_core.getHashServer)(String(value))]:[key,value]));return Object.fromEntries(entries)}var types_exports={},destinationSnapchat={type:"snapchat",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,pixelId:pixelId}=settings;accessToken||logger.throw("Config settings accessToken missing"),pixelId||logger.throw("Config settings pixelId missing");const settingsConfig={action_source:"WEB",url:"https://tr.snapchat.com/v3/",...settings,accessToken:accessToken,pixelId:pixelId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,collector:collector,env:env,logger:logger}){const{accessToken:accessToken,pixelId:pixelId,action_source:action_source="WEB",doNotHash:doNotHash,url:url="https://tr.snapchat.com/v3/",user_data:user_data,testMode:testMode}=config.settings,eventData=(0,import_core.isObject)(data)?data:{},configData=config.data?await(0,import_core.getMappingValue)(event,config.data,{collector:collector}):{},userDataCustom=user_data?await(0,import_core.getMappingValue)(event,{map:user_data},{collector:collector}):{},eventMappedUserData=(0,import_core.isObject)(eventData.user_data)?eventData.user_data:{},userData={...(0,import_core.isObject)(configData)&&(0,import_core.isObject)(configData.user_data)?configData.user_data:{},...(0,import_core.isObject)(userDataCustom)?userDataCustom:{},...eventMappedUserData},hashedUserData=await hashUserData(userData,doNotHash),customData={};(0,import_core.isObject)(eventData.custom_data)&&Object.assign(customData,eventData.custom_data);for(const[key,value]of Object.entries(eventData))"user_data"!==key&&"custom_data"!==key&&(customData[key]=value);const snapchatEvent={event_name:event.name,event_time:Math.round((event.timestamp||Date.now())/1e3),action_source:action_source,event_id:event.id,user_data:hashedUserData,custom_data:customData};"WEB"===action_source&&event.source?.url&&(snapchatEvent.event_source_url=event.source.url);const body={data:[snapchatEvent]},endpoint=`${url}${pixelId}/${testMode?"events/validate":"events"}?access_token=${accessToken}`;logger.debug("Calling Snapchat Conversions API",{endpoint:endpoint,method:"POST",eventName:snapchatEvent.event_name,eventId:snapchatEvent.event_id});const sendServerFn=env?.sendServer||import_server_core2.sendServer,result=await sendServerFn(endpoint,JSON.stringify(body));logger.debug("Snapchat API response",{ok:!(0,import_core.isObject)(result)||result.ok}),(0,import_core.isObject)(result)&&!1===result.ok&&logger.throw(`Snapchat API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationSnapchat;//# 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 DestinationSnapchat from './types';\n\nexport const destinationSnapchat: Destination = {\n type: 'snapchat',\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 destinationSnapchat;\n","import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, pixelId } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!pixelId) logger.throw('Config settings pixelId missing');\n\n const settingsConfig: Settings = {\n action_source: 'WEB',\n url: 'https://tr.snapchat.com/v3/',\n ...settings,\n accessToken,\n pixelId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n CustomData,\n Env,\n PushFn,\n RequestBody,\n Settings,\n SnapchatEvent,\n UserData,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashUserData } from './hash';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const {\n accessToken,\n pixelId,\n action_source = 'WEB',\n doNotHash,\n url = 'https://tr.snapchat.com/v3/',\n user_data,\n testMode,\n } = config.settings as Settings;\n\n const eventData = isObject(data) ? data : {};\n const configData = config.data\n ? await getMappingValue(event, config.data)\n : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data })\n : {};\n\n // Build user_data from three merge sources (priority: later overrides earlier)\n const eventMappedUserData = isObject(eventData.user_data)\n ? (eventData.user_data as UserData)\n : {};\n\n const userData: UserData = {\n // Destination config data\n ...(isObject(configData) && isObject(configData.user_data)\n ? (configData.user_data as UserData)\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? (userDataCustom as UserData) : {}),\n // Event mapping data\n ...eventMappedUserData,\n };\n\n // Hash identity fields\n const hashedUserData = await hashUserData(userData, doNotHash);\n\n // Build custom_data from mapped event data, excluding the user_data key\n // and any explicit custom_data nesting from the mapping\n const customData: CustomData = {};\n if (isObject(eventData.custom_data)) {\n Object.assign(customData, eventData.custom_data);\n }\n for (const [key, value] of Object.entries(eventData)) {\n if (key === 'user_data' || key === 'custom_data') continue;\n customData[key] = value;\n }\n\n // Build Snapchat event\n const snapchatEvent: SnapchatEvent = {\n event_name: event.name,\n event_time: Math.round((event.timestamp || Date.now()) / 1000),\n action_source,\n event_id: event.id,\n user_data: hashedUserData,\n custom_data: customData,\n };\n\n if (action_source === 'WEB' && event.source?.id) {\n snapchatEvent.event_source_url = event.source.id;\n }\n\n const body: RequestBody = { data: [snapchatEvent] };\n\n const path = testMode ? 'events/validate' : 'events';\n const endpoint = `${url}${pixelId}/${path}?access_token=${accessToken}`;\n\n logger.debug('Calling Snapchat Conversions API', {\n endpoint,\n method: 'POST',\n eventName: snapchatEvent.event_name,\n eventId: snapchatEvent.event_id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body));\n\n logger.debug('Snapchat API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Snapchat API error: ${JSON.stringify(result)}`);\n }\n};\n","import type { UserData } from './types';\nimport { getHashServer } from '@walkeros/server-core';\n\n/**\n * Snapchat Conversions API user data fields that must be SHA-256 hashed\n * before sending. Same 11 identity fields as Meta's CAPI.\n * https://businesshelp.snapchat.com/s/article/capi-parameters\n */\nconst keysToHash = [\n 'em',\n 'ph',\n 'fn',\n 'ln',\n 'db',\n 'ge',\n 'ct',\n 'st',\n 'zp',\n 'country',\n 'external_id',\n];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\nexport async function hashUserData(\n userData: UserData,\n doNotHash: string[] = [],\n): Promise<UserData> {\n const entries = await Promise.all(\n Object.entries(userData).map(async ([key, value]) => {\n if (value === undefined) return [key, value];\n if (shouldBeHashed(key, doNotHash)) {\n return [key, await getHashServer(String(value))];\n }\n return [key, value];\n }),\n );\n\n return Object.fromEntries(entries) as UserData;\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 accessToken: string;\n pixelId: string;\n url?: string;\n action_source?: ActionSource;\n doNotHash?: string[];\n user_data?: WalkerOSMapping.Map;\n testMode?: boolean;\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/**\n * Snapchat Conversions API v3\n * https://businesshelp.snapchat.com/s/article/conversions-api\n */\nexport type ActionSource = 'WEB' | 'MOBILE_APP' | 'OFFLINE';\n\nexport interface RequestBody {\n data: SnapchatEvent[];\n}\n\nexport interface SnapchatEvent {\n event_name: string;\n event_time: number;\n action_source: ActionSource;\n event_source_url?: string;\n event_id?: string;\n user_data: UserData;\n custom_data?: CustomData;\n}\n\n// User identity fields. Hashable: em, ph, fn, ln, db, ge, ct, st, zp, country,\n// external_id. Non-hashable: sc_cookie1, client_ip_address, client_user_agent,\n// sc_click_id, idfv, madid.\nexport interface UserData {\n /** Email, SHA-256 hashed, lowercase trimmed */\n em?: string;\n /** Phone number, SHA-256 hashed, E.164 digits */\n ph?: string;\n /** First name, SHA-256 hashed, lowercase */\n fn?: string;\n /** Last name, SHA-256 hashed, lowercase */\n ln?: string;\n /** Date of birth YYYYMMDD, SHA-256 hashed */\n db?: string;\n /** Gender (m/f), SHA-256 hashed */\n ge?: string;\n /** City, SHA-256 hashed, lowercase */\n ct?: string;\n /** State, SHA-256 hashed, lowercase */\n st?: string;\n /** Zip/postal code, SHA-256 hashed */\n zp?: string;\n /** Country code ISO 3166-1 alpha-2, SHA-256 hashed */\n country?: string;\n /** External/customer ID, SHA-256 hash recommended */\n external_id?: string;\n /** Snap cookie. Do NOT hash. */\n sc_cookie1?: string;\n /** Client IP address (IPv4 or IPv6). Do NOT hash. */\n client_ip_address?: string;\n /** Client user agent. Do NOT hash. */\n client_user_agent?: string;\n /** Snap click ID. Do NOT hash. */\n sc_click_id?: string;\n /** iOS IDFV. Do NOT hash. */\n idfv?: string;\n /** Mobile advertiser ID (IDFA/AAID). Do NOT hash. */\n madid?: string;\n}\n\nexport interface CustomData {\n value?: number;\n currency?: string;\n contents?: ContentItem[];\n item_ids?: string[];\n number_items?: number;\n price?: number;\n cart_total?: number;\n search_string?: string;\n item_category?: string;\n brands?: string[];\n description?: string;\n transaction_id?: string;\n payment_info_available?: number;\n delivery_category?: string;\n sign_up_method?: string;\n level?: string;\n [key: string]: unknown;\n}\n\nexport interface ContentItem {\n id?: string;\n quantity?: number;\n item_price?: number;\n brand?: string;\n}\n\nexport interface ResponseBody {\n status: string;\n request_id?: string;\n}\n\n/**\n * Standard Snapchat event names (UPPERCASE).\n * Custom events via CUSTOM_EVENT_1..5 or arbitrary strings.\n */\nexport type StandardEventName =\n | 'PAGE_VIEW'\n | 'VIEW_CONTENT'\n | 'ADD_CART'\n | 'ADD_TO_WISHLIST'\n | 'START_CHECKOUT'\n | 'ADD_BILLING'\n | 'PURCHASE'\n | 'SIGN_UP'\n | 'SEARCH'\n | 'SAVE'\n | 'SUBSCRIBE'\n | 'COMPLETE_TUTORIAL'\n | 'START_TRIAL'\n | 'AD_CLICK'\n | 'AD_VIEW'\n | 'APP_OPEN'\n | 'LEVEL_COMPLETE'\n | 'INVITE'\n | 'LOGIN'\n | 'SHARE'\n | 'RESERVE'\n | 'ACHIEVEMENT_UNLOCKED'\n | 'SPENT_CREDITS'\n | 'RATE'\n | 'LIST_VIEW'\n | 'CUSTOM_EVENT_1'\n | 'CUSTOM_EVENT_2'\n | 'CUSTOM_EVENT_3'\n | 'CUSTOM_EVENT_4'\n | 'CUSTOM_EVENT_5'\n | (string & {});\n"],"mappings":"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","names":["import_server_core"]}
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 DestinationSnapchat from './types';\n\nexport const destinationSnapchat: Destination = {\n type: 'snapchat',\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 destinationSnapchat;\n","import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, pixelId } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!pixelId) logger.throw('Config settings pixelId missing');\n\n const settingsConfig: Settings = {\n action_source: 'WEB',\n url: 'https://tr.snapchat.com/v3/',\n ...settings,\n accessToken,\n pixelId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n CustomData,\n Env,\n PushFn,\n RequestBody,\n Settings,\n SnapchatEvent,\n UserData,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashUserData } from './hash';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const {\n accessToken,\n pixelId,\n action_source = 'WEB',\n doNotHash,\n url = 'https://tr.snapchat.com/v3/',\n user_data,\n testMode,\n } = config.settings as Settings;\n\n const eventData = isObject(data) ? data : {};\n const configData = config.data\n ? await getMappingValue(event, config.data, { collector })\n : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Build user_data from three merge sources (priority: later overrides earlier)\n const eventMappedUserData = isObject(eventData.user_data)\n ? (eventData.user_data as UserData)\n : {};\n\n const userData: UserData = {\n // Destination config data\n ...(isObject(configData) && isObject(configData.user_data)\n ? (configData.user_data as UserData)\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? (userDataCustom as UserData) : {}),\n // Event mapping data\n ...eventMappedUserData,\n };\n\n // Hash identity fields\n const hashedUserData = await hashUserData(userData, doNotHash);\n\n // Build custom_data from mapped event data, excluding the user_data key\n // and any explicit custom_data nesting from the mapping\n const customData: CustomData = {};\n if (isObject(eventData.custom_data)) {\n Object.assign(customData, eventData.custom_data);\n }\n for (const [key, value] of Object.entries(eventData)) {\n if (key === 'user_data' || key === 'custom_data') continue;\n customData[key] = value;\n }\n\n // Build Snapchat event\n const snapchatEvent: SnapchatEvent = {\n event_name: event.name,\n event_time: Math.round((event.timestamp || Date.now()) / 1000),\n action_source,\n event_id: event.id,\n user_data: hashedUserData,\n custom_data: customData,\n };\n\n if (action_source === 'WEB' && event.source?.url) {\n snapchatEvent.event_source_url = event.source.url;\n }\n\n const body: RequestBody = { data: [snapchatEvent] };\n\n const path = testMode ? 'events/validate' : 'events';\n const endpoint = `${url}${pixelId}/${path}?access_token=${accessToken}`;\n\n logger.debug('Calling Snapchat Conversions API', {\n endpoint,\n method: 'POST',\n eventName: snapchatEvent.event_name,\n eventId: snapchatEvent.event_id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body));\n\n logger.debug('Snapchat API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Snapchat API error: ${JSON.stringify(result)}`);\n }\n};\n","import type { UserData } from './types';\nimport { getHashServer } from '@walkeros/server-core';\n\n/**\n * Snapchat Conversions API user data fields that must be SHA-256 hashed\n * before sending. Same 11 identity fields as Meta's CAPI.\n * https://businesshelp.snapchat.com/s/article/capi-parameters\n */\nconst keysToHash = [\n 'em',\n 'ph',\n 'fn',\n 'ln',\n 'db',\n 'ge',\n 'ct',\n 'st',\n 'zp',\n 'country',\n 'external_id',\n];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\nexport async function hashUserData(\n userData: UserData,\n doNotHash: string[] = [],\n): Promise<UserData> {\n const entries = await Promise.all(\n Object.entries(userData).map(async ([key, value]) => {\n if (value === undefined) return [key, value];\n if (shouldBeHashed(key, doNotHash)) {\n return [key, await getHashServer(String(value))];\n }\n return [key, value];\n }),\n );\n\n return Object.fromEntries(entries) as UserData;\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 accessToken: string;\n pixelId: string;\n url?: string;\n action_source?: ActionSource;\n doNotHash?: string[];\n user_data?: WalkerOSMapping.Map;\n testMode?: boolean;\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/**\n * Snapchat Conversions API v3\n * https://businesshelp.snapchat.com/s/article/conversions-api\n */\nexport type ActionSource = 'WEB' | 'MOBILE_APP' | 'OFFLINE';\n\nexport interface RequestBody {\n data: SnapchatEvent[];\n}\n\nexport interface SnapchatEvent {\n event_name: string;\n event_time: number;\n action_source: ActionSource;\n event_source_url?: string;\n event_id?: string;\n user_data: UserData;\n custom_data?: CustomData;\n}\n\n// User identity fields. Hashable: em, ph, fn, ln, db, ge, ct, st, zp, country,\n// external_id. Non-hashable: sc_cookie1, client_ip_address, client_user_agent,\n// sc_click_id, idfv, madid.\nexport interface UserData {\n /** Email, SHA-256 hashed, lowercase trimmed */\n em?: string;\n /** Phone number, SHA-256 hashed, E.164 digits */\n ph?: string;\n /** First name, SHA-256 hashed, lowercase */\n fn?: string;\n /** Last name, SHA-256 hashed, lowercase */\n ln?: string;\n /** Date of birth YYYYMMDD, SHA-256 hashed */\n db?: string;\n /** Gender (m/f), SHA-256 hashed */\n ge?: string;\n /** City, SHA-256 hashed, lowercase */\n ct?: string;\n /** State, SHA-256 hashed, lowercase */\n st?: string;\n /** Zip/postal code, SHA-256 hashed */\n zp?: string;\n /** Country code ISO 3166-1 alpha-2, SHA-256 hashed */\n country?: string;\n /** External/customer ID, SHA-256 hash recommended */\n external_id?: string;\n /** Snap cookie. Do NOT hash. */\n sc_cookie1?: string;\n /** Client IP address (IPv4 or IPv6). Do NOT hash. */\n client_ip_address?: string;\n /** Client user agent. Do NOT hash. */\n client_user_agent?: string;\n /** Snap click ID. Do NOT hash. */\n sc_click_id?: string;\n /** iOS IDFV. Do NOT hash. */\n idfv?: string;\n /** Mobile advertiser ID (IDFA/AAID). Do NOT hash. */\n madid?: string;\n}\n\nexport interface CustomData {\n value?: number;\n currency?: string;\n contents?: ContentItem[];\n item_ids?: string[];\n number_items?: number;\n price?: number;\n cart_total?: number;\n search_string?: string;\n item_category?: string;\n brands?: string[];\n description?: string;\n transaction_id?: string;\n payment_info_available?: number;\n delivery_category?: string;\n sign_up_method?: string;\n level?: string;\n [key: string]: unknown;\n}\n\nexport interface ContentItem {\n id?: string;\n quantity?: number;\n item_price?: number;\n brand?: string;\n}\n\nexport interface ResponseBody {\n status: string;\n request_id?: string;\n}\n\n/**\n * Standard Snapchat event names (UPPERCASE).\n * Custom events via CUSTOM_EVENT_1..5 or arbitrary strings.\n */\nexport type StandardEventName =\n | 'PAGE_VIEW'\n | 'VIEW_CONTENT'\n | 'ADD_CART'\n | 'ADD_TO_WISHLIST'\n | 'START_CHECKOUT'\n | 'ADD_BILLING'\n | 'PURCHASE'\n | 'SIGN_UP'\n | 'SEARCH'\n | 'SAVE'\n | 'SUBSCRIBE'\n | 'COMPLETE_TUTORIAL'\n | 'START_TRIAL'\n | 'AD_CLICK'\n | 'AD_VIEW'\n | 'APP_OPEN'\n | 'LEVEL_COMPLETE'\n | 'INVITE'\n | 'LOGIN'\n | 'SHARE'\n | 'RESERVE'\n | 'ACHIEVEMENT_UNLOCKED'\n | 'SPENT_CREDITS'\n | 'RATE'\n | 'LIST_VIEW'\n | 'CUSTOM_EVENT_1'\n | 'CUSTOM_EVENT_2'\n | 'CUSTOM_EVENT_3'\n | 'CUSTOM_EVENT_4'\n | 'CUSTOM_EVENT_5'\n | (string & {});\n"],"mappings":"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","names":["import_server_core"]}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{getMappingValue,isObject}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{getHashServer}from"@walkeros/server-core";var keysToHash=["em","ph","fn","ln","db","ge","ct","st","zp","country","external_id"];async function hashUserData(userData,doNotHash=[]){const entries=await Promise.all(Object.entries(userData).map(async([key,value])=>void 0===value?[key,value]:function(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}(key,doNotHash)?[key,await getHashServer(String(value))]:[key,value]));return Object.fromEntries(entries)}var types_exports={},destinationSnapchat={type:"snapchat",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,pixelId:pixelId}=settings;accessToken||logger.throw("Config settings accessToken missing"),pixelId||logger.throw("Config settings pixelId missing");const settingsConfig={action_source:"WEB",url:"https://tr.snapchat.com/v3/",...settings,accessToken:accessToken,pixelId:pixelId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,collector:collector,env:env,logger:logger}){var _a;const{accessToken:accessToken,pixelId:pixelId,action_source:action_source="WEB",doNotHash:doNotHash,url:url="https://tr.snapchat.com/v3/",user_data:user_data,testMode:testMode}=config.settings,eventData=isObject(data)?data:{},configData=config.data?await getMappingValue(event,config.data):{},userDataCustom=user_data?await getMappingValue(event,{map:user_data}):{},eventMappedUserData=isObject(eventData.user_data)?eventData.user_data:{},userData={...isObject(configData)&&isObject(configData.user_data)?configData.user_data:{},...isObject(userDataCustom)?userDataCustom:{},...eventMappedUserData},hashedUserData=await hashUserData(userData,doNotHash),customData={};isObject(eventData.custom_data)&&Object.assign(customData,eventData.custom_data);for(const[key,value]of Object.entries(eventData))"user_data"!==key&&"custom_data"!==key&&(customData[key]=value);const snapchatEvent={event_name:event.name,event_time:Math.round((event.timestamp||Date.now())/1e3),action_source:action_source,event_id:event.id,user_data:hashedUserData,custom_data:customData};"WEB"===action_source&&(null==(_a=event.source)?void 0:_a.id)&&(snapchatEvent.event_source_url=event.source.id);const body={data:[snapchatEvent]},endpoint=`${url}${pixelId}/${testMode?"events/validate":"events"}?access_token=${accessToken}`;logger.debug("Calling Snapchat Conversions API",{endpoint:endpoint,method:"POST",eventName:snapchatEvent.event_name,eventId:snapchatEvent.event_id});const sendServerFn=(null==env?void 0:env.sendServer)||sendServer,result=await sendServerFn(endpoint,JSON.stringify(body));logger.debug("Snapchat API response",{ok:!isObject(result)||result.ok}),isObject(result)&&!1===result.ok&&logger.throw(`Snapchat API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationSnapchat;export{types_exports as DestinationSnapchat,index_default as default,destinationSnapchat};//# sourceMappingURL=index.mjs.map
1
+ import{getMappingValue,isObject}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{getHashServer}from"@walkeros/server-core";var keysToHash=["em","ph","fn","ln","db","ge","ct","st","zp","country","external_id"];async function hashUserData(userData,doNotHash=[]){const entries=await Promise.all(Object.entries(userData).map(async([key,value])=>void 0===value?[key,value]:function(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}(key,doNotHash)?[key,await getHashServer(String(value))]:[key,value]));return Object.fromEntries(entries)}var types_exports={},destinationSnapchat={type:"snapchat",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,pixelId:pixelId}=settings;accessToken||logger.throw("Config settings accessToken missing"),pixelId||logger.throw("Config settings pixelId missing");const settingsConfig={action_source:"WEB",url:"https://tr.snapchat.com/v3/",...settings,accessToken:accessToken,pixelId:pixelId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,collector:collector,env:env,logger:logger}){const{accessToken:accessToken,pixelId:pixelId,action_source:action_source="WEB",doNotHash:doNotHash,url:url="https://tr.snapchat.com/v3/",user_data:user_data,testMode:testMode}=config.settings,eventData=isObject(data)?data:{},configData=config.data?await getMappingValue(event,config.data,{collector:collector}):{},userDataCustom=user_data?await getMappingValue(event,{map:user_data},{collector:collector}):{},eventMappedUserData=isObject(eventData.user_data)?eventData.user_data:{},userData={...isObject(configData)&&isObject(configData.user_data)?configData.user_data:{},...isObject(userDataCustom)?userDataCustom:{},...eventMappedUserData},hashedUserData=await hashUserData(userData,doNotHash),customData={};isObject(eventData.custom_data)&&Object.assign(customData,eventData.custom_data);for(const[key,value]of Object.entries(eventData))"user_data"!==key&&"custom_data"!==key&&(customData[key]=value);const snapchatEvent={event_name:event.name,event_time:Math.round((event.timestamp||Date.now())/1e3),action_source:action_source,event_id:event.id,user_data:hashedUserData,custom_data:customData};"WEB"===action_source&&event.source?.url&&(snapchatEvent.event_source_url=event.source.url);const body={data:[snapchatEvent]},endpoint=`${url}${pixelId}/${testMode?"events/validate":"events"}?access_token=${accessToken}`;logger.debug("Calling Snapchat Conversions API",{endpoint:endpoint,method:"POST",eventName:snapchatEvent.event_name,eventId:snapchatEvent.event_id});const sendServerFn=env?.sendServer||sendServer,result=await sendServerFn(endpoint,JSON.stringify(body));logger.debug("Snapchat API response",{ok:!isObject(result)||result.ok}),isObject(result)&&!1===result.ok&&logger.throw(`Snapchat API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationSnapchat;export{types_exports as DestinationSnapchat,index_default as default,destinationSnapchat};//# sourceMappingURL=index.mjs.map
@@ -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 function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, pixelId } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!pixelId) logger.throw('Config settings pixelId missing');\n\n const settingsConfig: Settings = {\n action_source: 'WEB',\n url: 'https://tr.snapchat.com/v3/',\n ...settings,\n accessToken,\n pixelId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n CustomData,\n Env,\n PushFn,\n RequestBody,\n Settings,\n SnapchatEvent,\n UserData,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashUserData } from './hash';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const {\n accessToken,\n pixelId,\n action_source = 'WEB',\n doNotHash,\n url = 'https://tr.snapchat.com/v3/',\n user_data,\n testMode,\n } = config.settings as Settings;\n\n const eventData = isObject(data) ? data : {};\n const configData = config.data\n ? await getMappingValue(event, config.data)\n : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data })\n : {};\n\n // Build user_data from three merge sources (priority: later overrides earlier)\n const eventMappedUserData = isObject(eventData.user_data)\n ? (eventData.user_data as UserData)\n : {};\n\n const userData: UserData = {\n // Destination config data\n ...(isObject(configData) && isObject(configData.user_data)\n ? (configData.user_data as UserData)\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? (userDataCustom as UserData) : {}),\n // Event mapping data\n ...eventMappedUserData,\n };\n\n // Hash identity fields\n const hashedUserData = await hashUserData(userData, doNotHash);\n\n // Build custom_data from mapped event data, excluding the user_data key\n // and any explicit custom_data nesting from the mapping\n const customData: CustomData = {};\n if (isObject(eventData.custom_data)) {\n Object.assign(customData, eventData.custom_data);\n }\n for (const [key, value] of Object.entries(eventData)) {\n if (key === 'user_data' || key === 'custom_data') continue;\n customData[key] = value;\n }\n\n // Build Snapchat event\n const snapchatEvent: SnapchatEvent = {\n event_name: event.name,\n event_time: Math.round((event.timestamp || Date.now()) / 1000),\n action_source,\n event_id: event.id,\n user_data: hashedUserData,\n custom_data: customData,\n };\n\n if (action_source === 'WEB' && event.source?.id) {\n snapchatEvent.event_source_url = event.source.id;\n }\n\n const body: RequestBody = { data: [snapchatEvent] };\n\n const path = testMode ? 'events/validate' : 'events';\n const endpoint = `${url}${pixelId}/${path}?access_token=${accessToken}`;\n\n logger.debug('Calling Snapchat Conversions API', {\n endpoint,\n method: 'POST',\n eventName: snapchatEvent.event_name,\n eventId: snapchatEvent.event_id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body));\n\n logger.debug('Snapchat API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Snapchat API error: ${JSON.stringify(result)}`);\n }\n};\n","import type { UserData } from './types';\nimport { getHashServer } from '@walkeros/server-core';\n\n/**\n * Snapchat Conversions API user data fields that must be SHA-256 hashed\n * before sending. Same 11 identity fields as Meta's CAPI.\n * https://businesshelp.snapchat.com/s/article/capi-parameters\n */\nconst keysToHash = [\n 'em',\n 'ph',\n 'fn',\n 'ln',\n 'db',\n 'ge',\n 'ct',\n 'st',\n 'zp',\n 'country',\n 'external_id',\n];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\nexport async function hashUserData(\n userData: UserData,\n doNotHash: string[] = [],\n): Promise<UserData> {\n const entries = await Promise.all(\n Object.entries(userData).map(async ([key, value]) => {\n if (value === undefined) return [key, value];\n if (shouldBeHashed(key, doNotHash)) {\n return [key, await getHashServer(String(value))];\n }\n return [key, value];\n }),\n );\n\n return Object.fromEntries(entries) as UserData;\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 accessToken: string;\n pixelId: string;\n url?: string;\n action_source?: ActionSource;\n doNotHash?: string[];\n user_data?: WalkerOSMapping.Map;\n testMode?: boolean;\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/**\n * Snapchat Conversions API v3\n * https://businesshelp.snapchat.com/s/article/conversions-api\n */\nexport type ActionSource = 'WEB' | 'MOBILE_APP' | 'OFFLINE';\n\nexport interface RequestBody {\n data: SnapchatEvent[];\n}\n\nexport interface SnapchatEvent {\n event_name: string;\n event_time: number;\n action_source: ActionSource;\n event_source_url?: string;\n event_id?: string;\n user_data: UserData;\n custom_data?: CustomData;\n}\n\n// User identity fields. Hashable: em, ph, fn, ln, db, ge, ct, st, zp, country,\n// external_id. Non-hashable: sc_cookie1, client_ip_address, client_user_agent,\n// sc_click_id, idfv, madid.\nexport interface UserData {\n /** Email, SHA-256 hashed, lowercase trimmed */\n em?: string;\n /** Phone number, SHA-256 hashed, E.164 digits */\n ph?: string;\n /** First name, SHA-256 hashed, lowercase */\n fn?: string;\n /** Last name, SHA-256 hashed, lowercase */\n ln?: string;\n /** Date of birth YYYYMMDD, SHA-256 hashed */\n db?: string;\n /** Gender (m/f), SHA-256 hashed */\n ge?: string;\n /** City, SHA-256 hashed, lowercase */\n ct?: string;\n /** State, SHA-256 hashed, lowercase */\n st?: string;\n /** Zip/postal code, SHA-256 hashed */\n zp?: string;\n /** Country code ISO 3166-1 alpha-2, SHA-256 hashed */\n country?: string;\n /** External/customer ID, SHA-256 hash recommended */\n external_id?: string;\n /** Snap cookie. Do NOT hash. */\n sc_cookie1?: string;\n /** Client IP address (IPv4 or IPv6). Do NOT hash. */\n client_ip_address?: string;\n /** Client user agent. Do NOT hash. */\n client_user_agent?: string;\n /** Snap click ID. Do NOT hash. */\n sc_click_id?: string;\n /** iOS IDFV. Do NOT hash. */\n idfv?: string;\n /** Mobile advertiser ID (IDFA/AAID). Do NOT hash. */\n madid?: string;\n}\n\nexport interface CustomData {\n value?: number;\n currency?: string;\n contents?: ContentItem[];\n item_ids?: string[];\n number_items?: number;\n price?: number;\n cart_total?: number;\n search_string?: string;\n item_category?: string;\n brands?: string[];\n description?: string;\n transaction_id?: string;\n payment_info_available?: number;\n delivery_category?: string;\n sign_up_method?: string;\n level?: string;\n [key: string]: unknown;\n}\n\nexport interface ContentItem {\n id?: string;\n quantity?: number;\n item_price?: number;\n brand?: string;\n}\n\nexport interface ResponseBody {\n status: string;\n request_id?: string;\n}\n\n/**\n * Standard Snapchat event names (UPPERCASE).\n * Custom events via CUSTOM_EVENT_1..5 or arbitrary strings.\n */\nexport type StandardEventName =\n | 'PAGE_VIEW'\n | 'VIEW_CONTENT'\n | 'ADD_CART'\n | 'ADD_TO_WISHLIST'\n | 'START_CHECKOUT'\n | 'ADD_BILLING'\n | 'PURCHASE'\n | 'SIGN_UP'\n | 'SEARCH'\n | 'SAVE'\n | 'SUBSCRIBE'\n | 'COMPLETE_TUTORIAL'\n | 'START_TRIAL'\n | 'AD_CLICK'\n | 'AD_VIEW'\n | 'APP_OPEN'\n | 'LEVEL_COMPLETE'\n | 'INVITE'\n | 'LOGIN'\n | 'SHARE'\n | 'RESERVE'\n | 'ACHIEVEMENT_UNLOCKED'\n | 'SPENT_CREDITS'\n | 'RATE'\n | 'LIST_VIEW'\n | 'CUSTOM_EVENT_1'\n | 'CUSTOM_EVENT_2'\n | 'CUSTOM_EVENT_3'\n | 'CUSTOM_EVENT_4'\n | 'CUSTOM_EVENT_5'\n | (string & {});\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationSnapchat from './types';\n\nexport const destinationSnapchat: Destination = {\n type: 'snapchat',\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 destinationSnapchat;\n"],"mappings":"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","names":[]}
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 function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, pixelId } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!pixelId) logger.throw('Config settings pixelId missing');\n\n const settingsConfig: Settings = {\n action_source: 'WEB',\n url: 'https://tr.snapchat.com/v3/',\n ...settings,\n accessToken,\n pixelId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n CustomData,\n Env,\n PushFn,\n RequestBody,\n Settings,\n SnapchatEvent,\n UserData,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashUserData } from './hash';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const {\n accessToken,\n pixelId,\n action_source = 'WEB',\n doNotHash,\n url = 'https://tr.snapchat.com/v3/',\n user_data,\n testMode,\n } = config.settings as Settings;\n\n const eventData = isObject(data) ? data : {};\n const configData = config.data\n ? await getMappingValue(event, config.data, { collector })\n : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Build user_data from three merge sources (priority: later overrides earlier)\n const eventMappedUserData = isObject(eventData.user_data)\n ? (eventData.user_data as UserData)\n : {};\n\n const userData: UserData = {\n // Destination config data\n ...(isObject(configData) && isObject(configData.user_data)\n ? (configData.user_data as UserData)\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? (userDataCustom as UserData) : {}),\n // Event mapping data\n ...eventMappedUserData,\n };\n\n // Hash identity fields\n const hashedUserData = await hashUserData(userData, doNotHash);\n\n // Build custom_data from mapped event data, excluding the user_data key\n // and any explicit custom_data nesting from the mapping\n const customData: CustomData = {};\n if (isObject(eventData.custom_data)) {\n Object.assign(customData, eventData.custom_data);\n }\n for (const [key, value] of Object.entries(eventData)) {\n if (key === 'user_data' || key === 'custom_data') continue;\n customData[key] = value;\n }\n\n // Build Snapchat event\n const snapchatEvent: SnapchatEvent = {\n event_name: event.name,\n event_time: Math.round((event.timestamp || Date.now()) / 1000),\n action_source,\n event_id: event.id,\n user_data: hashedUserData,\n custom_data: customData,\n };\n\n if (action_source === 'WEB' && event.source?.url) {\n snapchatEvent.event_source_url = event.source.url;\n }\n\n const body: RequestBody = { data: [snapchatEvent] };\n\n const path = testMode ? 'events/validate' : 'events';\n const endpoint = `${url}${pixelId}/${path}?access_token=${accessToken}`;\n\n logger.debug('Calling Snapchat Conversions API', {\n endpoint,\n method: 'POST',\n eventName: snapchatEvent.event_name,\n eventId: snapchatEvent.event_id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body));\n\n logger.debug('Snapchat API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Snapchat API error: ${JSON.stringify(result)}`);\n }\n};\n","import type { UserData } from './types';\nimport { getHashServer } from '@walkeros/server-core';\n\n/**\n * Snapchat Conversions API user data fields that must be SHA-256 hashed\n * before sending. Same 11 identity fields as Meta's CAPI.\n * https://businesshelp.snapchat.com/s/article/capi-parameters\n */\nconst keysToHash = [\n 'em',\n 'ph',\n 'fn',\n 'ln',\n 'db',\n 'ge',\n 'ct',\n 'st',\n 'zp',\n 'country',\n 'external_id',\n];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\nexport async function hashUserData(\n userData: UserData,\n doNotHash: string[] = [],\n): Promise<UserData> {\n const entries = await Promise.all(\n Object.entries(userData).map(async ([key, value]) => {\n if (value === undefined) return [key, value];\n if (shouldBeHashed(key, doNotHash)) {\n return [key, await getHashServer(String(value))];\n }\n return [key, value];\n }),\n );\n\n return Object.fromEntries(entries) as UserData;\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 accessToken: string;\n pixelId: string;\n url?: string;\n action_source?: ActionSource;\n doNotHash?: string[];\n user_data?: WalkerOSMapping.Map;\n testMode?: boolean;\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/**\n * Snapchat Conversions API v3\n * https://businesshelp.snapchat.com/s/article/conversions-api\n */\nexport type ActionSource = 'WEB' | 'MOBILE_APP' | 'OFFLINE';\n\nexport interface RequestBody {\n data: SnapchatEvent[];\n}\n\nexport interface SnapchatEvent {\n event_name: string;\n event_time: number;\n action_source: ActionSource;\n event_source_url?: string;\n event_id?: string;\n user_data: UserData;\n custom_data?: CustomData;\n}\n\n// User identity fields. Hashable: em, ph, fn, ln, db, ge, ct, st, zp, country,\n// external_id. Non-hashable: sc_cookie1, client_ip_address, client_user_agent,\n// sc_click_id, idfv, madid.\nexport interface UserData {\n /** Email, SHA-256 hashed, lowercase trimmed */\n em?: string;\n /** Phone number, SHA-256 hashed, E.164 digits */\n ph?: string;\n /** First name, SHA-256 hashed, lowercase */\n fn?: string;\n /** Last name, SHA-256 hashed, lowercase */\n ln?: string;\n /** Date of birth YYYYMMDD, SHA-256 hashed */\n db?: string;\n /** Gender (m/f), SHA-256 hashed */\n ge?: string;\n /** City, SHA-256 hashed, lowercase */\n ct?: string;\n /** State, SHA-256 hashed, lowercase */\n st?: string;\n /** Zip/postal code, SHA-256 hashed */\n zp?: string;\n /** Country code ISO 3166-1 alpha-2, SHA-256 hashed */\n country?: string;\n /** External/customer ID, SHA-256 hash recommended */\n external_id?: string;\n /** Snap cookie. Do NOT hash. */\n sc_cookie1?: string;\n /** Client IP address (IPv4 or IPv6). Do NOT hash. */\n client_ip_address?: string;\n /** Client user agent. Do NOT hash. */\n client_user_agent?: string;\n /** Snap click ID. Do NOT hash. */\n sc_click_id?: string;\n /** iOS IDFV. Do NOT hash. */\n idfv?: string;\n /** Mobile advertiser ID (IDFA/AAID). Do NOT hash. */\n madid?: string;\n}\n\nexport interface CustomData {\n value?: number;\n currency?: string;\n contents?: ContentItem[];\n item_ids?: string[];\n number_items?: number;\n price?: number;\n cart_total?: number;\n search_string?: string;\n item_category?: string;\n brands?: string[];\n description?: string;\n transaction_id?: string;\n payment_info_available?: number;\n delivery_category?: string;\n sign_up_method?: string;\n level?: string;\n [key: string]: unknown;\n}\n\nexport interface ContentItem {\n id?: string;\n quantity?: number;\n item_price?: number;\n brand?: string;\n}\n\nexport interface ResponseBody {\n status: string;\n request_id?: string;\n}\n\n/**\n * Standard Snapchat event names (UPPERCASE).\n * Custom events via CUSTOM_EVENT_1..5 or arbitrary strings.\n */\nexport type StandardEventName =\n | 'PAGE_VIEW'\n | 'VIEW_CONTENT'\n | 'ADD_CART'\n | 'ADD_TO_WISHLIST'\n | 'START_CHECKOUT'\n | 'ADD_BILLING'\n | 'PURCHASE'\n | 'SIGN_UP'\n | 'SEARCH'\n | 'SAVE'\n | 'SUBSCRIBE'\n | 'COMPLETE_TUTORIAL'\n | 'START_TRIAL'\n | 'AD_CLICK'\n | 'AD_VIEW'\n | 'APP_OPEN'\n | 'LEVEL_COMPLETE'\n | 'INVITE'\n | 'LOGIN'\n | 'SHARE'\n | 'RESERVE'\n | 'ACHIEVEMENT_UNLOCKED'\n | 'SPENT_CREDITS'\n | 'RATE'\n | 'LIST_VIEW'\n | 'CUSTOM_EVENT_1'\n | 'CUSTOM_EVENT_2'\n | 'CUSTOM_EVENT_3'\n | 'CUSTOM_EVENT_4'\n | 'CUSTOM_EVENT_5'\n | (string & {});\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationSnapchat from './types';\n\nexport const destinationSnapchat: Destination = {\n type: 'snapchat',\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 destinationSnapchat;\n"],"mappings":";AAGO,SAAS,UACd,gBAA+B,CAAC,GAChC,QACQ;AACR,QAAM,WAAY,cAAc,YAAY,CAAC;AAC7C,QAAM,EAAE,aAAa,QAAQ,IAAI;AAEjC,MAAI,CAAC,YAAa,QAAO,MAAM,qCAAqC;AACpE,MAAI,CAAC,QAAS,QAAO,MAAM,iCAAiC;AAE5D,QAAM,iBAA2B;AAAA,IAC/B,eAAe;AAAA,IACf,KAAK;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,eAAe,UAAU,eAAe;AACtD;;;ACbA,SAAS,iBAAiB,gBAAgB;AAC1C,SAAS,kBAAkB;;;ACT3B,SAAS,qBAAqB;AAO9B,IAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,eAAe,KAAa,YAAsB,CAAC,GAAY;AACtE,SAAO,WAAW,SAAS,GAAG,KAAK,CAAC,UAAU,SAAS,GAAG;AAC5D;AAEA,eAAsB,aACpB,UACA,YAAsB,CAAC,GACJ;AACnB,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,OAAO,QAAQ,QAAQ,EAAE,IAAI,OAAO,CAAC,KAAK,KAAK,MAAM;AACnD,UAAI,UAAU,OAAW,QAAO,CAAC,KAAK,KAAK;AAC3C,UAAI,eAAe,KAAK,SAAS,GAAG;AAClC,eAAO,CAAC,KAAK,MAAM,cAAc,OAAO,KAAK,CAAC,CAAC;AAAA,MACjD;AACA,aAAO,CAAC,KAAK,KAAK;AAAA,IACpB,CAAC;AAAA,EACH;AAEA,SAAO,OAAO,YAAY,OAAO;AACnC;;;AD5BO,IAAM,OAAe,eAC1B,OACA,EAAE,QAAQ,MAAM,MAAM,WAAW,KAAK,OAAO,GAC7C;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF,IAAI,OAAO;AAEX,QAAM,YAAY,SAAS,IAAI,IAAI,OAAO,CAAC;AAC3C,QAAM,aAAa,OAAO,OACtB,MAAM,gBAAgB,OAAO,OAAO,MAAM,EAAE,UAAU,CAAC,IACvD,CAAC;AACL,QAAM,iBAAiB,YACnB,MAAM,gBAAgB,OAAO,EAAE,KAAK,UAAU,GAAG,EAAE,UAAU,CAAC,IAC9D,CAAC;AAGL,QAAM,sBAAsB,SAAS,UAAU,SAAS,IACnD,UAAU,YACX,CAAC;AAEL,QAAM,WAAqB;AAAA;AAAA,IAEzB,GAAI,SAAS,UAAU,KAAK,SAAS,WAAW,SAAS,IACpD,WAAW,YACZ,CAAC;AAAA;AAAA,IAEL,GAAI,SAAS,cAAc,IAAK,iBAA8B,CAAC;AAAA;AAAA,IAE/D,GAAG;AAAA,EACL;AAGA,QAAM,iBAAiB,MAAM,aAAa,UAAU,SAAS;AAI7D,QAAM,aAAyB,CAAC;AAChC,MAAI,SAAS,UAAU,WAAW,GAAG;AACnC,WAAO,OAAO,YAAY,UAAU,WAAW;AAAA,EACjD;AACA,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,GAAG;AACpD,QAAI,QAAQ,eAAe,QAAQ,cAAe;AAClD,eAAW,GAAG,IAAI;AAAA,EACpB;AAGA,QAAM,gBAA+B;AAAA,IACnC,YAAY,MAAM;AAAA,IAClB,YAAY,KAAK,OAAO,MAAM,aAAa,KAAK,IAAI,KAAK,GAAI;AAAA,IAC7D;AAAA,IACA,UAAU,MAAM;AAAA,IAChB,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAEA,MAAI,kBAAkB,SAAS,MAAM,QAAQ,KAAK;AAChD,kBAAc,mBAAmB,MAAM,OAAO;AAAA,EAChD;AAEA,QAAM,OAAoB,EAAE,MAAM,CAAC,aAAa,EAAE;AAElD,QAAM,OAAO,WAAW,oBAAoB;AAC5C,QAAM,WAAW,GAAG,GAAG,GAAG,OAAO,IAAI,IAAI,iBAAiB,WAAW;AAErE,SAAO,MAAM,oCAAoC;AAAA,IAC/C;AAAA,IACA,QAAQ;AAAA,IACR,WAAW,cAAc;AAAA,IACzB,SAAS,cAAc;AAAA,EACzB,CAAC;AAED,QAAM,eAAgB,KAAa,cAAc;AACjD,QAAM,SAAS,MAAM,aAAa,UAAU,KAAK,UAAU,IAAI,CAAC;AAEhE,SAAO,MAAM,yBAAyB;AAAA,IACpC,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK;AAAA,EACrC,CAAC;AAED,MAAI,SAAS,MAAM,KAAK,OAAO,OAAO,OAAO;AAC3C,WAAO,MAAM,uBAAuB,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,EAC9D;AACF;;;AErGA;;;ACOO,IAAM,sBAAmC;AAAA,EAC9C,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":[]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/server-destination-snapchat",
4
- "version": "3.4.2",
4
+ "version": "4.0.0-next-1777882869103",
5
5
  "type": "destination",
6
6
  "platform": [
7
7
  "server"
@@ -127,22 +127,16 @@
127
127
  "consent": {
128
128
  "functional": true
129
129
  },
130
- "id": "1700000901000-gr0up-1",
130
+ "id": "e1f2a3b4c5d60002",
131
131
  "trigger": "click",
132
132
  "entity": "product",
133
133
  "action": "add",
134
134
  "timestamp": 1700000901000,
135
135
  "timing": 3.14,
136
- "group": "gr0up",
137
- "count": 1,
138
- "version": {
139
- "source": "3.4.2",
140
- "tagging": 1
141
- },
142
136
  "source": {
143
- "type": "server",
144
- "id": "https://shop.example.com/products/running-shoes",
145
- "previous_id": ""
137
+ "type": "browser",
138
+ "platform": "web",
139
+ "url": "https://shop.example.com/products/running-shoes"
146
140
  }
147
141
  },
148
142
  "mapping": {
@@ -182,7 +176,7 @@
182
176
  [
183
177
  "sendServer",
184
178
  "https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t",
185
- "{\"data\":[{\"event_name\":\"ADD_CART\",\"event_time\":1700000901,\"action_source\":\"WEB\",\"event_id\":\"1700000901000-gr0up-1\",\"user_data\":{},\"custom_data\":{\"value\":89.99,\"currency\":\"EUR\",\"contents\":[{\"id\":\"SKU-B2\",\"item_price\":89.99,\"quantity\":1}]},\"event_source_url\":\"https://shop.example.com/products/running-shoes\"}]}"
179
+ "{\"data\":[{\"event_name\":\"ADD_CART\",\"event_time\":1700000901,\"action_source\":\"WEB\",\"event_id\":\"e1f2a3b4c5d60002\",\"user_data\":{},\"custom_data\":{\"value\":89.99,\"currency\":\"EUR\",\"contents\":[{\"id\":\"SKU-B2\",\"item_price\":89.99,\"quantity\":1}]},\"event_source_url\":\"https://shop.example.com/products/running-shoes\"}]}"
186
180
  ]
187
181
  ]
188
182
  },
@@ -214,35 +208,22 @@
214
208
  "entity": "child",
215
209
  "data": {
216
210
  "is": "subordinated"
217
- },
218
- "nested": [],
219
- "context": {
220
- "element": [
221
- "child",
222
- 0
223
- ]
224
211
  }
225
212
  }
226
213
  ],
227
214
  "consent": {
228
215
  "functional": true
229
216
  },
230
- "id": "1700000903000-gr0up-1",
217
+ "id": "e1f2a3b4c5d60004",
231
218
  "trigger": "test",
232
219
  "entity": "form",
233
220
  "action": "submit",
234
221
  "timestamp": 1700000903000,
235
222
  "timing": 3.14,
236
- "group": "gr0up",
237
- "count": 1,
238
- "version": {
239
- "source": "3.4.2",
240
- "tagging": 1
241
- },
242
223
  "source": {
243
- "type": "server",
244
- "id": "https://example.com/contact",
245
- "previous_id": ""
224
+ "type": "browser",
225
+ "platform": "web",
226
+ "url": "https://example.com/contact"
246
227
  }
247
228
  },
248
229
  "mapping": {
@@ -268,7 +249,7 @@
268
249
  [
269
250
  "sendServer",
270
251
  "https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t",
271
- "{\"data\":[{\"event_name\":\"SIGN_UP\",\"event_time\":1700000903,\"action_source\":\"WEB\",\"event_id\":\"1700000903000-gr0up-1\",\"user_data\":{\"em\":\"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514\"},\"custom_data\":{\"sign_up_method\":\"newsletter\"},\"event_source_url\":\"https://example.com/contact\"}]}"
252
+ "{\"data\":[{\"event_name\":\"SIGN_UP\",\"event_time\":1700000903,\"action_source\":\"WEB\",\"event_id\":\"e1f2a3b4c5d60004\",\"user_data\":{\"em\":\"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514\"},\"custom_data\":{\"sign_up_method\":\"newsletter\"},\"event_source_url\":\"https://example.com/contact\"}]}"
272
253
  ]
273
254
  ]
274
255
  },
@@ -307,42 +288,29 @@
307
288
  "entity": "child",
308
289
  "data": {
309
290
  "is": "subordinated"
310
- },
311
- "nested": [],
312
- "context": {
313
- "element": [
314
- "child",
315
- 0
316
- ]
317
291
  }
318
292
  }
319
293
  ],
320
294
  "consent": {
321
295
  "functional": true
322
296
  },
323
- "id": "1700000902000-gr0up-1",
297
+ "id": "e1f2a3b4c5d60003",
324
298
  "trigger": "load",
325
299
  "entity": "page",
326
300
  "action": "view",
327
301
  "timestamp": 1700000902000,
328
302
  "timing": 3.14,
329
- "group": "gr0up",
330
- "count": 1,
331
- "version": {
332
- "source": "3.4.2",
333
- "tagging": 1
334
- },
335
303
  "source": {
336
- "type": "server",
337
- "id": "https://example.com/docs/",
338
- "previous_id": ""
304
+ "type": "browser",
305
+ "platform": "web",
306
+ "url": "https://example.com/docs/"
339
307
  }
340
308
  },
341
309
  "out": [
342
310
  [
343
311
  "sendServer",
344
312
  "https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t",
345
- "{\"data\":[{\"event_name\":\"page view\",\"event_time\":1700000902,\"action_source\":\"WEB\",\"event_id\":\"1700000902000-gr0up-1\",\"user_data\":{},\"custom_data\":{},\"event_source_url\":\"https://example.com/docs/\"}]}"
313
+ "{\"data\":[{\"event_name\":\"page view\",\"event_time\":1700000902,\"action_source\":\"WEB\",\"event_id\":\"e1f2a3b4c5d60003\",\"user_data\":{},\"custom_data\":{},\"event_source_url\":\"https://example.com/docs/\"}]}"
346
314
  ]
347
315
  ]
348
316
  },
@@ -386,22 +354,16 @@
386
354
  "consent": {
387
355
  "functional": true
388
356
  },
389
- "id": "1700000900000-gr0up-1",
357
+ "id": "e1f2a3b4c5d60001",
390
358
  "trigger": "load",
391
359
  "entity": "order",
392
360
  "action": "complete",
393
361
  "timestamp": 1700000900000,
394
362
  "timing": 3.14,
395
- "group": "gr0up",
396
- "count": 1,
397
- "version": {
398
- "source": "3.4.2",
399
- "tagging": 1
400
- },
401
363
  "source": {
402
- "type": "server",
403
- "id": "https://shop.example.com/checkout/complete",
404
- "previous_id": ""
364
+ "type": "browser",
365
+ "platform": "web",
366
+ "url": "https://shop.example.com/checkout/complete"
405
367
  }
406
368
  },
407
369
  "mapping": {
@@ -448,7 +410,7 @@
448
410
  [
449
411
  "sendServer",
450
412
  "https://tr.snapchat.com/v3/p1x3l1d/events?access_token=s3cr3t",
451
- "{\"data\":[{\"event_name\":\"PURCHASE\",\"event_time\":1700000900,\"action_source\":\"WEB\",\"event_id\":\"1700000900000-gr0up-1\",\"user_data\":{\"external_id\":\"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8\"},\"custom_data\":{\"value\":249.99,\"currency\":\"EUR\",\"transaction_id\":\"ORD-300\",\"contents\":[{\"id\":\"SKU-A1\",\"item_price\":124.99,\"quantity\":2}]},\"event_source_url\":\"https://shop.example.com/checkout/complete\"}]}"
413
+ "{\"data\":[{\"event_name\":\"PURCHASE\",\"event_time\":1700000900,\"action_source\":\"WEB\",\"event_id\":\"e1f2a3b4c5d60001\",\"user_data\":{\"external_id\":\"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8\"},\"custom_data\":{\"value\":249.99,\"currency\":\"EUR\",\"transaction_id\":\"ORD-300\",\"contents\":[{\"id\":\"SKU-A1\",\"item_price\":124.99,\"quantity\":2}]},\"event_source_url\":\"https://shop.example.com/checkout/complete\"}]}"
452
414
  ]
453
415
  ]
454
416
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@walkeros/server-destination-snapchat",
3
3
  "description": "Snapchat Conversions API server destination for walkerOS",
4
- "version": "3.4.2",
4
+ "version": "4.0.0-next-1777882869103",
5
5
  "license": "MIT",
6
6
  "exports": {
7
7
  ".": {
@@ -34,11 +34,11 @@
34
34
  "update": "npx npm-check-updates -u && npm update"
35
35
  },
36
36
  "dependencies": {
37
- "@walkeros/core": "3.4.2",
38
- "@walkeros/server-core": "3.4.2"
37
+ "@walkeros/core": "4.0.0-next-1777882869103",
38
+ "@walkeros/server-core": "4.0.0-next-1777882869103"
39
39
  },
40
40
  "devDependencies": {
41
- "@walkeros/collector": "3.4.2"
41
+ "@walkeros/collector": "4.0.0-next-1777882869103"
42
42
  },
43
43
  "repository": {
44
44
  "url": "git+https://github.com/elbwalker/walkerOS.git",