@walkeros/server-destination-pinterest 4.8.1-next-1792019907609 → 4.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,38 @@
1
1
  # @walkeros/server-destination-pinterest
2
2
 
3
- ## 4.8.1-next-1792019907609
3
+ ## 4.8.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 2374f54: An event that Pinterest reports as `failed` in its HTTP 200 answer
8
+ now fails the push instead of counting as delivered, with the dead-letter
9
+ queue and one ERROR line. Rules with `silent: true` send nothing.
10
+ - 2374f54: A failed request is reported as a failed push (dead-letter queue, one
11
+ ERROR line with the status) instead of counting as delivered or being logged
12
+ at debug. Events a destination cannot send, such as a missing user identifier,
13
+ fail with `missing-input`. Rules with `silent: true` send no event of their
14
+ own.
15
+ - Updated dependencies [2374f54]
16
+ - Updated dependencies [7e5fc27]
17
+ - Updated dependencies [2374f54]
18
+ - Updated dependencies [964590a]
19
+ - Updated dependencies [4100ede]
20
+ - Updated dependencies [2374f54]
21
+ - Updated dependencies [2374f54]
22
+ - Updated dependencies [15eb7b2]
23
+ - Updated dependencies [33a2779]
24
+ - Updated dependencies [33a2779]
25
+ - Updated dependencies [2374f54]
26
+ - @walkeros/core@4.8.2
27
+ - @walkeros/server-core@4.8.2
28
+
29
+ ## 4.8.1
4
30
 
5
31
  ### Patch Changes
6
32
 
7
33
  - Updated dependencies [1062e99]
8
- - @walkeros/core@4.8.1-next-1792019907609
9
- - @walkeros/server-core@4.8.1-next-1792019907609
34
+ - @walkeros/core@4.8.1
35
+ - @walkeros/server-core@4.8.1
10
36
 
11
37
  ## 4.8.0
12
38
 
package/README.md CHANGED
@@ -33,7 +33,12 @@ npm install @walkeros/server-destination-pinterest
33
33
  "destinations": {
34
34
  "pinterest": {
35
35
  "package": "@walkeros/server-destination-pinterest",
36
- "config": {}
36
+ "config": {
37
+ "settings": {
38
+ "accessToken": "YOUR_ACCESS_TOKEN",
39
+ "adAccountId": "YOUR_AD_ACCOUNT_ID"
40
+ }
41
+ }
37
42
  }
38
43
  }
39
44
  }
package/dist/dev.d.mts CHANGED
@@ -59,7 +59,7 @@ declare const SettingsSchema: z.ZodObject<{
59
59
  partner_name: z.ZodOptional<z.ZodString>;
60
60
  ip: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodLiteral<false>]>>;
61
61
  userAgent: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodLiteral<false>]>>;
62
- }, z.core.$strip>;
62
+ }, z.core.$strict>;
63
63
  type Settings = z.infer<typeof SettingsSchema>;
64
64
 
65
65
  /**
@@ -111,14 +111,20 @@ declare const addToCart: Flow.StepExample;
111
111
  declare const pageVisit: Flow.StepExample;
112
112
  declare const search: Flow.StepExample;
113
113
  declare const signup: Flow.StepExample;
114
+ /** A silent rule sends nothing to Pinterest. */
115
+ declare const silentRule: Flow.StepExample;
116
+ /** Pinterest rejects the event in an HTTP 200 body. */
117
+ declare const rejectedEvent: Flow.StepExample;
114
118
 
115
119
  declare const step_addToCart: typeof addToCart;
116
120
  declare const step_checkout: typeof checkout;
117
121
  declare const step_pageVisit: typeof pageVisit;
122
+ declare const step_rejectedEvent: typeof rejectedEvent;
118
123
  declare const step_search: typeof search;
119
124
  declare const step_signup: typeof signup;
125
+ declare const step_silentRule: typeof silentRule;
120
126
  declare namespace step {
121
- export { step_addToCart as addToCart, step_checkout as checkout, step_pageVisit as pageVisit, step_search as search, step_signup as signup };
127
+ export { step_addToCart as addToCart, step_checkout as checkout, step_pageVisit as pageVisit, step_rejectedEvent as rejectedEvent, step_search as search, step_signup as signup, step_silentRule as silentRule };
122
128
  }
123
129
 
124
130
  declare const index_env: typeof env;
package/dist/dev.d.ts CHANGED
@@ -59,7 +59,7 @@ declare const SettingsSchema: z.ZodObject<{
59
59
  partner_name: z.ZodOptional<z.ZodString>;
60
60
  ip: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodLiteral<false>]>>;
61
61
  userAgent: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodLiteral<false>]>>;
62
- }, z.core.$strip>;
62
+ }, z.core.$strict>;
63
63
  type Settings = z.infer<typeof SettingsSchema>;
64
64
 
65
65
  /**
@@ -111,14 +111,20 @@ declare const addToCart: Flow.StepExample;
111
111
  declare const pageVisit: Flow.StepExample;
112
112
  declare const search: Flow.StepExample;
113
113
  declare const signup: Flow.StepExample;
114
+ /** A silent rule sends nothing to Pinterest. */
115
+ declare const silentRule: Flow.StepExample;
116
+ /** Pinterest rejects the event in an HTTP 200 body. */
117
+ declare const rejectedEvent: Flow.StepExample;
114
118
 
115
119
  declare const step_addToCart: typeof addToCart;
116
120
  declare const step_checkout: typeof checkout;
117
121
  declare const step_pageVisit: typeof pageVisit;
122
+ declare const step_rejectedEvent: typeof rejectedEvent;
118
123
  declare const step_search: typeof search;
119
124
  declare const step_signup: typeof signup;
125
+ declare const step_silentRule: typeof silentRule;
120
126
  declare namespace step {
121
- export { step_addToCart as addToCart, step_checkout as checkout, step_pageVisit as pageVisit, step_search as search, step_signup as signup };
127
+ export { step_addToCart as addToCart, step_checkout as checkout, step_pageVisit as pageVisit, step_rejectedEvent as rejectedEvent, step_search as search, step_signup as signup, step_silentRule as silentRule };
122
128
  }
123
129
 
