@walkeros/server-destination-reddit 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,i=Object.getOwnPropertyNames,r=Object.prototype.hasOwnProperty,s=(e,a)=>{for(var i in a)t(e,i,{get:a[i],enumerable:!0})},n={};s(n,{examples:()=>y,schemas:()=>d}),module.exports=(e=n,((e,s,n,d)=>{if(s&&"object"==typeof s||"function"==typeof s)for(let o of i(s))r.call(e,o)||o===n||t(e,o,{get:()=>s[o],enumerable:!(d=a(s,o))||d.enumerable});return e})(t({},"__esModule",{value:!0}),e));var d={};s(d,{ActionSourceSchema:()=>u,MappingSchema:()=>l,SettingsSchema:()=>v,TrackingTypeSchema:()=>m,mapping:()=>_,settings:()=>g});var o=require("@walkeros/core/dev"),c=require("@walkeros/core/dev"),p=require("@walkeros/core/dev"),u=p.z.enum(["WEBSITE","APP","PHYSICAL_STORE"]),m=p.z.enum(["PageVisit","ViewContent","Search","AddToCart","AddToWishlist","Purchase","Lead","SignUp","Custom"]),v=c.z.object({accessToken:c.z.string().min(1).describe("Reddit Conversion Access Token for Bearer authentication (like rdt_ABC123...)"),pixelId:c.z.string().min(1).describe("Reddit Pixel ID used as the API path parameter (like a2_abcdef123456)"),action_source:u.describe("Source of the event (WEBSITE, APP, PHYSICAL_STORE) (like WEBSITE)").optional(),doNotHash:c.z.array(c.z.string()).describe("Array of user fields that should not be hashed (like ['email'])").optional(),test_mode:c.z.boolean().describe("Enable test mode by sending test_mode: true in the request body (like true)").optional(),url:c.z.string().url().describe("Custom URL for Reddit Conversions API endpoint (like https://ads-api.reddit.com/api/v2.0/conversions/events/)").optional(),user_data:c.z.record(c.z.string(),c.z.string()).describe("Mapping configuration for user fields (like { email: 'user.email', external_id: 'user.id' })").optional()}),l=require("@walkeros/core/dev").z.object({}),g=(0,o.zodToSchema)(v),_=(0,o.zodToSchema)(l),y={};s(y,{env:()=>h,step:()=>S});var h={};s(h,{push:()=>f,simulation:()=>b});var f={sendServer:async()=>({ok:!0,data:{success:!0}})},b=["sendServer"],S={};s(S,{addToCart:()=>T,lead:()=>R,pageVisit:()=>E,purchase:()=>P,search:()=>z,signUp:()=>x});var w=require("@walkeros/core"),k="https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",A={headers:{Authorization:"Bearer s3cr3t"}},P={title:"Purchase",description:"A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.",in:(0,w.getEvent)("order complete",{timestamp:1700000900,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Everyday Ruck Snack",category:"bags",price:"129.99",quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"server",id:"https://shop.example.com",previous_id:""}}),mapping:{name:"Purchase",data:{map:{event_metadata:{map:{value_decimal:"data.total",currency:{key:"data.currency",value:"EUR"},item_count:{fn:e=>e.nested.filter(e=>"product"===e.entity).length},products:{loop:["nested",{condition:e=>(0,w.isObject)(e)&&"product"===e.entity,map:{id:"data.id",name:"data.name",category:{key:"data.category",value:"uncategorized"}}}]}}}}}},out:[["sendServer",k,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.900Z",event_at_ms:1700000900,event_type:{tracking_type:"Purchase"},user:{},event_metadata:{conversion_id:"1700000900-gr0up-1",value_decimal:249.99,currency:"EUR",item_count:1,products:[{id:"SKU-A1",name:"Everyday Ruck Snack",category:"bags"}]}}]}}),A]]},T={title:"Add to cart",description:"A product add is sent to Reddit as an AddToCart conversion with value and product details.",in:(0,w.getEvent)("product add",{timestamp:1700000901,data:{id:"SKU-B2",name:"Cool Cap",category:"hats",price:"42.00",quantity:1},user:{id:"user-456"},source:{type:"server",id:"https://shop.example.com/products",previous_id:""}}),mapping:{name:"AddToCart",data:{map:{event_metadata:{map:{value_decimal:"data.price",currency:{value:"EUR"},item_count:{value:1},products:{set:[{map:{id:"data.id",name:"data.name",category:{key:"data.category",value:"uncategorized"}}}]}}}}}},out:[["sendServer",k,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.901Z",event_at_ms:1700000901,event_type:{tracking_type:"AddToCart"},user:{},event_metadata:{conversion_id:"1700000901-gr0up-1",value_decimal:"42.00",currency:"EUR",item_count:1,products:[{id:"SKU-B2",name:"Cool Cap",category:"hats"}]}}]}}),A]]},E={title:"Page visit",description:"A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.",in:(0,w.getEvent)("page view",{timestamp:1700000902,user:{id:"user-789"},source:{type:"server",id:"https://www.example.com/docs/",previous_id:""}}),mapping:{name:"PageVisit"},out:[["sendServer",k,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.902Z",event_at_ms:1700000902,event_type:{tracking_type:"PageVisit"},user:{},event_metadata:{conversion_id:"1700000902-gr0up-1"}}]}}),A]]},R={title:"Lead",description:"A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.",in:(0,w.getEvent)("form submit",{timestamp:1700000903,data:{form:"contact"},user:{id:"user-lead-1",email:"lead@example.com"},source:{type:"server",id:"https://www.example.com/contact",previous_id:""}}),mapping:{name:"Lead",data:{map:{user:{map:{email:"user.email",external_id:"user.id"}}}}},out:[["sendServer",k,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.903Z",event_at_ms:1700000903,event_type:{tracking_type:"Lead"},user:{email:"9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2",external_id:"ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8"},event_metadata:{conversion_id:"1700000903-gr0up-1"}}]}}),A]]},x={title:"Sign up",description:"A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.",in:(0,w.getEvent)("user signup",{timestamp:1700000904,data:{method:"email"},user:{id:"new-user-1",email:"new@example.com"},source:{type:"server",id:"https://www.example.com/register",previous_id:""}}),mapping:{name:"SignUp",data:{map:{user:{map:{email:"user.email",external_id:"user.id"}}}}},out:[["sendServer",k,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.904Z",event_at_ms:1700000904,event_type:{tracking_type:"SignUp"},user:{email:"f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716",external_id:"b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"},event_metadata:{conversion_id:"1700000904-gr0up-1"}}]}}),A]]},z={title:"Search",description:"A site search is sent to Reddit as a Search conversion with an item count in event_metadata.",in:(0,w.getEvent)("site search",{timestamp:1700000905,data:{query:"walkerOS destinations"},user:{id:"user-101"},source:{type:"server",id:"https://www.example.com/search",previous_id:""}}),mapping:{name:"Search",data:{map:{event_metadata:{map:{item_count:{value:1}}}}}},out:[["sendServer",k,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.905Z",event_at_ms:1700000905,event_type:{tracking_type:"Search"},user:{},event_metadata:{conversion_id:"1700000905-gr0up-1",item_count:1}}]}}),A]]};//# sourceMappingURL=dev.js.map
1
+ "use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.prototype.hasOwnProperty,n=(e,a)=>{for(var r in a)t(e,r,{get:a[r],enumerable:!0})},s={};n(s,{examples:()=>y,schemas:()=>d}),module.exports=(e=s,((e,n,s,d)=>{if(n&&"object"==typeof n||"function"==typeof n)for(let o of r(n))i.call(e,o)||o===s||t(e,o,{get:()=>n[o],enumerable:!(d=a(n,o))||d.enumerable});return e})(t({},"__esModule",{value:!0}),e));var d={};n(d,{ActionSourceSchema:()=>p,MappingSchema:()=>l,SettingsSchema:()=>v,TrackingTypeSchema:()=>m,mapping:()=>_,settings:()=>g});var o=require("@walkeros/core/dev"),c=require("@walkeros/core/dev"),u=require("@walkeros/core/dev"),p=u.z.enum(["WEBSITE","APP","PHYSICAL_STORE"]),m=u.z.enum(["PageVisit","ViewContent","Search","AddToCart","AddToWishlist","Purchase","Lead","SignUp","Custom"]),v=c.z.object({accessToken:c.z.string().min(1).describe("Reddit Conversion Access Token for Bearer authentication (like rdt_ABC123...)"),pixelId:c.z.string().min(1).describe("Reddit Pixel ID used as the API path parameter (like a2_abcdef123456)"),action_source:p.describe("Source of the event (WEBSITE, APP, PHYSICAL_STORE) (like WEBSITE)").optional(),doNotHash:c.z.array(c.z.string()).describe("Array of user fields that should not be hashed (like ['email'])").optional(),test_mode:c.z.boolean().describe("Enable test mode by sending test_mode: true in the request body (like true)").optional(),url:c.z.string().url().describe("Custom URL for Reddit Conversions API endpoint (like https://ads-api.reddit.com/api/v2.0/conversions/events/)").optional(),user_data:c.z.record(c.z.string(),c.z.string()).describe("Mapping configuration for user fields (like { email: 'user.email', external_id: 'user.id' })").optional()}),l=require("@walkeros/core/dev").z.object({}),g=(0,o.zodToSchema)(v),_=(0,o.zodToSchema)(l),y={};n(y,{env:()=>f,step:()=>S});var f={};n(f,{push:()=>h,simulation:()=>b});var h={sendServer:async()=>({ok:!0,data:{success:!0}})},b=["sendServer"],S={};n(S,{addToCart:()=>E,lead:()=>w,pageVisit:()=>R,purchase:()=>T,search:()=>z,signUp:()=>x});var k=require("@walkeros/core"),A="https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",P={headers:{Authorization:"Bearer s3cr3t"}},T={title:"Purchase",description:"A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.",in:(0,k.getEvent)("order complete",{id:"ev-1700000900",timestamp:1700000900,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Everyday Ruck Snack",category:"bags",price:"129.99",quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"express",platform:"server"}}),mapping:{name:"Purchase",data:{map:{event_metadata:{map:{value_decimal:"data.total",currency:{key:"data.currency",value:"EUR"},item_count:{fn:e=>e.nested.filter(e=>"product"===e.entity).length},products:{loop:["nested",{condition:e=>(0,k.isObject)(e)&&"product"===e.entity,map:{id:"data.id",name:"data.name",category:{key:"data.category",value:"uncategorized"}}}]}}}}}},out:[["sendServer",A,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.900Z",event_at_ms:1700000900,event_type:{tracking_type:"Purchase"},user:{},event_metadata:{conversion_id:"ev-1700000900",value_decimal:249.99,currency:"EUR",item_count:1,products:[{id:"SKU-A1",name:"Everyday Ruck Snack",category:"bags"}]}}]}}),P]]},E={title:"Add to cart",description:"A product add is sent to Reddit as an AddToCart conversion with value and product details.",in:(0,k.getEvent)("product add",{id:"ev-1700000901",timestamp:1700000901,data:{id:"SKU-B2",name:"Cool Cap",category:"hats",price:"42.00",quantity:1},user:{id:"user-456"},source:{type:"express",platform:"server"}}),mapping:{name:"AddToCart",data:{map:{event_metadata:{map:{value_decimal:"data.price",currency:{value:"EUR"},item_count:{value:1},products:{set:[{map:{id:"data.id",name:"data.name",category:{key:"data.category",value:"uncategorized"}}}]}}}}}},out:[["sendServer",A,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.901Z",event_at_ms:1700000901,event_type:{tracking_type:"AddToCart"},user:{},event_metadata:{conversion_id:"ev-1700000901",value_decimal:"42.00",currency:"EUR",item_count:1,products:[{id:"SKU-B2",name:"Cool Cap",category:"hats"}]}}]}}),P]]},R={title:"Page visit",description:"A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.",in:(0,k.getEvent)("page view",{id:"ev-1700000902",timestamp:1700000902,user:{id:"user-789"},source:{type:"express",platform:"server"}}),mapping:{name:"PageVisit"},out:[["sendServer",A,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.902Z",event_at_ms:1700000902,event_type:{tracking_type:"PageVisit"},user:{},event_metadata:{conversion_id:"ev-1700000902"}}]}}),P]]},w={title:"Lead",description:"A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.",in:(0,k.getEvent)("form submit",{id:"ev-1700000903",timestamp:1700000903,data:{form:"contact"},user:{id:"user-lead-1",email:"lead@example.com"},source:{type:"express",platform:"server"}}),mapping:{name:"Lead",data:{map:{user:{map:{email:"user.email",external_id:"user.id"}}}}},out:[["sendServer",A,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.903Z",event_at_ms:1700000903,event_type:{tracking_type:"Lead"},user:{email:"9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2",external_id:"ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8"},event_metadata:{conversion_id:"ev-1700000903"}}]}}),P]]},x={title:"Sign up",description:"A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.",in:(0,k.getEvent)("user signup",{id:"ev-1700000904",timestamp:1700000904,data:{method:"email"},user:{id:"new-user-1",email:"new@example.com"},source:{type:"express",platform:"server"}}),mapping:{name:"SignUp",data:{map:{user:{map:{email:"user.email",external_id:"user.id"}}}}},out:[["sendServer",A,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.904Z",event_at_ms:1700000904,event_type:{tracking_type:"SignUp"},user:{email:"f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716",external_id:"b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"},event_metadata:{conversion_id:"ev-1700000904"}}]}}),P]]},z={title:"Search",description:"A site search is sent to Reddit as a Search conversion with an item count in event_metadata.",in:(0,k.getEvent)("site search",{id:"ev-1700000905",timestamp:1700000905,data:{query:"walkerOS destinations"},user:{id:"user-101"},source:{type:"express",platform:"server"}}),mapping:{name:"Search",data:{map:{event_metadata:{map:{item_count:{value:1}}}}}},out:[["sendServer",A,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.905Z",event_at_ms:1700000905,event_type:{tracking_type:"Search"},user:{},event_metadata:{conversion_id:"ev-1700000905",item_count:1}}]}}),P]]};//# 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/primitives.ts","../src/schemas/mapping.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';\nimport { ActionSourceSchema } from './primitives';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Reddit Conversion Access Token for Bearer authentication (like rdt_ABC123...)',\n ),\n pixelId: z\n .string()\n .min(1)\n .describe(\n 'Reddit Pixel ID used as the API path parameter (like a2_abcdef123456)',\n ),\n action_source: ActionSourceSchema.describe(\n 'Source of the event (WEBSITE, APP, PHYSICAL_STORE) (like WEBSITE)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\"Array of user fields that should not be hashed (like ['email'])\")\n .optional(),\n test_mode: z\n .boolean()\n .describe(\n 'Enable test mode by sending test_mode: true in the request body (like true)',\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for Reddit Conversions API endpoint (like https://ads-api.reddit.com/api/v2.0/conversions/events/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user fields (like { email: 'user.email', external_id: 'user.id' })\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Action Source Enum\n * Where the conversion event took place\n * https://ads-api.reddit.com/docs/v2/#tag/Conversions-API\n */\nexport const ActionSourceSchema = z.enum(['WEBSITE', 'APP', 'PHYSICAL_STORE']);\n\n/**\n * Tracking Type\n * Standard Reddit Conversions API event types.\n * Custom events use `Custom` with a `custom_event_name`.\n */\nexport const TrackingTypeSchema = z.enum([\n 'PageVisit',\n 'ViewContent',\n 'Search',\n 'AddToCart',\n 'AddToWishlist',\n 'Purchase',\n 'Lead',\n 'SignUp',\n 'Custom',\n]);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Reddit Conversions API Mapping Schema\n * Reddit 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","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 Reddit 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\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nconst mockSendServer: MockSendServer = async () => {\n // Simulate successful Reddit API response\n return {\n ok: true,\n data: {\n success: true,\n },\n };\n};\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing Reddit Conversions API events without making\n * actual HTTP requests to Reddit's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow, WalkerOS } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * Reddit Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), options)` where\n * `endpoint = ${settings.url}${settings.pixelId}` and\n * `body = { data: { events: [hashedServerEvent] } }`.\n *\n * Test fixture pins `pixelId = 'a2_abcdef123456'` and the default url, so\n * every endpoint resolves to:\n * https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456\n *\n * The serverEvent keys are assembled in this order (insertion order matters\n * for `JSON.stringify` string equality):\n * 1. event_at (ISO timestamp)\n * 2. event_at_ms\n * 3. event_type ({ tracking_type, custom_event_name? })\n * 4. ...restEventData (mapped event data minus user/event_metadata/click_id)\n * 5. user (hashed — email, external_id, ip_address, user_agent, idfa, aaid)\n * 6. event_metadata (conversion_id first, then merged metadata)\n * 7. click_id (only when a string is present)\n *\n * `options` carries the Authorization: Bearer <accessToken> header.\n */\nconst ENDPOINT =\n 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456';\nconst OPTIONS = {\n headers: { Authorization: 'Bearer s3cr3t' },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.',\n in: getEvent('order complete', {\n timestamp: 1700000900,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n category: 'bags',\n price: '129.99',\n quantity: 2,\n },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: { type: 'server', id: 'https://shop.example.com', previous_id: '' },\n }),\n mapping: {\n name: 'Purchase',\n data: {\n map: {\n event_metadata: {\n map: {\n value_decimal: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n item_count: {\n fn: (event: unknown) =>\n (event as WalkerOS.Event).nested.filter(\n (item) => item.entity === 'product',\n ).length,\n },\n products: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n name: 'data.name',\n category: { key: 'data.category', value: 'uncategorized' },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.900Z',\n event_at_ms: 1700000900,\n event_type: { tracking_type: 'Purchase' },\n user: {},\n event_metadata: {\n conversion_id: '1700000900-gr0up-1',\n value_decimal: 249.99,\n currency: 'EUR',\n item_count: 1,\n products: [\n {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n category: 'bags',\n },\n ],\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to Reddit as an AddToCart conversion with value and product details.',\n in: getEvent('product add', {\n timestamp: 1700000901,\n data: {\n id: 'SKU-B2',\n name: 'Cool Cap',\n category: 'hats',\n price: '42.00',\n quantity: 1,\n },\n user: { id: 'user-456' },\n source: {\n type: 'server',\n id: 'https://shop.example.com/products',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'AddToCart',\n data: {\n map: {\n event_metadata: {\n map: {\n value_decimal: 'data.price',\n currency: { value: 'EUR' },\n item_count: { value: 1 },\n products: {\n set: [\n {\n map: {\n id: 'data.id',\n name: 'data.name',\n category: { key: 'data.category', value: 'uncategorized' },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.901Z',\n event_at_ms: 1700000901,\n event_type: { tracking_type: 'AddToCart' },\n user: {},\n event_metadata: {\n conversion_id: '1700000901-gr0up-1',\n value_decimal: '42.00',\n currency: 'EUR',\n item_count: 1,\n products: [\n { id: 'SKU-B2', name: 'Cool Cap', category: 'hats' },\n ],\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const pageVisit: Flow.StepExample = {\n title: 'Page visit',\n description:\n 'A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.',\n in: getEvent('page view', {\n timestamp: 1700000902,\n user: { id: 'user-789' },\n source: {\n type: 'server',\n id: 'https://www.example.com/docs/',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'PageVisit',\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.902Z',\n event_at_ms: 1700000902,\n event_type: { tracking_type: 'PageVisit' },\n user: {},\n event_metadata: { conversion_id: '1700000902-gr0up-1' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Lead',\n description:\n 'A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.',\n in: getEvent('form submit', {\n timestamp: 1700000903,\n data: { form: 'contact' },\n user: { id: 'user-lead-1', email: 'lead@example.com' },\n source: {\n type: 'server',\n id: 'https://www.example.com/contact',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'Lead',\n data: {\n map: {\n user: {\n map: {\n email: 'user.email',\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.903Z',\n event_at_ms: 1700000903,\n event_type: { tracking_type: 'Lead' },\n user: {\n // sha256('lead@example.com')\n email:\n '9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2',\n // sha256('user-lead-1')\n external_id:\n 'ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8',\n },\n event_metadata: { conversion_id: '1700000903-gr0up-1' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const signUp: Flow.StepExample = {\n title: 'Sign up',\n description:\n 'A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.',\n in: getEvent('user signup', {\n timestamp: 1700000904,\n data: { method: 'email' },\n user: { id: 'new-user-1', email: 'new@example.com' },\n source: {\n type: 'server',\n id: 'https://www.example.com/register',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'SignUp',\n data: {\n map: {\n user: {\n map: {\n email: 'user.email',\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.904Z',\n event_at_ms: 1700000904,\n event_type: { tracking_type: 'SignUp' },\n user: {\n // sha256('new@example.com')\n email:\n 'f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716',\n // sha256('new-user-1')\n external_id:\n 'b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde',\n },\n event_metadata: { conversion_id: '1700000904-gr0up-1' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const search: Flow.StepExample = {\n title: 'Search',\n description:\n 'A site search is sent to Reddit as a Search conversion with an item count in event_metadata.',\n in: getEvent('site search', {\n timestamp: 1700000905,\n data: { query: 'walkerOS destinations' },\n user: { id: 'user-101' },\n source: {\n type: 'server',\n id: 'https://www.example.com/search',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'Search',\n data: {\n map: {\n event_metadata: {\n map: {\n item_count: { value: 1 },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.905Z',\n event_at_ms: 1700000905,\n event_type: { tracking_type: 'Search' },\n user: {},\n event_metadata: {\n conversion_id: '1700000905-gr0up-1',\n item_count: 1,\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n"],"mappings":"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","names":["import_dev","import_dev","import_dev"]}
1
+ {"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/schemas/mapping.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';\nimport { ActionSourceSchema } from './primitives';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Reddit Conversion Access Token for Bearer authentication (like rdt_ABC123...)',\n ),\n pixelId: z\n .string()\n .min(1)\n .describe(\n 'Reddit Pixel ID used as the API path parameter (like a2_abcdef123456)',\n ),\n action_source: ActionSourceSchema.describe(\n 'Source of the event (WEBSITE, APP, PHYSICAL_STORE) (like WEBSITE)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\"Array of user fields that should not be hashed (like ['email'])\")\n .optional(),\n test_mode: z\n .boolean()\n .describe(\n 'Enable test mode by sending test_mode: true in the request body (like true)',\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for Reddit Conversions API endpoint (like https://ads-api.reddit.com/api/v2.0/conversions/events/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user fields (like { email: 'user.email', external_id: 'user.id' })\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Action Source Enum\n * Where the conversion event took place\n * https://ads-api.reddit.com/docs/v2/#tag/Conversions-API\n */\nexport const ActionSourceSchema = z.enum(['WEBSITE', 'APP', 'PHYSICAL_STORE']);\n\n/**\n * Tracking Type\n * Standard Reddit Conversions API event types.\n * Custom events use `Custom` with a `custom_event_name`.\n */\nexport const TrackingTypeSchema = z.enum([\n 'PageVisit',\n 'ViewContent',\n 'Search',\n 'AddToCart',\n 'AddToWishlist',\n 'Purchase',\n 'Lead',\n 'SignUp',\n 'Custom',\n]);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Reddit Conversions API Mapping Schema\n * Reddit 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","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 Reddit 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\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nconst mockSendServer: MockSendServer = async () => {\n // Simulate successful Reddit API response\n return {\n ok: true,\n data: {\n success: true,\n },\n };\n};\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing Reddit Conversions API events without making\n * actual HTTP requests to Reddit's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow, WalkerOS } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * Reddit Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), options)` where\n * `endpoint = ${settings.url}${settings.pixelId}` and\n * `body = { data: { events: [hashedServerEvent] } }`.\n *\n * Test fixture pins `pixelId = 'a2_abcdef123456'` and the default url, so\n * every endpoint resolves to:\n * https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456\n *\n * The serverEvent keys are assembled in this order (insertion order matters\n * for `JSON.stringify` string equality):\n * 1. event_at (ISO timestamp)\n * 2. event_at_ms\n * 3. event_type ({ tracking_type, custom_event_name? })\n * 4. ...restEventData (mapped event data minus user/event_metadata/click_id)\n * 5. user (hashed - email, external_id, ip_address, user_agent, idfa, aaid)\n * 6. event_metadata (conversion_id first, then merged metadata)\n * 7. click_id (only when a string is present)\n *\n * `options` carries the Authorization: Bearer <accessToken> header.\n */\nconst ENDPOINT =\n 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456';\nconst OPTIONS = {\n headers: { Authorization: 'Bearer s3cr3t' },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.',\n in: getEvent('order complete', {\n id: 'ev-1700000900',\n timestamp: 1700000900,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n category: 'bags',\n price: '129.99',\n quantity: 2,\n },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'Purchase',\n data: {\n map: {\n event_metadata: {\n map: {\n value_decimal: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n item_count: {\n fn: (event: unknown) =>\n (event as WalkerOS.Event).nested.filter(\n (item) => item.entity === 'product',\n ).length,\n },\n products: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n name: 'data.name',\n category: { key: 'data.category', value: 'uncategorized' },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.900Z',\n event_at_ms: 1700000900,\n event_type: { tracking_type: 'Purchase' },\n user: {},\n event_metadata: {\n conversion_id: 'ev-1700000900',\n value_decimal: 249.99,\n currency: 'EUR',\n item_count: 1,\n products: [\n {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n category: 'bags',\n },\n ],\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to Reddit as an AddToCart conversion with value and product details.',\n in: getEvent('product add', {\n id: 'ev-1700000901',\n timestamp: 1700000901,\n data: {\n id: 'SKU-B2',\n name: 'Cool Cap',\n category: 'hats',\n price: '42.00',\n quantity: 1,\n },\n user: { id: 'user-456' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'AddToCart',\n data: {\n map: {\n event_metadata: {\n map: {\n value_decimal: 'data.price',\n currency: { value: 'EUR' },\n item_count: { value: 1 },\n products: {\n set: [\n {\n map: {\n id: 'data.id',\n name: 'data.name',\n category: { key: 'data.category', value: 'uncategorized' },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.901Z',\n event_at_ms: 1700000901,\n event_type: { tracking_type: 'AddToCart' },\n user: {},\n event_metadata: {\n conversion_id: 'ev-1700000901',\n value_decimal: '42.00',\n currency: 'EUR',\n item_count: 1,\n products: [\n { id: 'SKU-B2', name: 'Cool Cap', category: 'hats' },\n ],\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const pageVisit: Flow.StepExample = {\n title: 'Page visit',\n description:\n 'A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.',\n in: getEvent('page view', {\n id: 'ev-1700000902',\n timestamp: 1700000902,\n user: { id: 'user-789' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'PageVisit',\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.902Z',\n event_at_ms: 1700000902,\n event_type: { tracking_type: 'PageVisit' },\n user: {},\n event_metadata: { conversion_id: 'ev-1700000902' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Lead',\n description:\n 'A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.',\n in: getEvent('form submit', {\n id: 'ev-1700000903',\n timestamp: 1700000903,\n data: { form: 'contact' },\n user: { id: 'user-lead-1', email: 'lead@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'Lead',\n data: {\n map: {\n user: {\n map: {\n email: 'user.email',\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.903Z',\n event_at_ms: 1700000903,\n event_type: { tracking_type: 'Lead' },\n user: {\n // sha256('lead@example.com')\n email:\n '9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2',\n // sha256('user-lead-1')\n external_id:\n 'ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8',\n },\n event_metadata: { conversion_id: 'ev-1700000903' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const signUp: Flow.StepExample = {\n title: 'Sign up',\n description:\n 'A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.',\n in: getEvent('user signup', {\n id: 'ev-1700000904',\n timestamp: 1700000904,\n data: { method: 'email' },\n user: { id: 'new-user-1', email: 'new@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'SignUp',\n data: {\n map: {\n user: {\n map: {\n email: 'user.email',\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.904Z',\n event_at_ms: 1700000904,\n event_type: { tracking_type: 'SignUp' },\n user: {\n // sha256('new@example.com')\n email:\n 'f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716',\n // sha256('new-user-1')\n external_id:\n 'b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde',\n },\n event_metadata: { conversion_id: 'ev-1700000904' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const search: Flow.StepExample = {\n title: 'Search',\n description:\n 'A site search is sent to Reddit as a Search conversion with an item count in event_metadata.',\n in: getEvent('site search', {\n id: 'ev-1700000905',\n timestamp: 1700000905,\n data: { query: 'walkerOS destinations' },\n user: { id: 'user-101' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'Search',\n data: {\n map: {\n event_metadata: {\n map: {\n item_count: { value: 1 },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.905Z',\n event_at_ms: 1700000905,\n event_type: { tracking_type: 'Search' },\n user: {},\n event_metadata: {\n conversion_id: 'ev-1700000905',\n item_count: 1,\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,cAA4B;;;ACA5B,IAAAC,cAAkB;;;ACAlB,iBAAkB;AAOX,IAAM,qBAAqB,aAAE,KAAK,CAAC,WAAW,OAAO,gBAAgB,CAAC;AAOtE,IAAM,qBAAqB,aAAE,KAAK;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;;;ADrBM,IAAM,iBAAiB,cAAE,OAAO;AAAA,EACrC,aAAa,cACV,OAAO,EACP,IAAI,CAAC,EACL;AAAA,IACC;AAAA,EACF;AAAA,EACF,SAAS,cACN,OAAO,EACP,IAAI,CAAC,EACL;AAAA,IACC;AAAA,EACF;AAAA,EACF,eAAe,mBAAmB;AAAA,IAChC;AAAA,EACF,EAAE,SAAS;AAAA,EACX,WAAW,cACR,MAAM,cAAE,OAAO,CAAC,EAChB,SAAS,iEAAiE,EAC1E,SAAS;AAAA,EACZ,WAAW,cACR,QAAQ,EACR;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,KAAK,cACF,OAAO,EACP,IAAI,EACJ;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,WAAW,cACR,OAAO,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC,EAC7B;AAAA,IACC;AAAA,EACF,EACC,SAAS;AACd,CAAC;;;AE1CD,IAAAC,cAAkB;AAMX,IAAM,gBAAgB,cAAE,OAAO,CAAC,CAAC;;;AHIjC,IAAM,eAAW,yBAAY,cAAc;AAC3C,IAAM,cAAU,yBAAY,aAAa;;;AIXhD;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAoBA,IAAM,iBAAiC,YAAY;AAEjD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,MACJ,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAQO,IAAM,OAAY;AAAA,EACvB,YAAY;AACd;AAEO,IAAM,aAAa,CAAC,YAAY;;;ACxCvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAmC;AA0BnC,IAAM,WACJ;AACF,IAAM,UAAU;AAAA,EACd,SAAS,EAAE,eAAe,gBAAgB;AAC5C;AAEO,IAAM,WAA6B;AAAA,EACxC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,kBAAkB;AAAA,IAC7B,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM,EAAE,IAAI,WAAW,OAAO,QAAQ,UAAU,MAAM;AAAA,IACtD,QAAQ;AAAA,MACN;AAAA,QACE,QAAQ;AAAA,QACR,MAAM;AAAA,UACJ,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,UAAU;AAAA,UACV,OAAO;AAAA,UACP,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,EAAE,IAAI,YAAY,QAAQ,aAAa;AAAA,IAC7C,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,gBAAgB;AAAA,UACd,KAAK;AAAA,YACH,eAAe;AAAA,YACf,UAAU,EAAE,KAAK,iBAAiB,OAAO,MAAM;AAAA,YAC/C,YAAY;AAAA,cACV,IAAI,CAAC,UACF,MAAyB,OAAO;AAAA,gBAC/B,CAAC,SAAS,KAAK,WAAW;AAAA,cAC5B,EAAE;AAAA,YACN;AAAA,YACA,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,MAAM;AAAA,oBACN,UAAU,EAAE,KAAK,iBAAiB,OAAO,gBAAgB;AAAA,kBAC3D;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,QAAQ;AAAA,YACN;AAAA,cACE,UAAU;AAAA,cACV,aAAa;AAAA,cACb,YAAY,EAAE,eAAe,WAAW;AAAA,cACxC,MAAM,CAAC;AAAA,cACP,gBAAgB;AAAA,gBACd,eAAe;AAAA,gBACf,eAAe;AAAA,gBACf,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,UAAU;AAAA,kBACR;AAAA,oBACE,IAAI;AAAA,oBACJ,MAAM;AAAA,oBACN,UAAU;AAAA,kBACZ;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,YAA8B;AAAA,EACzC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,eAAe;AAAA,IAC1B,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM;AAAA,MACJ,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,UAAU;AAAA,MACV,OAAO;AAAA,MACP,UAAU;AAAA,IACZ;AAAA,IACA,MAAM,EAAE,IAAI,WAAW;AAAA,IACvB,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,gBAAgB;AAAA,UACd,KAAK;AAAA,YACH,eAAe;AAAA,YACf,UAAU,EAAE,OAAO,MAAM;AAAA,YACzB,YAAY,EAAE,OAAO,EAAE;AAAA,YACvB,UAAU;AAAA,cACR,KAAK;AAAA,gBACH;AAAA,kBACE,KAAK;AAAA,oBACH,IAAI;AAAA,oBACJ,MAAM;AAAA,oBACN,UAAU,EAAE,KAAK,iBAAiB,OAAO,gBAAgB;AAAA,kBAC3D;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,QAAQ;AAAA,YACN;AAAA,cACE,UAAU;AAAA,cACV,aAAa;AAAA,cACb,YAAY,EAAE,eAAe,YAAY;AAAA,cACzC,MAAM,CAAC;AAAA,cACP,gBAAgB;AAAA,gBACd,eAAe;AAAA,gBACf,eAAe;AAAA,gBACf,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,UAAU;AAAA,kBACR,EAAE,IAAI,UAAU,MAAM,YAAY,UAAU,OAAO;AAAA,gBACrD;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,YAA8B;AAAA,EACzC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,aAAa;AAAA,IACxB,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM,EAAE,IAAI,WAAW;AAAA,IACvB,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,UACJ,QAAQ;AAAA,YACN;AAAA,cACE,UAAU;AAAA,cACV,aAAa;AAAA,cACb,YAAY,EAAE,eAAe,YAAY;AAAA,cACzC,MAAM,CAAC;AAAA,cACP,gBAAgB,EAAE,eAAe,gBAAgB;AAAA,YACnD;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,OAAyB;AAAA,EACpC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,eAAe;AAAA,IAC1B,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM,EAAE,MAAM,UAAU;AAAA,IACxB,MAAM,EAAE,IAAI,eAAe,OAAO,mBAAmB;AAAA,IACrD,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,MAAM;AAAA,UACJ,KAAK;AAAA,YACH,OAAO;AAAA,YACP,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,QAAQ;AAAA,YACN;AAAA,cACE,UAAU;AAAA,cACV,aAAa;AAAA,cACb,YAAY,EAAE,eAAe,OAAO;AAAA,cACpC,MAAM;AAAA;AAAA,gBAEJ,OACE;AAAA;AAAA,gBAEF,aACE;AAAA,cACJ;AAAA,cACA,gBAAgB,EAAE,eAAe,gBAAgB;AAAA,YACnD;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,SAA2B;AAAA,EACtC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,eAAe;AAAA,IAC1B,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM,EAAE,QAAQ,QAAQ;AAAA,IACxB,MAAM,EAAE,IAAI,cAAc,OAAO,kBAAkB;AAAA,IACnD,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,MAAM;AAAA,UACJ,KAAK;AAAA,YACH,OAAO;AAAA,YACP,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,QAAQ;AAAA,YACN;AAAA,cACE,UAAU;AAAA,cACV,aAAa;AAAA,cACb,YAAY,EAAE,eAAe,SAAS;AAAA,cACtC,MAAM;AAAA;AAAA,gBAEJ,OACE;AAAA;AAAA,gBAEF,aACE;AAAA,cACJ;AAAA,cACA,gBAAgB,EAAE,eAAe,gBAAgB;AAAA,YACnD;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,SAA2B;AAAA,EACtC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,eAAe;AAAA,IAC1B,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM,EAAE,OAAO,wBAAwB;AAAA,IACvC,MAAM,EAAE,IAAI,WAAW;AAAA,IACvB,QAAQ,EAAE,MAAM,WAAW,UAAU,SAAS;AAAA,EAChD,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,gBAAgB;AAAA,UACd,KAAK;AAAA,YACH,YAAY,EAAE,OAAO,EAAE;AAAA,UACzB;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,QAAQ;AAAA,YACN;AAAA,cACE,UAAU;AAAA,cACV,aAAa;AAAA,cACb,YAAY,EAAE,eAAe,SAAS;AAAA,cACtC,MAAM,CAAC;AAAA,cACP,gBAAgB;AAAA,gBACd,eAAe;AAAA,gBACf,YAAY;AAAA,cACd;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;","names":["import_dev","import_dev","import_dev"]}
package/dist/dev.mjs CHANGED
@@ -1 +1 @@
1
- var e=Object.defineProperty,t=(t,a)=>{for(var i in a)e(t,i,{get:a[i],enumerable:!0})},a={};t(a,{ActionSourceSchema:()=>n,MappingSchema:()=>p,SettingsSchema:()=>o,TrackingTypeSchema:()=>d,mapping:()=>u,settings:()=>m});import{zodToSchema as i}from"@walkeros/core/dev";import{z as r}from"@walkeros/core/dev";import{z as s}from"@walkeros/core/dev";var n=s.enum(["WEBSITE","APP","PHYSICAL_STORE"]),d=s.enum(["PageVisit","ViewContent","Search","AddToCart","AddToWishlist","Purchase","Lead","SignUp","Custom"]),o=r.object({accessToken:r.string().min(1).describe("Reddit Conversion Access Token for Bearer authentication (like rdt_ABC123...)"),pixelId:r.string().min(1).describe("Reddit Pixel ID used as the API path parameter (like a2_abcdef123456)"),action_source:n.describe("Source of the event (WEBSITE, APP, PHYSICAL_STORE) (like WEBSITE)").optional(),doNotHash:r.array(r.string()).describe("Array of user fields that should not be hashed (like ['email'])").optional(),test_mode:r.boolean().describe("Enable test mode by sending test_mode: true in the request body (like true)").optional(),url:r.string().url().describe("Custom URL for Reddit Conversions API endpoint (like https://ads-api.reddit.com/api/v2.0/conversions/events/)").optional(),user_data:r.record(r.string(),r.string()).describe("Mapping configuration for user fields (like { email: 'user.email', external_id: 'user.id' })").optional()});import{z as c}from"@walkeros/core/dev";var p=c.object({}),m=i(o),u=i(p),v={};t(v,{env:()=>l,step:()=>h});var l={};t(l,{push:()=>_,simulation:()=>g});var _={sendServer:async()=>({ok:!0,data:{success:!0}})},g=["sendServer"],h={};t(h,{addToCart:()=>w,lead:()=>P,pageVisit:()=>A,purchase:()=>k,search:()=>R,signUp:()=>T});import{getEvent as y,isObject as f}from"@walkeros/core";var S="https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",b={headers:{Authorization:"Bearer s3cr3t"}},k={title:"Purchase",description:"A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.",in:y("order complete",{timestamp:1700000900,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Everyday Ruck Snack",category:"bags",price:"129.99",quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"server",id:"https://shop.example.com",previous_id:""}}),mapping:{name:"Purchase",data:{map:{event_metadata:{map:{value_decimal:"data.total",currency:{key:"data.currency",value:"EUR"},item_count:{fn:e=>e.nested.filter(e=>"product"===e.entity).length},products:{loop:["nested",{condition:e=>f(e)&&"product"===e.entity,map:{id:"data.id",name:"data.name",category:{key:"data.category",value:"uncategorized"}}}]}}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.900Z",event_at_ms:1700000900,event_type:{tracking_type:"Purchase"},user:{},event_metadata:{conversion_id:"1700000900-gr0up-1",value_decimal:249.99,currency:"EUR",item_count:1,products:[{id:"SKU-A1",name:"Everyday Ruck Snack",category:"bags"}]}}]}}),b]]},w={title:"Add to cart",description:"A product add is sent to Reddit as an AddToCart conversion with value and product details.",in:y("product add",{timestamp:1700000901,data:{id:"SKU-B2",name:"Cool Cap",category:"hats",price:"42.00",quantity:1},user:{id:"user-456"},source:{type:"server",id:"https://shop.example.com/products",previous_id:""}}),mapping:{name:"AddToCart",data:{map:{event_metadata:{map:{value_decimal:"data.price",currency:{value:"EUR"},item_count:{value:1},products:{set:[{map:{id:"data.id",name:"data.name",category:{key:"data.category",value:"uncategorized"}}}]}}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.901Z",event_at_ms:1700000901,event_type:{tracking_type:"AddToCart"},user:{},event_metadata:{conversion_id:"1700000901-gr0up-1",value_decimal:"42.00",currency:"EUR",item_count:1,products:[{id:"SKU-B2",name:"Cool Cap",category:"hats"}]}}]}}),b]]},A={title:"Page visit",description:"A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.",in:y("page view",{timestamp:1700000902,user:{id:"user-789"},source:{type:"server",id:"https://www.example.com/docs/",previous_id:""}}),mapping:{name:"PageVisit"},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.902Z",event_at_ms:1700000902,event_type:{tracking_type:"PageVisit"},user:{},event_metadata:{conversion_id:"1700000902-gr0up-1"}}]}}),b]]},P={title:"Lead",description:"A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.",in:y("form submit",{timestamp:1700000903,data:{form:"contact"},user:{id:"user-lead-1",email:"lead@example.com"},source:{type:"server",id:"https://www.example.com/contact",previous_id:""}}),mapping:{name:"Lead",data:{map:{user:{map:{email:"user.email",external_id:"user.id"}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.903Z",event_at_ms:1700000903,event_type:{tracking_type:"Lead"},user:{email:"9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2",external_id:"ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8"},event_metadata:{conversion_id:"1700000903-gr0up-1"}}]}}),b]]},T={title:"Sign up",description:"A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.",in:y("user signup",{timestamp:1700000904,data:{method:"email"},user:{id:"new-user-1",email:"new@example.com"},source:{type:"server",id:"https://www.example.com/register",previous_id:""}}),mapping:{name:"SignUp",data:{map:{user:{map:{email:"user.email",external_id:"user.id"}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.904Z",event_at_ms:1700000904,event_type:{tracking_type:"SignUp"},user:{email:"f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716",external_id:"b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"},event_metadata:{conversion_id:"1700000904-gr0up-1"}}]}}),b]]},R={title:"Search",description:"A site search is sent to Reddit as a Search conversion with an item count in event_metadata.",in:y("site search",{timestamp:1700000905,data:{query:"walkerOS destinations"},user:{id:"user-101"},source:{type:"server",id:"https://www.example.com/search",previous_id:""}}),mapping:{name:"Search",data:{map:{event_metadata:{map:{item_count:{value:1}}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.905Z",event_at_ms:1700000905,event_type:{tracking_type:"Search"},user:{},event_metadata:{conversion_id:"1700000905-gr0up-1",item_count:1}}]}}),b]]};export{v as examples,a as schemas};//# sourceMappingURL=dev.mjs.map
1
+ var e=Object.defineProperty,t=(t,a)=>{for(var i in a)e(t,i,{get:a[i],enumerable:!0})},a={};t(a,{ActionSourceSchema:()=>n,MappingSchema:()=>m,SettingsSchema:()=>o,TrackingTypeSchema:()=>d,mapping:()=>u,settings:()=>p});import{zodToSchema as i}from"@walkeros/core/dev";import{z as r}from"@walkeros/core/dev";import{z as s}from"@walkeros/core/dev";var n=s.enum(["WEBSITE","APP","PHYSICAL_STORE"]),d=s.enum(["PageVisit","ViewContent","Search","AddToCart","AddToWishlist","Purchase","Lead","SignUp","Custom"]),o=r.object({accessToken:r.string().min(1).describe("Reddit Conversion Access Token for Bearer authentication (like rdt_ABC123...)"),pixelId:r.string().min(1).describe("Reddit Pixel ID used as the API path parameter (like a2_abcdef123456)"),action_source:n.describe("Source of the event (WEBSITE, APP, PHYSICAL_STORE) (like WEBSITE)").optional(),doNotHash:r.array(r.string()).describe("Array of user fields that should not be hashed (like ['email'])").optional(),test_mode:r.boolean().describe("Enable test mode by sending test_mode: true in the request body (like true)").optional(),url:r.string().url().describe("Custom URL for Reddit Conversions API endpoint (like https://ads-api.reddit.com/api/v2.0/conversions/events/)").optional(),user_data:r.record(r.string(),r.string()).describe("Mapping configuration for user fields (like { email: 'user.email', external_id: 'user.id' })").optional()});import{z as c}from"@walkeros/core/dev";var m=c.object({}),p=i(o),u=i(m),v={};t(v,{env:()=>l,step:()=>y});var l={};t(l,{push:()=>_,simulation:()=>g});var _={sendServer:async()=>({ok:!0,data:{success:!0}})},g=["sendServer"],y={};t(y,{addToCart:()=>A,lead:()=>T,pageVisit:()=>P,purchase:()=>k,search:()=>x,signUp:()=>R});import{getEvent as f,isObject as h}from"@walkeros/core";var S="https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",b={headers:{Authorization:"Bearer s3cr3t"}},k={title:"Purchase",description:"A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.",in:f("order complete",{id:"ev-1700000900",timestamp:1700000900,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Everyday Ruck Snack",category:"bags",price:"129.99",quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"express",platform:"server"}}),mapping:{name:"Purchase",data:{map:{event_metadata:{map:{value_decimal:"data.total",currency:{key:"data.currency",value:"EUR"},item_count:{fn:e=>e.nested.filter(e=>"product"===e.entity).length},products:{loop:["nested",{condition:e=>h(e)&&"product"===e.entity,map:{id:"data.id",name:"data.name",category:{key:"data.category",value:"uncategorized"}}}]}}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.900Z",event_at_ms:1700000900,event_type:{tracking_type:"Purchase"},user:{},event_metadata:{conversion_id:"ev-1700000900",value_decimal:249.99,currency:"EUR",item_count:1,products:[{id:"SKU-A1",name:"Everyday Ruck Snack",category:"bags"}]}}]}}),b]]},A={title:"Add to cart",description:"A product add is sent to Reddit as an AddToCart conversion with value and product details.",in:f("product add",{id:"ev-1700000901",timestamp:1700000901,data:{id:"SKU-B2",name:"Cool Cap",category:"hats",price:"42.00",quantity:1},user:{id:"user-456"},source:{type:"express",platform:"server"}}),mapping:{name:"AddToCart",data:{map:{event_metadata:{map:{value_decimal:"data.price",currency:{value:"EUR"},item_count:{value:1},products:{set:[{map:{id:"data.id",name:"data.name",category:{key:"data.category",value:"uncategorized"}}}]}}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.901Z",event_at_ms:1700000901,event_type:{tracking_type:"AddToCart"},user:{},event_metadata:{conversion_id:"ev-1700000901",value_decimal:"42.00",currency:"EUR",item_count:1,products:[{id:"SKU-B2",name:"Cool Cap",category:"hats"}]}}]}}),b]]},P={title:"Page visit",description:"A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.",in:f("page view",{id:"ev-1700000902",timestamp:1700000902,user:{id:"user-789"},source:{type:"express",platform:"server"}}),mapping:{name:"PageVisit"},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.902Z",event_at_ms:1700000902,event_type:{tracking_type:"PageVisit"},user:{},event_metadata:{conversion_id:"ev-1700000902"}}]}}),b]]},T={title:"Lead",description:"A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.",in:f("form submit",{id:"ev-1700000903",timestamp:1700000903,data:{form:"contact"},user:{id:"user-lead-1",email:"lead@example.com"},source:{type:"express",platform:"server"}}),mapping:{name:"Lead",data:{map:{user:{map:{email:"user.email",external_id:"user.id"}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.903Z",event_at_ms:1700000903,event_type:{tracking_type:"Lead"},user:{email:"9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2",external_id:"ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8"},event_metadata:{conversion_id:"ev-1700000903"}}]}}),b]]},R={title:"Sign up",description:"A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.",in:f("user signup",{id:"ev-1700000904",timestamp:1700000904,data:{method:"email"},user:{id:"new-user-1",email:"new@example.com"},source:{type:"express",platform:"server"}}),mapping:{name:"SignUp",data:{map:{user:{map:{email:"user.email",external_id:"user.id"}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.904Z",event_at_ms:1700000904,event_type:{tracking_type:"SignUp"},user:{email:"f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716",external_id:"b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"},event_metadata:{conversion_id:"ev-1700000904"}}]}}),b]]},x={title:"Search",description:"A site search is sent to Reddit as a Search conversion with an item count in event_metadata.",in:f("site search",{id:"ev-1700000905",timestamp:1700000905,data:{query:"walkerOS destinations"},user:{id:"user-101"},source:{type:"express",platform:"server"}}),mapping:{name:"Search",data:{map:{event_metadata:{map:{item_count:{value:1}}}}}},out:[["sendServer",S,JSON.stringify({data:{events:[{event_at:"1970-01-20T16:13:20.905Z",event_at_ms:1700000905,event_type:{tracking_type:"Search"},user:{},event_metadata:{conversion_id:"ev-1700000905",item_count:1}}]}}),b]]};export{v 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/primitives.ts","../src/schemas/mapping.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';\nimport { ActionSourceSchema } from './primitives';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Reddit Conversion Access Token for Bearer authentication (like rdt_ABC123...)',\n ),\n pixelId: z\n .string()\n .min(1)\n .describe(\n 'Reddit Pixel ID used as the API path parameter (like a2_abcdef123456)',\n ),\n action_source: ActionSourceSchema.describe(\n 'Source of the event (WEBSITE, APP, PHYSICAL_STORE) (like WEBSITE)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\"Array of user fields that should not be hashed (like ['email'])\")\n .optional(),\n test_mode: z\n .boolean()\n .describe(\n 'Enable test mode by sending test_mode: true in the request body (like true)',\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for Reddit Conversions API endpoint (like https://ads-api.reddit.com/api/v2.0/conversions/events/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user fields (like { email: 'user.email', external_id: 'user.id' })\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Action Source Enum\n * Where the conversion event took place\n * https://ads-api.reddit.com/docs/v2/#tag/Conversions-API\n */\nexport const ActionSourceSchema = z.enum(['WEBSITE', 'APP', 'PHYSICAL_STORE']);\n\n/**\n * Tracking Type\n * Standard Reddit Conversions API event types.\n * Custom events use `Custom` with a `custom_event_name`.\n */\nexport const TrackingTypeSchema = z.enum([\n 'PageVisit',\n 'ViewContent',\n 'Search',\n 'AddToCart',\n 'AddToWishlist',\n 'Purchase',\n 'Lead',\n 'SignUp',\n 'Custom',\n]);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Reddit Conversions API Mapping Schema\n * Reddit 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","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 Reddit 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\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nconst mockSendServer: MockSendServer = async () => {\n // Simulate successful Reddit API response\n return {\n ok: true,\n data: {\n success: true,\n },\n };\n};\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing Reddit Conversions API events without making\n * actual HTTP requests to Reddit's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow, WalkerOS } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * Reddit Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), options)` where\n * `endpoint = ${settings.url}${settings.pixelId}` and\n * `body = { data: { events: [hashedServerEvent] } }`.\n *\n * Test fixture pins `pixelId = 'a2_abcdef123456'` and the default url, so\n * every endpoint resolves to:\n * https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456\n *\n * The serverEvent keys are assembled in this order (insertion order matters\n * for `JSON.stringify` string equality):\n * 1. event_at (ISO timestamp)\n * 2. event_at_ms\n * 3. event_type ({ tracking_type, custom_event_name? })\n * 4. ...restEventData (mapped event data minus user/event_metadata/click_id)\n * 5. user (hashed — email, external_id, ip_address, user_agent, idfa, aaid)\n * 6. event_metadata (conversion_id first, then merged metadata)\n * 7. click_id (only when a string is present)\n *\n * `options` carries the Authorization: Bearer <accessToken> header.\n */\nconst ENDPOINT =\n 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456';\nconst OPTIONS = {\n headers: { Authorization: 'Bearer s3cr3t' },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.',\n in: getEvent('order complete', {\n timestamp: 1700000900,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n category: 'bags',\n price: '129.99',\n quantity: 2,\n },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: { type: 'server', id: 'https://shop.example.com', previous_id: '' },\n }),\n mapping: {\n name: 'Purchase',\n data: {\n map: {\n event_metadata: {\n map: {\n value_decimal: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n item_count: {\n fn: (event: unknown) =>\n (event as WalkerOS.Event).nested.filter(\n (item) => item.entity === 'product',\n ).length,\n },\n products: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n name: 'data.name',\n category: { key: 'data.category', value: 'uncategorized' },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.900Z',\n event_at_ms: 1700000900,\n event_type: { tracking_type: 'Purchase' },\n user: {},\n event_metadata: {\n conversion_id: '1700000900-gr0up-1',\n value_decimal: 249.99,\n currency: 'EUR',\n item_count: 1,\n products: [\n {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n category: 'bags',\n },\n ],\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to Reddit as an AddToCart conversion with value and product details.',\n in: getEvent('product add', {\n timestamp: 1700000901,\n data: {\n id: 'SKU-B2',\n name: 'Cool Cap',\n category: 'hats',\n price: '42.00',\n quantity: 1,\n },\n user: { id: 'user-456' },\n source: {\n type: 'server',\n id: 'https://shop.example.com/products',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'AddToCart',\n data: {\n map: {\n event_metadata: {\n map: {\n value_decimal: 'data.price',\n currency: { value: 'EUR' },\n item_count: { value: 1 },\n products: {\n set: [\n {\n map: {\n id: 'data.id',\n name: 'data.name',\n category: { key: 'data.category', value: 'uncategorized' },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.901Z',\n event_at_ms: 1700000901,\n event_type: { tracking_type: 'AddToCart' },\n user: {},\n event_metadata: {\n conversion_id: '1700000901-gr0up-1',\n value_decimal: '42.00',\n currency: 'EUR',\n item_count: 1,\n products: [\n { id: 'SKU-B2', name: 'Cool Cap', category: 'hats' },\n ],\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const pageVisit: Flow.StepExample = {\n title: 'Page visit',\n description:\n 'A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.',\n in: getEvent('page view', {\n timestamp: 1700000902,\n user: { id: 'user-789' },\n source: {\n type: 'server',\n id: 'https://www.example.com/docs/',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'PageVisit',\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.902Z',\n event_at_ms: 1700000902,\n event_type: { tracking_type: 'PageVisit' },\n user: {},\n event_metadata: { conversion_id: '1700000902-gr0up-1' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Lead',\n description:\n 'A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.',\n in: getEvent('form submit', {\n timestamp: 1700000903,\n data: { form: 'contact' },\n user: { id: 'user-lead-1', email: 'lead@example.com' },\n source: {\n type: 'server',\n id: 'https://www.example.com/contact',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'Lead',\n data: {\n map: {\n user: {\n map: {\n email: 'user.email',\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.903Z',\n event_at_ms: 1700000903,\n event_type: { tracking_type: 'Lead' },\n user: {\n // sha256('lead@example.com')\n email:\n '9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2',\n // sha256('user-lead-1')\n external_id:\n 'ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8',\n },\n event_metadata: { conversion_id: '1700000903-gr0up-1' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const signUp: Flow.StepExample = {\n title: 'Sign up',\n description:\n 'A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.',\n in: getEvent('user signup', {\n timestamp: 1700000904,\n data: { method: 'email' },\n user: { id: 'new-user-1', email: 'new@example.com' },\n source: {\n type: 'server',\n id: 'https://www.example.com/register',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'SignUp',\n data: {\n map: {\n user: {\n map: {\n email: 'user.email',\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.904Z',\n event_at_ms: 1700000904,\n event_type: { tracking_type: 'SignUp' },\n user: {\n // sha256('new@example.com')\n email:\n 'f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716',\n // sha256('new-user-1')\n external_id:\n 'b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde',\n },\n event_metadata: { conversion_id: '1700000904-gr0up-1' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const search: Flow.StepExample = {\n title: 'Search',\n description:\n 'A site search is sent to Reddit as a Search conversion with an item count in event_metadata.',\n in: getEvent('site search', {\n timestamp: 1700000905,\n data: { query: 'walkerOS destinations' },\n user: { id: 'user-101' },\n source: {\n type: 'server',\n id: 'https://www.example.com/search',\n previous_id: '',\n },\n }),\n mapping: {\n name: 'Search',\n data: {\n map: {\n event_metadata: {\n map: {\n item_count: { value: 1 },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.905Z',\n event_at_ms: 1700000905,\n event_type: { tracking_type: 'Search' },\n user: {},\n event_metadata: {\n conversion_id: '1700000905-gr0up-1',\n item_count: 1,\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n"],"mappings":"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","names":["z","z","z"]}
1
+ {"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/schemas/mapping.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';\nimport { ActionSourceSchema } from './primitives';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Reddit Conversion Access Token for Bearer authentication (like rdt_ABC123...)',\n ),\n pixelId: z\n .string()\n .min(1)\n .describe(\n 'Reddit Pixel ID used as the API path parameter (like a2_abcdef123456)',\n ),\n action_source: ActionSourceSchema.describe(\n 'Source of the event (WEBSITE, APP, PHYSICAL_STORE) (like WEBSITE)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\"Array of user fields that should not be hashed (like ['email'])\")\n .optional(),\n test_mode: z\n .boolean()\n .describe(\n 'Enable test mode by sending test_mode: true in the request body (like true)',\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for Reddit Conversions API endpoint (like https://ads-api.reddit.com/api/v2.0/conversions/events/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user fields (like { email: 'user.email', external_id: 'user.id' })\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Action Source Enum\n * Where the conversion event took place\n * https://ads-api.reddit.com/docs/v2/#tag/Conversions-API\n */\nexport const ActionSourceSchema = z.enum(['WEBSITE', 'APP', 'PHYSICAL_STORE']);\n\n/**\n * Tracking Type\n * Standard Reddit Conversions API event types.\n * Custom events use `Custom` with a `custom_event_name`.\n */\nexport const TrackingTypeSchema = z.enum([\n 'PageVisit',\n 'ViewContent',\n 'Search',\n 'AddToCart',\n 'AddToWishlist',\n 'Purchase',\n 'Lead',\n 'SignUp',\n 'Custom',\n]);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Reddit Conversions API Mapping Schema\n * Reddit 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","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 Reddit 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\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nconst mockSendServer: MockSendServer = async () => {\n // Simulate successful Reddit API response\n return {\n ok: true,\n data: {\n success: true,\n },\n };\n};\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing Reddit Conversions API events without making\n * actual HTTP requests to Reddit's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow, WalkerOS } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * Reddit Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), options)` where\n * `endpoint = ${settings.url}${settings.pixelId}` and\n * `body = { data: { events: [hashedServerEvent] } }`.\n *\n * Test fixture pins `pixelId = 'a2_abcdef123456'` and the default url, so\n * every endpoint resolves to:\n * https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456\n *\n * The serverEvent keys are assembled in this order (insertion order matters\n * for `JSON.stringify` string equality):\n * 1. event_at (ISO timestamp)\n * 2. event_at_ms\n * 3. event_type ({ tracking_type, custom_event_name? })\n * 4. ...restEventData (mapped event data minus user/event_metadata/click_id)\n * 5. user (hashed - email, external_id, ip_address, user_agent, idfa, aaid)\n * 6. event_metadata (conversion_id first, then merged metadata)\n * 7. click_id (only when a string is present)\n *\n * `options` carries the Authorization: Bearer <accessToken> header.\n */\nconst ENDPOINT =\n 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456';\nconst OPTIONS = {\n headers: { Authorization: 'Bearer s3cr3t' },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.',\n in: getEvent('order complete', {\n id: 'ev-1700000900',\n timestamp: 1700000900,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n category: 'bags',\n price: '129.99',\n quantity: 2,\n },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'Purchase',\n data: {\n map: {\n event_metadata: {\n map: {\n value_decimal: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n item_count: {\n fn: (event: unknown) =>\n (event as WalkerOS.Event).nested.filter(\n (item) => item.entity === 'product',\n ).length,\n },\n products: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n name: 'data.name',\n category: { key: 'data.category', value: 'uncategorized' },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.900Z',\n event_at_ms: 1700000900,\n event_type: { tracking_type: 'Purchase' },\n user: {},\n event_metadata: {\n conversion_id: 'ev-1700000900',\n value_decimal: 249.99,\n currency: 'EUR',\n item_count: 1,\n products: [\n {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n category: 'bags',\n },\n ],\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to Reddit as an AddToCart conversion with value and product details.',\n in: getEvent('product add', {\n id: 'ev-1700000901',\n timestamp: 1700000901,\n data: {\n id: 'SKU-B2',\n name: 'Cool Cap',\n category: 'hats',\n price: '42.00',\n quantity: 1,\n },\n user: { id: 'user-456' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'AddToCart',\n data: {\n map: {\n event_metadata: {\n map: {\n value_decimal: 'data.price',\n currency: { value: 'EUR' },\n item_count: { value: 1 },\n products: {\n set: [\n {\n map: {\n id: 'data.id',\n name: 'data.name',\n category: { key: 'data.category', value: 'uncategorized' },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.901Z',\n event_at_ms: 1700000901,\n event_type: { tracking_type: 'AddToCart' },\n user: {},\n event_metadata: {\n conversion_id: 'ev-1700000901',\n value_decimal: '42.00',\n currency: 'EUR',\n item_count: 1,\n products: [\n { id: 'SKU-B2', name: 'Cool Cap', category: 'hats' },\n ],\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const pageVisit: Flow.StepExample = {\n title: 'Page visit',\n description:\n 'A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.',\n in: getEvent('page view', {\n id: 'ev-1700000902',\n timestamp: 1700000902,\n user: { id: 'user-789' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'PageVisit',\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.902Z',\n event_at_ms: 1700000902,\n event_type: { tracking_type: 'PageVisit' },\n user: {},\n event_metadata: { conversion_id: 'ev-1700000902' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Lead',\n description:\n 'A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.',\n in: getEvent('form submit', {\n id: 'ev-1700000903',\n timestamp: 1700000903,\n data: { form: 'contact' },\n user: { id: 'user-lead-1', email: 'lead@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'Lead',\n data: {\n map: {\n user: {\n map: {\n email: 'user.email',\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.903Z',\n event_at_ms: 1700000903,\n event_type: { tracking_type: 'Lead' },\n user: {\n // sha256('lead@example.com')\n email:\n '9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2',\n // sha256('user-lead-1')\n external_id:\n 'ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8',\n },\n event_metadata: { conversion_id: 'ev-1700000903' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const signUp: Flow.StepExample = {\n title: 'Sign up',\n description:\n 'A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.',\n in: getEvent('user signup', {\n id: 'ev-1700000904',\n timestamp: 1700000904,\n data: { method: 'email' },\n user: { id: 'new-user-1', email: 'new@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'SignUp',\n data: {\n map: {\n user: {\n map: {\n email: 'user.email',\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.904Z',\n event_at_ms: 1700000904,\n event_type: { tracking_type: 'SignUp' },\n user: {\n // sha256('new@example.com')\n email:\n 'f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716',\n // sha256('new-user-1')\n external_id:\n 'b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde',\n },\n event_metadata: { conversion_id: 'ev-1700000904' },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const search: Flow.StepExample = {\n title: 'Search',\n description:\n 'A site search is sent to Reddit as a Search conversion with an item count in event_metadata.',\n in: getEvent('site search', {\n id: 'ev-1700000905',\n timestamp: 1700000905,\n data: { query: 'walkerOS destinations' },\n user: { id: 'user-101' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n name: 'Search',\n data: {\n map: {\n event_metadata: {\n map: {\n item_count: { value: 1 },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: {\n events: [\n {\n event_at: '1970-01-20T16:13:20.905Z',\n event_at_ms: 1700000905,\n event_type: { tracking_type: 'Search' },\n user: {},\n event_metadata: {\n conversion_id: 'ev-1700000905',\n item_count: 1,\n },\n },\n ],\n },\n }),\n OPTIONS,\n ],\n ],\n};\n"],"mappings":"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","names":["z","z","z"]}
@@ -63,6 +63,7 @@ var purchase = {
63
63
  title: "Purchase",
64
64
  description: "A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.",
65
65
  in: (0, import_core.getEvent)("order complete", {
66
+ id: "ev-1700000900",
66
67
  timestamp: 1700000900,
67
68
  data: { id: "ORD-300", total: 249.99, currency: "EUR" },
68
69
  nested: [
@@ -78,7 +79,7 @@ var purchase = {
78
79
  }
79
80
  ],
80
81
  user: { id: "user-123", device: "device-456" },
81
- source: { type: "server", id: "https://shop.example.com", previous_id: "" }
82
+ source: { type: "express", platform: "server" }
82
83
  }),
83
84
  mapping: {
84
85
  name: "Purchase",
@@ -124,7 +125,7 @@ var purchase = {
124
125
  event_type: { tracking_type: "Purchase" },
125
126
  user: {},
126
127
  event_metadata: {
127
- conversion_id: "1700000900-gr0up-1",
128
+ conversion_id: "ev-1700000900",
128
129
  value_decimal: 249.99,
129
130
  currency: "EUR",
130
131
  item_count: 1,
@@ -148,6 +149,7 @@ var addToCart = {
148
149
  title: "Add to cart",
149
150
  description: "A product add is sent to Reddit as an AddToCart conversion with value and product details.",
150
151
  in: (0, import_core.getEvent)("product add", {
152
+ id: "ev-1700000901",
151
153
  timestamp: 1700000901,
152
154
  data: {
153
155
  id: "SKU-B2",
@@ -157,11 +159,7 @@ var addToCart = {
157
159
  quantity: 1
158
160
  },
159
161
  user: { id: "user-456" },
160
- source: {
161
- type: "server",
162
- id: "https://shop.example.com/products",
163
- previous_id: ""
164
- }
162
+ source: { type: "express", platform: "server" }
165
163
  }),
166
164
  mapping: {
167
165
  name: "AddToCart",
@@ -201,7 +199,7 @@ var addToCart = {
201
199
  event_type: { tracking_type: "AddToCart" },
202
200
  user: {},
203
201
  event_metadata: {
204
- conversion_id: "1700000901-gr0up-1",
202
+ conversion_id: "ev-1700000901",
205
203
  value_decimal: "42.00",
206
204
  currency: "EUR",
207
205
  item_count: 1,
@@ -221,13 +219,10 @@ var pageVisit = {
221
219
  title: "Page visit",
222
220
  description: "A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.",
223
221
  in: (0, import_core.getEvent)("page view", {
222
+ id: "ev-1700000902",
224
223
  timestamp: 1700000902,
225
224
  user: { id: "user-789" },
226
- source: {
227
- type: "server",
228
- id: "https://www.example.com/docs/",
229
- previous_id: ""
230
- }
225
+ source: { type: "express", platform: "server" }
231
226
  }),
232
227
  mapping: {
233
228
  name: "PageVisit"
@@ -244,7 +239,7 @@ var pageVisit = {
244
239
  event_at_ms: 1700000902,
245
240
  event_type: { tracking_type: "PageVisit" },
246
241
  user: {},
247
- event_metadata: { conversion_id: "1700000902-gr0up-1" }
242
+ event_metadata: { conversion_id: "ev-1700000902" }
248
243
  }
249
244
  ]
250
245
  }
@@ -257,14 +252,11 @@ var lead = {
257
252
  title: "Lead",
258
253
  description: "A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.",
259
254
  in: (0, import_core.getEvent)("form submit", {
255
+ id: "ev-1700000903",
260
256
  timestamp: 1700000903,
261
257
  data: { form: "contact" },
262
258
  user: { id: "user-lead-1", email: "lead@example.com" },
263
- source: {
264
- type: "server",
265
- id: "https://www.example.com/contact",
266
- previous_id: ""
267
- }
259
+ source: { type: "express", platform: "server" }
268
260
  }),
269
261
  mapping: {
270
262
  name: "Lead",
@@ -296,7 +288,7 @@ var lead = {
296
288
  // sha256('user-lead-1')
297
289
  external_id: "ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8"
298
290
  },
299
- event_metadata: { conversion_id: "1700000903-gr0up-1" }
291
+ event_metadata: { conversion_id: "ev-1700000903" }
300
292
  }
301
293
  ]
302
294
  }
@@ -309,14 +301,11 @@ var signUp = {
309
301
  title: "Sign up",
310
302
  description: "A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.",
311
303
  in: (0, import_core.getEvent)("user signup", {
304
+ id: "ev-1700000904",
312
305
  timestamp: 1700000904,
313
306
  data: { method: "email" },
314
307
  user: { id: "new-user-1", email: "new@example.com" },
315
- source: {
316
- type: "server",
317
- id: "https://www.example.com/register",
318
- previous_id: ""
319
- }
308
+ source: { type: "express", platform: "server" }
320
309
  }),
321
310
  mapping: {
322
311
  name: "SignUp",
@@ -348,7 +337,7 @@ var signUp = {
348
337
  // sha256('new-user-1')
349
338
  external_id: "b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"
350
339
  },
351
- event_metadata: { conversion_id: "1700000904-gr0up-1" }
340
+ event_metadata: { conversion_id: "ev-1700000904" }
352
341
  }
353
342
  ]
354
343
  }
@@ -361,14 +350,11 @@ var search = {
361
350
  title: "Search",
362
351
  description: "A site search is sent to Reddit as a Search conversion with an item count in event_metadata.",
363
352
  in: (0, import_core.getEvent)("site search", {
353
+ id: "ev-1700000905",
364
354
  timestamp: 1700000905,
365
355
  data: { query: "walkerOS destinations" },
366
356
  user: { id: "user-101" },
367
- source: {
368
- type: "server",
369
- id: "https://www.example.com/search",
370
- previous_id: ""
371
- }
357
+ source: { type: "express", platform: "server" }
372
358
  }),
373
359
  mapping: {
374
360
  name: "Search",
@@ -395,7 +381,7 @@ var search = {
395
381
  event_type: { tracking_type: "Search" },
396
382
  user: {},
397
383
  event_metadata: {
398
- conversion_id: "1700000905-gr0up-1",
384
+ conversion_id: "ev-1700000905",
399
385
  item_count: 1
400
386
  }
401
387
  }
@@ -42,6 +42,7 @@ var purchase = {
42
42
  title: "Purchase",
43
43
  description: "A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.",
44
44
  in: getEvent("order complete", {
45
+ id: "ev-1700000900",
45
46
  timestamp: 1700000900,
46
47
  data: { id: "ORD-300", total: 249.99, currency: "EUR" },
47
48
  nested: [
@@ -57,7 +58,7 @@ var purchase = {
57
58
  }
58
59
  ],
59
60
  user: { id: "user-123", device: "device-456" },
60
- source: { type: "server", id: "https://shop.example.com", previous_id: "" }
61
+ source: { type: "express", platform: "server" }
61
62
  }),
62
63
  mapping: {
63
64
  name: "Purchase",
@@ -103,7 +104,7 @@ var purchase = {
103
104
  event_type: { tracking_type: "Purchase" },
104
105
  user: {},
105
106
  event_metadata: {
106
- conversion_id: "1700000900-gr0up-1",
107
+ conversion_id: "ev-1700000900",
107
108
  value_decimal: 249.99,
108
109
  currency: "EUR",
109
110
  item_count: 1,
@@ -127,6 +128,7 @@ var addToCart = {
127
128
  title: "Add to cart",
128
129
  description: "A product add is sent to Reddit as an AddToCart conversion with value and product details.",
129
130
  in: getEvent("product add", {
131
+ id: "ev-1700000901",
130
132
  timestamp: 1700000901,
131
133
  data: {
132
134
  id: "SKU-B2",
@@ -136,11 +138,7 @@ var addToCart = {
136
138
  quantity: 1
137
139
  },
138
140
  user: { id: "user-456" },
139
- source: {
140
- type: "server",
141
- id: "https://shop.example.com/products",
142
- previous_id: ""
143
- }
141
+ source: { type: "express", platform: "server" }
144
142
  }),
145
143
  mapping: {
146
144
  name: "AddToCart",
@@ -180,7 +178,7 @@ var addToCart = {
180
178
  event_type: { tracking_type: "AddToCart" },
181
179
  user: {},
182
180
  event_metadata: {
183
- conversion_id: "1700000901-gr0up-1",
181
+ conversion_id: "ev-1700000901",
184
182
  value_decimal: "42.00",
185
183
  currency: "EUR",
186
184
  item_count: 1,
@@ -200,13 +198,10 @@ var pageVisit = {
200
198
  title: "Page visit",
201
199
  description: "A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.",
202
200
  in: getEvent("page view", {
201
+ id: "ev-1700000902",
203
202
  timestamp: 1700000902,
204
203
  user: { id: "user-789" },
205
- source: {
206
- type: "server",
207
- id: "https://www.example.com/docs/",
208
- previous_id: ""
209
- }
204
+ source: { type: "express", platform: "server" }
210
205
  }),
211
206
  mapping: {
212
207
  name: "PageVisit"
@@ -223,7 +218,7 @@ var pageVisit = {
223
218
  event_at_ms: 1700000902,
224
219
  event_type: { tracking_type: "PageVisit" },
225
220
  user: {},
226
- event_metadata: { conversion_id: "1700000902-gr0up-1" }
221
+ event_metadata: { conversion_id: "ev-1700000902" }
227
222
  }
228
223
  ]
229
224
  }
@@ -236,14 +231,11 @@ var lead = {
236
231
  title: "Lead",
237
232
  description: "A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.",
238
233
  in: getEvent("form submit", {
234
+ id: "ev-1700000903",
239
235
  timestamp: 1700000903,
240
236
  data: { form: "contact" },
241
237
  user: { id: "user-lead-1", email: "lead@example.com" },
242
- source: {
243
- type: "server",
244
- id: "https://www.example.com/contact",
245
- previous_id: ""
246
- }
238
+ source: { type: "express", platform: "server" }
247
239
  }),
248
240
  mapping: {
249
241
  name: "Lead",
@@ -275,7 +267,7 @@ var lead = {
275
267
  // sha256('user-lead-1')
276
268
  external_id: "ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8"
277
269
  },
278
- event_metadata: { conversion_id: "1700000903-gr0up-1" }
270
+ event_metadata: { conversion_id: "ev-1700000903" }
279
271
  }
280
272
  ]
281
273
  }
@@ -288,14 +280,11 @@ var signUp = {
288
280
  title: "Sign up",
289
281
  description: "A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.",
290
282
  in: getEvent("user signup", {
283
+ id: "ev-1700000904",
291
284
  timestamp: 1700000904,
292
285
  data: { method: "email" },
293
286
  user: { id: "new-user-1", email: "new@example.com" },
294
- source: {
295
- type: "server",
296
- id: "https://www.example.com/register",
297
- previous_id: ""
298
- }
287
+ source: { type: "express", platform: "server" }
299
288
  }),
300
289
  mapping: {
301
290
  name: "SignUp",
@@ -327,7 +316,7 @@ var signUp = {
327
316
  // sha256('new-user-1')
328
317
  external_id: "b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"
329
318
  },
330
- event_metadata: { conversion_id: "1700000904-gr0up-1" }
319
+ event_metadata: { conversion_id: "ev-1700000904" }
331
320
  }
332
321
  ]
333
322
  }
@@ -340,14 +329,11 @@ var search = {
340
329
  title: "Search",
341
330
  description: "A site search is sent to Reddit as a Search conversion with an item count in event_metadata.",
342
331
  in: getEvent("site search", {
332
+ id: "ev-1700000905",
343
333
  timestamp: 1700000905,
344
334
  data: { query: "walkerOS destinations" },
345
335
  user: { id: "user-101" },
346
- source: {
347
- type: "server",
348
- id: "https://www.example.com/search",
349
- previous_id: ""
350
- }
336
+ source: { type: "express", platform: "server" }
351
337
  }),
352
338
  mapping: {
353
339
  name: "Search",
@@ -374,7 +360,7 @@ var search = {
374
360
  event_type: { tracking_type: "Search" },
375
361
  user: {},
376
362
  event_metadata: {
377
- conversion_id: "1700000905-gr0up-1",
363
+ conversion_id: "ev-1700000905",
378
364
  item_count: 1
379
365
  }
380
366
  }
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,{DestinationReddit:()=>types_exports,default:()=>index_default,destinationReddit:()=>destinationReddit}),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_core2=require("@walkeros/core"),import_server_core2=require("@walkeros/server-core"),import_core=require("@walkeros/core"),import_server_core=require("@walkeros/server-core"),keysToHash=["email","external_id","ip_address","user_agent","idfa","aaid"];function shouldBeHashed(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}async function processValue(value,shouldHash){return shouldHash?(0,import_core.isArray)(value)?Promise.all(value.map(item=>(0,import_server_core.getHashServer)(String(item)))):(0,import_server_core.getHashServer)(String(value)):value}var STANDARD_TRACKING_TYPES=new Set(["PageVisit","ViewContent","Search","AddToCart","AddToWishlist","Purchase","Lead","SignUp","Custom"]);function buildEventType(name){return function(name){return STANDARD_TRACKING_TYPES.has(name)}(name)&&"Custom"!==name?{tracking_type:name}:{tracking_type:"Custom",custom_event_name:name}}var push=async function(event,{config:config,data:data,env:env,logger:logger}){var _a;const{accessToken:accessToken,pixelId:pixelId,action_source:_action_source,doNotHash:doNotHash,test_mode:test_mode,url:url="https://ads-api.reddit.com/api/v2.0/conversions/events/",user_data:user_data}=config.settings,eventData=(0,import_core2.isObject)(data)?data:{},configData=config.data?await(0,import_core2.getMappingValue)(event,config.data):{},userDataCustom=user_data?await(0,import_core2.getMappingValue)(event,{map:user_data}):{},userData={...(0,import_core2.isObject)(configData)&&(0,import_core2.isObject)(configData.user)?configData.user:{},...(0,import_core2.isObject)(userDataCustom)?userDataCustom:{},...(0,import_core2.isObject)(eventData.user)?eventData.user:{}},{user:_u,event_metadata:eventMetadata,click_id:eventClickId,...restEventData}=eventData,timestampMs=event.timestamp||Date.now(),serverEvent={event_at:new Date(timestampMs).toISOString(),event_at_ms:timestampMs,event_type:buildEventType(event.name),...restEventData,user:userData},metadataFromMapping=(0,import_core2.isObject)(eventMetadata)?eventMetadata:{};serverEvent.event_metadata={conversion_id:event.id,...metadataFromMapping},"string"==typeof eventClickId&&(serverEvent.click_id=eventClickId);const hashedServerEvent=await async function(value,doNotHash=[]){if(!(0,import_core.isObject)(value))return value;const isUser="user"in value,target=isUser?value.user:value,result=(await Promise.all(Object.entries(target).map(async([k,v])=>[k,await processValue(v,isUser&&shouldBeHashed(k,doNotHash))]))).reduce((acc,[k,v])=>((0,import_core.isString)(k)&&(acc[k]=v),acc),{});return isUser?{...value,user:result}:result}(serverEvent,doNotHash),body={...test_mode?{test_mode:!0}:{},data:{events:[hashedServerEvent]}},endpoint=`${url}${pixelId}`;logger.debug("Calling Reddit API",{endpoint:endpoint,method:"POST",trackingType:serverEvent.event_type.tracking_type,eventId:null==(_a=serverEvent.event_metadata)?void 0:_a.conversion_id});const sendServerFn=(null==env?void 0:env.sendServer)||import_server_core2.sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`}});logger.debug("Reddit API response",{ok:!(0,import_core2.isObject)(result)||result.ok}),(0,import_core2.isObject)(result)&&!1===result.ok&&logger.throw(`Reddit API error: ${JSON.stringify(result)}`)},types_exports={},destinationReddit={type:"reddit",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={...settings,accessToken:accessToken,pixelId:pixelId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await push(event,context)},index_default=destinationReddit;//# 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,{DestinationReddit:()=>types_exports,default:()=>index_default,destinationReddit:()=>destinationReddit}),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_core2=require("@walkeros/core"),import_server_core2=require("@walkeros/server-core"),import_core=require("@walkeros/core"),import_server_core=require("@walkeros/server-core"),keysToHash=["email","external_id","ip_address","user_agent","idfa","aaid"];function shouldBeHashed(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}async function processValue(value,shouldHash){return shouldHash?(0,import_core.isArray)(value)?Promise.all(value.map(item=>(0,import_server_core.getHashServer)(String(item)))):(0,import_server_core.getHashServer)(String(value)):value}var STANDARD_TRACKING_TYPES=new Set(["PageVisit","ViewContent","Search","AddToCart","AddToWishlist","Purchase","Lead","SignUp","Custom"]);function buildEventType(name){return function(name){return STANDARD_TRACKING_TYPES.has(name)}(name)&&"Custom"!==name?{tracking_type:name}:{tracking_type:"Custom",custom_event_name:name}}var push=async function(event,{config:config,data:data,env:env,logger:logger,collector:collector}){const{accessToken:accessToken,pixelId:pixelId,action_source:_action_source,doNotHash:doNotHash,test_mode:test_mode,url:url="https://ads-api.reddit.com/api/v2.0/conversions/events/",user_data:user_data}=config.settings,eventData=(0,import_core2.isObject)(data)?data:{},configData=config.data?await(0,import_core2.getMappingValue)(event,config.data,{collector:collector}):{},userDataCustom=user_data?await(0,import_core2.getMappingValue)(event,{map:user_data},{collector:collector}):{},userData={...(0,import_core2.isObject)(configData)&&(0,import_core2.isObject)(configData.user)?configData.user:{},...(0,import_core2.isObject)(userDataCustom)?userDataCustom:{},...(0,import_core2.isObject)(eventData.user)?eventData.user:{}},{user:_u,event_metadata:eventMetadata,click_id:eventClickId,...restEventData}=eventData,timestampMs=event.timestamp||Date.now(),serverEvent={event_at:new Date(timestampMs).toISOString(),event_at_ms:timestampMs,event_type:buildEventType(event.name),...restEventData,user:userData},metadataFromMapping=(0,import_core2.isObject)(eventMetadata)?eventMetadata:{};serverEvent.event_metadata={conversion_id:event.id,...metadataFromMapping},"string"==typeof eventClickId&&(serverEvent.click_id=eventClickId);const hashedServerEvent=await async function(value,doNotHash=[]){if(!(0,import_core.isObject)(value))return value;const isUser="user"in value,target=isUser?value.user:value,result=(await Promise.all(Object.entries(target).map(async([k,v])=>[k,await processValue(v,isUser&&shouldBeHashed(k,doNotHash))]))).reduce((acc,[k,v])=>((0,import_core.isString)(k)&&(acc[k]=v),acc),{});return isUser?{...value,user:result}:result}(serverEvent,doNotHash),body={...test_mode?{test_mode:!0}:{},data:{events:[hashedServerEvent]}},endpoint=`${url}${pixelId}`;logger.debug("Calling Reddit API",{endpoint:endpoint,method:"POST",trackingType:serverEvent.event_type.tracking_type,eventId:serverEvent.event_metadata?.conversion_id});const sendServerFn=env?.sendServer||import_server_core2.sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`}});logger.debug("Reddit API response",{ok:!(0,import_core2.isObject)(result)||result.ok}),(0,import_core2.isObject)(result)&&!1===result.ok&&logger.throw(`Reddit API error: ${JSON.stringify(result)}`)},types_exports={},destinationReddit={type:"reddit",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={...settings,accessToken:accessToken,pixelId:pixelId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await push(event,context)},index_default=destinationReddit;//# 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 DestinationReddit from './types';\n\nexport const destinationReddit: Destination = {\n type: 'reddit',\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 destinationReddit;\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 ...settings,\n accessToken,\n pixelId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n EventType,\n PushFn,\n RequestBody,\n TrackingType,\n UserData,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEvent } from './hash';\n\nconst STANDARD_TRACKING_TYPES: ReadonlySet<TrackingType> =\n new Set<TrackingType>([\n 'PageVisit',\n 'ViewContent',\n 'Search',\n 'AddToCart',\n 'AddToWishlist',\n 'Purchase',\n 'Lead',\n 'SignUp',\n 'Custom',\n ]);\n\nfunction isStandardTrackingType(name: string): name is TrackingType {\n return STANDARD_TRACKING_TYPES.has(name as TrackingType);\n}\n\nfunction buildEventType(name: string): EventType {\n if (isStandardTrackingType(name) && name !== 'Custom') {\n return { tracking_type: name };\n }\n return { tracking_type: 'Custom', custom_event_name: name };\n}\n\nexport const push: PushFn = async function (\n event,\n { config, data, env, logger },\n) {\n const {\n accessToken,\n pixelId,\n action_source: _action_source,\n doNotHash,\n test_mode,\n url = 'https://ads-api.reddit.com/api/v2.0/conversions/events/',\n user_data,\n } = config.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 // Merge user data from config.data, settings.user_data, and event mapping\n const userData: UserData = {\n ...(isObject(configData) && isObject(configData.user)\n ? configData.user\n : {}),\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n ...(isObject(eventData.user) ? eventData.user : {}),\n };\n\n const {\n user: _u,\n event_metadata: eventMetadata,\n click_id: eventClickId,\n ...restEventData\n } = eventData;\n\n const timestampMs = event.timestamp || Date.now();\n\n const serverEvent: ConversionEvent = {\n event_at: new Date(timestampMs).toISOString(),\n event_at_ms: timestampMs,\n event_type: buildEventType(event.name),\n ...restEventData,\n user: userData,\n };\n\n // Merge event_metadata with auto-populated conversion_id (event.id for dedup)\n const metadataFromMapping = isObject(eventMetadata) ? eventMetadata : {};\n serverEvent.event_metadata = {\n conversion_id: event.id,\n ...metadataFromMapping,\n };\n\n if (typeof eventClickId === 'string') {\n serverEvent.click_id = eventClickId;\n }\n\n const hashedServerEvent = await hashEvent(serverEvent, doNotHash);\n\n const body: RequestBody = {\n ...(test_mode ? { test_mode: true } : {}),\n data: { events: [hashedServerEvent] },\n };\n\n const endpoint = `${url}${pixelId}`;\n\n logger.debug('Calling Reddit API', {\n endpoint,\n method: 'POST',\n trackingType: serverEvent.event_type.tracking_type,\n eventId: serverEvent.event_metadata?.conversion_id,\n });\n\n const sendServerFn = env?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body), {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n logger.debug('Reddit API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Reddit API error: ${JSON.stringify(result)}`);\n }\n};\n","import { WalkerOS } from '@walkeros/core';\nimport { isArray, isObject, isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = [\n 'email',\n 'external_id',\n 'ip_address',\n 'user_agent',\n 'idfa',\n 'aaid',\n];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\ntype HashableValue = WalkerOS.AnyObject | unknown | unknown[];\n\nasync function processValue(\n value: unknown,\n shouldHash: boolean,\n): Promise<unknown> {\n if (!shouldHash) return value;\n if (isArray(value)) {\n return Promise.all(value.map((item) => getHashServer(String(item))));\n }\n return getHashServer(String(value));\n}\n\nexport async function hashEvent<T extends HashableValue>(\n value: T,\n doNotHash: string[] = [],\n): Promise<T> {\n if (!isObject(value)) return value;\n\n const isUser = 'user' in value;\n const target = (isUser ? value.user : value) as WalkerOS.AnyObject;\n\n const entries = await Promise.all(\n Object.entries(target).map(async ([k, v]) => [\n k,\n await processValue(v, isUser && shouldBeHashed(k, doNotHash)),\n ]),\n );\n\n const result = entries.reduce((acc, [k, v]) => {\n if (isString(k)) acc[k] = v;\n return acc;\n }, {} as WalkerOS.AnyObject);\n\n return isUser ? { ...value, user: result } : (result as T);\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 action_source?: ActionSource;\n doNotHash?: string[];\n test_mode?: boolean;\n url?: string;\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n sendServer?: typeof sendServer;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n// Reddit Conversions API types\n// https://ads-api.reddit.com/docs/v2/#tag/Conversions-API\n\nexport type ActionSource = 'WEBSITE' | 'APP' | 'PHYSICAL_STORE';\n\nexport type TrackingType =\n | 'PageVisit'\n | 'ViewContent'\n | 'Search'\n | 'AddToCart'\n | 'AddToWishlist'\n | 'Purchase'\n | 'Lead'\n | 'SignUp'\n | 'Custom';\n\nexport interface EventType {\n tracking_type: TrackingType;\n custom_event_name?: string;\n}\n\nexport interface Product {\n id: string;\n name?: string;\n category: string;\n}\n\nexport interface EventMetadata {\n conversion_id?: string;\n item_count?: number;\n currency?: string;\n value?: number;\n value_decimal?: number;\n products?: Product[];\n units_sold?: number;\n country_code?: string;\n}\n\nexport interface ScreenDimensions {\n width: number;\n height: number;\n}\n\nexport interface DataProcessingOptions {\n modes: string[];\n country?: string;\n region?: string;\n}\n\nexport interface UserData {\n // Hashable fields (SHA-256)\n email?: string;\n external_id?: string;\n ip_address?: string;\n user_agent?: string;\n idfa?: string;\n aaid?: string;\n\n // Pass-through fields (not hashed)\n uuid?: string;\n opt_out?: boolean;\n screen_dimensions?: ScreenDimensions;\n data_processing_options?: DataProcessingOptions;\n}\n\nexport interface ConversionEvent {\n click_id?: string;\n event_at: string;\n event_at_ms?: number;\n event_type: EventType;\n event_metadata?: EventMetadata;\n user: UserData;\n}\n\nexport interface RequestBody {\n test_mode?: boolean;\n data: {\n events: ConversionEvent[];\n };\n}\n\nexport interface ResponseBody {\n success?: boolean;\n message?: string;\n}\n"],"mappings":"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","names":["import_core","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 DestinationReddit from './types';\n\nexport const destinationReddit: Destination = {\n type: 'reddit',\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 destinationReddit;\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 ...settings,\n accessToken,\n pixelId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n EventType,\n PushFn,\n RequestBody,\n TrackingType,\n UserData,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEvent } from './hash';\n\nconst STANDARD_TRACKING_TYPES: ReadonlySet<TrackingType> =\n new Set<TrackingType>([\n 'PageVisit',\n 'ViewContent',\n 'Search',\n 'AddToCart',\n 'AddToWishlist',\n 'Purchase',\n 'Lead',\n 'SignUp',\n 'Custom',\n ]);\n\nfunction isStandardTrackingType(name: string): name is TrackingType {\n return STANDARD_TRACKING_TYPES.has(name as TrackingType);\n}\n\nfunction buildEventType(name: string): EventType {\n if (isStandardTrackingType(name) && name !== 'Custom') {\n return { tracking_type: name };\n }\n return { tracking_type: 'Custom', custom_event_name: name };\n}\n\nexport const push: PushFn = async function (\n event,\n { config, data, env, logger, collector },\n) {\n const {\n accessToken,\n pixelId,\n action_source: _action_source,\n doNotHash,\n test_mode,\n url = 'https://ads-api.reddit.com/api/v2.0/conversions/events/',\n user_data,\n } = config.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 // Merge user data from config.data, settings.user_data, and event mapping\n const userData: UserData = {\n ...(isObject(configData) && isObject(configData.user)\n ? configData.user\n : {}),\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n ...(isObject(eventData.user) ? eventData.user : {}),\n };\n\n const {\n user: _u,\n event_metadata: eventMetadata,\n click_id: eventClickId,\n ...restEventData\n } = eventData;\n\n const timestampMs = event.timestamp || Date.now();\n\n const serverEvent: ConversionEvent = {\n event_at: new Date(timestampMs).toISOString(),\n event_at_ms: timestampMs,\n event_type: buildEventType(event.name),\n ...restEventData,\n user: userData,\n };\n\n // Merge event_metadata with auto-populated conversion_id (event.id for dedup)\n const metadataFromMapping = isObject(eventMetadata) ? eventMetadata : {};\n serverEvent.event_metadata = {\n conversion_id: event.id,\n ...metadataFromMapping,\n };\n\n if (typeof eventClickId === 'string') {\n serverEvent.click_id = eventClickId;\n }\n\n const hashedServerEvent = await hashEvent(serverEvent, doNotHash);\n\n const body: RequestBody = {\n ...(test_mode ? { test_mode: true } : {}),\n data: { events: [hashedServerEvent] },\n };\n\n const endpoint = `${url}${pixelId}`;\n\n logger.debug('Calling Reddit API', {\n endpoint,\n method: 'POST',\n trackingType: serverEvent.event_type.tracking_type,\n eventId: serverEvent.event_metadata?.conversion_id,\n });\n\n const sendServerFn = env?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body), {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n logger.debug('Reddit API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Reddit API error: ${JSON.stringify(result)}`);\n }\n};\n","import { WalkerOS } from '@walkeros/core';\nimport { isArray, isObject, isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = [\n 'email',\n 'external_id',\n 'ip_address',\n 'user_agent',\n 'idfa',\n 'aaid',\n];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\ntype HashableValue = WalkerOS.AnyObject | unknown | unknown[];\n\nasync function processValue(\n value: unknown,\n shouldHash: boolean,\n): Promise<unknown> {\n if (!shouldHash) return value;\n if (isArray(value)) {\n return Promise.all(value.map((item) => getHashServer(String(item))));\n }\n return getHashServer(String(value));\n}\n\nexport async function hashEvent<T extends HashableValue>(\n value: T,\n doNotHash: string[] = [],\n): Promise<T> {\n if (!isObject(value)) return value;\n\n const isUser = 'user' in value;\n const target = (isUser ? value.user : value) as WalkerOS.AnyObject;\n\n const entries = await Promise.all(\n Object.entries(target).map(async ([k, v]) => [\n k,\n await processValue(v, isUser && shouldBeHashed(k, doNotHash)),\n ]),\n );\n\n const result = entries.reduce((acc, [k, v]) => {\n if (isString(k)) acc[k] = v;\n return acc;\n }, {} as WalkerOS.AnyObject);\n\n return isUser ? { ...value, user: result } : (result as T);\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 action_source?: ActionSource;\n doNotHash?: string[];\n test_mode?: boolean;\n url?: string;\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n sendServer?: typeof sendServer;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n// Reddit Conversions API types\n// https://ads-api.reddit.com/docs/v2/#tag/Conversions-API\n\nexport type ActionSource = 'WEBSITE' | 'APP' | 'PHYSICAL_STORE';\n\nexport type TrackingType =\n | 'PageVisit'\n | 'ViewContent'\n | 'Search'\n | 'AddToCart'\n | 'AddToWishlist'\n | 'Purchase'\n | 'Lead'\n | 'SignUp'\n | 'Custom';\n\nexport interface EventType {\n tracking_type: TrackingType;\n custom_event_name?: string;\n}\n\nexport interface Product {\n id: string;\n name?: string;\n category: string;\n}\n\nexport interface EventMetadata {\n conversion_id?: string;\n item_count?: number;\n currency?: string;\n value?: number;\n value_decimal?: number;\n products?: Product[];\n units_sold?: number;\n country_code?: string;\n}\n\nexport interface ScreenDimensions {\n width: number;\n height: number;\n}\n\nexport interface DataProcessingOptions {\n modes: string[];\n country?: string;\n region?: string;\n}\n\nexport interface UserData {\n // Hashable fields (SHA-256)\n email?: string;\n external_id?: string;\n ip_address?: string;\n user_agent?: string;\n idfa?: string;\n aaid?: string;\n\n // Pass-through fields (not hashed)\n uuid?: string;\n opt_out?: boolean;\n screen_dimensions?: ScreenDimensions;\n data_processing_options?: DataProcessingOptions;\n}\n\nexport interface ConversionEvent {\n click_id?: string;\n event_at: string;\n event_at_ms?: number;\n event_type: EventType;\n event_metadata?: EventMetadata;\n user: UserData;\n}\n\nexport interface RequestBody {\n test_mode?: boolean;\n data: {\n events: ConversionEvent[];\n };\n}\n\nexport interface ResponseBody {\n success?: boolean;\n message?: string;\n}\n"],"mappings":"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","names":["import_core","import_server_core"]}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{getMappingValue,isObject as isObject2}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{isArray,isObject,isString}from"@walkeros/core";import{getHashServer}from"@walkeros/server-core";var keysToHash=["email","external_id","ip_address","user_agent","idfa","aaid"];function shouldBeHashed(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}async function processValue(value,shouldHash){return shouldHash?isArray(value)?Promise.all(value.map(item=>getHashServer(String(item)))):getHashServer(String(value)):value}var STANDARD_TRACKING_TYPES=new Set(["PageVisit","ViewContent","Search","AddToCart","AddToWishlist","Purchase","Lead","SignUp","Custom"]);function buildEventType(name){return function(name){return STANDARD_TRACKING_TYPES.has(name)}(name)&&"Custom"!==name?{tracking_type:name}:{tracking_type:"Custom",custom_event_name:name}}var push=async function(event,{config:config,data:data,env:env,logger:logger}){var _a;const{accessToken:accessToken,pixelId:pixelId,action_source:_action_source,doNotHash:doNotHash,test_mode:test_mode,url:url="https://ads-api.reddit.com/api/v2.0/conversions/events/",user_data:user_data}=config.settings,eventData=isObject2(data)?data:{},configData=config.data?await getMappingValue(event,config.data):{},userDataCustom=user_data?await getMappingValue(event,{map:user_data}):{},userData={...isObject2(configData)&&isObject2(configData.user)?configData.user:{},...isObject2(userDataCustom)?userDataCustom:{},...isObject2(eventData.user)?eventData.user:{}},{user:_u,event_metadata:eventMetadata,click_id:eventClickId,...restEventData}=eventData,timestampMs=event.timestamp||Date.now(),serverEvent={event_at:new Date(timestampMs).toISOString(),event_at_ms:timestampMs,event_type:buildEventType(event.name),...restEventData,user:userData},metadataFromMapping=isObject2(eventMetadata)?eventMetadata:{};serverEvent.event_metadata={conversion_id:event.id,...metadataFromMapping},"string"==typeof eventClickId&&(serverEvent.click_id=eventClickId);const hashedServerEvent=await async function(value,doNotHash=[]){if(!isObject(value))return value;const isUser="user"in value,target=isUser?value.user:value,result=(await Promise.all(Object.entries(target).map(async([k,v])=>[k,await processValue(v,isUser&&shouldBeHashed(k,doNotHash))]))).reduce((acc,[k,v])=>(isString(k)&&(acc[k]=v),acc),{});return isUser?{...value,user:result}:result}(serverEvent,doNotHash),body={...test_mode?{test_mode:!0}:{},data:{events:[hashedServerEvent]}},endpoint=`${url}${pixelId}`;logger.debug("Calling Reddit API",{endpoint:endpoint,method:"POST",trackingType:serverEvent.event_type.tracking_type,eventId:null==(_a=serverEvent.event_metadata)?void 0:_a.conversion_id});const sendServerFn=(null==env?void 0:env.sendServer)||sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`}});logger.debug("Reddit API response",{ok:!isObject2(result)||result.ok}),isObject2(result)&&!1===result.ok&&logger.throw(`Reddit API error: ${JSON.stringify(result)}`)},types_exports={},destinationReddit={type:"reddit",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={...settings,accessToken:accessToken,pixelId:pixelId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await push(event,context)},index_default=destinationReddit;export{types_exports as DestinationReddit,index_default as default,destinationReddit};//# sourceMappingURL=index.mjs.map
1
+ import{getMappingValue,isObject as isObject2}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{isArray,isObject,isString}from"@walkeros/core";import{getHashServer}from"@walkeros/server-core";var keysToHash=["email","external_id","ip_address","user_agent","idfa","aaid"];function shouldBeHashed(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}async function processValue(value,shouldHash){return shouldHash?isArray(value)?Promise.all(value.map(item=>getHashServer(String(item)))):getHashServer(String(value)):value}var STANDARD_TRACKING_TYPES=new Set(["PageVisit","ViewContent","Search","AddToCart","AddToWishlist","Purchase","Lead","SignUp","Custom"]);function buildEventType(name){return function(name){return STANDARD_TRACKING_TYPES.has(name)}(name)&&"Custom"!==name?{tracking_type:name}:{tracking_type:"Custom",custom_event_name:name}}var push=async function(event,{config:config,data:data,env:env,logger:logger,collector:collector}){const{accessToken:accessToken,pixelId:pixelId,action_source:_action_source,doNotHash:doNotHash,test_mode:test_mode,url:url="https://ads-api.reddit.com/api/v2.0/conversions/events/",user_data:user_data}=config.settings,eventData=isObject2(data)?data:{},configData=config.data?await getMappingValue(event,config.data,{collector:collector}):{},userDataCustom=user_data?await getMappingValue(event,{map:user_data},{collector:collector}):{},userData={...isObject2(configData)&&isObject2(configData.user)?configData.user:{},...isObject2(userDataCustom)?userDataCustom:{},...isObject2(eventData.user)?eventData.user:{}},{user:_u,event_metadata:eventMetadata,click_id:eventClickId,...restEventData}=eventData,timestampMs=event.timestamp||Date.now(),serverEvent={event_at:new Date(timestampMs).toISOString(),event_at_ms:timestampMs,event_type:buildEventType(event.name),...restEventData,user:userData},metadataFromMapping=isObject2(eventMetadata)?eventMetadata:{};serverEvent.event_metadata={conversion_id:event.id,...metadataFromMapping},"string"==typeof eventClickId&&(serverEvent.click_id=eventClickId);const hashedServerEvent=await async function(value,doNotHash=[]){if(!isObject(value))return value;const isUser="user"in value,target=isUser?value.user:value,result=(await Promise.all(Object.entries(target).map(async([k,v])=>[k,await processValue(v,isUser&&shouldBeHashed(k,doNotHash))]))).reduce((acc,[k,v])=>(isString(k)&&(acc[k]=v),acc),{});return isUser?{...value,user:result}:result}(serverEvent,doNotHash),body={...test_mode?{test_mode:!0}:{},data:{events:[hashedServerEvent]}},endpoint=`${url}${pixelId}`;logger.debug("Calling Reddit API",{endpoint:endpoint,method:"POST",trackingType:serverEvent.event_type.tracking_type,eventId:serverEvent.event_metadata?.conversion_id});const sendServerFn=env?.sendServer||sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`}});logger.debug("Reddit API response",{ok:!isObject2(result)||result.ok}),isObject2(result)&&!1===result.ok&&logger.throw(`Reddit API error: ${JSON.stringify(result)}`)},types_exports={},destinationReddit={type:"reddit",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={...settings,accessToken:accessToken,pixelId:pixelId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await push(event,context)},index_default=destinationReddit;export{types_exports as DestinationReddit,index_default as default,destinationReddit};//# 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 ...settings,\n accessToken,\n pixelId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n EventType,\n PushFn,\n RequestBody,\n TrackingType,\n UserData,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEvent } from './hash';\n\nconst STANDARD_TRACKING_TYPES: ReadonlySet<TrackingType> =\n new Set<TrackingType>([\n 'PageVisit',\n 'ViewContent',\n 'Search',\n 'AddToCart',\n 'AddToWishlist',\n 'Purchase',\n 'Lead',\n 'SignUp',\n 'Custom',\n ]);\n\nfunction isStandardTrackingType(name: string): name is TrackingType {\n return STANDARD_TRACKING_TYPES.has(name as TrackingType);\n}\n\nfunction buildEventType(name: string): EventType {\n if (isStandardTrackingType(name) && name !== 'Custom') {\n return { tracking_type: name };\n }\n return { tracking_type: 'Custom', custom_event_name: name };\n}\n\nexport const push: PushFn = async function (\n event,\n { config, data, env, logger },\n) {\n const {\n accessToken,\n pixelId,\n action_source: _action_source,\n doNotHash,\n test_mode,\n url = 'https://ads-api.reddit.com/api/v2.0/conversions/events/',\n user_data,\n } = config.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 // Merge user data from config.data, settings.user_data, and event mapping\n const userData: UserData = {\n ...(isObject(configData) && isObject(configData.user)\n ? configData.user\n : {}),\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n ...(isObject(eventData.user) ? eventData.user : {}),\n };\n\n const {\n user: _u,\n event_metadata: eventMetadata,\n click_id: eventClickId,\n ...restEventData\n } = eventData;\n\n const timestampMs = event.timestamp || Date.now();\n\n const serverEvent: ConversionEvent = {\n event_at: new Date(timestampMs).toISOString(),\n event_at_ms: timestampMs,\n event_type: buildEventType(event.name),\n ...restEventData,\n user: userData,\n };\n\n // Merge event_metadata with auto-populated conversion_id (event.id for dedup)\n const metadataFromMapping = isObject(eventMetadata) ? eventMetadata : {};\n serverEvent.event_metadata = {\n conversion_id: event.id,\n ...metadataFromMapping,\n };\n\n if (typeof eventClickId === 'string') {\n serverEvent.click_id = eventClickId;\n }\n\n const hashedServerEvent = await hashEvent(serverEvent, doNotHash);\n\n const body: RequestBody = {\n ...(test_mode ? { test_mode: true } : {}),\n data: { events: [hashedServerEvent] },\n };\n\n const endpoint = `${url}${pixelId}`;\n\n logger.debug('Calling Reddit API', {\n endpoint,\n method: 'POST',\n trackingType: serverEvent.event_type.tracking_type,\n eventId: serverEvent.event_metadata?.conversion_id,\n });\n\n const sendServerFn = env?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body), {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n logger.debug('Reddit API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Reddit API error: ${JSON.stringify(result)}`);\n }\n};\n","import { WalkerOS } from '@walkeros/core';\nimport { isArray, isObject, isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = [\n 'email',\n 'external_id',\n 'ip_address',\n 'user_agent',\n 'idfa',\n 'aaid',\n];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\ntype HashableValue = WalkerOS.AnyObject | unknown | unknown[];\n\nasync function processValue(\n value: unknown,\n shouldHash: boolean,\n): Promise<unknown> {\n if (!shouldHash) return value;\n if (isArray(value)) {\n return Promise.all(value.map((item) => getHashServer(String(item))));\n }\n return getHashServer(String(value));\n}\n\nexport async function hashEvent<T extends HashableValue>(\n value: T,\n doNotHash: string[] = [],\n): Promise<T> {\n if (!isObject(value)) return value;\n\n const isUser = 'user' in value;\n const target = (isUser ? value.user : value) as WalkerOS.AnyObject;\n\n const entries = await Promise.all(\n Object.entries(target).map(async ([k, v]) => [\n k,\n await processValue(v, isUser && shouldBeHashed(k, doNotHash)),\n ]),\n );\n\n const result = entries.reduce((acc, [k, v]) => {\n if (isString(k)) acc[k] = v;\n return acc;\n }, {} as WalkerOS.AnyObject);\n\n return isUser ? { ...value, user: result } : (result as T);\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 action_source?: ActionSource;\n doNotHash?: string[];\n test_mode?: boolean;\n url?: string;\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n sendServer?: typeof sendServer;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n// Reddit Conversions API types\n// https://ads-api.reddit.com/docs/v2/#tag/Conversions-API\n\nexport type ActionSource = 'WEBSITE' | 'APP' | 'PHYSICAL_STORE';\n\nexport type TrackingType =\n | 'PageVisit'\n | 'ViewContent'\n | 'Search'\n | 'AddToCart'\n | 'AddToWishlist'\n | 'Purchase'\n | 'Lead'\n | 'SignUp'\n | 'Custom';\n\nexport interface EventType {\n tracking_type: TrackingType;\n custom_event_name?: string;\n}\n\nexport interface Product {\n id: string;\n name?: string;\n category: string;\n}\n\nexport interface EventMetadata {\n conversion_id?: string;\n item_count?: number;\n currency?: string;\n value?: number;\n value_decimal?: number;\n products?: Product[];\n units_sold?: number;\n country_code?: string;\n}\n\nexport interface ScreenDimensions {\n width: number;\n height: number;\n}\n\nexport interface DataProcessingOptions {\n modes: string[];\n country?: string;\n region?: string;\n}\n\nexport interface UserData {\n // Hashable fields (SHA-256)\n email?: string;\n external_id?: string;\n ip_address?: string;\n user_agent?: string;\n idfa?: string;\n aaid?: string;\n\n // Pass-through fields (not hashed)\n uuid?: string;\n opt_out?: boolean;\n screen_dimensions?: ScreenDimensions;\n data_processing_options?: DataProcessingOptions;\n}\n\nexport interface ConversionEvent {\n click_id?: string;\n event_at: string;\n event_at_ms?: number;\n event_type: EventType;\n event_metadata?: EventMetadata;\n user: UserData;\n}\n\nexport interface RequestBody {\n test_mode?: boolean;\n data: {\n events: ConversionEvent[];\n };\n}\n\nexport interface ResponseBody {\n success?: boolean;\n message?: string;\n}\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationReddit from './types';\n\nexport const destinationReddit: Destination = {\n type: 'reddit',\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 destinationReddit;\n"],"mappings":"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","names":["isObject","isObject"]}
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 ...settings,\n accessToken,\n pixelId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n EventType,\n PushFn,\n RequestBody,\n TrackingType,\n UserData,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEvent } from './hash';\n\nconst STANDARD_TRACKING_TYPES: ReadonlySet<TrackingType> =\n new Set<TrackingType>([\n 'PageVisit',\n 'ViewContent',\n 'Search',\n 'AddToCart',\n 'AddToWishlist',\n 'Purchase',\n 'Lead',\n 'SignUp',\n 'Custom',\n ]);\n\nfunction isStandardTrackingType(name: string): name is TrackingType {\n return STANDARD_TRACKING_TYPES.has(name as TrackingType);\n}\n\nfunction buildEventType(name: string): EventType {\n if (isStandardTrackingType(name) && name !== 'Custom') {\n return { tracking_type: name };\n }\n return { tracking_type: 'Custom', custom_event_name: name };\n}\n\nexport const push: PushFn = async function (\n event,\n { config, data, env, logger, collector },\n) {\n const {\n accessToken,\n pixelId,\n action_source: _action_source,\n doNotHash,\n test_mode,\n url = 'https://ads-api.reddit.com/api/v2.0/conversions/events/',\n user_data,\n } = config.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 // Merge user data from config.data, settings.user_data, and event mapping\n const userData: UserData = {\n ...(isObject(configData) && isObject(configData.user)\n ? configData.user\n : {}),\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n ...(isObject(eventData.user) ? eventData.user : {}),\n };\n\n const {\n user: _u,\n event_metadata: eventMetadata,\n click_id: eventClickId,\n ...restEventData\n } = eventData;\n\n const timestampMs = event.timestamp || Date.now();\n\n const serverEvent: ConversionEvent = {\n event_at: new Date(timestampMs).toISOString(),\n event_at_ms: timestampMs,\n event_type: buildEventType(event.name),\n ...restEventData,\n user: userData,\n };\n\n // Merge event_metadata with auto-populated conversion_id (event.id for dedup)\n const metadataFromMapping = isObject(eventMetadata) ? eventMetadata : {};\n serverEvent.event_metadata = {\n conversion_id: event.id,\n ...metadataFromMapping,\n };\n\n if (typeof eventClickId === 'string') {\n serverEvent.click_id = eventClickId;\n }\n\n const hashedServerEvent = await hashEvent(serverEvent, doNotHash);\n\n const body: RequestBody = {\n ...(test_mode ? { test_mode: true } : {}),\n data: { events: [hashedServerEvent] },\n };\n\n const endpoint = `${url}${pixelId}`;\n\n logger.debug('Calling Reddit API', {\n endpoint,\n method: 'POST',\n trackingType: serverEvent.event_type.tracking_type,\n eventId: serverEvent.event_metadata?.conversion_id,\n });\n\n const sendServerFn = env?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body), {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n logger.debug('Reddit API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Reddit API error: ${JSON.stringify(result)}`);\n }\n};\n","import { WalkerOS } from '@walkeros/core';\nimport { isArray, isObject, isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = [\n 'email',\n 'external_id',\n 'ip_address',\n 'user_agent',\n 'idfa',\n 'aaid',\n];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\ntype HashableValue = WalkerOS.AnyObject | unknown | unknown[];\n\nasync function processValue(\n value: unknown,\n shouldHash: boolean,\n): Promise<unknown> {\n if (!shouldHash) return value;\n if (isArray(value)) {\n return Promise.all(value.map((item) => getHashServer(String(item))));\n }\n return getHashServer(String(value));\n}\n\nexport async function hashEvent<T extends HashableValue>(\n value: T,\n doNotHash: string[] = [],\n): Promise<T> {\n if (!isObject(value)) return value;\n\n const isUser = 'user' in value;\n const target = (isUser ? value.user : value) as WalkerOS.AnyObject;\n\n const entries = await Promise.all(\n Object.entries(target).map(async ([k, v]) => [\n k,\n await processValue(v, isUser && shouldBeHashed(k, doNotHash)),\n ]),\n );\n\n const result = entries.reduce((acc, [k, v]) => {\n if (isString(k)) acc[k] = v;\n return acc;\n }, {} as WalkerOS.AnyObject);\n\n return isUser ? { ...value, user: result } : (result as T);\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 action_source?: ActionSource;\n doNotHash?: string[];\n test_mode?: boolean;\n url?: string;\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n sendServer?: typeof sendServer;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n// Reddit Conversions API types\n// https://ads-api.reddit.com/docs/v2/#tag/Conversions-API\n\nexport type ActionSource = 'WEBSITE' | 'APP' | 'PHYSICAL_STORE';\n\nexport type TrackingType =\n | 'PageVisit'\n | 'ViewContent'\n | 'Search'\n | 'AddToCart'\n | 'AddToWishlist'\n | 'Purchase'\n | 'Lead'\n | 'SignUp'\n | 'Custom';\n\nexport interface EventType {\n tracking_type: TrackingType;\n custom_event_name?: string;\n}\n\nexport interface Product {\n id: string;\n name?: string;\n category: string;\n}\n\nexport interface EventMetadata {\n conversion_id?: string;\n item_count?: number;\n currency?: string;\n value?: number;\n value_decimal?: number;\n products?: Product[];\n units_sold?: number;\n country_code?: string;\n}\n\nexport interface ScreenDimensions {\n width: number;\n height: number;\n}\n\nexport interface DataProcessingOptions {\n modes: string[];\n country?: string;\n region?: string;\n}\n\nexport interface UserData {\n // Hashable fields (SHA-256)\n email?: string;\n external_id?: string;\n ip_address?: string;\n user_agent?: string;\n idfa?: string;\n aaid?: string;\n\n // Pass-through fields (not hashed)\n uuid?: string;\n opt_out?: boolean;\n screen_dimensions?: ScreenDimensions;\n data_processing_options?: DataProcessingOptions;\n}\n\nexport interface ConversionEvent {\n click_id?: string;\n event_at: string;\n event_at_ms?: number;\n event_type: EventType;\n event_metadata?: EventMetadata;\n user: UserData;\n}\n\nexport interface RequestBody {\n test_mode?: boolean;\n data: {\n events: ConversionEvent[];\n };\n}\n\nexport interface ResponseBody {\n success?: boolean;\n message?: string;\n}\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationReddit from './types';\n\nexport const destinationReddit: Destination = {\n type: 'reddit',\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 destinationReddit;\n"],"mappings":"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","names":["isObject","isObject"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/server-destination-reddit",
4
- "version": "3.4.2",
4
+ "version": "4.0.0-next-1777882869103",
5
5
  "type": "destination",
6
6
  "platform": [
7
7
  "server"
@@ -116,22 +116,15 @@
116
116
  "consent": {
117
117
  "functional": true
118
118
  },
119
- "id": "1700000901-gr0up-1",
119
+ "id": "ev-1700000901",
120
120
  "trigger": "click",
121
121
  "entity": "product",
122
122
  "action": "add",
123
123
  "timestamp": 1700000901,
124
124
  "timing": 3.14,
125
- "group": "gr0up",
126
- "count": 1,
127
- "version": {
128
- "source": "3.4.2",
129
- "tagging": 1
130
- },
131
125
  "source": {
132
- "type": "server",
133
- "id": "https://shop.example.com/products",
134
- "previous_id": ""
126
+ "type": "express",
127
+ "platform": "server"
135
128
  }
136
129
  },
137
130
  "mapping": {
@@ -170,7 +163,7 @@
170
163
  [
171
164
  "sendServer",
172
165
  "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
173
- "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.901Z\",\"event_at_ms\":1700000901,\"event_type\":{\"tracking_type\":\"AddToCart\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"1700000901-gr0up-1\",\"value_decimal\":\"42.00\",\"currency\":\"EUR\",\"item_count\":1,\"products\":[{\"id\":\"SKU-B2\",\"name\":\"Cool Cap\",\"category\":\"hats\"}]}}]}}",
166
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.901Z\",\"event_at_ms\":1700000901,\"event_type\":{\"tracking_type\":\"AddToCart\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"ev-1700000901\",\"value_decimal\":\"42.00\",\"currency\":\"EUR\",\"item_count\":1,\"products\":[{\"id\":\"SKU-B2\",\"name\":\"Cool Cap\",\"category\":\"hats\"}]}}]}}",
174
167
  {
175
168
  "headers": {
176
169
  "Authorization": "Bearer s3cr3t"
@@ -208,35 +201,21 @@
208
201
  "entity": "child",
209
202
  "data": {
210
203
  "is": "subordinated"
211
- },
212
- "nested": [],
213
- "context": {
214
- "element": [
215
- "child",
216
- 0
217
- ]
218
204
  }
219
205
  }
220
206
  ],
221
207
  "consent": {
222
208
  "functional": true
223
209
  },
224
- "id": "1700000903-gr0up-1",
210
+ "id": "ev-1700000903",
225
211
  "trigger": "test",
226
212
  "entity": "form",
227
213
  "action": "submit",
228
214
  "timestamp": 1700000903,
229
215
  "timing": 3.14,
230
- "group": "gr0up",
231
- "count": 1,
232
- "version": {
233
- "source": "3.4.2",
234
- "tagging": 1
235
- },
236
216
  "source": {
237
- "type": "server",
238
- "id": "https://www.example.com/contact",
239
- "previous_id": ""
217
+ "type": "express",
218
+ "platform": "server"
240
219
  }
241
220
  },
242
221
  "mapping": {
@@ -256,7 +235,7 @@
256
235
  [
257
236
  "sendServer",
258
237
  "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
259
- "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.903Z\",\"event_at_ms\":1700000903,\"event_type\":{\"tracking_type\":\"Lead\"},\"user\":{\"email\":\"9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2\",\"external_id\":\"ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8\"},\"event_metadata\":{\"conversion_id\":\"1700000903-gr0up-1\"}}]}}",
238
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.903Z\",\"event_at_ms\":1700000903,\"event_type\":{\"tracking_type\":\"Lead\"},\"user\":{\"email\":\"9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2\",\"external_id\":\"ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8\"},\"event_metadata\":{\"conversion_id\":\"ev-1700000903\"}}]}}",
260
239
  {
261
240
  "headers": {
262
241
  "Authorization": "Bearer s3cr3t"
@@ -298,35 +277,21 @@
298
277
  "entity": "child",
299
278
  "data": {
300
279
  "is": "subordinated"
301
- },
302
- "nested": [],
303
- "context": {
304
- "element": [
305
- "child",
306
- 0
307
- ]
308
280
  }
309
281
  }
310
282
  ],
311
283
  "consent": {
312
284
  "functional": true
313
285
  },
314
- "id": "1700000902-gr0up-1",
286
+ "id": "ev-1700000902",
315
287
  "trigger": "load",
316
288
  "entity": "page",
317
289
  "action": "view",
318
290
  "timestamp": 1700000902,
319
291
  "timing": 3.14,
320
- "group": "gr0up",
321
- "count": 1,
322
- "version": {
323
- "source": "3.4.2",
324
- "tagging": 1
325
- },
326
292
  "source": {
327
- "type": "server",
328
- "id": "https://www.example.com/docs/",
329
- "previous_id": ""
293
+ "type": "express",
294
+ "platform": "server"
330
295
  }
331
296
  },
332
297
  "mapping": {
@@ -336,7 +301,7 @@
336
301
  [
337
302
  "sendServer",
338
303
  "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
339
- "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.902Z\",\"event_at_ms\":1700000902,\"event_type\":{\"tracking_type\":\"PageVisit\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"1700000902-gr0up-1\"}}]}}",
304
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.902Z\",\"event_at_ms\":1700000902,\"event_type\":{\"tracking_type\":\"PageVisit\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"ev-1700000902\"}}]}}",
340
305
  {
341
306
  "headers": {
342
307
  "Authorization": "Bearer s3cr3t"
@@ -386,22 +351,15 @@
386
351
  "consent": {
387
352
  "functional": true
388
353
  },
389
- "id": "1700000900-gr0up-1",
354
+ "id": "ev-1700000900",
390
355
  "trigger": "load",
391
356
  "entity": "order",
392
357
  "action": "complete",
393
358
  "timestamp": 1700000900,
394
359
  "timing": 3.14,
395
- "group": "gr0up",
396
- "count": 1,
397
- "version": {
398
- "source": "3.4.2",
399
- "tagging": 1
400
- },
401
360
  "source": {
402
- "type": "server",
403
- "id": "https://shop.example.com",
404
- "previous_id": ""
361
+ "type": "express",
362
+ "platform": "server"
405
363
  }
406
364
  },
407
365
  "mapping": {
@@ -425,7 +383,7 @@
425
383
  "nested",
426
384
  {
427
385
  "condition": {
428
- "$code": "e=>f(e)&&\"product\"===e.entity"
386
+ "$code": "e=>h(e)&&\"product\"===e.entity"
429
387
  },
430
388
  "map": {
431
389
  "id": "data.id",
@@ -447,7 +405,7 @@
447
405
  [
448
406
  "sendServer",
449
407
  "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
450
- "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.900Z\",\"event_at_ms\":1700000900,\"event_type\":{\"tracking_type\":\"Purchase\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"1700000900-gr0up-1\",\"value_decimal\":249.99,\"currency\":\"EUR\",\"item_count\":1,\"products\":[{\"id\":\"SKU-A1\",\"name\":\"Everyday Ruck Snack\",\"category\":\"bags\"}]}}]}}",
408
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.900Z\",\"event_at_ms\":1700000900,\"event_type\":{\"tracking_type\":\"Purchase\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"ev-1700000900\",\"value_decimal\":249.99,\"currency\":\"EUR\",\"item_count\":1,\"products\":[{\"id\":\"SKU-A1\",\"name\":\"Everyday Ruck Snack\",\"category\":\"bags\"}]}}]}}",
451
409
  {
452
410
  "headers": {
453
411
  "Authorization": "Bearer s3cr3t"
@@ -484,35 +442,21 @@
484
442
  "entity": "child",
485
443
  "data": {
486
444
  "is": "subordinated"
487
- },
488
- "nested": [],
489
- "context": {
490
- "element": [
491
- "child",
492
- 0
493
- ]
494
445
  }
495
446
  }
496
447
  ],
497
448
  "consent": {
498
449
  "functional": true
499
450
  },
500
- "id": "1700000905-gr0up-1",
451
+ "id": "ev-1700000905",
501
452
  "trigger": "test",
502
453
  "entity": "site",
503
454
  "action": "search",
504
455
  "timestamp": 1700000905,
505
456
  "timing": 3.14,
506
- "group": "gr0up",
507
- "count": 1,
508
- "version": {
509
- "source": "3.4.2",
510
- "tagging": 1
511
- },
512
457
  "source": {
513
- "type": "server",
514
- "id": "https://www.example.com/search",
515
- "previous_id": ""
458
+ "type": "express",
459
+ "platform": "server"
516
460
  }
517
461
  },
518
462
  "mapping": {
@@ -533,7 +477,7 @@
533
477
  [
534
478
  "sendServer",
535
479
  "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
536
- "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.905Z\",\"event_at_ms\":1700000905,\"event_type\":{\"tracking_type\":\"Search\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"1700000905-gr0up-1\",\"item_count\":1}}]}}",
480
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.905Z\",\"event_at_ms\":1700000905,\"event_type\":{\"tracking_type\":\"Search\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"ev-1700000905\",\"item_count\":1}}]}}",
537
481
  {
538
482
  "headers": {
539
483
  "Authorization": "Bearer s3cr3t"
@@ -571,35 +515,21 @@
571
515
  "entity": "child",
572
516
  "data": {
573
517
  "is": "subordinated"
574
- },
575
- "nested": [],
576
- "context": {
577
- "element": [
578
- "child",
579
- 0
580
- ]
581
518
  }
582
519
  }
583
520
  ],
584
521
  "consent": {
585
522
  "functional": true
586
523
  },
587
- "id": "1700000904-gr0up-1",
524
+ "id": "ev-1700000904",
588
525
  "trigger": "test",
589
526
  "entity": "user",
590
527
  "action": "signup",
591
528
  "timestamp": 1700000904,
592
529
  "timing": 3.14,
593
- "group": "gr0up",
594
- "count": 1,
595
- "version": {
596
- "source": "3.4.2",
597
- "tagging": 1
598
- },
599
530
  "source": {
600
- "type": "server",
601
- "id": "https://www.example.com/register",
602
- "previous_id": ""
531
+ "type": "express",
532
+ "platform": "server"
603
533
  }
604
534
  },
605
535
  "mapping": {
@@ -619,7 +549,7 @@
619
549
  [
620
550
  "sendServer",
621
551
  "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
622
- "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.904Z\",\"event_at_ms\":1700000904,\"event_type\":{\"tracking_type\":\"SignUp\"},\"user\":{\"email\":\"f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716\",\"external_id\":\"b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde\"},\"event_metadata\":{\"conversion_id\":\"1700000904-gr0up-1\"}}]}}",
552
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.904Z\",\"event_at_ms\":1700000904,\"event_type\":{\"tracking_type\":\"SignUp\"},\"user\":{\"email\":\"f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716\",\"external_id\":\"b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde\"},\"event_metadata\":{\"conversion_id\":\"ev-1700000904\"}}]}}",
623
553
  {
624
554
  "headers": {
625
555
  "Authorization": "Bearer s3cr3t"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@walkeros/server-destination-reddit",
3
3
  "description": "Reddit 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",