124
130
  declare const index_env: typeof env;
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:()=>f,schemas:()=>o}),module.exports=(e=n,((e,s,n,o)=>{if(s&&"object"==typeof s||"function"==typeof s)for(let c of i(s))r.call(e,c)||c===n||t(e,c,{get:()=>s[c],enumerable:!(o=a(s,c))||o.enumerable});return e})(t({},"__esModule",{value:!0}),e));var o={};s(o,{ActionSourceSchema:()=>p,EventNameSchema:()=>m,MappingSchema:()=>v,SettingsSchema:()=>_,mapping:()=>g,settings:()=>h});var c=require("@walkeros/core/dev"),d=require("@walkeros/core/dev"),u=require("@walkeros/core/dev"),p=u.z.enum(["app_android","app_ios","web","offline"]),m=u.z.union([u.z.enum(["add_payment_info","add_to_cart","add_to_wishlist","app_install","app_open","checkout","contact","custom","customize_product","find_location","initiate_checkout","lead","page_visit","schedule","search","signup","start_trial","submit_application","subscribe","view_category","view_content","watch_video"]),u.z.string()]),l=d.z.union([d.schemas.MappingSchemas.ValueSchema,d.z.literal(!1)]),_=d.z.object({accessToken:d.z.string().min(1).describe("Pinterest conversion access token for Bearer authentication (like pina_ABC123...)"),adAccountId:d.z.string().regex(/^[0-9]+$/,"Ad account ID must contain only digits").describe("Pinterest ad account ID from Ads Manager (like 123456789)"),action_source:p.describe("Source of the event (web, app_android, app_ios, offline) (like web)").optional(),doNotHash:d.z.array(d.z.string()).describe("Array of user_data fields that should not be hashed (like ['external_id'])").optional(),test:d.z.boolean().describe("Enable test mode by appending ?test=true to the API URL (like true)").optional(),url:d.z.string().url().describe("Custom URL for Pinterest Conversions API endpoint (like https://api.pinterest.com/v5/)").optional(),user_data:d.z.record(d.z.string(),d.z.string()).describe("Mapping configuration for user data fields (like { em: 'user.email', ph: 'user.phone' })").optional(),partner_name:d.z.string().describe("Third-party partner name for attribution (like ss-walkeros)").optional(),ip:l.describe('Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }. Default: ["ingest.ip", "event.user.ip"]. false switches it off. A mapped user_data.client_ip_address wins.').optional(),userAgent:l.describe('Client user agent, sent as user_data.client_user_agent. Resolves against { ingest, event }. Default: ["ingest.userAgent", "event.user.userAgent"]. false switches it off. A mapped user_data.client_user_agent wins.').optional()}),v=require("@walkeros/core/dev").z.object({}),h=(0,c.zodToSchema)(_),g=(0,c.zodToSchema)(v),f={};s(f,{env:()=>b,step:()=>k});var b={};s(b,{push:()=>w,simulation:()=>y});var w={sendServer:async function(e,t,a){return{ok:!0,data:{num_events_received:1,num_events_processed:1,events:[{status:"processed"}]}}}},y=["sendServer"],k={};s(k,{addToCart:()=>O,checkout:()=>x,pageVisit:()=>P,search:()=>q,signup:()=>E});var S=require("@walkeros/core"),A="https://api.pinterest.com/v5/ad_accounts/123456789/events",z={headers:{Authorization:"Bearer s3cr3t"}},x={title:"Checkout",description:"A completed order is sent to the Pinterest Conversions API as a checkout event with value, currency, and contents.",in:(0,S.getEvent)("order complete",{id:"a1b2c3d4e5f60001",timestamp:1700000900,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Everyday Ruck Snack",price:"129.99",quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com"}}),mapping:{name:"checkout",data:{map:{custom_data:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"},order_id:"data.id",num_items:{fn:e=>e.nested.filter(e=>"product"===e.entity).length},contents:{loop:["nested",{condition:e=>(0,S.isObject)(e)&&"product"===e.entity,map:{id:"data.id",item_name:"data.name",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",A,JSON.stringify({data:[{event_name:"checkout",event_id:"a1b2c3d4e5f60001",event_time:1700001,action_source:"web",user_data:{},custom_data:{value:249.99,currency:"EUR",order_id:"ORD-300",num_items:1,contents:[{id:"SKU-A1",item_name:"Everyday Ruck Snack",item_price:"129.99",quantity:2}]},event_source_url:"https://shop.example.com"}]}),z]]},O={title:"Add to cart",description:"A product add is sent to Pinterest as an add_to_cart conversion with the added item details.",in:(0,S.getEvent)("product add",{id:"a1b2c3d4e5f60002",timestamp:1700000901,data:{id:"SKU-B2",name:"Cool Cap",price:"42.00",quantity:1},user:{id:"user-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/products"}}),mapping:{name:"add_to_cart",data:{map:{custom_data:{map:{value:"data.price",currency:{value:"EUR"},contents:{set:[{map:{id:"data.id",item_name:"data.name",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",A,JSON.stringify({data:[{event_name:"add_to_cart",event_id:"a1b2c3d4e5f60002",event_time:1700001,action_source:"web",user_data:{},custom_data:{value:"42.00",currency:"EUR",contents:[{id:"SKU-B2",item_name:"Cool Cap",item_price:"42.00",quantity:1}]},event_source_url:"https://shop.example.com/products"}]}),z]]},P={title:"Page visit",description:"A page view is sent to Pinterest as a page_visit conversion with the source URL.",in:(0,S.getEvent)("page view",{id:"a1b2c3d4e5f60003",timestamp:1700000902,user:{id:"user-789"},source:{type:"browser",platform:"web",url:"https://www.example.com/docs/"}}),mapping:{name:"page_visit"},out:[["sendServer",A,JSON.stringify({data:[{event_name:"page_visit",event_id:"a1b2c3d4e5f60003",event_time:1700001,action_source:"web",user_data:{},event_source_url:"https://www.example.com/docs/"}]}),z]]},q={title:"Search",description:"A site search event is forwarded to Pinterest as a search conversion with the query in custom data.",in:(0,S.getEvent)("entity action",{id:"a1b2c3d4e5f60004",timestamp:1700000903,name:"site search",data:{query:"walkerOS destinations"},user:{id:"user-101"},source:{type:"browser",platform:"web",url:"https://www.example.com/search"}}),mapping:{name:"search",data:{map:{custom_data:{map:{search_string:"data.query"}}}}},out:[["sendServer",A,JSON.stringify({data:[{event_name:"search",event_id:"a1b2c3d4e5f60004",event_time:1700001,action_source:"web",user_data:{},custom_data:{search_string:"walkerOS destinations"},event_source_url:"https://www.example.com/search"}]}),z]]},E={title:"Signup",description:"A user signup is sent to Pinterest as a signup conversion with the hashed email and external id.",in:(0,S.getEvent)("entity action",{id:"a1b2c3d4e5f60005",timestamp:1700000904,name:"user signup",data:{method:"email"},user:{id:"new-user-1",email:"new@example.com"},source:{type:"browser",platform:"web",url:"https://www.example.com/register"}}),mapping:{name:"signup",data:{map:{user_data:{map:{em:{set:["user.email"]},external_id:{set:["user.id"]}}}}}},out:[["sendServer",A,JSON.stringify({data:[{event_name:"signup",event_id:"a1b2c3d4e5f60005",event_time:1700001,action_source:"web",user_data:{em:["f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716"],external_id:["b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"]},event_source_url:"https://www.example.com/register"}]}),z]]};//# sourceMappingURL=dev.js.map
1
+ "use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,r=(e,a)=>{for(var i in a)t(e,i,{get:a[i],enumerable:!0})},n={};r(n,{examples:()=>f,schemas:()=>o}),module.exports=(e=n,((e,r,n,o)=>{if(r&&"object"==typeof r||"function"==typeof r)for(let c of i(r))s.call(e,c)||c===n||t(e,c,{get:()=>r[c],enumerable:!(o=a(r,c))||o.enumerable});return e})(t({},"__esModule",{value:!0}),e));var o={};r(o,{ActionSourceSchema:()=>p,EventNameSchema:()=>m,MappingSchema:()=>v,SettingsSchema:()=>_,mapping:()=>g,settings:()=>h});var c=require("@walkeros/core/dev"),d=require("@walkeros/core/dev"),u=require("@walkeros/core/dev"),p=u.z.enum(["app_android","app_ios","web","offline"]),m=u.z.union([u.z.enum(["add_payment_info","add_to_cart","add_to_wishlist","app_install","app_open","checkout","contact","custom","customize_product","find_location","initiate_checkout","lead","page_visit","schedule","search","signup","start_trial","submit_application","subscribe","view_category","view_content","watch_video"]),u.z.string()]),l=d.z.union([d.schemas.MappingSchemas.ValueSchema,d.z.literal(!1)]),_=d.z.object({accessToken:d.z.string().min(1).describe("Pinterest conversion access token for Bearer authentication (like pina_ABC123...)"),adAccountId:d.z.string().regex(/^[0-9]+$/,"Ad account ID must contain only digits").describe("Pinterest ad account ID from Ads Manager (like 123456789)"),action_source:p.describe("Source of the event (web, app_android, app_ios, offline) (like web)").optional(),doNotHash:d.z.array(d.z.string()).describe("Array of user_data fields that should not be hashed (like ['external_id'])").optional(),test:d.z.boolean().describe("Enable test mode by appending ?test=true to the API URL (like true)").optional(),url:d.z.string().url().describe("Custom URL for Pinterest Conversions API endpoint (like https://api.pinterest.com/v5/)").optional(),user_data:d.z.record(d.z.string(),d.z.string()).describe("Mapping configuration for user data fields (like { em: 'user.email', ph: 'user.phone' })").optional(),partner_name:d.z.string().describe("Third-party partner name for attribution (like ss-walkeros)").optional(),ip:l.describe('Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }. Default: ["ingest.ip", "event.user.ip"]. false switches it off. A mapped user_data.client_ip_address wins.').optional(),userAgent:l.describe('Client user agent, sent as user_data.client_user_agent. Resolves against { ingest, event }. Default: ["ingest.userAgent", "event.user.userAgent"]. false switches it off. A mapped user_data.client_user_agent wins.').optional()}).strict(),v=require("@walkeros/core/dev").z.object({}),h=(0,c.zodToSchema)(_),g=(0,c.zodToSchema)(v),f={};r(f,{env:()=>b,step:()=>S});var b={};r(b,{push:()=>w,simulation:()=>y});var w={sendServer:async function(e,t,a){return{data:{num_events_received:1,num_events_processed:1,events:[{status:"processed"}]}}}},y=["sendServer"],S={};r(S,{addToCart:()=>x,checkout:()=>P,pageVisit:()=>q,rejectedEvent:()=>C,search:()=>E,signup:()=>O,silentRule:()=>R});var k=require("@walkeros/core"),A="https://api.pinterest.com/v5/ad_accounts/123456789/events",z={headers:{Authorization:"Bearer s3cr3t"}},P={title:"Checkout",description:"A completed order is sent to the Pinterest Conversions API as a checkout event with value, currency, and contents.",in:(0,k.getEvent)("order complete",{id:"a1b2c3d4e5f60001",timestamp:1700000900,data:{id:"ORD-300",value:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Everyday Ruck Snack",price:"129.99",quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com"}}),mapping:{name:"checkout",data:{map:{custom_data:{map:{value:"data.value",currency:{key:"data.currency",value:"EUR"},order_id:"data.id",num_items:{fn:e=>e.nested.filter(e=>"product"===e.entity).length},contents:{loop:["nested",{condition:e=>(0,k.isObject)(e)&&"product"===e.entity,map:{id:"data.id",item_name:"data.name",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",A,JSON.stringify({data:[{event_name:"checkout",event_id:"a1b2c3d4e5f60001",event_time:1700001,action_source:"web",user_data:{},custom_data:{value:249.99,currency:"EUR",order_id:"ORD-300",num_items:1,contents:[{id:"SKU-A1",item_name:"Everyday Ruck Snack",item_price:"129.99",quantity:2}]},event_source_url:"https://shop.example.com"}]}),z]]},x={title:"Add to cart",description:"A product add is sent to Pinterest as an add_to_cart conversion with the added item details.",in:(0,k.getEvent)("product add",{id:"a1b2c3d4e5f60002",timestamp:1700000901,data:{id:"SKU-B2",name:"Cool Cap",price:"42.00",quantity:1},user:{id:"user-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/products"}}),mapping:{name:"add_to_cart",data:{map:{custom_data:{map:{value:"data.price",currency:{value:"EUR"},contents:{set:[{map:{id:"data.id",item_name:"data.name",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",A,JSON.stringify({data:[{event_name:"add_to_cart",event_id:"a1b2c3d4e5f60002",event_time:1700001,action_source:"web",user_data:{},custom_data:{value:"42.00",currency:"EUR",contents:[{id:"SKU-B2",item_name:"Cool Cap",item_price:"42.00",quantity:1}]},event_source_url:"https://shop.example.com/products"}]}),z]]},q={title:"Page visit",description:"A page view is sent to Pinterest as a page_visit conversion with the source URL.",in:(0,k.getEvent)("page view",{id:"a1b2c3d4e5f60003",timestamp:1700000902,user:{id:"user-789"},source:{type:"browser",platform:"web",url:"https://www.example.com/docs/"}}),mapping:{name:"page_visit"},out:[["sendServer",A,JSON.stringify({data:[{event_name:"page_visit",event_id:"a1b2c3d4e5f60003",event_time:1700001,action_source:"web",user_data:{},event_source_url:"https://www.example.com/docs/"}]}),z]]},E={title:"Search",description:"A site search event is forwarded to Pinterest as a search conversion with the query in custom data.",in:(0,k.getEvent)("entity action",{id:"a1b2c3d4e5f60004",timestamp:1700000903,name:"site search",data:{query:"walkerOS destinations"},user:{id:"user-101"},source:{type:"browser",platform:"web",url:"https://www.example.com/search"}}),mapping:{name:"search",data:{map:{custom_data:{map:{search_string:"data.query"}}}}},out:[["sendServer",A,JSON.stringify({data:[{event_name:"search",event_id:"a1b2c3d4e5f60004",event_time:1700001,action_source:"web",user_data:{},custom_data:{search_string:"walkerOS destinations"},event_source_url:"https://www.example.com/search"}]}),z]]},O={title:"Signup",description:"A user signup is sent to Pinterest as a signup conversion with the hashed email and external id.",in:(0,k.getEvent)("entity action",{id:"a1b2c3d4e5f60005",timestamp:1700000904,name:"user signup",data:{method:"email"},user:{id:"new-user-1",email:"new@example.com"},source:{type:"browser",platform:"web",url:"https://www.example.com/register"}}),mapping:{name:"signup",data:{map:{user_data:{map:{em:{set:["user.email"]},external_id:{set:["user.id"]}}}}}},out:[["sendServer",A,JSON.stringify({data:[{event_name:"signup",event_id:"a1b2c3d4e5f60005",event_time:1700001,action_source:"web",user_data:{em:["f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716"],external_id:["b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"]},event_source_url:"https://www.example.com/register"}]}),z]]},R={public:!1,description:"A rule with silent: true sends no request to Pinterest.",in:(0,k.getEvent)("page view",{id:"a1b2c3d4e5f60006",timestamp:1700000905}),mapping:{silent:!0},out:[]},C={public:!1,description:"Pinterest answers HTTP 200 and reports the event as failed: the push fails with transport, not retryable, and the event goes to the DLQ.",in:(0,k.getEvent)("page view",{id:"a1b2c3d4e5f60007",timestamp:1700000906}),respond:{status:200,body:{num_events_received:1,num_events_processed:0,events:[{status:"failed",error_message:"Invalid event_time"}]}},outcome:{status:"failed",code:"transport",retryable:!1}};//# 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 { schemas, z } from '@walkeros/core/dev';\nimport { ActionSourceSchema } from './primitives';\n\nconst InputSchema = z.union([\n schemas.MappingSchemas.ValueSchema,\n z.literal(false),\n]);\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Pinterest conversion access token for Bearer authentication (like pina_ABC123...)',\n ),\n adAccountId: z\n .string()\n .regex(/^[0-9]+$/, 'Ad account ID must contain only digits')\n .describe('Pinterest ad account ID from Ads Manager (like 123456789)'),\n action_source: ActionSourceSchema.describe(\n 'Source of the event (web, app_android, app_ios, offline) (like web)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"Array of user_data fields that should not be hashed (like ['external_id'])\",\n )\n .optional(),\n test: z\n .boolean()\n .describe(\n 'Enable test mode by appending ?test=true to the API URL (like true)',\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for Pinterest Conversions API endpoint (like https://api.pinterest.com/v5/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user data fields (like { em: 'user.email', ph: 'user.phone' })\",\n )\n .optional(),\n partner_name: z\n .string()\n .describe('Third-party partner name for attribution (like ss-walkeros)')\n .optional(),\n ip: InputSchema.describe(\n 'Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }. Default: [\"ingest.ip\", \"event.user.ip\"]. false switches it off. A mapped user_data.client_ip_address wins.',\n ).optional(),\n userAgent: InputSchema.describe(\n 'Client user agent, sent as user_data.client_user_agent. Resolves against { ingest, event }. Default: [\"ingest.userAgent\", \"event.user.userAgent\"]. false switches it off. A mapped user_data.client_user_agent wins.',\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://developers.pinterest.com/docs/conversions/conversions/\n */\nexport const ActionSourceSchema = z.enum([\n 'app_android',\n 'app_ios',\n 'web',\n 'offline',\n]);\n\n/**\n * Event Name\n * Standard Pinterest CAPI event names or custom event identifiers\n */\nexport const EventNameSchema = z.union([\n z.enum([\n 'add_payment_info',\n 'add_to_cart',\n 'add_to_wishlist',\n 'app_install',\n 'app_open',\n 'checkout',\n 'contact',\n 'custom',\n 'customize_product',\n 'find_location',\n 'initiate_checkout',\n 'lead',\n 'page_visit',\n 'schedule',\n 'search',\n 'signup',\n 'start_trial',\n 'submit_application',\n 'subscribe',\n 'view_category',\n 'view_content',\n 'watch_video',\n ]),\n z.string(), // Allow custom event names\n]);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Pinterest Conversions API Mapping Schema\n * Pinterest 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 Pinterest Conversions API destination\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nasync function mockSendServer(\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n): Promise<SendResponse> {\n // Simulate successful Pinterest API response\n return {\n ok: true,\n data: {\n num_events_received: 1,\n num_events_processed: 1,\n events: [{ status: 'processed' }],\n },\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing Pinterest Conversions API events without making\n * actual HTTP requests to Pinterest'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 * Pinterest Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), { headers })` where\n * `endpoint = ${settings.url}ad_accounts/${settings.adAccountId}/events`\n * and `body = { data: [hashedServerEvent] }`.\n *\n * Test fixture pins `accessToken = 's3cr3t'` and `adAccountId = '123456789'`,\n * so every endpoint resolves to:\n * https://api.pinterest.com/v5/ad_accounts/123456789/events\n *\n * Body is emitted with keys in insertion order from push.ts:\n * 1. event_name\n * 2. event_id\n * 3. event_time (unix seconds; `Math.round(event.timestamp / 1000)`)\n * 4. action_source (default 'web')\n * 5. ...restEventData (from mapping.data, excluding user_data/custom_data)\n * 6. user_data (hashed per Pinterest's PII requirements)\n * 7. custom_data (only when mapping sets custom_data)\n * 8. event_source_url (appended when action_source === 'web')\n *\n * The `options` argument carries the Authorization header.\n */\nconst ENDPOINT = 'https://api.pinterest.com/v5/ad_accounts/123456789/events';\nconst OPTIONS = {\n headers: { Authorization: 'Bearer s3cr3t' },\n};\n\nexport const checkout: Flow.StepExample = {\n title: 'Checkout',\n description:\n 'A completed order is sent to the Pinterest Conversions API as a checkout event with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'a1b2c3d4e5f60001',\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 price: '129.99',\n quantity: 2,\n },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com',\n },\n }),\n mapping: {\n name: 'checkout',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n order_id: 'data.id',\n num_items: {\n fn: (event: unknown) =>\n (event as WalkerOS.Event).nested.filter(\n (item) => item.entity === 'product',\n ).length,\n },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_name: 'data.name',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'checkout',\n event_id: 'a1b2c3d4e5f60001',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n value: 249.99,\n currency: 'EUR',\n order_id: 'ORD-300',\n num_items: 1,\n contents: [\n {\n id: 'SKU-A1',\n item_name: 'Everyday Ruck Snack',\n item_price: '129.99',\n quantity: 2,\n },\n ],\n },\n event_source_url: 'https://shop.example.com',\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 Pinterest as an add_to_cart conversion with the added item details.',\n in: getEvent('product add', {\n id: 'a1b2c3d4e5f60002',\n timestamp: 1700000901,\n data: { id: 'SKU-B2', name: 'Cool Cap', price: '42.00', quantity: 1 },\n user: { id: 'user-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products',\n },\n }),\n mapping: {\n name: 'add_to_cart',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n set: [\n {\n map: {\n id: 'data.id',\n item_name: 'data.name',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'add_to_cart',\n event_id: 'a1b2c3d4e5f60002',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n value: '42.00',\n currency: 'EUR',\n contents: [\n {\n id: 'SKU-B2',\n item_name: 'Cool Cap',\n item_price: '42.00',\n quantity: 1,\n },\n ],\n },\n event_source_url: 'https://shop.example.com/products',\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 Pinterest as a page_visit conversion with the source URL.',\n in: getEvent('page view', {\n id: 'a1b2c3d4e5f60003',\n timestamp: 1700000902,\n user: { id: 'user-789' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/docs/',\n },\n }),\n mapping: {\n name: 'page_visit',\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'page_visit',\n event_id: 'a1b2c3d4e5f60003',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n event_source_url: 'https://www.example.com/docs/',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const search: Flow.StepExample = {\n title: 'Search',\n description:\n 'A site search event is forwarded to Pinterest as a search conversion with the query in custom data.',\n in: getEvent('entity action', {\n id: 'a1b2c3d4e5f60004',\n timestamp: 1700000903,\n name: 'site search',\n data: { query: 'walkerOS destinations' },\n user: { id: 'user-101' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/search',\n },\n }),\n mapping: {\n name: 'search',\n data: {\n map: {\n custom_data: {\n map: {\n search_string: 'data.query',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'search',\n event_id: 'a1b2c3d4e5f60004',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n search_string: 'walkerOS destinations',\n },\n event_source_url: 'https://www.example.com/search',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const signup: Flow.StepExample = {\n title: 'Signup',\n description:\n 'A user signup is sent to Pinterest as a signup conversion with the hashed email and external id.',\n in: getEvent('entity action', {\n id: 'a1b2c3d4e5f60005',\n timestamp: 1700000904,\n name: 'user signup',\n data: { method: 'email' },\n user: { id: 'new-user-1', email: 'new@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/register',\n },\n }),\n mapping: {\n name: 'signup',\n data: {\n map: {\n user_data: {\n map: {\n em: { set: ['user.email'] },\n external_id: { set: ['user.id'] },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'signup',\n event_id: 'a1b2c3d4e5f60005',\n event_time: 1700001,\n action_source: 'web',\n user_data: {\n // sha256('new@example.com')\n em: [\n 'f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716',\n ],\n // sha256('new-user-1')\n external_id: [\n 'b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde',\n ],\n },\n event_source_url: 'https://www.example.com/register',\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 { schemas, z } from '@walkeros/core/dev';\nimport { ActionSourceSchema } from './primitives';\n\nconst InputSchema = z.union([\n schemas.MappingSchemas.ValueSchema,\n z.literal(false),\n]);\n\nexport const SettingsSchema = z\n .object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Pinterest conversion access token for Bearer authentication (like pina_ABC123...)',\n ),\n adAccountId: z\n .string()\n .regex(/^[0-9]+$/, 'Ad account ID must contain only digits')\n .describe('Pinterest ad account ID from Ads Manager (like 123456789)'),\n action_source: ActionSourceSchema.describe(\n 'Source of the event (web, app_android, app_ios, offline) (like web)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"Array of user_data fields that should not be hashed (like ['external_id'])\",\n )\n .optional(),\n test: z\n .boolean()\n .describe(\n 'Enable test mode by appending ?test=true to the API URL (like true)',\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for Pinterest Conversions API endpoint (like https://api.pinterest.com/v5/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user data fields (like { em: 'user.email', ph: 'user.phone' })\",\n )\n .optional(),\n partner_name: z\n .string()\n .describe('Third-party partner name for attribution (like ss-walkeros)')\n .optional(),\n ip: InputSchema.describe(\n 'Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }. Default: [\"ingest.ip\", \"event.user.ip\"]. false switches it off. A mapped user_data.client_ip_address wins.',\n ).optional(),\n userAgent: InputSchema.describe(\n 'Client user agent, sent as user_data.client_user_agent. Resolves against { ingest, event }. Default: [\"ingest.userAgent\", \"event.user.userAgent\"]. false switches it off. A mapped user_data.client_user_agent wins.',\n ).optional(),\n })\n .strict();\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://developers.pinterest.com/docs/conversions/conversions/\n */\nexport const ActionSourceSchema = z.enum([\n 'app_android',\n 'app_ios',\n 'web',\n 'offline',\n]);\n\n/**\n * Event Name\n * Standard Pinterest CAPI event names or custom event identifiers\n */\nexport const EventNameSchema = z.union([\n z.enum([\n 'add_payment_info',\n 'add_to_cart',\n 'add_to_wishlist',\n 'app_install',\n 'app_open',\n 'checkout',\n 'contact',\n 'custom',\n 'customize_product',\n 'find_location',\n 'initiate_checkout',\n 'lead',\n 'page_visit',\n 'schedule',\n 'search',\n 'signup',\n 'start_trial',\n 'submit_application',\n 'subscribe',\n 'view_category',\n 'view_content',\n 'watch_video',\n ]),\n z.string(), // Allow custom event names\n]);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Pinterest Conversions API Mapping Schema\n * Pinterest 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 Pinterest Conversions API destination\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nasync function mockSendServer(\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n): Promise<SendResponse> {\n // Simulate successful Pinterest API response\n return {\n data: {\n num_events_received: 1,\n num_events_processed: 1,\n events: [{ status: 'processed' }],\n },\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing Pinterest Conversions API events without making\n * actual HTTP requests to Pinterest'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 * Pinterest Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), { headers })` where\n * `endpoint = ${settings.url}ad_accounts/${settings.adAccountId}/events`\n * and `body = { data: [hashedServerEvent] }`.\n *\n * Test fixture pins `accessToken = 's3cr3t'` and `adAccountId = '123456789'`,\n * so every endpoint resolves to:\n * https://api.pinterest.com/v5/ad_accounts/123456789/events\n *\n * Body is emitted with keys in insertion order from push.ts:\n * 1. event_name\n * 2. event_id\n * 3. event_time (unix seconds; `Math.round(event.timestamp / 1000)`)\n * 4. action_source (default 'web')\n * 5. ...restEventData (from mapping.data, excluding user_data/custom_data)\n * 6. user_data (hashed per Pinterest's PII requirements)\n * 7. custom_data (only when mapping sets custom_data)\n * 8. event_source_url (appended when action_source === 'web')\n *\n * The `options` argument carries the Authorization header.\n */\nconst ENDPOINT = 'https://api.pinterest.com/v5/ad_accounts/123456789/events';\nconst OPTIONS = {\n headers: { Authorization: 'Bearer s3cr3t' },\n};\n\nexport const checkout: Flow.StepExample = {\n title: 'Checkout',\n description:\n 'A completed order is sent to the Pinterest Conversions API as a checkout event with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'a1b2c3d4e5f60001',\n timestamp: 1700000900,\n data: { id: 'ORD-300', value: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n price: '129.99',\n quantity: 2,\n },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com',\n },\n }),\n mapping: {\n name: 'checkout',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.value',\n currency: { key: 'data.currency', value: 'EUR' },\n order_id: 'data.id',\n num_items: {\n fn: (event: unknown) =>\n (event as WalkerOS.Event).nested.filter(\n (item) => item.entity === 'product',\n ).length,\n },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_name: 'data.name',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'checkout',\n event_id: 'a1b2c3d4e5f60001',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n value: 249.99,\n currency: 'EUR',\n order_id: 'ORD-300',\n num_items: 1,\n contents: [\n {\n id: 'SKU-A1',\n item_name: 'Everyday Ruck Snack',\n item_price: '129.99',\n quantity: 2,\n },\n ],\n },\n event_source_url: 'https://shop.example.com',\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 Pinterest as an add_to_cart conversion with the added item details.',\n in: getEvent('product add', {\n id: 'a1b2c3d4e5f60002',\n timestamp: 1700000901,\n data: { id: 'SKU-B2', name: 'Cool Cap', price: '42.00', quantity: 1 },\n user: { id: 'user-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products',\n },\n }),\n mapping: {\n name: 'add_to_cart',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n set: [\n {\n map: {\n id: 'data.id',\n item_name: 'data.name',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'add_to_cart',\n event_id: 'a1b2c3d4e5f60002',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n value: '42.00',\n currency: 'EUR',\n contents: [\n {\n id: 'SKU-B2',\n item_name: 'Cool Cap',\n item_price: '42.00',\n quantity: 1,\n },\n ],\n },\n event_source_url: 'https://shop.example.com/products',\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 Pinterest as a page_visit conversion with the source URL.',\n in: getEvent('page view', {\n id: 'a1b2c3d4e5f60003',\n timestamp: 1700000902,\n user: { id: 'user-789' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/docs/',\n },\n }),\n mapping: {\n name: 'page_visit',\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'page_visit',\n event_id: 'a1b2c3d4e5f60003',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n event_source_url: 'https://www.example.com/docs/',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const search: Flow.StepExample = {\n title: 'Search',\n description:\n 'A site search event is forwarded to Pinterest as a search conversion with the query in custom data.',\n in: getEvent('entity action', {\n id: 'a1b2c3d4e5f60004',\n timestamp: 1700000903,\n name: 'site search',\n data: { query: 'walkerOS destinations' },\n user: { id: 'user-101' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/search',\n },\n }),\n mapping: {\n name: 'search',\n data: {\n map: {\n custom_data: {\n map: {\n search_string: 'data.query',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'search',\n event_id: 'a1b2c3d4e5f60004',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n search_string: 'walkerOS destinations',\n },\n event_source_url: 'https://www.example.com/search',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const signup: Flow.StepExample = {\n title: 'Signup',\n description:\n 'A user signup is sent to Pinterest as a signup conversion with the hashed email and external id.',\n in: getEvent('entity action', {\n id: 'a1b2c3d4e5f60005',\n timestamp: 1700000904,\n name: 'user signup',\n data: { method: 'email' },\n user: { id: 'new-user-1', email: 'new@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/register',\n },\n }),\n mapping: {\n name: 'signup',\n data: {\n map: {\n user_data: {\n map: {\n em: { set: ['user.email'] },\n external_id: { set: ['user.id'] },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'signup',\n event_id: 'a1b2c3d4e5f60005',\n event_time: 1700001,\n action_source: 'web',\n user_data: {\n // sha256('new@example.com')\n em: [\n 'f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716',\n ],\n // sha256('new-user-1')\n external_id: [\n 'b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde',\n ],\n },\n event_source_url: 'https://www.example.com/register',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\n/** A silent rule sends nothing to Pinterest. */\nexport const silentRule: Flow.StepExample = {\n public: false,\n description: 'A rule with silent: true sends no request to Pinterest.',\n in: getEvent('page view', {\n id: 'a1b2c3d4e5f60006',\n timestamp: 1700000905,\n }),\n mapping: { silent: true },\n out: [],\n};\n\n/** Pinterest rejects the event in an HTTP 200 body. */\nexport const rejectedEvent: Flow.StepExample = {\n public: false,\n description:\n 'Pinterest answers HTTP 200 and reports the event as failed: the push fails with transport, not retryable, and the event goes to the DLQ.',\n in: getEvent('page view', {\n id: 'a1b2c3d4e5f60007',\n timestamp: 1700000906,\n }),\n respond: {\n status: 200,\n body: {\n num_events_received: 1,\n num_events_processed: 0,\n events: [{ status: 'failed', error_message: 'Invalid event_time' }],\n },\n },\n outcome: { status: 'failed', code: 'transport', retryable: false },\n};\n"],"mappings":"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","names":["import_dev","import_dev","import_dev"]}
package/dist/dev.mjs CHANGED
@@ -1 +1 @@
1
- var e=Object.defineProperty,t=(t,a)=>{for(var i in a)e(t,i,{get:a[i],enumerable:!0})},a={};t(a,{ActionSourceSchema:()=>o,EventNameSchema:()=>c,MappingSchema:()=>m,SettingsSchema:()=>p,mapping:()=>_,settings:()=>l});import{zodToSchema as i}from"@walkeros/core/dev";import{schemas as s,z as r}from"@walkeros/core/dev";import{z as n}from"@walkeros/core/dev";var o=n.enum(["app_android","app_ios","web","offline"]),c=n.union([n.enum(["add_payment_info","add_to_cart","add_to_wishlist","app_install","app_open","checkout","contact","custom","customize_product","find_location","initiate_checkout","lead","page_visit","schedule","search","signup","start_trial","submit_application","subscribe","view_category","view_content","watch_video"]),n.string()]),d=r.union([s.MappingSchemas.ValueSchema,r.literal(!1)]),p=r.object({accessToken:r.string().min(1).describe("Pinterest conversion access token for Bearer authentication (like pina_ABC123...)"),adAccountId:r.string().regex(/^[0-9]+$/,"Ad account ID must contain only digits").describe("Pinterest ad account ID from Ads Manager (like 123456789)"),action_source:o.describe("Source of the event (web, app_android, app_ios, offline) (like web)").optional(),doNotHash:r.array(r.string()).describe("Array of user_data fields that should not be hashed (like ['external_id'])").optional(),test:r.boolean().describe("Enable test mode by appending ?test=true to the API URL (like true)").optional(),url:r.string().url().describe("Custom URL for Pinterest Conversions API endpoint (like https://api.pinterest.com/v5/)").optional(),user_data:r.record(r.string(),r.string()).describe("Mapping configuration for user data fields (like { em: 'user.email', ph: 'user.phone' })").optional(),partner_name:r.string().describe("Third-party partner name for attribution (like ss-walkeros)").optional(),ip:d.describe('Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }. Default: ["ingest.ip", "event.user.ip"]. false switches it off. A mapped user_data.client_ip_address wins.').optional(),userAgent:d.describe('Client user agent, sent as user_data.client_user_agent. Resolves against { ingest, event }. Default: ["ingest.userAgent", "event.user.userAgent"]. false switches it off. A mapped user_data.client_user_agent wins.').optional()});import{z as u}from"@walkeros/core/dev";var m=u.object({}),l=i(p),_=i(m),v={};t(v,{env:()=>h,step:()=>w});var h={};t(h,{push:()=>f,simulation:()=>g});var f={sendServer:async function(e,t,a){return{ok:!0,data:{num_events_received:1,num_events_processed:1,events:[{status:"processed"}]}}}},g=["sendServer"],w={};t(w,{addToCart:()=>x,checkout:()=>A,pageVisit:()=>P,search:()=>R,signup:()=>C});import{getEvent as b,isObject as y}from"@walkeros/core";var k="https://api.pinterest.com/v5/ad_accounts/123456789/events",S={headers:{Authorization:"Bearer s3cr3t"}},A={title:"Checkout",description:"A completed order is sent to the Pinterest Conversions API as a checkout event with value, currency, and contents.",in:b("order complete",{id:"a1b2c3d4e5f60001",timestamp:1700000900,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Everyday Ruck Snack",price:"129.99",quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com"}}),mapping:{name:"checkout",data:{map:{custom_data:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"},order_id:"data.id",num_items:{fn:e=>e.nested.filter(e=>"product"===e.entity).length},contents:{loop:["nested",{condition:e=>y(e)&&"product"===e.entity,map:{id:"data.id",item_name:"data.name",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",k,JSON.stringify({data:[{event_name:"checkout",event_id:"a1b2c3d4e5f60001",event_time:1700001,action_source:"web",user_data:{},custom_data:{value:249.99,currency:"EUR",order_id:"ORD-300",num_items:1,contents:[{id:"SKU-A1",item_name:"Everyday Ruck Snack",item_price:"129.99",quantity:2}]},event_source_url:"https://shop.example.com"}]}),S]]},x={title:"Add to cart",description:"A product add is sent to Pinterest as an add_to_cart conversion with the added item details.",in:b("product add",{id:"a1b2c3d4e5f60002",timestamp:1700000901,data:{id:"SKU-B2",name:"Cool Cap",price:"42.00",quantity:1},user:{id:"user-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/products"}}),mapping:{name:"add_to_cart",data:{map:{custom_data:{map:{value:"data.price",currency:{value:"EUR"},contents:{set:[{map:{id:"data.id",item_name:"data.name",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",k,JSON.stringify({data:[{event_name:"add_to_cart",event_id:"a1b2c3d4e5f60002",event_time:1700001,action_source:"web",user_data:{},custom_data:{value:"42.00",currency:"EUR",contents:[{id:"SKU-B2",item_name:"Cool Cap",item_price:"42.00",quantity:1}]},event_source_url:"https://shop.example.com/products"}]}),S]]},P={title:"Page visit",description:"A page view is sent to Pinterest as a page_visit conversion with the source URL.",in:b("page view",{id:"a1b2c3d4e5f60003",timestamp:1700000902,user:{id:"user-789"},source:{type:"browser",platform:"web",url:"https://www.example.com/docs/"}}),mapping:{name:"page_visit"},out:[["sendServer",k,JSON.stringify({data:[{event_name:"page_visit",event_id:"a1b2c3d4e5f60003",event_time:1700001,action_source:"web",user_data:{},event_source_url:"https://www.example.com/docs/"}]}),S]]},R={title:"Search",description:"A site search event is forwarded to Pinterest as a search conversion with the query in custom data.",in:b("entity action",{id:"a1b2c3d4e5f60004",timestamp:1700000903,name:"site search",data:{query:"walkerOS destinations"},user:{id:"user-101"},source:{type:"browser",platform:"web",url:"https://www.example.com/search"}}),mapping:{name:"search",data:{map:{custom_data:{map:{search_string:"data.query"}}}}},out:[["sendServer",k,JSON.stringify({data:[{event_name:"search",event_id:"a1b2c3d4e5f60004",event_time:1700001,action_source:"web",user_data:{},custom_data:{search_string:"walkerOS destinations"},event_source_url:"https://www.example.com/search"}]}),S]]},C={title:"Signup",description:"A user signup is sent to Pinterest as a signup conversion with the hashed email and external id.",in:b("entity action",{id:"a1b2c3d4e5f60005",timestamp:1700000904,name:"user signup",data:{method:"email"},user:{id:"new-user-1",email:"new@example.com"},source:{type:"browser",platform:"web",url:"https://www.example.com/register"}}),mapping:{name:"signup",data:{map:{user_data:{map:{em:{set:["user.email"]},external_id:{set:["user.id"]}}}}}},out:[["sendServer",k,JSON.stringify({data:[{event_name:"signup",event_id:"a1b2c3d4e5f60005",event_time:1700001,action_source:"web",user_data:{em:["f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716"],external_id:["b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"]},event_source_url:"https://www.example.com/register"}]}),S]]};export{v as examples,a as schemas};//# sourceMappingURL=dev.mjs.map
1
+ import{createRequire as e}from"module";e(import.meta.url);var t=Object.defineProperty,a=(e,a)=>{for(var i in a)t(e,i,{get:a[i],enumerable:!0})},i={};a(i,{ActionSourceSchema:()=>d,EventNameSchema:()=>c,MappingSchema:()=>l,SettingsSchema:()=>u,mapping:()=>v,settings:()=>_});import{zodToSchema as s}from"@walkeros/core/dev";import{schemas as r,z as n}from"@walkeros/core/dev";import{z as o}from"@walkeros/core/dev";var d=o.enum(["app_android","app_ios","web","offline"]),c=o.union([o.enum(["add_payment_info","add_to_cart","add_to_wishlist","app_install","app_open","checkout","contact","custom","customize_product","find_location","initiate_checkout","lead","page_visit","schedule","search","signup","start_trial","submit_application","subscribe","view_category","view_content","watch_video"]),o.string()]),p=n.union([r.MappingSchemas.ValueSchema,n.literal(!1)]),u=n.object({accessToken:n.string().min(1).describe("Pinterest conversion access token for Bearer authentication (like pina_ABC123...)"),adAccountId:n.string().regex(/^[0-9]+$/,"Ad account ID must contain only digits").describe("Pinterest ad account ID from Ads Manager (like 123456789)"),action_source:d.describe("Source of the event (web, app_android, app_ios, offline) (like web)").optional(),doNotHash:n.array(n.string()).describe("Array of user_data fields that should not be hashed (like ['external_id'])").optional(),test:n.boolean().describe("Enable test mode by appending ?test=true to the API URL (like true)").optional(),url:n.string().url().describe("Custom URL for Pinterest Conversions API endpoint (like https://api.pinterest.com/v5/)").optional(),user_data:n.record(n.string(),n.string()).describe("Mapping configuration for user data fields (like { em: 'user.email', ph: 'user.phone' })").optional(),partner_name:n.string().describe("Third-party partner name for attribution (like ss-walkeros)").optional(),ip:p.describe('Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }. Default: ["ingest.ip", "event.user.ip"]. false switches it off. A mapped user_data.client_ip_address wins.').optional(),userAgent:p.describe('Client user agent, sent as user_data.client_user_agent. Resolves against { ingest, event }. Default: ["ingest.userAgent", "event.user.userAgent"]. false switches it off. A mapped user_data.client_user_agent wins.').optional()}).strict();import{z as m}from"@walkeros/core/dev";var l=m.object({}),_=s(u),v=s(l),h={};a(h,{env:()=>f,step:()=>b});var f={};a(f,{push:()=>g,simulation:()=>w});var g={sendServer:async function(e,t,a){return{data:{num_events_received:1,num_events_processed:1,events:[{status:"processed"}]}}}},w=["sendServer"],b={};a(b,{addToCart:()=>P,checkout:()=>x,pageVisit:()=>R,rejectedEvent:()=>E,search:()=>q,signup:()=>C,silentRule:()=>U});import{getEvent as y,isObject as k}from"@walkeros/core";var S="https://api.pinterest.com/v5/ad_accounts/123456789/events",A={headers:{Authorization:"Bearer s3cr3t"}},x={title:"Checkout",description:"A completed order is sent to the Pinterest Conversions API as a checkout event with value, currency, and contents.",in:y("order complete",{id:"a1b2c3d4e5f60001",timestamp:1700000900,data:{id:"ORD-300",value:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Everyday Ruck Snack",price:"129.99",quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com"}}),mapping:{name:"checkout",data:{map:{custom_data:{map:{value:"data.value",currency:{key:"data.currency",value:"EUR"},order_id:"data.id",num_items:{fn:e=>e.nested.filter(e=>"product"===e.entity).length},contents:{loop:["nested",{condition:e=>k(e)&&"product"===e.entity,map:{id:"data.id",item_name:"data.name",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",S,JSON.stringify({data:[{event_name:"checkout",event_id:"a1b2c3d4e5f60001",event_time:1700001,action_source:"web",user_data:{},custom_data:{value:249.99,currency:"EUR",order_id:"ORD-300",num_items:1,contents:[{id:"SKU-A1",item_name:"Everyday Ruck Snack",item_price:"129.99",quantity:2}]},event_source_url:"https://shop.example.com"}]}),A]]},P={title:"Add to cart",description:"A product add is sent to Pinterest as an add_to_cart conversion with the added item details.",in:y("product add",{id:"a1b2c3d4e5f60002",timestamp:1700000901,data:{id:"SKU-B2",name:"Cool Cap",price:"42.00",quantity:1},user:{id:"user-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/products"}}),mapping:{name:"add_to_cart",data:{map:{custom_data:{map:{value:"data.price",currency:{value:"EUR"},contents:{set:[{map:{id:"data.id",item_name:"data.name",item_price:"data.price",quantity:{key:"data.quantity",value:1}}}]}}}}}},out:[["sendServer",S,JSON.stringify({data:[{event_name:"add_to_cart",event_id:"a1b2c3d4e5f60002",event_time:1700001,action_source:"web",user_data:{},custom_data:{value:"42.00",currency:"EUR",contents:[{id:"SKU-B2",item_name:"Cool Cap",item_price:"42.00",quantity:1}]},event_source_url:"https://shop.example.com/products"}]}),A]]},R={title:"Page visit",description:"A page view is sent to Pinterest as a page_visit conversion with the source URL.",in:y("page view",{id:"a1b2c3d4e5f60003",timestamp:1700000902,user:{id:"user-789"},source:{type:"browser",platform:"web",url:"https://www.example.com/docs/"}}),mapping:{name:"page_visit"},out:[["sendServer",S,JSON.stringify({data:[{event_name:"page_visit",event_id:"a1b2c3d4e5f60003",event_time:1700001,action_source:"web",user_data:{},event_source_url:"https://www.example.com/docs/"}]}),A]]},q={title:"Search",description:"A site search event is forwarded to Pinterest as a search conversion with the query in custom data.",in:y("entity action",{id:"a1b2c3d4e5f60004",timestamp:1700000903,name:"site search",data:{query:"walkerOS destinations"},user:{id:"user-101"},source:{type:"browser",platform:"web",url:"https://www.example.com/search"}}),mapping:{name:"search",data:{map:{custom_data:{map:{search_string:"data.query"}}}}},out:[["sendServer",S,JSON.stringify({data:[{event_name:"search",event_id:"a1b2c3d4e5f60004",event_time:1700001,action_source:"web",user_data:{},custom_data:{search_string:"walkerOS destinations"},event_source_url:"https://www.example.com/search"}]}),A]]},C={title:"Signup",description:"A user signup is sent to Pinterest as a signup conversion with the hashed email and external id.",in:y("entity action",{id:"a1b2c3d4e5f60005",timestamp:1700000904,name:"user signup",data:{method:"email"},user:{id:"new-user-1",email:"new@example.com"},source:{type:"browser",platform:"web",url:"https://www.example.com/register"}}),mapping:{name:"signup",data:{map:{user_data:{map:{em:{set:["user.email"]},external_id:{set:["user.id"]}}}}}},out:[["sendServer",S,JSON.stringify({data:[{event_name:"signup",event_id:"a1b2c3d4e5f60005",event_time:1700001,action_source:"web",user_data:{em:["f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716"],external_id:["b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde"]},event_source_url:"https://www.example.com/register"}]}),A]]},U={public:!1,description:"A rule with silent: true sends no request to Pinterest.",in:y("page view",{id:"a1b2c3d4e5f60006",timestamp:1700000905}),mapping:{silent:!0},out:[]},E={public:!1,description:"Pinterest answers HTTP 200 and reports the event as failed: the push fails with transport, not retryable, and the event goes to the DLQ.",in:y("page view",{id:"a1b2c3d4e5f60007",timestamp:1700000906}),respond:{status:200,body:{num_events_received:1,num_events_processed:0,events:[{status:"failed",error_message:"Invalid event_time"}]}},outcome:{status:"failed",code:"transport",retryable:!1}};export{h as examples,i 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 { schemas, z } from '@walkeros/core/dev';\nimport { ActionSourceSchema } from './primitives';\n\nconst InputSchema = z.union([\n schemas.MappingSchemas.ValueSchema,\n z.literal(false),\n]);\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Pinterest conversion access token for Bearer authentication (like pina_ABC123...)',\n ),\n adAccountId: z\n .string()\n .regex(/^[0-9]+$/, 'Ad account ID must contain only digits')\n .describe('Pinterest ad account ID from Ads Manager (like 123456789)'),\n action_source: ActionSourceSchema.describe(\n 'Source of the event (web, app_android, app_ios, offline) (like web)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"Array of user_data fields that should not be hashed (like ['external_id'])\",\n )\n .optional(),\n test: z\n .boolean()\n .describe(\n 'Enable test mode by appending ?test=true to the API URL (like true)',\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for Pinterest Conversions API endpoint (like https://api.pinterest.com/v5/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user data fields (like { em: 'user.email', ph: 'user.phone' })\",\n )\n .optional(),\n partner_name: z\n .string()\n .describe('Third-party partner name for attribution (like ss-walkeros)')\n .optional(),\n ip: InputSchema.describe(\n 'Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }. Default: [\"ingest.ip\", \"event.user.ip\"]. false switches it off. A mapped user_data.client_ip_address wins.',\n ).optional(),\n userAgent: InputSchema.describe(\n 'Client user agent, sent as user_data.client_user_agent. Resolves against { ingest, event }. Default: [\"ingest.userAgent\", \"event.user.userAgent\"]. false switches it off. A mapped user_data.client_user_agent wins.',\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://developers.pinterest.com/docs/conversions/conversions/\n */\nexport const ActionSourceSchema = z.enum([\n 'app_android',\n 'app_ios',\n 'web',\n 'offline',\n]);\n\n/**\n * Event Name\n * Standard Pinterest CAPI event names or custom event identifiers\n */\nexport const EventNameSchema = z.union([\n z.enum([\n 'add_payment_info',\n 'add_to_cart',\n 'add_to_wishlist',\n 'app_install',\n 'app_open',\n 'checkout',\n 'contact',\n 'custom',\n 'customize_product',\n 'find_location',\n 'initiate_checkout',\n 'lead',\n 'page_visit',\n 'schedule',\n 'search',\n 'signup',\n 'start_trial',\n 'submit_application',\n 'subscribe',\n 'view_category',\n 'view_content',\n 'watch_video',\n ]),\n z.string(), // Allow custom event names\n]);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Pinterest Conversions API Mapping Schema\n * Pinterest 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 Pinterest Conversions API destination\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nasync function mockSendServer(\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n): Promise<SendResponse> {\n // Simulate successful Pinterest API response\n return {\n ok: true,\n data: {\n num_events_received: 1,\n num_events_processed: 1,\n events: [{ status: 'processed' }],\n },\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing Pinterest Conversions API events without making\n * actual HTTP requests to Pinterest'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 * Pinterest Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), { headers })` where\n * `endpoint = ${settings.url}ad_accounts/${settings.adAccountId}/events`\n * and `body = { data: [hashedServerEvent] }`.\n *\n * Test fixture pins `accessToken = 's3cr3t'` and `adAccountId = '123456789'`,\n * so every endpoint resolves to:\n * https://api.pinterest.com/v5/ad_accounts/123456789/events\n *\n * Body is emitted with keys in insertion order from push.ts:\n * 1. event_name\n * 2. event_id\n * 3. event_time (unix seconds; `Math.round(event.timestamp / 1000)`)\n * 4. action_source (default 'web')\n * 5. ...restEventData (from mapping.data, excluding user_data/custom_data)\n * 6. user_data (hashed per Pinterest's PII requirements)\n * 7. custom_data (only when mapping sets custom_data)\n * 8. event_source_url (appended when action_source === 'web')\n *\n * The `options` argument carries the Authorization header.\n */\nconst ENDPOINT = 'https://api.pinterest.com/v5/ad_accounts/123456789/events';\nconst OPTIONS = {\n headers: { Authorization: 'Bearer s3cr3t' },\n};\n\nexport const checkout: Flow.StepExample = {\n title: 'Checkout',\n description:\n 'A completed order is sent to the Pinterest Conversions API as a checkout event with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'a1b2c3d4e5f60001',\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 price: '129.99',\n quantity: 2,\n },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com',\n },\n }),\n mapping: {\n name: 'checkout',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n order_id: 'data.id',\n num_items: {\n fn: (event: unknown) =>\n (event as WalkerOS.Event).nested.filter(\n (item) => item.entity === 'product',\n ).length,\n },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_name: 'data.name',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'checkout',\n event_id: 'a1b2c3d4e5f60001',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n value: 249.99,\n currency: 'EUR',\n order_id: 'ORD-300',\n num_items: 1,\n contents: [\n {\n id: 'SKU-A1',\n item_name: 'Everyday Ruck Snack',\n item_price: '129.99',\n quantity: 2,\n },\n ],\n },\n event_source_url: 'https://shop.example.com',\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 Pinterest as an add_to_cart conversion with the added item details.',\n in: getEvent('product add', {\n id: 'a1b2c3d4e5f60002',\n timestamp: 1700000901,\n data: { id: 'SKU-B2', name: 'Cool Cap', price: '42.00', quantity: 1 },\n user: { id: 'user-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products',\n },\n }),\n mapping: {\n name: 'add_to_cart',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n set: [\n {\n map: {\n id: 'data.id',\n item_name: 'data.name',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'add_to_cart',\n event_id: 'a1b2c3d4e5f60002',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n value: '42.00',\n currency: 'EUR',\n contents: [\n {\n id: 'SKU-B2',\n item_name: 'Cool Cap',\n item_price: '42.00',\n quantity: 1,\n },\n ],\n },\n event_source_url: 'https://shop.example.com/products',\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 Pinterest as a page_visit conversion with the source URL.',\n in: getEvent('page view', {\n id: 'a1b2c3d4e5f60003',\n timestamp: 1700000902,\n user: { id: 'user-789' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/docs/',\n },\n }),\n mapping: {\n name: 'page_visit',\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'page_visit',\n event_id: 'a1b2c3d4e5f60003',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n event_source_url: 'https://www.example.com/docs/',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const search: Flow.StepExample = {\n title: 'Search',\n description:\n 'A site search event is forwarded to Pinterest as a search conversion with the query in custom data.',\n in: getEvent('entity action', {\n id: 'a1b2c3d4e5f60004',\n timestamp: 1700000903,\n name: 'site search',\n data: { query: 'walkerOS destinations' },\n user: { id: 'user-101' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/search',\n },\n }),\n mapping: {\n name: 'search',\n data: {\n map: {\n custom_data: {\n map: {\n search_string: 'data.query',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'search',\n event_id: 'a1b2c3d4e5f60004',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n search_string: 'walkerOS destinations',\n },\n event_source_url: 'https://www.example.com/search',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const signup: Flow.StepExample = {\n title: 'Signup',\n description:\n 'A user signup is sent to Pinterest as a signup conversion with the hashed email and external id.',\n in: getEvent('entity action', {\n id: 'a1b2c3d4e5f60005',\n timestamp: 1700000904,\n name: 'user signup',\n data: { method: 'email' },\n user: { id: 'new-user-1', email: 'new@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/register',\n },\n }),\n mapping: {\n name: 'signup',\n data: {\n map: {\n user_data: {\n map: {\n em: { set: ['user.email'] },\n external_id: { set: ['user.id'] },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'signup',\n event_id: 'a1b2c3d4e5f60005',\n event_time: 1700001,\n action_source: 'web',\n user_data: {\n // sha256('new@example.com')\n em: [\n 'f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716',\n ],\n // sha256('new-user-1')\n external_id: [\n 'b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde',\n ],\n },\n event_source_url: 'https://www.example.com/register',\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 { schemas, z } from '@walkeros/core/dev';\nimport { ActionSourceSchema } from './primitives';\n\nconst InputSchema = z.union([\n schemas.MappingSchemas.ValueSchema,\n z.literal(false),\n]);\n\nexport const SettingsSchema = z\n .object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'Pinterest conversion access token for Bearer authentication (like pina_ABC123...)',\n ),\n adAccountId: z\n .string()\n .regex(/^[0-9]+$/, 'Ad account ID must contain only digits')\n .describe('Pinterest ad account ID from Ads Manager (like 123456789)'),\n action_source: ActionSourceSchema.describe(\n 'Source of the event (web, app_android, app_ios, offline) (like web)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"Array of user_data fields that should not be hashed (like ['external_id'])\",\n )\n .optional(),\n test: z\n .boolean()\n .describe(\n 'Enable test mode by appending ?test=true to the API URL (like true)',\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for Pinterest Conversions API endpoint (like https://api.pinterest.com/v5/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user data fields (like { em: 'user.email', ph: 'user.phone' })\",\n )\n .optional(),\n partner_name: z\n .string()\n .describe('Third-party partner name for attribution (like ss-walkeros)')\n .optional(),\n ip: InputSchema.describe(\n 'Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }. Default: [\"ingest.ip\", \"event.user.ip\"]. false switches it off. A mapped user_data.client_ip_address wins.',\n ).optional(),\n userAgent: InputSchema.describe(\n 'Client user agent, sent as user_data.client_user_agent. Resolves against { ingest, event }. Default: [\"ingest.userAgent\", \"event.user.userAgent\"]. false switches it off. A mapped user_data.client_user_agent wins.',\n ).optional(),\n })\n .strict();\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://developers.pinterest.com/docs/conversions/conversions/\n */\nexport const ActionSourceSchema = z.enum([\n 'app_android',\n 'app_ios',\n 'web',\n 'offline',\n]);\n\n/**\n * Event Name\n * Standard Pinterest CAPI event names or custom event identifiers\n */\nexport const EventNameSchema = z.union([\n z.enum([\n 'add_payment_info',\n 'add_to_cart',\n 'add_to_wishlist',\n 'app_install',\n 'app_open',\n 'checkout',\n 'contact',\n 'custom',\n 'customize_product',\n 'find_location',\n 'initiate_checkout',\n 'lead',\n 'page_visit',\n 'schedule',\n 'search',\n 'signup',\n 'start_trial',\n 'submit_application',\n 'subscribe',\n 'view_category',\n 'view_content',\n 'watch_video',\n ]),\n z.string(), // Allow custom event names\n]);\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Pinterest Conversions API Mapping Schema\n * Pinterest 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 Pinterest Conversions API destination\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nasync function mockSendServer(\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n): Promise<SendResponse> {\n // Simulate successful Pinterest API response\n return {\n data: {\n num_events_received: 1,\n num_events_processed: 1,\n events: [{ status: 'processed' }],\n },\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing Pinterest Conversions API events without making\n * actual HTTP requests to Pinterest'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 * Pinterest Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), { headers })` where\n * `endpoint = ${settings.url}ad_accounts/${settings.adAccountId}/events`\n * and `body = { data: [hashedServerEvent] }`.\n *\n * Test fixture pins `accessToken = 's3cr3t'` and `adAccountId = '123456789'`,\n * so every endpoint resolves to:\n * https://api.pinterest.com/v5/ad_accounts/123456789/events\n *\n * Body is emitted with keys in insertion order from push.ts:\n * 1. event_name\n * 2. event_id\n * 3. event_time (unix seconds; `Math.round(event.timestamp / 1000)`)\n * 4. action_source (default 'web')\n * 5. ...restEventData (from mapping.data, excluding user_data/custom_data)\n * 6. user_data (hashed per Pinterest's PII requirements)\n * 7. custom_data (only when mapping sets custom_data)\n * 8. event_source_url (appended when action_source === 'web')\n *\n * The `options` argument carries the Authorization header.\n */\nconst ENDPOINT = 'https://api.pinterest.com/v5/ad_accounts/123456789/events';\nconst OPTIONS = {\n headers: { Authorization: 'Bearer s3cr3t' },\n};\n\nexport const checkout: Flow.StepExample = {\n title: 'Checkout',\n description:\n 'A completed order is sent to the Pinterest Conversions API as a checkout event with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'a1b2c3d4e5f60001',\n timestamp: 1700000900,\n data: { id: 'ORD-300', value: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-A1',\n name: 'Everyday Ruck Snack',\n price: '129.99',\n quantity: 2,\n },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com',\n },\n }),\n mapping: {\n name: 'checkout',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.value',\n currency: { key: 'data.currency', value: 'EUR' },\n order_id: 'data.id',\n num_items: {\n fn: (event: unknown) =>\n (event as WalkerOS.Event).nested.filter(\n (item) => item.entity === 'product',\n ).length,\n },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n id: 'data.id',\n item_name: 'data.name',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'checkout',\n event_id: 'a1b2c3d4e5f60001',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n value: 249.99,\n currency: 'EUR',\n order_id: 'ORD-300',\n num_items: 1,\n contents: [\n {\n id: 'SKU-A1',\n item_name: 'Everyday Ruck Snack',\n item_price: '129.99',\n quantity: 2,\n },\n ],\n },\n event_source_url: 'https://shop.example.com',\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 Pinterest as an add_to_cart conversion with the added item details.',\n in: getEvent('product add', {\n id: 'a1b2c3d4e5f60002',\n timestamp: 1700000901,\n data: { id: 'SKU-B2', name: 'Cool Cap', price: '42.00', quantity: 1 },\n user: { id: 'user-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products',\n },\n }),\n mapping: {\n name: 'add_to_cart',\n data: {\n map: {\n custom_data: {\n map: {\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n set: [\n {\n map: {\n id: 'data.id',\n item_name: 'data.name',\n item_price: 'data.price',\n quantity: { key: 'data.quantity', value: 1 },\n },\n },\n ],\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'add_to_cart',\n event_id: 'a1b2c3d4e5f60002',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n value: '42.00',\n currency: 'EUR',\n contents: [\n {\n id: 'SKU-B2',\n item_name: 'Cool Cap',\n item_price: '42.00',\n quantity: 1,\n },\n ],\n },\n event_source_url: 'https://shop.example.com/products',\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 Pinterest as a page_visit conversion with the source URL.',\n in: getEvent('page view', {\n id: 'a1b2c3d4e5f60003',\n timestamp: 1700000902,\n user: { id: 'user-789' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/docs/',\n },\n }),\n mapping: {\n name: 'page_visit',\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'page_visit',\n event_id: 'a1b2c3d4e5f60003',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n event_source_url: 'https://www.example.com/docs/',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const search: Flow.StepExample = {\n title: 'Search',\n description:\n 'A site search event is forwarded to Pinterest as a search conversion with the query in custom data.',\n in: getEvent('entity action', {\n id: 'a1b2c3d4e5f60004',\n timestamp: 1700000903,\n name: 'site search',\n data: { query: 'walkerOS destinations' },\n user: { id: 'user-101' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/search',\n },\n }),\n mapping: {\n name: 'search',\n data: {\n map: {\n custom_data: {\n map: {\n search_string: 'data.query',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'search',\n event_id: 'a1b2c3d4e5f60004',\n event_time: 1700001,\n action_source: 'web',\n user_data: {},\n custom_data: {\n search_string: 'walkerOS destinations',\n },\n event_source_url: 'https://www.example.com/search',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const signup: Flow.StepExample = {\n title: 'Signup',\n description:\n 'A user signup is sent to Pinterest as a signup conversion with the hashed email and external id.',\n in: getEvent('entity action', {\n id: 'a1b2c3d4e5f60005',\n timestamp: 1700000904,\n name: 'user signup',\n data: { method: 'email' },\n user: { id: 'new-user-1', email: 'new@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://www.example.com/register',\n },\n }),\n mapping: {\n name: 'signup',\n data: {\n map: {\n user_data: {\n map: {\n em: { set: ['user.email'] },\n external_id: { set: ['user.id'] },\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n data: [\n {\n event_name: 'signup',\n event_id: 'a1b2c3d4e5f60005',\n event_time: 1700001,\n action_source: 'web',\n user_data: {\n // sha256('new@example.com')\n em: [\n 'f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716',\n ],\n // sha256('new-user-1')\n external_id: [\n 'b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde',\n ],\n },\n event_source_url: 'https://www.example.com/register',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\n/** A silent rule sends nothing to Pinterest. */\nexport const silentRule: Flow.StepExample = {\n public: false,\n description: 'A rule with silent: true sends no request to Pinterest.',\n in: getEvent('page view', {\n id: 'a1b2c3d4e5f60006',\n timestamp: 1700000905,\n }),\n mapping: { silent: true },\n out: [],\n};\n\n/** Pinterest rejects the event in an HTTP 200 body. */\nexport const rejectedEvent: Flow.StepExample = {\n public: false,\n description:\n 'Pinterest answers HTTP 200 and reports the event as failed: the push fails with transport, not retryable, and the event goes to the DLQ.',\n in: getEvent('page view', {\n id: 'a1b2c3d4e5f60007',\n timestamp: 1700000906,\n }),\n respond: {\n status: 200,\n body: {\n num_events_received: 1,\n num_events_processed: 0,\n events: [{ status: 'failed', error_message: 'Invalid event_time' }],\n },\n },\n outcome: { status: 'failed', code: 'transport', retryable: false },\n};\n"],"mappings":"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","names":["z","z","z"]}
@@ -25,14 +25,20 @@ declare const addToCart: Flow.StepExample;
25
25
  declare const pageVisit: Flow.StepExample;
26
26
  declare const search: Flow.StepExample;
27
27
  declare const signup: Flow.StepExample;
28
+ /** A silent rule sends nothing to Pinterest. */
29
+ declare const silentRule: Flow.StepExample;
30
+ /** Pinterest rejects the event in an HTTP 200 body. */
31
+ declare const rejectedEvent: Flow.StepExample;
28
32
 
29
33
  declare const step_addToCart: typeof addToCart;
30
34
  declare const step_checkout: typeof checkout;
31
35
  declare const step_pageVisit: typeof pageVisit;
36
+ declare const step_rejectedEvent: typeof rejectedEvent;
32
37
  declare const step_search: typeof search;
33
38
  declare const step_signup: typeof signup;
39
+ declare const step_silentRule: typeof silentRule;
34
40
  declare namespace step {
35
- export { step_addToCart as addToCart, step_checkout as checkout, step_pageVisit as pageVisit, step_search as search, step_signup as signup };
41
+ export { step_addToCart as addToCart, step_checkout as checkout, step_pageVisit as pageVisit, step_rejectedEvent as rejectedEvent, step_search as search, step_signup as signup, step_silentRule as silentRule };
36
42
  }
37
43
 
38
44
  export { env, step };
@@ -25,14 +25,20 @@ declare const addToCart: Flow.StepExample;
25
25
  declare const pageVisit: Flow.StepExample;
26
26
  declare const search: Flow.StepExample;
27
27
  declare const signup: Flow.StepExample;
28
+ /** A silent rule sends nothing to Pinterest. */
29
+ declare const silentRule: Flow.StepExample;
30
+ /** Pinterest rejects the event in an HTTP 200 body. */
31
+ declare const rejectedEvent: Flow.StepExample;
28
32
 
29
33
  declare const step_addToCart: typeof addToCart;
30
34
  declare const step_checkout: typeof checkout;
31
35
  declare const step_pageVisit: typeof pageVisit;
36
+ declare const step_rejectedEvent: typeof rejectedEvent;
32
37
  declare const step_search: typeof search;
33
38
  declare const step_signup: typeof signup;
39
+ declare const step_silentRule: typeof silentRule;
34
40
  declare namespace step {
35
- export { step_addToCart as addToCart, step_checkout as checkout, step_pageVisit as pageVisit, step_search as search, step_signup as signup };
41
+ export { step_addToCart as addToCart, step_checkout as checkout, step_pageVisit as pageVisit, step_rejectedEvent as rejectedEvent, step_search as search, step_signup as signup, step_silentRule as silentRule };
36
42
  }
37
43
 
38
44
  export { env, step };
@@ -33,7 +33,6 @@ __export(env_exports, {
33
33
  });
34
34
  async function mockSendServer(url, data, options) {
35
35
  return {
36
- ok: true,
37
36
  data: {
38
37
  num_events_received: 1,
39
38
  num_events_processed: 1,
@@ -52,8 +51,10 @@ __export(step_exports, {
52
51
  addToCart: () => addToCart,
53
52
  checkout: () => checkout,
54
53
  pageVisit: () => pageVisit,
54
+ rejectedEvent: () => rejectedEvent,
55
55
  search: () => search,
56
- signup: () => signup
56
+ signup: () => signup,
57
+ silentRule: () => silentRule
57
58
  });
58
59
  var import_core = require("@walkeros/core");
59
60
  var ENDPOINT = "https://api.pinterest.com/v5/ad_accounts/123456789/events";
@@ -66,7 +67,7 @@ var checkout = {
66
67
  in: (0, import_core.getEvent)("order complete", {
67
68
  id: "a1b2c3d4e5f60001",
68
69
  timestamp: 1700000900,
69
- data: { id: "ORD-300", total: 249.99, currency: "EUR" },
70
+ data: { id: "ORD-300", value: 249.99, currency: "EUR" },
70
71
  nested: [
71
72
  {
72
73
  entity: "product",
@@ -91,7 +92,7 @@ var checkout = {
91
92
  map: {
92
93
  custom_data: {
93
94
  map: {
94
- value: "data.total",
95
+ value: "data.value",
95
96
  currency: { key: "data.currency", value: "EUR" },
96
97
  order_id: "data.id",
97
98
  num_items: {
@@ -366,6 +367,33 @@ var signup = {
366
367
  ]
367
368
  ]
368
369
  };
370
+ var silentRule = {
371
+ public: false,
372
+ description: "A rule with silent: true sends no request to Pinterest.",
373
+ in: (0, import_core.getEvent)("page view", {
374
+ id: "a1b2c3d4e5f60006",
375
+ timestamp: 1700000905
376
+ }),
377
+ mapping: { silent: true },
378
+ out: []
379
+ };
380
+ var rejectedEvent = {
381
+ public: false,
382
+ description: "Pinterest answers HTTP 200 and reports the event as failed: the push fails with transport, not retryable, and the event goes to the DLQ.",
383
+ in: (0, import_core.getEvent)("page view", {
384
+ id: "a1b2c3d4e5f60007",
385
+ timestamp: 1700000906
386
+ }),
387
+ respond: {
388
+ status: 200,
389
+ body: {
390
+ num_events_received: 1,
391
+ num_events_processed: 0,
392
+ events: [{ status: "failed", error_message: "Invalid event_time" }]
393
+ }
394
+ },
395
+ outcome: { status: "failed", code: "transport", retryable: false }
396
+ };
369
397
  // Annotate the CommonJS export names for ESM import in node:
370
398
  0 && (module.exports = {
371
399
  env,
@@ -12,7 +12,6 @@ __export(env_exports, {
12
12
  });
13
13
  async function mockSendServer(url, data, options) {
14
14
  return {
15
- ok: true,
16
15
  data: {
17
16
  num_events_received: 1,
18
17
  num_events_processed: 1,
@@ -31,8 +30,10 @@ __export(step_exports, {
31
30
  addToCart: () => addToCart,
32
31
  checkout: () => checkout,
33
32
  pageVisit: () => pageVisit,
33
+ rejectedEvent: () => rejectedEvent,
34
34
  search: () => search,
35
- signup: () => signup
35
+ signup: () => signup,
36
+ silentRule: () => silentRule
36
37
  });
37
38
  import { getEvent, isObject } from "@walkeros/core";
38
39
  var ENDPOINT = "https://api.pinterest.com/v5/ad_accounts/123456789/events";
@@ -45,7 +46,7 @@ var checkout = {
45
46
  in: getEvent("order complete", {
46
47
  id: "a1b2c3d4e5f60001",
47
48
  timestamp: 1700000900,
48
- data: { id: "ORD-300", total: 249.99, currency: "EUR" },
49
+ data: { id: "ORD-300", value: 249.99, currency: "EUR" },
49
50
  nested: [
50
51
  {
51
52
  entity: "product",
@@ -70,7 +71,7 @@ var checkout = {
70
71
  map: {
71
72
  custom_data: {
72
73
  map: {
73
- value: "data.total",
74
+ value: "data.value",
74
75
  currency: { key: "data.currency", value: "EUR" },
75
76
  order_id: "data.id",
76
77
  num_items: {
@@ -345,6 +346,33 @@ var signup = {
345
346
  ]
346
347
  ]
347
348
  };
349
+ var silentRule = {
350
+ public: false,
351
+ description: "A rule with silent: true sends no request to Pinterest.",
352
+ in: getEvent("page view", {
353
+ id: "a1b2c3d4e5f60006",
354
+ timestamp: 1700000905
355
+ }),
356
+ mapping: { silent: true },
357
+ out: []
358
+ };
359
+ var rejectedEvent = {
360
+ public: false,
361
+ description: "Pinterest answers HTTP 200 and reports the event as failed: the push fails with transport, not retryable, and the event goes to the DLQ.",
362
+ in: getEvent("page view", {
363
+ id: "a1b2c3d4e5f60007",
364
+ timestamp: 1700000906
365
+ }),
366
+ respond: {
367
+ status: 200,
368
+ body: {
369
+ num_events_received: 1,
370
+ num_events_processed: 0,
371
+ events: [{ status: "failed", error_message: "Invalid event_time" }]
372
+ }
373
+ },
374
+ outcome: { status: "failed", code: "transport", retryable: false }
375
+ };
348
376
  export {
349
377
  env_exports as env,
350
378
  step_exports as step
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,{DestinationPinterest:()=>types_exports,default:()=>index_default,destinationPinterest:()=>destinationPinterest}),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=["em","ph","fn","ln","db","ge","ct","st","zp","country","external_id","hashed_maids"];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 push=async function(event,{config:config,data:data,ingest:ingest,env:env,logger:logger,collector:collector}){const{accessToken:accessToken,adAccountId:adAccountId,action_source:action_source="web",doNotHash:doNotHash,test:test,url:url="https://api.pinterest.com/v5/",user_data:user_data,partner_name:partner_name,ip:ip,userAgent:userAgent}=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}):{},root=(0,import_core2.createMappingRoot)(ingest,event),clientIp=await resolveClient(ip,DEFAULT_IP,root,collector),clientUserAgent=await resolveClient(userAgent,DEFAULT_USER_AGENT,root,collector),userData={...void 0!==clientIp?{client_ip_address:clientIp}:{},...void 0!==clientUserAgent?{client_user_agent:clientUserAgent}:{},...(0,import_core2.isObject)(configData)&&(0,import_core2.isObject)(configData.user_data)?configData.user_data:{},...(0,import_core2.isObject)(userDataCustom)?userDataCustom:{},...(0,import_core2.isObject)(eventData.user_data)?eventData.user_data:{}},{user_data:_ud,custom_data:eventCustomData,...restEventData}=eventData,serverEvent={event_name:event.name,event_id:event.id,event_time:Math.round((event.timestamp||Date.now())/1e3),action_source:action_source,...restEventData,user_data:userData};(0,import_core2.isObject)(eventCustomData)&&(serverEvent.custom_data=eventCustomData),"web"===action_source&&event.source?.url&&(serverEvent.event_source_url=event.source.url),partner_name&&(serverEvent.partner_name=partner_name);const hashedServerEvent=await async function(value,doNotHash=[]){if(!(0,import_core.isObject)(value))return value;const isUserData="user_data"in value,target=isUserData?value.user_data:value,result=(await Promise.all(Object.entries(target).map(async([k,v])=>[k,await processValue(v,isUserData&&shouldBeHashed(k,doNotHash))]))).reduce((acc,[k,v])=>((0,import_core.isString)(k)&&(acc[k]=v),acc),{});return isUserData?{...value,user_data:result}:result}(serverEvent,doNotHash),body={data:[hashedServerEvent]},endpoint=`${url}ad_accounts/${adAccountId}/events${test?"?test=true":""}`;logger.debug("Calling Pinterest API",{endpoint:endpoint,method:"POST",eventName:serverEvent.event_name,eventId:serverEvent.event_id});const sendServerFn=env?.sendServer||import_server_core2.sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`}});logger.debug("Pinterest API response",{ok:!(0,import_core2.isObject)(result)||result.ok}),(0,import_core2.isObject)(result)&&!1===result.ok&&logger.throw(`Pinterest API error: ${JSON.stringify(result)}`)},DEFAULT_IP=["ingest.ip","event.user.ip"],DEFAULT_USER_AGENT=["ingest.userAgent","event.user.userAgent"];async function resolveClient(setting,fallback,root,collector){if(!1===setting)return;const value=await(0,import_core2.getMappingValue)(root,setting??fallback,{collector:collector});return"string"==typeof value&&""!==value?value:void 0}var types_exports={},destinationPinterest={type:"pinterest",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,adAccountId:adAccountId}=settings;accessToken||logger.throw("Config settings accessToken missing"),adAccountId||logger.throw("Config settings adAccountId missing");const settingsConfig={...settings,accessToken:accessToken,adAccountId:adAccountId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await push(event,context)},index_default=destinationPinterest;//# 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,{DestinationPinterest:()=>types_exports,default:()=>index_default,destinationPinterest:()=>destinationPinterest}),module.exports=(mod=index_exports,((to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to})(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core");var import_core3=require("@walkeros/core"),import_server_core2=require("@walkeros/server-core"),import_core2=require("@walkeros/core"),import_server_core=require("@walkeros/server-core"),keysToHash=["em","ph","fn","ln","db","ge","ct","st","zp","country","external_id","hashed_maids"];function shouldBeHashed(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}async function processValue(value,shouldHash){return shouldHash?(0,import_core2.isArray)(value)?Promise.all(value.map(item=>(0,import_server_core.getHashServer)(String(item)))):(0,import_server_core.getHashServer)(String(value)):value}var send=async function(event,{config:config,data:data,ingest:ingest,env:env,logger:logger,collector:collector}){if(!config.settings)throw new import_core3.StepError("Pinterest settings missing, init() not run",{code:"not-ready"});const{accessToken:accessToken,adAccountId:adAccountId,action_source:action_source="web",doNotHash:doNotHash,test:test,url:url="https://api.pinterest.com/v5/",user_data:user_data,partner_name:partner_name,ip:ip,userAgent:userAgent}=config.settings,eventData=(0,import_core3.isObject)(data)?data:{},configData=config.data?await(0,import_core3.getMappingValue)(event,config.data,{collector:collector}):{},userDataCustom=user_data?await(0,import_core3.getMappingValue)(event,{map:user_data},{collector:collector}):{},root=(0,import_core3.createMappingRoot)(ingest,event),clientIp=await resolveClient(ip,DEFAULT_IP,root,collector),clientUserAgent=await resolveClient(userAgent,DEFAULT_USER_AGENT,root,collector),userData={...void 0!==clientIp?{client_ip_address:clientIp}:{},...void 0!==clientUserAgent?{client_user_agent:clientUserAgent}:{},...(0,import_core3.isObject)(configData)&&(0,import_core3.isObject)(configData.user_data)?configData.user_data:{},...(0,import_core3.isObject)(userDataCustom)?userDataCustom:{},...(0,import_core3.isObject)(eventData.user_data)?eventData.user_data:{}},{user_data:_ud,custom_data:eventCustomData,...restEventData}=eventData,serverEvent={event_name:event.name,event_id:event.id,event_time:Math.round((event.timestamp||Date.now())/1e3),action_source:action_source,...restEventData,user_data:userData};(0,import_core3.isObject)(eventCustomData)&&(serverEvent.custom_data=eventCustomData),"web"===action_source&&event.source?.url&&(serverEvent.event_source_url=event.source.url),partner_name&&(serverEvent.partner_name=partner_name);const hashedServerEvent=await async function(value,doNotHash=[]){if(!(0,import_core2.isObject)(value))return value;const isUserData="user_data"in value,target=isUserData?value.user_data:value,result=(await Promise.all(Object.entries(target).map(async([k,v])=>[k,await processValue(v,isUserData&&shouldBeHashed(k,doNotHash))]))).reduce((acc,[k,v])=>((0,import_core2.isString)(k)&&(acc[k]=v),acc),{});return isUserData?{...value,user_data:result}:result}(serverEvent,doNotHash),body={data:[hashedServerEvent]},endpoint=`${url}ad_accounts/${adAccountId}/events${test?"?test=true":""}`;logger.debug("Calling Pinterest API",{endpoint:endpoint,method:"POST",eventName:serverEvent.event_name,eventId:serverEvent.event_id});const sendServerFn=env?.sendServer||import_server_core2.sendServer;!function(data){if(!(0,import_core3.isObject)(data)||!Array.isArray(data.events))return;const failed=data.events.filter(result=>(0,import_core3.isObject)(result)&&"failed"===result.status).length;if(!failed)return;throw new import_core3.StepError("Pinterest Conversions API rejected the event",{code:"transport",retryable:!1,body:data})}((await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`}})).data)};var DEFAULT_IP=["ingest.ip","event.user.ip"],DEFAULT_USER_AGENT=["ingest.userAgent","event.user.userAgent"];async function resolveClient(setting,fallback,root,collector){if(!1===setting)return;const value=await(0,import_core3.getMappingValue)(root,setting??fallback,{collector:collector});return"string"==typeof value&&""!==value?value:void 0}var types_exports={},destinationPinterest={type:"pinterest",config:{},init:async({config:partialConfig})=>function(partialConfig={}){const settings=partialConfig.settings||{},{accessToken:accessToken,adAccountId:adAccountId}=settings;if(!accessToken||!adAccountId){const missing=[...accessToken?[]:["accessToken"],...adAccountId?[]:["adAccountId"]];throw new import_core.StepError(`Config settings ${missing.join(", ")} missing`,{code:"config"})}const settingsConfig={...settings,accessToken:accessToken,adAccountId:adAccountId};return{...partialConfig,settings:settingsConfig}}(partialConfig),push:async(event,context)=>await async function(event,context){context.rule?.silent||await send(event,context)}(event,context)},index_default=destinationPinterest;//# 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 DestinationPinterest from './types';\n\nexport const destinationPinterest: Destination = {\n type: 'pinterest',\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 destinationPinterest;\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, adAccountId } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!adAccountId) logger.throw('Config settings adAccountId missing');\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n adAccountId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { ConversionEvent, PushFn, RequestBody, UserData } from './types';\nimport type { Collector, Mapping as WalkerOSMapping } from '@walkeros/core';\nimport { createMappingRoot, getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEvent } from './hash';\n\nexport const push: PushFn = async function (\n event,\n { config, data, ingest, env, logger, collector },\n) {\n const {\n accessToken,\n adAccountId,\n action_source = 'web',\n doNotHash,\n test,\n url = 'https://api.pinterest.com/v5/',\n user_data,\n partner_name,\n ip,\n userAgent,\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 // Client IP and user agent auto-fill, overridden by any mapped value\n const root = createMappingRoot(ingest, event);\n const clientIp = await resolveClient(ip, DEFAULT_IP, root, collector);\n const clientUserAgent = await resolveClient(\n userAgent,\n DEFAULT_USER_AGENT,\n root,\n collector,\n );\n\n const userData: UserData = {\n ...(clientIp !== undefined ? { client_ip_address: clientIp } : {}),\n ...(clientUserAgent !== undefined\n ? { client_user_agent: clientUserAgent }\n : {}),\n // Destination config\n ...(isObject(configData) && isObject(configData.user_data)\n ? configData.user_data\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n // Event mapping\n ...(isObject(eventData.user_data) ? eventData.user_data : {}),\n };\n\n // Extract custom_data and user_data from eventData, leave the rest\n const {\n user_data: _ud,\n custom_data: eventCustomData,\n ...restEventData\n } = eventData;\n\n const serverEvent: ConversionEvent = {\n event_name: event.name,\n event_id: event.id,\n event_time: Math.round((event.timestamp || Date.now()) / 1000),\n action_source,\n ...restEventData,\n user_data: userData,\n };\n\n // Nest custom_data from mapping\n if (isObject(eventCustomData)) {\n serverEvent.custom_data = eventCustomData as ConversionEvent['custom_data'];\n }\n\n // Set event_source_url for web events\n if (action_source === 'web' && event.source?.url) {\n serverEvent.event_source_url = event.source.url;\n }\n\n // Add partner_name from settings\n if (partner_name) {\n serverEvent.partner_name = partner_name;\n }\n\n const hashedServerEvent = await hashEvent(serverEvent, doNotHash);\n\n const body: RequestBody = { data: [hashedServerEvent] };\n\n // Build endpoint URL\n const testParam = test ? '?test=true' : '';\n const endpoint = `${url}ad_accounts/${adAccountId}/events${testParam}`;\n\n logger.debug('Calling Pinterest API', {\n endpoint,\n method: 'POST',\n eventName: serverEvent.event_name,\n eventId: serverEvent.event_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('Pinterest API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Pinterest API error: ${JSON.stringify(result)}`);\n }\n};\n\nconst DEFAULT_IP: WalkerOSMapping.Value = ['ingest.ip', 'event.user.ip'];\nconst DEFAULT_USER_AGENT: WalkerOSMapping.Value = [\n 'ingest.userAgent',\n 'event.user.userAgent',\n];\n\n/** A client IP or user agent setting resolved to a non-empty string. */\nasync function resolveClient(\n setting: WalkerOSMapping.Value | false | undefined,\n fallback: WalkerOSMapping.Value,\n root: WalkerOSMapping.Root,\n collector: Collector.Instance,\n): Promise<string | undefined> {\n if (setting === false) return undefined;\n const value = await getMappingValue(root, setting ?? fallback, { collector });\n return typeof value === 'string' && value !== '' ? value : undefined;\n}\n","import { WalkerOS } from '@walkeros/core';\nimport { isArray, isObject, isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = [\n 'em',\n 'ph',\n 'fn',\n 'ln',\n 'db',\n 'ge',\n 'ct',\n 'st',\n 'zp',\n 'country',\n 'external_id',\n 'hashed_maids',\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 isUserData = 'user_data' in value;\n const target = (isUserData ? value.user_data : 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, isUserData && 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 isUserData ? { ...value, user_data: 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 adAccountId: string;\n action_source?: ActionSource;\n doNotHash?: string[];\n test?: boolean;\n url?: string;\n user_data?: WalkerOSMapping.Map;\n partner_name?: string;\n /**\n * Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }.\n * `false` switches it off.\n * @default ['ingest.ip', 'event.user.ip']\n */\n ip?: WalkerOSMapping.Value | false;\n /**\n * Client user agent, sent as user_data.client_user_agent. Resolves against\n * { ingest, event }. `false` switches it off.\n * @default ['ingest.userAgent', 'event.user.userAgent']\n */\n userAgent?: WalkerOSMapping.Value | false;\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// Pinterest Conversions API types\n// https://developers.pinterest.com/docs/conversions/conversions/\n\nexport type ActionSource = 'app_android' | 'app_ios' | 'web' | 'offline';\n\nexport type EventName =\n | 'add_payment_info'\n | 'add_to_cart'\n | 'add_to_wishlist'\n | 'app_install'\n | 'app_open'\n | 'checkout'\n | 'contact'\n | 'custom'\n | 'customize_product'\n | 'find_location'\n | 'initiate_checkout'\n | 'lead'\n | 'page_visit'\n | 'schedule'\n | 'search'\n | 'signup'\n | 'start_trial'\n | 'submit_application'\n | 'subscribe'\n | 'view_category'\n | 'view_content'\n | 'watch_video'\n | string;\n\nexport interface ConversionEvent {\n // Required\n event_name: EventName;\n event_time: number;\n event_id: string;\n action_source: ActionSource;\n user_data: UserData;\n\n // Optional\n event_source_url?: string;\n opt_out?: boolean;\n partner_name?: string;\n app_id?: string;\n app_name?: string;\n app_version?: string;\n device_brand?: string;\n device_carrier?: string;\n device_model?: string;\n device_type?: string;\n os_version?: string;\n language?: string;\n wifi?: boolean;\n custom_data?: CustomData;\n}\n\nexport interface UserData {\n // Hashable fields (SHA-256, arrays)\n em?: string[];\n ph?: string[];\n fn?: string[];\n ln?: string[];\n db?: string[];\n ge?: string[];\n ct?: string[];\n st?: string[];\n zp?: string[];\n country?: string[];\n external_id?: string[];\n hashed_maids?: string[];\n\n // Pass-through fields (do NOT hash)\n client_ip_address?: string;\n client_user_agent?: string;\n click_id?: string;\n partner_id?: string;\n}\n\nexport interface CustomData {\n currency?: string;\n value?: string;\n content_ids?: string[];\n content_name?: string;\n content_category?: string;\n content_brand?: string;\n contents?: ContentItem[];\n num_items?: number;\n order_id?: string;\n search_string?: string;\n opt_out_type?: string;\n np?: string;\n predicted_ltv?: string;\n}\n\nexport interface ContentItem {\n id?: string;\n item_name?: string;\n item_category?: string;\n item_brand?: string;\n item_price?: string;\n quantity?: number;\n}\n\nexport interface RequestBody {\n data: ConversionEvent[];\n}\n\nexport interface ResponseBody {\n num_events_received: number;\n num_events_processed: number;\n events: Array<{\n status: string;\n error_message?: string;\n warning_message?: string;\n }>;\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 DestinationPinterest from './types';\n\nexport const destinationPinterest: Destination = {\n type: 'pinterest',\n\n config: {},\n\n async init({ config: partialConfig }) {\n return getConfig(partialConfig);\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationPinterest;\n","import type { Config, Settings, PartialConfig } from './types';\nimport { StepError } from '@walkeros/core';\n\nexport function getConfig(partialConfig: PartialConfig = {}): Config {\n const settings: Partial<Settings> = partialConfig.settings || {};\n const { accessToken, adAccountId } = settings;\n\n if (!accessToken || !adAccountId) {\n const missing = [\n ...(accessToken ? [] : ['accessToken']),\n ...(adAccountId ? [] : ['adAccountId']),\n ];\n throw new StepError(`Config settings ${missing.join(', ')} missing`, {\n code: 'config',\n });\n }\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n adAccountId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { ConversionEvent, PushFn, RequestBody, UserData } from './types';\nimport type { Collector, Mapping as WalkerOSMapping } from '@walkeros/core';\nimport {\n createMappingRoot,\n getMappingValue,\n isObject,\n StepError,\n} from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEvent } from './hash';\n\n// A silent rule has no Pinterest call of its own: nothing to send.\nexport const push: PushFn = async function (event, context) {\n if (!context.rule?.silent) await send(event, context);\n};\n\nconst send: PushFn = async function (\n event,\n { config, data, ingest, env, logger, collector },\n) {\n if (!config.settings)\n throw new StepError('Pinterest settings missing, init() not run', {\n code: 'not-ready',\n });\n const {\n accessToken,\n adAccountId,\n action_source = 'web',\n doNotHash,\n test,\n url = 'https://api.pinterest.com/v5/',\n user_data,\n partner_name,\n ip,\n userAgent,\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 // Client IP and user agent auto-fill, overridden by any mapped value\n const root = createMappingRoot(ingest, event);\n const clientIp = await resolveClient(ip, DEFAULT_IP, root, collector);\n const clientUserAgent = await resolveClient(\n userAgent,\n DEFAULT_USER_AGENT,\n root,\n collector,\n );\n\n const userData: UserData = {\n ...(clientIp !== undefined ? { client_ip_address: clientIp } : {}),\n ...(clientUserAgent !== undefined\n ? { client_user_agent: clientUserAgent }\n : {}),\n // Destination config\n ...(isObject(configData) && isObject(configData.user_data)\n ? configData.user_data\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n // Event mapping\n ...(isObject(eventData.user_data) ? eventData.user_data : {}),\n };\n\n // Extract custom_data and user_data from eventData, leave the rest\n const {\n user_data: _ud,\n custom_data: eventCustomData,\n ...restEventData\n } = eventData;\n\n const serverEvent: ConversionEvent = {\n event_name: event.name,\n event_id: event.id,\n event_time: Math.round((event.timestamp || Date.now()) / 1000),\n action_source,\n ...restEventData,\n user_data: userData,\n };\n\n // Nest custom_data from mapping\n if (isObject(eventCustomData)) {\n serverEvent.custom_data = eventCustomData as ConversionEvent['custom_data'];\n }\n\n // Set event_source_url for web events\n if (action_source === 'web' && event.source?.url) {\n serverEvent.event_source_url = event.source.url;\n }\n\n // Add partner_name from settings\n if (partner_name) {\n serverEvent.partner_name = partner_name;\n }\n\n const hashedServerEvent = await hashEvent(serverEvent, doNotHash);\n\n const body: RequestBody = { data: [hashedServerEvent] };\n\n // Build endpoint URL\n const testParam = test ? '?test=true' : '';\n const endpoint = `${url}ad_accounts/${adAccountId}/events${testParam}`;\n\n logger.debug('Calling Pinterest API', {\n endpoint,\n method: 'POST',\n eventName: serverEvent.event_name,\n eventId: serverEvent.event_id,\n });\n\n const sendServerFn = env?.sendServer || sendServer;\n const response = await sendServerFn(endpoint, JSON.stringify(body), {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n checkResponse(response.data);\n};\n\n/**\n * Pinterest answers HTTP 200 with a per-event `status` and reports an event\n * it did not process as `failed` (with its `error_message`). A rejected\n * event fails the push, not retryable; the body stays on the error.\n */\nfunction checkResponse(data: unknown): void {\n if (!isObject(data) || !Array.isArray(data.events)) return;\n const failed = data.events.filter(\n (result) => isObject(result) && result.status === 'failed',\n ).length;\n if (!failed) return;\n throw new StepError('Pinterest Conversions API rejected the event', {\n code: 'transport',\n retryable: false,\n body: data,\n });\n}\n\nconst DEFAULT_IP: WalkerOSMapping.Value = ['ingest.ip', 'event.user.ip'];\nconst DEFAULT_USER_AGENT: WalkerOSMapping.Value = [\n 'ingest.userAgent',\n 'event.user.userAgent',\n];\n\n/** A client IP or user agent setting resolved to a non-empty string. */\nasync function resolveClient(\n setting: WalkerOSMapping.Value | false | undefined,\n fallback: WalkerOSMapping.Value,\n root: WalkerOSMapping.Root,\n collector: Collector.Instance,\n): Promise<string | undefined> {\n if (setting === false) return undefined;\n const value = await getMappingValue(root, setting ?? fallback, { collector });\n return typeof value === 'string' && value !== '' ? value : undefined;\n}\n","import { WalkerOS } from '@walkeros/core';\nimport { isArray, isObject, isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = [\n 'em',\n 'ph',\n 'fn',\n 'ln',\n 'db',\n 'ge',\n 'ct',\n 'st',\n 'zp',\n 'country',\n 'external_id',\n 'hashed_maids',\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 isUserData = 'user_data' in value;\n const target = (isUserData ? value.user_data : 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, isUserData && 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 isUserData ? { ...value, user_data: 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 adAccountId: string;\n action_source?: ActionSource;\n doNotHash?: string[];\n test?: boolean;\n url?: string;\n user_data?: WalkerOSMapping.Map;\n partner_name?: string;\n /**\n * Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }.\n * `false` switches it off.\n * @default ['ingest.ip', 'event.user.ip']\n */\n ip?: WalkerOSMapping.Value | false;\n /**\n * Client user agent, sent as user_data.client_user_agent. Resolves against\n * { ingest, event }. `false` switches it off.\n * @default ['ingest.userAgent', 'event.user.userAgent']\n */\n userAgent?: WalkerOSMapping.Value | false;\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// Pinterest Conversions API types\n// https://developers.pinterest.com/docs/conversions/conversions/\n\nexport type ActionSource = 'app_android' | 'app_ios' | 'web' | 'offline';\n\nexport type EventName =\n | 'add_payment_info'\n | 'add_to_cart'\n | 'add_to_wishlist'\n | 'app_install'\n | 'app_open'\n | 'checkout'\n | 'contact'\n | 'custom'\n | 'customize_product'\n | 'find_location'\n | 'initiate_checkout'\n | 'lead'\n | 'page_visit'\n | 'schedule'\n | 'search'\n | 'signup'\n | 'start_trial'\n | 'submit_application'\n | 'subscribe'\n | 'view_category'\n | 'view_content'\n | 'watch_video'\n | string;\n\nexport interface ConversionEvent {\n // Required\n event_name: EventName;\n event_time: number;\n event_id: string;\n action_source: ActionSource;\n user_data: UserData;\n\n // Optional\n event_source_url?: string;\n opt_out?: boolean;\n partner_name?: string;\n app_id?: string;\n app_name?: string;\n app_version?: string;\n device_brand?: string;\n device_carrier?: string;\n device_model?: string;\n device_type?: string;\n os_version?: string;\n language?: string;\n wifi?: boolean;\n custom_data?: CustomData;\n}\n\nexport interface UserData {\n // Hashable fields (SHA-256, arrays)\n em?: string[];\n ph?: string[];\n fn?: string[];\n ln?: string[];\n db?: string[];\n ge?: string[];\n ct?: string[];\n st?: string[];\n zp?: string[];\n country?: string[];\n external_id?: string[];\n hashed_maids?: string[];\n\n // Pass-through fields (do NOT hash)\n client_ip_address?: string;\n client_user_agent?: string;\n click_id?: string;\n partner_id?: string;\n}\n\nexport interface CustomData {\n currency?: string;\n value?: string;\n content_ids?: string[];\n content_name?: string;\n content_category?: string;\n content_brand?: string;\n contents?: ContentItem[];\n num_items?: number;\n order_id?: string;\n search_string?: string;\n opt_out_type?: string;\n np?: string;\n predicted_ltv?: string;\n}\n\nexport interface ContentItem {\n id?: string;\n item_name?: string;\n item_category?: string;\n item_brand?: string;\n item_price?: string;\n quantity?: number;\n}\n\nexport interface RequestBody {\n data: ConversionEvent[];\n}\n\nexport interface ResponseBody {\n num_events_received: number;\n num_events_processed: number;\n events: Array<{\n status: string;\n error_message?: string;\n warning_message?: string;\n }>;\n}\n"],"mappings":"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","names":["import_core","import_server_core","import_core"]}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createMappingRoot,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=["em","ph","fn","ln","db","ge","ct","st","zp","country","external_id","hashed_maids"];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 push=async function(event,{config:config,data:data,ingest:ingest,env:env,logger:logger,collector:collector}){const{accessToken:accessToken,adAccountId:adAccountId,action_source:action_source="web",doNotHash:doNotHash,test:test,url:url="https://api.pinterest.com/v5/",user_data:user_data,partner_name:partner_name,ip:ip,userAgent:userAgent}=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}):{},root=createMappingRoot(ingest,event),clientIp=await resolveClient(ip,DEFAULT_IP,root,collector),clientUserAgent=await resolveClient(userAgent,DEFAULT_USER_AGENT,root,collector),userData={...void 0!==clientIp?{client_ip_address:clientIp}:{},...void 0!==clientUserAgent?{client_user_agent:clientUserAgent}:{},...isObject2(configData)&&isObject2(configData.user_data)?configData.user_data:{},...isObject2(userDataCustom)?userDataCustom:{},...isObject2(eventData.user_data)?eventData.user_data:{}},{user_data:_ud,custom_data:eventCustomData,...restEventData}=eventData,serverEvent={event_name:event.name,event_id:event.id,event_time:Math.round((event.timestamp||Date.now())/1e3),action_source:action_source,...restEventData,user_data:userData};isObject2(eventCustomData)&&(serverEvent.custom_data=eventCustomData),"web"===action_source&&event.source?.url&&(serverEvent.event_source_url=event.source.url),partner_name&&(serverEvent.partner_name=partner_name);const hashedServerEvent=await async function(value,doNotHash=[]){if(!isObject(value))return value;const isUserData="user_data"in value,target=isUserData?value.user_data:value,result=(await Promise.all(Object.entries(target).map(async([k,v])=>[k,await processValue(v,isUserData&&shouldBeHashed(k,doNotHash))]))).reduce((acc,[k,v])=>(isString(k)&&(acc[k]=v),acc),{});return isUserData?{...value,user_data:result}:result}(serverEvent,doNotHash),body={data:[hashedServerEvent]},endpoint=`${url}ad_accounts/${adAccountId}/events${test?"?test=true":""}`;logger.debug("Calling Pinterest API",{endpoint:endpoint,method:"POST",eventName:serverEvent.event_name,eventId:serverEvent.event_id});const sendServerFn=env?.sendServer||sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`}});logger.debug("Pinterest API response",{ok:!isObject2(result)||result.ok}),isObject2(result)&&!1===result.ok&&logger.throw(`Pinterest API error: ${JSON.stringify(result)}`)},DEFAULT_IP=["ingest.ip","event.user.ip"],DEFAULT_USER_AGENT=["ingest.userAgent","event.user.userAgent"];async function resolveClient(setting,fallback,root,collector){if(!1===setting)return;const value=await getMappingValue(root,setting??fallback,{collector:collector});return"string"==typeof value&&""!==value?value:void 0}var types_exports={},destinationPinterest={type:"pinterest",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,adAccountId:adAccountId}=settings;accessToken||logger.throw("Config settings accessToken missing"),adAccountId||logger.throw("Config settings adAccountId missing");const settingsConfig={...settings,accessToken:accessToken,adAccountId:adAccountId};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await push(event,context)},index_default=destinationPinterest;export{types_exports as DestinationPinterest,index_default as default,destinationPinterest};//# sourceMappingURL=index.mjs.map
1
+ import{createRequire}from"module";createRequire(import.meta.url);import{StepError}from"@walkeros/core";import{createMappingRoot,getMappingValue,isObject as isObject2,StepError as StepError2}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{isArray,isObject,isString}from"@walkeros/core";import{getHashServer}from"@walkeros/server-core";var keysToHash=["em","ph","fn","ln","db","ge","ct","st","zp","country","external_id","hashed_maids"];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 send=async function(event,{config:config,data:data,ingest:ingest,env:env,logger:logger,collector:collector}){if(!config.settings)throw new StepError2("Pinterest settings missing, init() not run",{code:"not-ready"});const{accessToken:accessToken,adAccountId:adAccountId,action_source:action_source="web",doNotHash:doNotHash,test:test,url:url="https://api.pinterest.com/v5/",user_data:user_data,partner_name:partner_name,ip:ip,userAgent:userAgent}=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}):{},root=createMappingRoot(ingest,event),clientIp=await resolveClient(ip,DEFAULT_IP,root,collector),clientUserAgent=await resolveClient(userAgent,DEFAULT_USER_AGENT,root,collector),userData={...void 0!==clientIp?{client_ip_address:clientIp}:{},...void 0!==clientUserAgent?{client_user_agent:clientUserAgent}:{},...isObject2(configData)&&isObject2(configData.user_data)?configData.user_data:{},...isObject2(userDataCustom)?userDataCustom:{},...isObject2(eventData.user_data)?eventData.user_data:{}},{user_data:_ud,custom_data:eventCustomData,...restEventData}=eventData,serverEvent={event_name:event.name,event_id:event.id,event_time:Math.round((event.timestamp||Date.now())/1e3),action_source:action_source,...restEventData,user_data:userData};isObject2(eventCustomData)&&(serverEvent.custom_data=eventCustomData),"web"===action_source&&event.source?.url&&(serverEvent.event_source_url=event.source.url),partner_name&&(serverEvent.partner_name=partner_name);const hashedServerEvent=await async function(value,doNotHash=[]){if(!isObject(value))return value;const isUserData="user_data"in value,target=isUserData?value.user_data:value,result=(await Promise.all(Object.entries(target).map(async([k,v])=>[k,await processValue(v,isUserData&&shouldBeHashed(k,doNotHash))]))).reduce((acc,[k,v])=>(isString(k)&&(acc[k]=v),acc),{});return isUserData?{...value,user_data:result}:result}(serverEvent,doNotHash),body={data:[hashedServerEvent]},endpoint=`${url}ad_accounts/${adAccountId}/events${test?"?test=true":""}`;logger.debug("Calling Pinterest API",{endpoint:endpoint,method:"POST",eventName:serverEvent.event_name,eventId:serverEvent.event_id});const sendServerFn=env?.sendServer||sendServer;!function(data){if(!isObject2(data)||!Array.isArray(data.events))return;const failed=data.events.filter(result=>isObject2(result)&&"failed"===result.status).length;if(!failed)return;throw new StepError2("Pinterest Conversions API rejected the event",{code:"transport",retryable:!1,body:data})}((await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`}})).data)};var DEFAULT_IP=["ingest.ip","event.user.ip"],DEFAULT_USER_AGENT=["ingest.userAgent","event.user.userAgent"];async function resolveClient(setting,fallback,root,collector){if(!1===setting)return;const value=await getMappingValue(root,setting??fallback,{collector:collector});return"string"==typeof value&&""!==value?value:void 0}var types_exports={},destinationPinterest={type:"pinterest",config:{},init:async({config:partialConfig})=>function(partialConfig={}){const settings=partialConfig.settings||{},{accessToken:accessToken,adAccountId:adAccountId}=settings;if(!accessToken||!adAccountId){const missing=[...accessToken?[]:["accessToken"],...adAccountId?[]:["adAccountId"]];throw new StepError(`Config settings ${missing.join(", ")} missing`,{code:"config"})}const settingsConfig={...settings,accessToken:accessToken,adAccountId:adAccountId};return{...partialConfig,settings:settingsConfig}}(partialConfig),push:async(event,context)=>await async function(event,context){context.rule?.silent||await send(event,context)}(event,context)},index_default=destinationPinterest;export{types_exports as DestinationPinterest,index_default as default,destinationPinterest};//# 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, adAccountId } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!adAccountId) logger.throw('Config settings adAccountId missing');\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n adAccountId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { ConversionEvent, PushFn, RequestBody, UserData } from './types';\nimport type { Collector, Mapping as WalkerOSMapping } from '@walkeros/core';\nimport { createMappingRoot, getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEvent } from './hash';\n\nexport const push: PushFn = async function (\n event,\n { config, data, ingest, env, logger, collector },\n) {\n const {\n accessToken,\n adAccountId,\n action_source = 'web',\n doNotHash,\n test,\n url = 'https://api.pinterest.com/v5/',\n user_data,\n partner_name,\n ip,\n userAgent,\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 // Client IP and user agent auto-fill, overridden by any mapped value\n const root = createMappingRoot(ingest, event);\n const clientIp = await resolveClient(ip, DEFAULT_IP, root, collector);\n const clientUserAgent = await resolveClient(\n userAgent,\n DEFAULT_USER_AGENT,\n root,\n collector,\n );\n\n const userData: UserData = {\n ...(clientIp !== undefined ? { client_ip_address: clientIp } : {}),\n ...(clientUserAgent !== undefined\n ? { client_user_agent: clientUserAgent }\n : {}),\n // Destination config\n ...(isObject(configData) && isObject(configData.user_data)\n ? configData.user_data\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n // Event mapping\n ...(isObject(eventData.user_data) ? eventData.user_data : {}),\n };\n\n // Extract custom_data and user_data from eventData, leave the rest\n const {\n user_data: _ud,\n custom_data: eventCustomData,\n ...restEventData\n } = eventData;\n\n const serverEvent: ConversionEvent = {\n event_name: event.name,\n event_id: event.id,\n event_time: Math.round((event.timestamp || Date.now()) / 1000),\n action_source,\n ...restEventData,\n user_data: userData,\n };\n\n // Nest custom_data from mapping\n if (isObject(eventCustomData)) {\n serverEvent.custom_data = eventCustomData as ConversionEvent['custom_data'];\n }\n\n // Set event_source_url for web events\n if (action_source === 'web' && event.source?.url) {\n serverEvent.event_source_url = event.source.url;\n }\n\n // Add partner_name from settings\n if (partner_name) {\n serverEvent.partner_name = partner_name;\n }\n\n const hashedServerEvent = await hashEvent(serverEvent, doNotHash);\n\n const body: RequestBody = { data: [hashedServerEvent] };\n\n // Build endpoint URL\n const testParam = test ? '?test=true' : '';\n const endpoint = `${url}ad_accounts/${adAccountId}/events${testParam}`;\n\n logger.debug('Calling Pinterest API', {\n endpoint,\n method: 'POST',\n eventName: serverEvent.event_name,\n eventId: serverEvent.event_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('Pinterest API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Pinterest API error: ${JSON.stringify(result)}`);\n }\n};\n\nconst DEFAULT_IP: WalkerOSMapping.Value = ['ingest.ip', 'event.user.ip'];\nconst DEFAULT_USER_AGENT: WalkerOSMapping.Value = [\n 'ingest.userAgent',\n 'event.user.userAgent',\n];\n\n/** A client IP or user agent setting resolved to a non-empty string. */\nasync function resolveClient(\n setting: WalkerOSMapping.Value | false | undefined,\n fallback: WalkerOSMapping.Value,\n root: WalkerOSMapping.Root,\n collector: Collector.Instance,\n): Promise<string | undefined> {\n if (setting === false) return undefined;\n const value = await getMappingValue(root, setting ?? fallback, { collector });\n return typeof value === 'string' && value !== '' ? value : undefined;\n}\n","import { WalkerOS } from '@walkeros/core';\nimport { isArray, isObject, isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = [\n 'em',\n 'ph',\n 'fn',\n 'ln',\n 'db',\n 'ge',\n 'ct',\n 'st',\n 'zp',\n 'country',\n 'external_id',\n 'hashed_maids',\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 isUserData = 'user_data' in value;\n const target = (isUserData ? value.user_data : 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, isUserData && 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 isUserData ? { ...value, user_data: 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 adAccountId: string;\n action_source?: ActionSource;\n doNotHash?: string[];\n test?: boolean;\n url?: string;\n user_data?: WalkerOSMapping.Map;\n partner_name?: string;\n /**\n * Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }.\n * `false` switches it off.\n * @default ['ingest.ip', 'event.user.ip']\n */\n ip?: WalkerOSMapping.Value | false;\n /**\n * Client user agent, sent as user_data.client_user_agent. Resolves against\n * { ingest, event }. `false` switches it off.\n * @default ['ingest.userAgent', 'event.user.userAgent']\n */\n userAgent?: WalkerOSMapping.Value | false;\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// Pinterest Conversions API types\n// https://developers.pinterest.com/docs/conversions/conversions/\n\nexport type ActionSource = 'app_android' | 'app_ios' | 'web' | 'offline';\n\nexport type EventName =\n | 'add_payment_info'\n | 'add_to_cart'\n | 'add_to_wishlist'\n | 'app_install'\n | 'app_open'\n | 'checkout'\n | 'contact'\n | 'custom'\n | 'customize_product'\n | 'find_location'\n | 'initiate_checkout'\n | 'lead'\n | 'page_visit'\n | 'schedule'\n | 'search'\n | 'signup'\n | 'start_trial'\n | 'submit_application'\n | 'subscribe'\n | 'view_category'\n | 'view_content'\n | 'watch_video'\n | string;\n\nexport interface ConversionEvent {\n // Required\n event_name: EventName;\n event_time: number;\n event_id: string;\n action_source: ActionSource;\n user_data: UserData;\n\n // Optional\n event_source_url?: string;\n opt_out?: boolean;\n partner_name?: string;\n app_id?: string;\n app_name?: string;\n app_version?: string;\n device_brand?: string;\n device_carrier?: string;\n device_model?: string;\n device_type?: string;\n os_version?: string;\n language?: string;\n wifi?: boolean;\n custom_data?: CustomData;\n}\n\nexport interface UserData {\n // Hashable fields (SHA-256, arrays)\n em?: string[];\n ph?: string[];\n fn?: string[];\n ln?: string[];\n db?: string[];\n ge?: string[];\n ct?: string[];\n st?: string[];\n zp?: string[];\n country?: string[];\n external_id?: string[];\n hashed_maids?: string[];\n\n // Pass-through fields (do NOT hash)\n client_ip_address?: string;\n client_user_agent?: string;\n click_id?: string;\n partner_id?: string;\n}\n\nexport interface CustomData {\n currency?: string;\n value?: string;\n content_ids?: string[];\n content_name?: string;\n content_category?: string;\n content_brand?: string;\n contents?: ContentItem[];\n num_items?: number;\n order_id?: string;\n search_string?: string;\n opt_out_type?: string;\n np?: string;\n predicted_ltv?: string;\n}\n\nexport interface ContentItem {\n id?: string;\n item_name?: string;\n item_category?: string;\n item_brand?: string;\n item_price?: string;\n quantity?: number;\n}\n\nexport interface RequestBody {\n data: ConversionEvent[];\n}\n\nexport interface ResponseBody {\n num_events_received: number;\n num_events_processed: number;\n events: Array<{\n status: string;\n error_message?: string;\n warning_message?: string;\n }>;\n}\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationPinterest from './types';\n\nexport const destinationPinterest: Destination = {\n type: 'pinterest',\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 destinationPinterest;\n"],"mappings":";AAGO,SAAS,UACd,gBAA+B,CAAC,GAChC,QACQ;AACR,QAAM,WAAY,cAAc,YAAY,CAAC;AAC7C,QAAM,EAAE,aAAa,YAAY,IAAI;AAErC,MAAI,CAAC,YAAa,QAAO,MAAM,qCAAqC;AACpE,MAAI,CAAC,YAAa,QAAO,MAAM,qCAAqC;AAEpE,QAAM,iBAA2B;AAAA,IAC/B,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,eAAe,UAAU,eAAe;AACtD;;;AClBA,SAAS,mBAAmB,iBAAiB,YAAAA,iBAAgB;AAC7D,SAAS,kBAAkB;;;ACF3B,SAAS,SAAS,UAAU,gBAAgB;AAC5C,SAAS,qBAAqB;AAE9B,IAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,eAAe,KAAa,YAAsB,CAAC,GAAY;AACtE,SAAO,WAAW,SAAS,GAAG,KAAK,CAAC,UAAU,SAAS,GAAG;AAC5D;AAIA,eAAe,aACb,OACA,YACkB;AAClB,MAAI,CAAC,WAAY,QAAO;AACxB,MAAI,QAAQ,KAAK,GAAG;AAClB,WAAO,QAAQ,IAAI,MAAM,IAAI,CAAC,SAAS,cAAc,OAAO,IAAI,CAAC,CAAC,CAAC;AAAA,EACrE;AACA,SAAO,cAAc,OAAO,KAAK,CAAC;AACpC;AAEA,eAAsB,UACpB,OACA,YAAsB,CAAC,GACX;AACZ,MAAI,CAAC,SAAS,KAAK,EAAG,QAAO;AAE7B,QAAM,aAAa,eAAe;AAClC,QAAM,SAAU,aAAa,MAAM,YAAY;AAE/C,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,OAAO,QAAQ,MAAM,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM;AAAA,MAC3C;AAAA,MACA,MAAM,aAAa,GAAG,cAAc,eAAe,GAAG,SAAS,CAAC;AAAA,IAClE,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,QAAQ,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;AAC7C,QAAI,SAAS,CAAC,EAAG,KAAI,CAAC,IAAI;AAC1B,WAAO;AAAA,EACT,GAAG,CAAC,CAAuB;AAE3B,SAAO,aAAa,EAAE,GAAG,OAAO,WAAW,OAAO,IAAK;AACzD;;;ADpDO,IAAM,OAAe,eAC1B,OACA,EAAE,QAAQ,MAAM,QAAQ,KAAK,QAAQ,UAAU,GAC/C;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,OAAO;AAEX,QAAM,YAAYC,UAAS,IAAI,IAAI,OAAO,CAAC;AAC3C,QAAM,aAAa,OAAO,OACtB,MAAM,gBAAgB,OAAO,OAAO,MAAM,EAAE,UAAU,CAAC,IACvD,CAAC;AACL,QAAM,iBAAiB,YACnB,MAAM,gBAAgB,OAAO,EAAE,KAAK,UAAU,GAAG,EAAE,UAAU,CAAC,IAC9D,CAAC;AAIL,QAAM,OAAO,kBAAkB,QAAQ,KAAK;AAC5C,QAAM,WAAW,MAAM,cAAc,IAAI,YAAY,MAAM,SAAS;AACpE,QAAM,kBAAkB,MAAM;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,WAAqB;AAAA,IACzB,GAAI,aAAa,SAAY,EAAE,mBAAmB,SAAS,IAAI,CAAC;AAAA,IAChE,GAAI,oBAAoB,SACpB,EAAE,mBAAmB,gBAAgB,IACrC,CAAC;AAAA;AAAA,IAEL,GAAIA,UAAS,UAAU,KAAKA,UAAS,WAAW,SAAS,IACrD,WAAW,YACX,CAAC;AAAA;AAAA,IAEL,GAAIA,UAAS,cAAc,IAAI,iBAAiB,CAAC;AAAA;AAAA,IAEjD,GAAIA,UAAS,UAAU,SAAS,IAAI,UAAU,YAAY,CAAC;AAAA,EAC7D;AAGA,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,aAAa;AAAA,IACb,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,cAA+B;AAAA,IACnC,YAAY,MAAM;AAAA,IAClB,UAAU,MAAM;AAAA,IAChB,YAAY,KAAK,OAAO,MAAM,aAAa,KAAK,IAAI,KAAK,GAAI;AAAA,IAC7D;AAAA,IACA,GAAG;AAAA,IACH,WAAW;AAAA,EACb;AAGA,MAAIA,UAAS,eAAe,GAAG;AAC7B,gBAAY,cAAc;AAAA,EAC5B;AAGA,MAAI,kBAAkB,SAAS,MAAM,QAAQ,KAAK;AAChD,gBAAY,mBAAmB,MAAM,OAAO;AAAA,EAC9C;AAGA,MAAI,cAAc;AAChB,gBAAY,eAAe;AAAA,EAC7B;AAEA,QAAM,oBAAoB,MAAM,UAAU,aAAa,SAAS;AAEhE,QAAM,OAAoB,EAAE,MAAM,CAAC,iBAAiB,EAAE;AAGtD,QAAM,YAAY,OAAO,eAAe;AACxC,QAAM,WAAW,GAAG,GAAG,eAAe,WAAW,UAAU,SAAS;AAEpE,SAAO,MAAM,yBAAyB;AAAA,IACpC;AAAA,IACA,QAAQ;AAAA,IACR,WAAW,YAAY;AAAA,IACvB,SAAS,YAAY;AAAA,EACvB,CAAC;AAED,QAAM,eAAe,KAAK,cAAc;AACxC,QAAM,SAAS,MAAM,aAAa,UAAU,KAAK,UAAU,IAAI,GAAG;AAAA,IAChE,SAAS,EAAE,eAAe,UAAU,WAAW,GAAG;AAAA,EACpD,CAAC;AAED,SAAO,MAAM,0BAA0B;AAAA,IACrC,IAAIA,UAAS,MAAM,IAAI,OAAO,KAAK;AAAA,EACrC,CAAC;AAED,MAAIA,UAAS,MAAM,KAAK,OAAO,OAAO,OAAO;AAC3C,WAAO,MAAM,wBAAwB,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,EAC/D;AACF;AAEA,IAAM,aAAoC,CAAC,aAAa,eAAe;AACvE,IAAM,qBAA4C;AAAA,EAChD;AAAA,EACA;AACF;AAGA,eAAe,cACb,SACA,UACA,MACA,WAC6B;AAC7B,MAAI,YAAY,MAAO,QAAO;AAC9B,QAAM,QAAQ,MAAM,gBAAgB,MAAM,WAAW,UAAU,EAAE,UAAU,CAAC;AAC5E,SAAO,OAAO,UAAU,YAAY,UAAU,KAAK,QAAQ;AAC7D;;;AErIA;;;ACOO,IAAM,uBAAoC;AAAA,EAC/C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,OAAO,GAAG;AAC5C,UAAM,SAAS,UAAU,eAAe,MAAM;AAC9C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AACF;AAEA,IAAO,gBAAQ;","names":["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 { StepError } from '@walkeros/core';\n\nexport function getConfig(partialConfig: PartialConfig = {}): Config {\n const settings: Partial<Settings> = partialConfig.settings || {};\n const { accessToken, adAccountId } = settings;\n\n if (!accessToken || !adAccountId) {\n const missing = [\n ...(accessToken ? [] : ['accessToken']),\n ...(adAccountId ? [] : ['adAccountId']),\n ];\n throw new StepError(`Config settings ${missing.join(', ')} missing`, {\n code: 'config',\n });\n }\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n adAccountId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { ConversionEvent, PushFn, RequestBody, UserData } from './types';\nimport type { Collector, Mapping as WalkerOSMapping } from '@walkeros/core';\nimport {\n createMappingRoot,\n getMappingValue,\n isObject,\n StepError,\n} from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEvent } from './hash';\n\n// A silent rule has no Pinterest call of its own: nothing to send.\nexport const push: PushFn = async function (event, context) {\n if (!context.rule?.silent) await send(event, context);\n};\n\nconst send: PushFn = async function (\n event,\n { config, data, ingest, env, logger, collector },\n) {\n if (!config.settings)\n throw new StepError('Pinterest settings missing, init() not run', {\n code: 'not-ready',\n });\n const {\n accessToken,\n adAccountId,\n action_source = 'web',\n doNotHash,\n test,\n url = 'https://api.pinterest.com/v5/',\n user_data,\n partner_name,\n ip,\n userAgent,\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 // Client IP and user agent auto-fill, overridden by any mapped value\n const root = createMappingRoot(ingest, event);\n const clientIp = await resolveClient(ip, DEFAULT_IP, root, collector);\n const clientUserAgent = await resolveClient(\n userAgent,\n DEFAULT_USER_AGENT,\n root,\n collector,\n );\n\n const userData: UserData = {\n ...(clientIp !== undefined ? { client_ip_address: clientIp } : {}),\n ...(clientUserAgent !== undefined\n ? { client_user_agent: clientUserAgent }\n : {}),\n // Destination config\n ...(isObject(configData) && isObject(configData.user_data)\n ? configData.user_data\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n // Event mapping\n ...(isObject(eventData.user_data) ? eventData.user_data : {}),\n };\n\n // Extract custom_data and user_data from eventData, leave the rest\n const {\n user_data: _ud,\n custom_data: eventCustomData,\n ...restEventData\n } = eventData;\n\n const serverEvent: ConversionEvent = {\n event_name: event.name,\n event_id: event.id,\n event_time: Math.round((event.timestamp || Date.now()) / 1000),\n action_source,\n ...restEventData,\n user_data: userData,\n };\n\n // Nest custom_data from mapping\n if (isObject(eventCustomData)) {\n serverEvent.custom_data = eventCustomData as ConversionEvent['custom_data'];\n }\n\n // Set event_source_url for web events\n if (action_source === 'web' && event.source?.url) {\n serverEvent.event_source_url = event.source.url;\n }\n\n // Add partner_name from settings\n if (partner_name) {\n serverEvent.partner_name = partner_name;\n }\n\n const hashedServerEvent = await hashEvent(serverEvent, doNotHash);\n\n const body: RequestBody = { data: [hashedServerEvent] };\n\n // Build endpoint URL\n const testParam = test ? '?test=true' : '';\n const endpoint = `${url}ad_accounts/${adAccountId}/events${testParam}`;\n\n logger.debug('Calling Pinterest API', {\n endpoint,\n method: 'POST',\n eventName: serverEvent.event_name,\n eventId: serverEvent.event_id,\n });\n\n const sendServerFn = env?.sendServer || sendServer;\n const response = await sendServerFn(endpoint, JSON.stringify(body), {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n checkResponse(response.data);\n};\n\n/**\n * Pinterest answers HTTP 200 with a per-event `status` and reports an event\n * it did not process as `failed` (with its `error_message`). A rejected\n * event fails the push, not retryable; the body stays on the error.\n */\nfunction checkResponse(data: unknown): void {\n if (!isObject(data) || !Array.isArray(data.events)) return;\n const failed = data.events.filter(\n (result) => isObject(result) && result.status === 'failed',\n ).length;\n if (!failed) return;\n throw new StepError('Pinterest Conversions API rejected the event', {\n code: 'transport',\n retryable: false,\n body: data,\n });\n}\n\nconst DEFAULT_IP: WalkerOSMapping.Value = ['ingest.ip', 'event.user.ip'];\nconst DEFAULT_USER_AGENT: WalkerOSMapping.Value = [\n 'ingest.userAgent',\n 'event.user.userAgent',\n];\n\n/** A client IP or user agent setting resolved to a non-empty string. */\nasync function resolveClient(\n setting: WalkerOSMapping.Value | false | undefined,\n fallback: WalkerOSMapping.Value,\n root: WalkerOSMapping.Root,\n collector: Collector.Instance,\n): Promise<string | undefined> {\n if (setting === false) return undefined;\n const value = await getMappingValue(root, setting ?? fallback, { collector });\n return typeof value === 'string' && value !== '' ? value : undefined;\n}\n","import { WalkerOS } from '@walkeros/core';\nimport { isArray, isObject, isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = [\n 'em',\n 'ph',\n 'fn',\n 'ln',\n 'db',\n 'ge',\n 'ct',\n 'st',\n 'zp',\n 'country',\n 'external_id',\n 'hashed_maids',\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 isUserData = 'user_data' in value;\n const target = (isUserData ? value.user_data : 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, isUserData && 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 isUserData ? { ...value, user_data: 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 adAccountId: string;\n action_source?: ActionSource;\n doNotHash?: string[];\n test?: boolean;\n url?: string;\n user_data?: WalkerOSMapping.Map;\n partner_name?: string;\n /**\n * Client IP, sent as user_data.client_ip_address. Resolves against { ingest, event }.\n * `false` switches it off.\n * @default ['ingest.ip', 'event.user.ip']\n */\n ip?: WalkerOSMapping.Value | false;\n /**\n * Client user agent, sent as user_data.client_user_agent. Resolves against\n * { ingest, event }. `false` switches it off.\n * @default ['ingest.userAgent', 'event.user.userAgent']\n */\n userAgent?: WalkerOSMapping.Value | false;\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// Pinterest Conversions API types\n// https://developers.pinterest.com/docs/conversions/conversions/\n\nexport type ActionSource = 'app_android' | 'app_ios' | 'web' | 'offline';\n\nexport type EventName =\n | 'add_payment_info'\n | 'add_to_cart'\n | 'add_to_wishlist'\n | 'app_install'\n | 'app_open'\n | 'checkout'\n | 'contact'\n | 'custom'\n | 'customize_product'\n | 'find_location'\n | 'initiate_checkout'\n | 'lead'\n | 'page_visit'\n | 'schedule'\n | 'search'\n | 'signup'\n | 'start_trial'\n | 'submit_application'\n | 'subscribe'\n | 'view_category'\n | 'view_content'\n | 'watch_video'\n | string;\n\nexport interface ConversionEvent {\n // Required\n event_name: EventName;\n event_time: number;\n event_id: string;\n action_source: ActionSource;\n user_data: UserData;\n\n // Optional\n event_source_url?: string;\n opt_out?: boolean;\n partner_name?: string;\n app_id?: string;\n app_name?: string;\n app_version?: string;\n device_brand?: string;\n device_carrier?: string;\n device_model?: string;\n device_type?: string;\n os_version?: string;\n language?: string;\n wifi?: boolean;\n custom_data?: CustomData;\n}\n\nexport interface UserData {\n // Hashable fields (SHA-256, arrays)\n em?: string[];\n ph?: string[];\n fn?: string[];\n ln?: string[];\n db?: string[];\n ge?: string[];\n ct?: string[];\n st?: string[];\n zp?: string[];\n country?: string[];\n external_id?: string[];\n hashed_maids?: string[];\n\n // Pass-through fields (do NOT hash)\n client_ip_address?: string;\n client_user_agent?: string;\n click_id?: string;\n partner_id?: string;\n}\n\nexport interface CustomData {\n currency?: string;\n value?: string;\n content_ids?: string[];\n content_name?: string;\n content_category?: string;\n content_brand?: string;\n contents?: ContentItem[];\n num_items?: number;\n order_id?: string;\n search_string?: string;\n opt_out_type?: string;\n np?: string;\n predicted_ltv?: string;\n}\n\nexport interface ContentItem {\n id?: string;\n item_name?: string;\n item_category?: string;\n item_brand?: string;\n item_price?: string;\n quantity?: number;\n}\n\nexport interface RequestBody {\n data: ConversionEvent[];\n}\n\nexport interface ResponseBody {\n num_events_received: number;\n num_events_processed: number;\n events: Array<{\n status: string;\n error_message?: string;\n warning_message?: string;\n }>;\n}\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationPinterest from './types';\n\nexport const destinationPinterest: Destination = {\n type: 'pinterest',\n\n config: {},\n\n async init({ config: partialConfig }) {\n return getConfig(partialConfig);\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationPinterest;\n"],"mappings":";;;AACA,SAAS,iBAAiB;AAEnB,SAAS,UAAU,gBAA+B,CAAC,GAAW;AACnE,QAAM,WAA8B,cAAc,YAAY,CAAC;AAC/D,QAAM,EAAE,aAAa,YAAY,IAAI;AAErC,MAAI,CAAC,eAAe,CAAC,aAAa;AAChC,UAAM,UAAU;AAAA,MACd,GAAI,cAAc,CAAC,IAAI,CAAC,aAAa;AAAA,MACrC,GAAI,cAAc,CAAC,IAAI,CAAC,aAAa;AAAA,IACvC;AACA,UAAM,IAAI,UAAU,mBAAmB,QAAQ,KAAK,IAAI,CAAC,YAAY;AAAA,MACnE,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,QAAM,iBAA2B;AAAA,IAC/B,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,eAAe,UAAU,eAAe;AACtD;;;ACtBA;AAAA,EACE;AAAA,EACA;AAAA,EACA,YAAAA;AAAA,EACA,aAAAC;AAAA,OACK;AACP,SAAS,kBAAkB;;;ACP3B,SAAS,SAAS,UAAU,gBAAgB;AAC5C,SAAS,qBAAqB;AAE9B,IAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,eAAe,KAAa,YAAsB,CAAC,GAAY;AACtE,SAAO,WAAW,SAAS,GAAG,KAAK,CAAC,UAAU,SAAS,GAAG;AAC5D;AAIA,eAAe,aACb,OACA,YACkB;AAClB,MAAI,CAAC,WAAY,QAAO;AACxB,MAAI,QAAQ,KAAK,GAAG;AAClB,WAAO,QAAQ,IAAI,MAAM,IAAI,CAAC,SAAS,cAAc,OAAO,IAAI,CAAC,CAAC,CAAC;AAAA,EACrE;AACA,SAAO,cAAc,OAAO,KAAK,CAAC;AACpC;AAEA,eAAsB,UACpB,OACA,YAAsB,CAAC,GACX;AACZ,MAAI,CAAC,SAAS,KAAK,EAAG,QAAO;AAE7B,QAAM,aAAa,eAAe;AAClC,QAAM,SAAU,aAAa,MAAM,YAAY;AAE/C,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,OAAO,QAAQ,MAAM,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM;AAAA,MAC3C;AAAA,MACA,MAAM,aAAa,GAAG,cAAc,eAAe,GAAG,SAAS,CAAC;AAAA,IAClE,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,QAAQ,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;AAC7C,QAAI,SAAS,CAAC,EAAG,KAAI,CAAC,IAAI;AAC1B,WAAO;AAAA,EACT,GAAG,CAAC,CAAuB;AAE3B,SAAO,aAAa,EAAE,GAAG,OAAO,WAAW,OAAO,IAAK;AACzD;;;AD9CO,IAAM,OAAe,eAAgB,OAAO,SAAS;AAC1D,MAAI,CAAC,QAAQ,MAAM,OAAQ,OAAM,KAAK,OAAO,OAAO;AACtD;AAEA,IAAM,OAAe,eACnB,OACA,EAAE,QAAQ,MAAM,QAAQ,KAAK,QAAQ,UAAU,GAC/C;AACA,MAAI,CAAC,OAAO;AACV,UAAM,IAAIC,WAAU,8CAA8C;AAAA,MAChE,MAAM;AAAA,IACR,CAAC;AACH,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,OAAO;AAEX,QAAM,YAAYC,UAAS,IAAI,IAAI,OAAO,CAAC;AAC3C,QAAM,aAAa,OAAO,OACtB,MAAM,gBAAgB,OAAO,OAAO,MAAM,EAAE,UAAU,CAAC,IACvD,CAAC;AACL,QAAM,iBAAiB,YACnB,MAAM,gBAAgB,OAAO,EAAE,KAAK,UAAU,GAAG,EAAE,UAAU,CAAC,IAC9D,CAAC;AAIL,QAAM,OAAO,kBAAkB,QAAQ,KAAK;AAC5C,QAAM,WAAW,MAAM,cAAc,IAAI,YAAY,MAAM,SAAS;AACpE,QAAM,kBAAkB,MAAM;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,WAAqB;AAAA,IACzB,GAAI,aAAa,SAAY,EAAE,mBAAmB,SAAS,IAAI,CAAC;AAAA,IAChE,GAAI,oBAAoB,SACpB,EAAE,mBAAmB,gBAAgB,IACrC,CAAC;AAAA;AAAA,IAEL,GAAIA,UAAS,UAAU,KAAKA,UAAS,WAAW,SAAS,IACrD,WAAW,YACX,CAAC;AAAA;AAAA,IAEL,GAAIA,UAAS,cAAc,IAAI,iBAAiB,CAAC;AAAA;AAAA,IAEjD,GAAIA,UAAS,UAAU,SAAS,IAAI,UAAU,YAAY,CAAC;AAAA,EAC7D;AAGA,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,aAAa;AAAA,IACb,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,cAA+B;AAAA,IACnC,YAAY,MAAM;AAAA,IAClB,UAAU,MAAM;AAAA,IAChB,YAAY,KAAK,OAAO,MAAM,aAAa,KAAK,IAAI,KAAK,GAAI;AAAA,IAC7D;AAAA,IACA,GAAG;AAAA,IACH,WAAW;AAAA,EACb;AAGA,MAAIA,UAAS,eAAe,GAAG;AAC7B,gBAAY,cAAc;AAAA,EAC5B;AAGA,MAAI,kBAAkB,SAAS,MAAM,QAAQ,KAAK;AAChD,gBAAY,mBAAmB,MAAM,OAAO;AAAA,EAC9C;AAGA,MAAI,cAAc;AAChB,gBAAY,eAAe;AAAA,EAC7B;AAEA,QAAM,oBAAoB,MAAM,UAAU,aAAa,SAAS;AAEhE,QAAM,OAAoB,EAAE,MAAM,CAAC,iBAAiB,EAAE;AAGtD,QAAM,YAAY,OAAO,eAAe;AACxC,QAAM,WAAW,GAAG,GAAG,eAAe,WAAW,UAAU,SAAS;AAEpE,SAAO,MAAM,yBAAyB;AAAA,IACpC;AAAA,IACA,QAAQ;AAAA,IACR,WAAW,YAAY;AAAA,IACvB,SAAS,YAAY;AAAA,EACvB,CAAC;AAED,QAAM,eAAe,KAAK,cAAc;AACxC,QAAM,WAAW,MAAM,aAAa,UAAU,KAAK,UAAU,IAAI,GAAG;AAAA,IAClE,SAAS,EAAE,eAAe,UAAU,WAAW,GAAG;AAAA,EACpD,CAAC;AACD,gBAAc,SAAS,IAAI;AAC7B;AAOA,SAAS,cAAc,MAAqB;AAC1C,MAAI,CAACA,UAAS,IAAI,KAAK,CAAC,MAAM,QAAQ,KAAK,MAAM,EAAG;AACpD,QAAM,SAAS,KAAK,OAAO;AAAA,IACzB,CAAC,WAAWA,UAAS,MAAM,KAAK,OAAO,WAAW;AAAA,EACpD,EAAE;AACF,MAAI,CAAC,OAAQ;AACb,QAAM,IAAID,WAAU,gDAAgD;AAAA,IAClE,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,EACR,CAAC;AACH;AAEA,IAAM,aAAoC,CAAC,aAAa,eAAe;AACvE,IAAM,qBAA4C;AAAA,EAChD;AAAA,EACA;AACF;AAGA,eAAe,cACb,SACA,UACA,MACA,WAC6B;AAC7B,MAAI,YAAY,MAAO,QAAO;AAC9B,QAAM,QAAQ,MAAM,gBAAgB,MAAM,WAAW,UAAU,EAAE,UAAU,CAAC;AAC5E,SAAO,OAAO,UAAU,YAAY,UAAU,KAAK,QAAQ;AAC7D;;;AE9JA;;;ACOO,IAAM,uBAAoC;AAAA,EAC/C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,cAAc,GAAG;AACpC,WAAO,UAAU,aAAa;AAAA,EAChC;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AACF;AAEA,IAAO,gBAAQ;","names":["isObject","StepError","StepError","isObject"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/server-destination-pinterest",
4
- "version": "4.8.1-next-1792019907609",
4
+ "version": "4.8.2",
5
5
  "type": "destination",
6
6
  "platform": [
7
7
  "server"
@@ -257,7 +257,7 @@
257
257
  "env": {
258
258
  "push": {
259
259
  "sendServer": {
260
- "$code": "async function(e,t,a){return{ok:!0,data:{num_events_received:1,num_events_processed:1,events:[{status:\"processed\"}]}}}"
260
+ "$code": "async function(e,t,a){return{data:{num_events_received:1,num_events_processed:1,events:[{status:\"processed\"}]}}}"
261
261
  }
262
262
  },
263
263
  "simulation": [
@@ -359,7 +359,7 @@
359
359
  "name": "order complete",
360
360
  "data": {
361
361
  "id": "ORD-300",
362
- "total": 249.99,
362
+ "value": 249.99,
363
363
  "currency": "EUR"
364
364
  },
365
365
  "context": {
@@ -412,7 +412,7 @@
412
412
  "map": {
413
413
  "custom_data": {
414
414
  "map": {
415
- "value": "data.total",
415
+ "value": "data.value",
416
416
  "currency": {
417
417
  "key": "data.currency",
418
418
  "value": "EUR"
@@ -428,7 +428,7 @@
428
428
  "nested",
429
429
  {
430
430
  "condition": {
431
- "$code": "e=>y(e)&&\"product\"===e.entity"
431
+ "$code": "e=>k(e)&&\"product\"===e.entity"
432
432
  },
433
433
  "map": {
434
434
  "id": "data.id",
@@ -529,6 +529,79 @@
529
529
  ]
530
530
  ]
531
531
  },
532
+ "rejectedEvent": {
533
+ "public": false,
534
+ "description": "Pinterest answers HTTP 200 and reports the event as failed: the push fails with transport, not retryable, and the event goes to the DLQ.",
535
+ "in": {
536
+ "name": "page view",
537
+ "data": {
538
+ "domain": "www.example.com",
539
+ "title": "walkerOS documentation",
540
+ "referrer": "https://www.walkeros.io/",
541
+ "search": "?foo=bar",
542
+ "hash": "#hash",
543
+ "id": "/docs/"
544
+ },
545
+ "context": {
546
+ "dev": [
547
+ "test",
548
+ 1
549
+ ]
550
+ },
551
+ "globals": {
552
+ "pagegroup": "docs"
553
+ },
554
+ "custom": {
555
+ "completely": "random"
556
+ },
557
+ "user": {
558
+ "id": "us3r",
559
+ "device": "c00k13",
560
+ "session": "s3ss10n"
561
+ },
562
+ "nested": [
563
+ {
564
+ "entity": "child",
565
+ "data": {
566
+ "is": "subordinated"
567
+ }
568
+ }
569
+ ],
570
+ "consent": {
571
+ "functional": true
572
+ },
573
+ "id": "a1b2c3d4e5f60007",
574
+ "trigger": "load",
575
+ "entity": "page",
576
+ "action": "view",
577
+ "timestamp": 1700000906,
578
+ "timing": 3.14,
579
+ "source": {
580
+ "count": 1,
581
+ "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
582
+ "type": "collector",
583
+ "schema": "4"
584
+ }
585
+ },
586
+ "respond": {
587
+ "status": 200,
588
+ "body": {
589
+ "num_events_received": 1,
590
+ "num_events_processed": 0,
591
+ "events": [
592
+ {
593
+ "status": "failed",
594
+ "error_message": "Invalid event_time"
595
+ }
596
+ ]
597
+ }
598
+ },
599
+ "outcome": {
600
+ "status": "failed",
601
+ "code": "transport",
602
+ "retryable": false
603
+ }
604
+ },
532
605
  "search": {
533
606
  "title": "Search",
534
607
  "description": "A site search event is forwarded to Pinterest as a search conversion with the query in custom data.",
@@ -684,6 +757,65 @@
684
757
  }
685
758
  ]
686
759
  ]
760
+ },
761
+ "silentRule": {
762
+ "public": false,
763
+ "description": "A rule with silent: true sends no request to Pinterest.",
764
+ "in": {
765
+ "name": "page view",
766
+ "data": {
767
+ "domain": "www.example.com",
768
+ "title": "walkerOS documentation",
769
+ "referrer": "https://www.walkeros.io/",
770
+ "search": "?foo=bar",
771
+ "hash": "#hash",
772
+ "id": "/docs/"
773
+ },
774
+ "context": {
775
+ "dev": [
776
+ "test",
777
+ 1
778
+ ]
779
+ },
780
+ "globals": {
781
+ "pagegroup": "docs"
782
+ },
783
+ "custom": {
784
+ "completely": "random"
785
+ },
786
+ "user": {
787
+ "id": "us3r",
788
+ "device": "c00k13",
789
+ "session": "s3ss10n"
790
+ },
791
+ "nested": [
792
+ {
793
+ "entity": "child",
794
+ "data": {
795
+ "is": "subordinated"
796
+ }
797
+ }
798
+ ],
799
+ "consent": {
800
+ "functional": true
801
+ },
802
+ "id": "a1b2c3d4e5f60006",
803
+ "trigger": "load",
804
+ "entity": "page",
805
+ "action": "view",
806
+ "timestamp": 1700000905,
807
+ "timing": 3.14,
808
+ "source": {
809
+ "count": 1,
810
+ "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
811
+ "type": "collector",
812
+ "schema": "4"
813
+ }
814
+ },
815
+ "mapping": {
816
+ "silent": true
817
+ },
818
+ "out": []
687
819
  }
688
820
  }
689
821
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@walkeros/server-destination-pinterest",
3
3
  "description": "Pinterest server destination for walkerOS",
4
- "version": "4.8.1-next-1792019907609",
4
+ "version": "4.8.2",
5
5
  "license": "MIT",
6
6
  "exports": {
7
7
  ".": {
@@ -35,11 +35,11 @@
35
35
  "update": "npx npm-check-updates -u && npm update"
36
36
  },
37
37
  "dependencies": {
38
- "@walkeros/core": "4.8.1-next-1792019907609",
39
- "@walkeros/server-core": "4.8.1-next-1792019907609"
38
+ "@walkeros/core": "4.8.2",
39
+ "@walkeros/server-core": "4.8.2"
40
40
  },
41
41
  "devDependencies": {
42
- "@walkeros/collector": "4.8.1-next-1792019907609"
42
+ "@walkeros/collector": "4.8.2"
43
43
  },
44
44
  "repository": {
45
45
  "url": "git+https://github.com/elbwalker/walkerOS.git",