@walkeros/server-destination-tiktok 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,39 @@
1
1
  # @walkeros/server-destination-meta
2
2
 
3
- ## 4.8.1-next-1792019907609
3
+ ## 4.8.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 2374f54: A request that TikTok answers with HTTP 200 and a non-zero `code` now
8
+ fails the push instead of counting as delivered; rate limits and server errors
9
+ are retryable, other rejections are not. Rules with `silent: true` send
10
+ nothing.
11
+ - 2374f54: A failed request is reported as a failed push (dead-letter queue, one
12
+ ERROR line with the status) instead of counting as delivered or being logged
13
+ at debug. Events a destination cannot send, such as a missing user identifier,
14
+ fail with `missing-input`. Rules with `silent: true` send no event of their
15
+ own.
16
+ - Updated dependencies [2374f54]
17
+ - Updated dependencies [7e5fc27]
18
+ - Updated dependencies [2374f54]
19
+ - Updated dependencies [964590a]
20
+ - Updated dependencies [4100ede]
21
+ - Updated dependencies [2374f54]
22
+ - Updated dependencies [2374f54]
23
+ - Updated dependencies [15eb7b2]
24
+ - Updated dependencies [33a2779]
25
+ - Updated dependencies [33a2779]
26
+ - Updated dependencies [2374f54]
27
+ - @walkeros/core@4.8.2
28
+ - @walkeros/server-core@4.8.2
29
+
30
+ ## 4.8.1
4
31
 
5
32
  ### Patch Changes
6
33
 
7
34
  - Updated dependencies [1062e99]
8
- - @walkeros/core@4.8.1-next-1792019907609
9
- - @walkeros/server-core@4.8.1-next-1792019907609
35
+ - @walkeros/core@4.8.1
36
+ - @walkeros/server-core@4.8.1
10
37
 
11
38
  ## 4.8.0
12
39
 
package/README.md CHANGED
@@ -32,7 +32,12 @@ npm install @walkeros/server-destination-tiktok
32
32
  "destinations": {
33
33
  "tiktok": {
34
34
  "package": "@walkeros/server-destination-tiktok",
35
- "config": {}
35
+ "config": {
36
+ "settings": {
37
+ "pixelCode": "YOUR_PIXEL_CODE",
38
+ "accessToken": "YOUR_ACCESS_TOKEN"
39
+ }
40
+ }
36
41
  }
37
42
  }
38
43
  }
package/dist/dev.d.mts CHANGED
@@ -34,7 +34,7 @@ declare const SettingsSchema: z.ZodObject<{
34
34
  partner_name: z.ZodOptional<z.ZodString>;
35
35
  ip: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodLiteral<false>]>>;
36
36
  userAgent: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodLiteral<false>]>>;
37
- }, z.core.$strip>;
37
+ }, z.core.$strict>;
38
38
  type Settings = z.infer<typeof SettingsSchema>;
39
39
 
40
40
  /**
@@ -84,13 +84,22 @@ declare const purchase: Flow.StepExample;
84
84
  declare const addToCart: Flow.StepExample;
85
85
  declare const pageView: Flow.StepExample;
86
86
  declare const lead: Flow.StepExample;
87
+ /** A silent rule sends nothing to TikTok. */
88
+ declare const silentRule: Flow.StepExample;
89
+ /** TikTok rejects the event in an HTTP 200 body. */
90
+ declare const rejectedEvent: Flow.StepExample;
91
+ /** TikTok is busy: a server error code in the HTTP 200 body. */
92
+ declare const busy: Flow.StepExample;
87
93
 
88
94
  declare const step_addToCart: typeof addToCart;
95
+ declare const step_busy: typeof busy;
89
96
  declare const step_lead: typeof lead;
90
97
  declare const step_pageView: typeof pageView;
91
98
  declare const step_purchase: typeof purchase;
99
+ declare const step_rejectedEvent: typeof rejectedEvent;
100
+ declare const step_silentRule: typeof silentRule;
92
101
  declare namespace step {
93
- export { step_addToCart as addToCart, step_lead as lead, step_pageView as pageView, step_purchase as purchase };
102
+ export { step_addToCart as addToCart, step_busy as busy, step_lead as lead, step_pageView as pageView, step_purchase as purchase, step_rejectedEvent as rejectedEvent, step_silentRule as silentRule };
94
103
  }
95
104
 
96
105
  declare const index_env: typeof env;
package/dist/dev.d.ts CHANGED
@@ -34,7 +34,7 @@ declare const SettingsSchema: z.ZodObject<{
34
34
  partner_name: z.ZodOptional<z.ZodString>;
35
35
  ip: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodLiteral<false>]>>;
36
36
  userAgent: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodLiteral<false>]>>;
37
- }, z.core.$strip>;
37
+ }, z.core.$strict>;
38
38
  type Settings = z.infer<typeof SettingsSchema>;
39
39
 
40
40
  /**
@@ -84,13 +84,22 @@ declare const purchase: Flow.StepExample;
84
84
  declare const addToCart: Flow.StepExample;
85
85
  declare const pageView: Flow.StepExample;
86
86
  declare const lead: Flow.StepExample;
87
+ /** A silent rule sends nothing to TikTok. */
88
+ declare const silentRule: Flow.StepExample;
89
+ /** TikTok rejects the event in an HTTP 200 body. */
90
+ declare const rejectedEvent: Flow.StepExample;
91
+ /** TikTok is busy: a server error code in the HTTP 200 body. */
92
+ declare const busy: Flow.StepExample;
87
93
 
88
94
  declare const step_addToCart: typeof addToCart;
95
+ declare const step_busy: typeof busy;
89
96
  declare const step_lead: typeof lead;
90
97
  declare const step_pageView: typeof pageView;
91
98
  declare const step_purchase: typeof purchase;
99
+ declare const step_rejectedEvent: typeof rejectedEvent;
100
+ declare const step_silentRule: typeof silentRule;
92
101
  declare namespace step {
93
- export { step_addToCart as addToCart, step_lead as lead, step_pageView as pageView, step_purchase as purchase };
102
+ export { step_addToCart as addToCart, step_busy as busy, step_lead as lead, step_pageView as pageView, step_purchase as purchase, step_rejectedEvent as rejectedEvent, step_silentRule as silentRule };
94
103
  }
95
104
 
96
105
  declare const index_env: typeof env;
package/dist/dev.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,r=Object.prototype.hasOwnProperty,i=(e,a)=>{for(var n in a)t(e,n,{get:a[n],enumerable:!0})},o={};i(o,{examples:()=>f,schemas:()=>s}),module.exports=(e=o,((e,i,o,s)=>{if(i&&"object"==typeof i||"function"==typeof i)for(let c of n(i))r.call(e,c)||c===o||t(e,c,{get:()=>i[c],enumerable:!(s=a(i,c))||s.enumerable});return e})(t({},"__esModule",{value:!0}),e));var s={};i(s,{MappingSchema:()=>u,SettingsSchema:()=>m,StandardEventNameSchema:()=>v,mapping:()=>b,settings:()=>g});var c=require("@walkeros/core/dev"),d=require("@walkeros/core/dev"),p=d.z.union([d.schemas.MappingSchemas.ValueSchema,d.z.literal(!1)]),m=d.z.object({pixelCode:d.z.string().min(1).describe("TikTok Pixel Code from Events Manager (like C0ABCDEF12345)"),accessToken:d.z.string().min(1).describe("Events API access token from TikTok Events Manager"),url:d.z.string().url().describe("Custom Events API endpoint URL").optional(),test_event_code:d.z.string().describe("Test event code for debugging in TikTok Events Manager (like TEST12345)").optional(),doNotHash:d.z.array(d.z.string()).describe("User data fields to skip hashing (like ['email', 'phone_number'])").optional(),user_data:d.z.record(d.z.string(),d.z.string()).describe("Mapping for user data fields (like { email: 'user.email' })").optional(),partner_name:d.z.string().describe("Partner name for TikTok attribution").optional(),ip:p.describe('Client IP, sent as context.ip. Resolves against { ingest, event }. Default: ["ingest.ip", "event.user.ip"]. false switches it off.').optional(),userAgent:p.describe('Client user agent, sent as context.user_agent. Resolves against { ingest, event }. Default: ["ingest.userAgent", "event.user.userAgent"]. false switches it off.').optional()}),u=require("@walkeros/core/dev").z.object({}),l=require("@walkeros/core/dev"),v=l.z.union([l.z.enum(["ViewContent","ClickButton","Search","AddToWishlist","AddToCart","InitiateCheckout","AddPaymentInfo","CompletePayment","PlaceAnOrder","Contact","Download","SubmitForm","CompleteRegistration","Subscribe"]),l.z.string()]),g=(0,c.zodToSchema)(m),b=(0,c.zodToSchema)(u),f={};i(f,{env:()=>h,step:()=>_});var h={};i(h,{push:()=>y,simulation:()=>k});var y={sendServer:async function(e,t,a){return{ok:!0,data:{code:0,message:"OK"}}}},k=["sendServer"],_={};i(_,{addToCart:()=>C,lead:()=>O,pageView:()=>E,purchase:()=>x});var S=require("@walkeros/core"),w="https://business-api.tiktok.com/open_api/v1.3/event/track/",T={headers:{"Access-Token":"s3cr3t","Content-Type":"application/json"}},x={title:"Complete payment",description:"A completed order is sent to the TikTok Events API as a CompletePayment with value, currency, and contents.",in:(0,S.getEvent)("order complete",{id:"d1e2f3a4b5c60001",timestamp:17000009e5,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Widget Pro",price:124.99,quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/checkout/complete"}}),mapping:{name:"CompletePayment",data:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"},order_id:"data.id",content_type:{value:"product"},contents:{loop:["nested",{condition:e=>(0,S.isObject)(e)&&"product"===e.entity,map:{content_id:"data.id",content_name:"data.name",quantity:{key:"data.quantity",value:1},price:"data.price"}}]},user_data:{map:{external_id:"user.id"}}}}},out:[["sendServer",w,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"CompletePayment",event_id:"d1e2f3a4b5c60001",timestamp:"2023-11-14T22:28:20.000Z",context:{user:{external_id:"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"},page:{url:"https://shop.example.com/checkout/complete"}},properties:{value:249.99,currency:"EUR",order_id:"ORD-300",content_type:"product",contents:[{content_id:"SKU-A1",content_name:"Widget Pro",quantity:2,price:124.99}]}}]}),T]]},C={title:"Add to cart",description:"A product add is sent to TikTok as an AddToCart event with value, currency, and product contents.",in:(0,S.getEvent)("product add",{id:"d1e2f3a4b5c60002",timestamp:1700000901e3,data:{id:"SKU-B2",name:"Running Shoes",price:89.99,color:"blue"},nested:[{entity:"product",data:{id:"SKU-B2",name:"Running Shoes",price:89.99,quantity:1}}],source:{type:"browser",platform:"web",url:"https://shop.example.com/products/running-shoes"}}),mapping:{name:"AddToCart",data:{map:{content_type:{value:"product"},value:"data.price",currency:{value:"EUR"},contents:{loop:["nested",{condition:e=>(0,S.isObject)(e)&&"product"===e.entity,map:{content_id:"data.id",content_name:"data.name",quantity:{key:"data.quantity",value:1},price:"data.price"}}]}}}},out:[["sendServer",w,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"AddToCart",event_id:"d1e2f3a4b5c60002",timestamp:"2023-11-14T22:28:21.000Z",context:{page:{url:"https://shop.example.com/products/running-shoes"}},properties:{content_type:"product",value:89.99,currency:"EUR",contents:[{content_id:"SKU-B2",content_name:"Running Shoes",quantity:1,price:89.99}]}}]}),T]]},E={title:"Page view",description:"A page view is forwarded to TikTok as a page view event with the source URL in the page context.",in:(0,S.getEvent)("page view",{id:"d1e2f3a4b5c60003",timestamp:1700000902e3,source:{type:"browser",platform:"web",url:"https://example.com/docs/"}}),mapping:void 0,out:[["sendServer",w,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"page view",event_id:"d1e2f3a4b5c60003",timestamp:"2023-11-14T22:28:22.000Z",context:{page:{url:"https://example.com/docs/"}},properties:{}}]}),T]]},O={title:"Submit form",description:"A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.",in:(0,S.getEvent)("form submit",{id:"d1e2f3a4b5c60004",timestamp:1700000903e3,data:{type:"newsletter"},user:{email:"user@example.com"},source:{type:"browser",platform:"web",url:"https://example.com/contact"}}),mapping:{name:"SubmitForm",data:{map:{user_data:{map:{email:"user.email"}}}}},out:[["sendServer",w,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"SubmitForm",event_id:"d1e2f3a4b5c60004",timestamp:"2023-11-14T22:28:23.000Z",context:{user:{email:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"},page:{url:"https://example.com/contact"}},properties:{}}]}),T]]};//# sourceMappingURL=dev.js.map
1
+ "use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,r=Object.prototype.hasOwnProperty,i=(e,a)=>{for(var n in a)t(e,n,{get:a[n],enumerable:!0})},o={};i(o,{examples:()=>f,schemas:()=>s}),module.exports=(e=o,((e,i,o,s)=>{if(i&&"object"==typeof i||"function"==typeof i)for(let c of n(i))r.call(e,c)||c===o||t(e,c,{get:()=>i[c],enumerable:!(s=a(i,c))||s.enumerable});return e})(t({},"__esModule",{value:!0}),e));var s={};i(s,{MappingSchema:()=>m,SettingsSchema:()=>u,StandardEventNameSchema:()=>v,mapping:()=>b,settings:()=>g});var c=require("@walkeros/core/dev"),d=require("@walkeros/core/dev"),p=d.z.union([d.schemas.MappingSchemas.ValueSchema,d.z.literal(!1)]),u=d.z.object({pixelCode:d.z.string().min(1).describe("TikTok Pixel Code from Events Manager (like C0ABCDEF12345)"),accessToken:d.z.string().min(1).describe("Events API access token from TikTok Events Manager"),url:d.z.string().url().describe("Custom Events API endpoint URL").optional(),test_event_code:d.z.string().describe("Test event code for debugging in TikTok Events Manager (like TEST12345)").optional(),doNotHash:d.z.array(d.z.string()).describe("User data fields to skip hashing (like ['email', 'phone_number'])").optional(),user_data:d.z.record(d.z.string(),d.z.string()).describe("Mapping for user data fields (like { email: 'user.email' })").optional(),partner_name:d.z.string().describe("Partner name for TikTok attribution").optional(),ip:p.describe('Client IP, sent as context.ip. Resolves against { ingest, event }. Default: ["ingest.ip", "event.user.ip"]. false switches it off.').optional(),userAgent:p.describe('Client user agent, sent as context.user_agent. Resolves against { ingest, event }. Default: ["ingest.userAgent", "event.user.userAgent"]. false switches it off.').optional()}).strict(),m=require("@walkeros/core/dev").z.object({}),l=require("@walkeros/core/dev"),v=l.z.union([l.z.enum(["ViewContent","ClickButton","Search","AddToWishlist","AddToCart","InitiateCheckout","AddPaymentInfo","CompletePayment","PlaceAnOrder","Contact","Download","SubmitForm","CompleteRegistration","Subscribe"]),l.z.string()]),g=(0,c.zodToSchema)(u),b=(0,c.zodToSchema)(m),f={};i(f,{env:()=>h,step:()=>w});var h={};i(h,{push:()=>y,simulation:()=>k});var y={sendServer:async function(e,t,a){return{data:{code:0,message:"OK"}}}},k=["sendServer"],w={};i(w,{addToCart:()=>x,busy:()=>z,lead:()=>O,pageView:()=>C,purchase:()=>E,rejectedEvent:()=>A,silentRule:()=>P});var T=require("@walkeros/core"),_="https://business-api.tiktok.com/open_api/v1.3/event/track/",S={headers:{"Access-Token":"s3cr3t","Content-Type":"application/json"}},E={title:"Complete payment",description:"A completed order is sent to the TikTok Events API as a CompletePayment with value, currency, and contents.",in:(0,T.getEvent)("order complete",{id:"d1e2f3a4b5c60001",timestamp:17000009e5,data:{id:"ORD-300",value:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Widget Pro",price:124.99,quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/checkout/complete"}}),mapping:{name:"CompletePayment",data:{map:{value:"data.value",currency:{key:"data.currency",value:"EUR"},order_id:"data.id",content_type:{value:"product"},contents:{loop:["nested",{condition:e=>(0,T.isObject)(e)&&"product"===e.entity,map:{content_id:"data.id",content_name:"data.name",quantity:{key:"data.quantity",value:1},price:"data.price"}}]},user_data:{map:{external_id:"user.id"}}}}},out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"CompletePayment",event_id:"d1e2f3a4b5c60001",timestamp:"2023-11-14T22:28:20.000Z",context:{user:{external_id:"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"},page:{url:"https://shop.example.com/checkout/complete"}},properties:{value:249.99,currency:"EUR",order_id:"ORD-300",content_type:"product",contents:[{content_id:"SKU-A1",content_name:"Widget Pro",quantity:2,price:124.99}]}}]}),S]]},x={title:"Add to cart",description:"A product add is sent to TikTok as an AddToCart event with value, currency, and product contents.",in:(0,T.getEvent)("product add",{id:"d1e2f3a4b5c60002",timestamp:1700000901e3,data:{id:"SKU-B2",name:"Running Shoes",price:89.99,color:"blue"},nested:[{entity:"product",data:{id:"SKU-B2",name:"Running Shoes",price:89.99,quantity:1}}],source:{type:"browser",platform:"web",url:"https://shop.example.com/products/running-shoes"}}),mapping:{name:"AddToCart",data:{map:{content_type:{value:"product"},value:"data.price",currency:{value:"EUR"},contents:{loop:["nested",{condition:e=>(0,T.isObject)(e)&&"product"===e.entity,map:{content_id:"data.id",content_name:"data.name",quantity:{key:"data.quantity",value:1},price:"data.price"}}]}}}},out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"AddToCart",event_id:"d1e2f3a4b5c60002",timestamp:"2023-11-14T22:28:21.000Z",context:{page:{url:"https://shop.example.com/products/running-shoes"}},properties:{content_type:"product",value:89.99,currency:"EUR",contents:[{content_id:"SKU-B2",content_name:"Running Shoes",quantity:1,price:89.99}]}}]}),S]]},C={title:"Page view",description:"A page view is forwarded to TikTok as a page view event with the source URL in the page context.",in:(0,T.getEvent)("page view",{id:"d1e2f3a4b5c60003",timestamp:1700000902e3,source:{type:"browser",platform:"web",url:"https://example.com/docs/"}}),mapping:void 0,out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"page view",event_id:"d1e2f3a4b5c60003",timestamp:"2023-11-14T22:28:22.000Z",context:{page:{url:"https://example.com/docs/"}},properties:{}}]}),S]]},O={title:"Submit form",description:"A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.",in:(0,T.createEvent)({name:"form submit",id:"d1e2f3a4b5c60004",timestamp:1700000903e3,data:{type:"newsletter"},user:{email:"user@example.com"},source:{type:"browser",platform:"web",url:"https://example.com/contact"}}),mapping:{name:"SubmitForm",data:{map:{user_data:{map:{email:"user.email"}}}}},out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"SubmitForm",event_id:"d1e2f3a4b5c60004",timestamp:"2023-11-14T22:28:23.000Z",context:{user:{email:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"},page:{url:"https://example.com/contact"}},properties:{}}]}),S]]},P={public:!1,description:"A rule with silent: true sends no request to TikTok.",in:(0,T.getEvent)("page view",{id:"d1e2f3a4b5c60005",timestamp:1700000904e3}),mapping:{silent:!0},out:[]},A={public:!1,description:"TikTok answers HTTP 200 with a non-zero code: the event was rejected, so the push fails with transport, not retryable, and the event goes to the DLQ.",in:(0,T.getEvent)("page view",{id:"d1e2f3a4b5c60006",timestamp:1700000905e3}),respond:{status:200,body:{code:40002,message:"Invalid value for field event"}},outcome:{status:"failed",code:"transport",retryable:!1}},z={public:!1,description:"TikTok answers HTTP 200 with a server error code: the push fails with transport, retryable.",in:(0,T.getEvent)("page view",{id:"d1e2f3a4b5c60007",timestamp:1700000906e3}),respond:{status:200,body:{code:5e4,message:"System error"}},outcome:{status:"failed",code:"transport",retryable:!0}};//# sourceMappingURL=dev.js.map
package/dist/dev.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { schemas, z } from '@walkeros/core/dev';\n\nconst InputSchema = z.union([\n schemas.MappingSchemas.ValueSchema,\n z.literal(false),\n]);\n\nexport const SettingsSchema = z.object({\n pixelCode: z\n .string()\n .min(1)\n .describe('TikTok Pixel Code from Events Manager (like C0ABCDEF12345)'),\n accessToken: z\n .string()\n .min(1)\n .describe('Events API access token from TikTok Events Manager'),\n url: z.string().url().describe('Custom Events API endpoint URL').optional(),\n test_event_code: z\n .string()\n .describe(\n 'Test event code for debugging in TikTok Events Manager (like TEST12345)',\n )\n .optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"User data fields to skip hashing (like ['email', 'phone_number'])\",\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\"Mapping for user data fields (like { email: 'user.email' })\")\n .optional(),\n partner_name: z\n .string()\n .describe('Partner name for TikTok attribution')\n .optional(),\n ip: InputSchema.describe(\n 'Client IP, sent as context.ip. Resolves against { ingest, event }. Default: [\"ingest.ip\", \"event.user.ip\"]. false switches it off.',\n ).optional(),\n userAgent: InputSchema.describe(\n 'Client user agent, sent as context.user_agent. Resolves against { ingest, event }. Default: [\"ingest.userAgent\", \"event.user.userAgent\"]. false switches it off.',\n ).optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * TikTok Events API Mapping Schema\n * TikTok Events API has no event-level mapping configuration\n */\nexport const MappingSchema = z.object({});\n\n/**\n * Type inference from MappingSchema\n */\nexport type Mapping = z.infer<typeof MappingSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Standard TikTok Event Names\n * https://business-api.tiktok.com/portal/docs?id=1771100865818625\n */\nexport const StandardEventNameSchema = z.union([\n z.enum([\n 'ViewContent',\n 'ClickButton',\n 'Search',\n 'AddToWishlist',\n 'AddToCart',\n 'InitiateCheckout',\n 'AddPaymentInfo',\n 'CompletePayment',\n 'PlaceAnOrder',\n 'Contact',\n 'Download',\n 'SubmitForm',\n 'CompleteRegistration',\n 'Subscribe',\n ]),\n z.string(), // Allow custom event names\n]);\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for TikTok Events 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 TikTok API response\n return {\n ok: true,\n data: {\n code: 0,\n message: 'OK',\n },\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing TikTok Events API events without making\n * actual HTTP requests to TikTok's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * TikTok Events API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(url, body, { headers })` where `url` is the fixed\n * TikTok Events API endpoint and `body` is the JSON-stringified payload\n * `{ pixel_code, partner_name, data: [tiktokEvent] }`.\n *\n * The test fixture pins `accessToken = 's3cr3t'` and `pixelCode = 'PIXEL_CODE'`.\n *\n * Body fields are emitted in the order the destination constructs them\n * (insertion order matters for `JSON.stringify` string equality):\n * pixel_code, partner_name, data[] with { event, event_id, timestamp,\n * context: { user?, page }, properties }.\n *\n * User identity fields (`email`, `phone_number`, `external_id`) are hashed\n * with SHA-256.\n */\nconst ENDPOINT = 'https://business-api.tiktok.com/open_api/v1.3/event/track/';\nconst HEADERS = {\n headers: {\n 'Access-Token': 's3cr3t',\n 'Content-Type': 'application/json',\n },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Complete payment',\n description:\n 'A completed order is sent to the TikTok Events API as a CompletePayment with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'd1e2f3a4b5c60001',\n timestamp: 1700000900000,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: { id: 'SKU-A1', name: 'Widget Pro', price: 124.99, quantity: 2 },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/checkout/complete',\n },\n }),\n mapping: {\n name: 'CompletePayment',\n data: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n order_id: 'data.id',\n content_type: { value: 'product' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n content_id: 'data.id',\n content_name: 'data.name',\n quantity: { key: 'data.quantity', value: 1 },\n price: 'data.price',\n },\n },\n ],\n },\n user_data: {\n map: {\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'CompletePayment',\n event_id: 'd1e2f3a4b5c60001',\n timestamp: '2023-11-14T22:28:20.000Z',\n context: {\n user: {\n external_id:\n 'fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8',\n },\n page: {\n url: 'https://shop.example.com/checkout/complete',\n },\n },\n properties: {\n value: 249.99,\n currency: 'EUR',\n order_id: 'ORD-300',\n content_type: 'product',\n contents: [\n {\n content_id: 'SKU-A1',\n content_name: 'Widget Pro',\n quantity: 2,\n price: 124.99,\n },\n ],\n },\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to TikTok as an AddToCart event with value, currency, and product contents.',\n in: getEvent('product add', {\n id: 'd1e2f3a4b5c60002',\n timestamp: 1700000901000,\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n color: 'blue',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n quantity: 1,\n },\n },\n ],\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products/running-shoes',\n },\n }),\n mapping: {\n name: 'AddToCart',\n data: {\n map: {\n content_type: { value: 'product' },\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n content_id: 'data.id',\n content_name: 'data.name',\n quantity: { key: 'data.quantity', value: 1 },\n price: 'data.price',\n },\n },\n ],\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'AddToCart',\n event_id: 'd1e2f3a4b5c60002',\n timestamp: '2023-11-14T22:28:21.000Z',\n context: {\n page: {\n url: 'https://shop.example.com/products/running-shoes',\n },\n },\n properties: {\n content_type: 'product',\n value: 89.99,\n currency: 'EUR',\n contents: [\n {\n content_id: 'SKU-B2',\n content_name: 'Running Shoes',\n quantity: 1,\n price: 89.99,\n },\n ],\n },\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const pageView: Flow.StepExample = {\n title: 'Page view',\n description:\n 'A page view is forwarded to TikTok as a page view event with the source URL in the page context.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60003',\n timestamp: 1700000902000,\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/docs/',\n },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'page view',\n event_id: 'd1e2f3a4b5c60003',\n timestamp: '2023-11-14T22:28:22.000Z',\n context: {\n page: {\n url: 'https://example.com/docs/',\n },\n },\n properties: {},\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Submit form',\n description:\n 'A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.',\n in: getEvent('form submit', {\n id: 'd1e2f3a4b5c60004',\n timestamp: 1700000903000,\n data: { type: 'newsletter' },\n user: { email: 'user@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/contact',\n },\n }),\n mapping: {\n name: 'SubmitForm',\n data: {\n map: {\n user_data: {\n map: {\n email: 'user.email',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'SubmitForm',\n event_id: 'd1e2f3a4b5c60004',\n timestamp: '2023-11-14T22:28:23.000Z',\n context: {\n user: {\n // sha256('user@example.com')\n email:\n 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n page: {\n url: 'https://example.com/contact',\n },\n },\n properties: {},\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,cAA4B;;;ACA5B,iBAA2B;AAE3B,IAAM,cAAc,aAAE,MAAM;AAAA,EAC1B,mBAAQ,eAAe;AAAA,EACvB,aAAE,QAAQ,KAAK;AACjB,CAAC;AAEM,IAAM,iBAAiB,aAAE,OAAO;AAAA,EACrC,WAAW,aACR,OAAO,EACP,IAAI,CAAC,EACL,SAAS,4DAA4D;AAAA,EACxE,aAAa,aACV,OAAO,EACP,IAAI,CAAC,EACL,SAAS,oDAAoD;AAAA,EAChE,KAAK,aAAE,OAAO,EAAE,IAAI,EAAE,SAAS,gCAAgC,EAAE,SAAS;AAAA,EAC1E,iBAAiB,aACd,OAAO,EACP;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,WAAW,aACR,MAAM,aAAE,OAAO,CAAC,EAChB;AAAA,IACC;AAAA,EACF,EACC,SAAS;AAAA,EACZ,WAAW,aACR,OAAO,aAAE,OAAO,GAAG,aAAE,OAAO,CAAC,EAC7B,SAAS,6DAA6D,EACtE,SAAS;AAAA,EACZ,cAAc,aACX,OAAO,EACP,SAAS,qCAAqC,EAC9C,SAAS;AAAA,EACZ,IAAI,YAAY;AAAA,IACd;AAAA,EACF,EAAE,SAAS;AAAA,EACX,WAAW,YAAY;AAAA,IACrB;AAAA,EACF,EAAE,SAAS;AACb,CAAC;;;AC3CD,IAAAC,cAAkB;AAMX,IAAM,gBAAgB,cAAE,OAAO,CAAC,CAAC;;;ACNxC,IAAAC,cAAkB;AAMX,IAAM,0BAA0B,cAAE,MAAM;AAAA,EAC7C,cAAE,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,cAAE,OAAO;AAAA;AACX,CAAC;;;AHdM,IAAM,eAAW,yBAAY,cAAc;AAC3C,IAAM,cAAU,yBAAY,aAAa;;;AIXhD;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAcA,eAAe,eACb,KACA,MACA,SACuB;AAEvB,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAQO,IAAM,OAAY;AAAA,EACvB,YAAY;AACd;AAEO,IAAM,aAAa,CAAC,YAAY;;;ACvCvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAmC;AAoBnC,IAAM,WAAW;AACjB,IAAM,UAAU;AAAA,EACd,SAAS;AAAA,IACP,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB;AACF;AAEO,IAAM,WAA6B;AAAA,EACxC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,kBAAkB;AAAA,IAC7B,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM,EAAE,IAAI,WAAW,OAAO,QAAQ,UAAU,MAAM;AAAA,IACtD,QAAQ;AAAA,MACN;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,EAAE,IAAI,UAAU,MAAM,cAAc,OAAO,QAAQ,UAAU,EAAE;AAAA,MACvE;AAAA,IACF;AAAA,IACA,MAAM,EAAE,IAAI,YAAY,QAAQ,aAAa;AAAA,IAC7C,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,MACV,KAAK;AAAA,IACP;AAAA,EACF,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,OAAO;AAAA,QACP,UAAU,EAAE,KAAK,iBAAiB,OAAO,MAAM;AAAA,QAC/C,UAAU;AAAA,QACV,cAAc,EAAE,OAAO,UAAU;AAAA,QACjC,UAAU;AAAA,UACR,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,cACE,WAAW,CAAC,eACV,sBAAS,MAAM,KAAK,OAAO,WAAW;AAAA,cACxC,KAAK;AAAA,gBACH,YAAY;AAAA,gBACZ,cAAc;AAAA,gBACd,UAAU,EAAE,KAAK,iBAAiB,OAAO,EAAE;AAAA,gBAC3C,OAAO;AAAA,cACT;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,WAAW;AAAA,UACT,KAAK;AAAA,YACH,aAAa;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,KAAK,UAAU;AAAA,QACb,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,MAAM;AAAA,UACJ;AAAA,YACE,OAAO;AAAA,YACP,UAAU;AAAA,YACV,WAAW;AAAA,YACX,SAAS;AAAA,cACP,MAAM;AAAA,gBACJ,aACE;AAAA,cACJ;AAAA,cACA,MAAM;AAAA,gBACJ,KAAK;AAAA,cACP;AAAA,YACF;AAAA,YACA,YAAY;AAAA,cACV,OAAO;AAAA,cACP,UAAU;AAAA,cACV,UAAU;AAAA,cACV,cAAc;AAAA,cACd,UAAU;AAAA,gBACR;AAAA,kBACE,YAAY;AAAA,kBACZ,cAAc;AAAA,kBACd,UAAU;AAAA,kBACV,OAAO;AAAA,gBACT;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,YAA8B;AAAA,EACzC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,eAAe;AAAA,IAC1B,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM;AAAA,MACJ,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,QAAQ;AAAA,QACR,MAAM;AAAA,UACJ,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,OAAO;AAAA,UACP,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,MACV,KAAK;AAAA,IACP;AAAA,EACF,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,cAAc,EAAE,OAAO,UAAU;AAAA,QACjC,OAAO;AAAA,QACP,UAAU,EAAE,OAAO,MAAM;AAAA,QACzB,UAAU;AAAA,UACR,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,cACE,WAAW,CAAC,eACV,sBAAS,MAAM,KAAK,OAAO,WAAW;AAAA,cACxC,KAAK;AAAA,gBACH,YAAY;AAAA,gBACZ,cAAc;AAAA,gBACd,UAAU,EAAE,KAAK,iBAAiB,OAAO,EAAE;AAAA,gBAC3C,OAAO;AAAA,cACT;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,KAAK,UAAU;AAAA,QACb,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,MAAM;AAAA,UACJ;AAAA,YACE,OAAO;AAAA,YACP,UAAU;AAAA,YACV,WAAW;AAAA,YACX,SAAS;AAAA,cACP,MAAM;AAAA,gBACJ,KAAK;AAAA,cACP;AAAA,YACF;AAAA,YACA,YAAY;AAAA,cACV,cAAc;AAAA,cACd,OAAO;AAAA,cACP,UAAU;AAAA,cACV,UAAU;AAAA,gBACR;AAAA,kBACE,YAAY;AAAA,kBACZ,cAAc;AAAA,kBACd,UAAU;AAAA,kBACV,OAAO;AAAA,gBACT;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,WAA6B;AAAA,EACxC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,aAAa;AAAA,IACxB,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,MACV,KAAK;AAAA,IACP;AAAA,EACF,CAAC;AAAA,EACD,SAAS;AAAA,EACT,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,KAAK,UAAU;AAAA,QACb,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,MAAM;AAAA,UACJ;AAAA,YACE,OAAO;AAAA,YACP,UAAU;AAAA,YACV,WAAW;AAAA,YACX,SAAS;AAAA,cACP,MAAM;AAAA,gBACJ,KAAK;AAAA,cACP;AAAA,YACF;AAAA,YACA,YAAY,CAAC;AAAA,UACf;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,OAAyB;AAAA,EACpC,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAI,sBAAS,eAAe;AAAA,IAC1B,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM,EAAE,MAAM,aAAa;AAAA,IAC3B,MAAM,EAAE,OAAO,mBAAmB;AAAA,IAClC,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,MACV,KAAK;AAAA,IACP;AAAA,EACF,CAAC;AAAA,EACD,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAK;AAAA,QACH,WAAW;AAAA,UACT,KAAK;AAAA,YACH,OAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,KAAK,UAAU;AAAA,QACb,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,MAAM;AAAA,UACJ;AAAA,YACE,OAAO;AAAA,YACP,UAAU;AAAA,YACV,WAAW;AAAA,YACX,SAAS;AAAA,cACP,MAAM;AAAA;AAAA,gBAEJ,OACE;AAAA,cACJ;AAAA,cACA,MAAM;AAAA,gBACJ,KAAK;AAAA,cACP;AAAA,YACF;AAAA,YACA,YAAY,CAAC;AAAA,UACf;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AACF;","names":["import_dev","import_dev","import_dev"]}
1
+ {"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { schemas, z } from '@walkeros/core/dev';\n\nconst InputSchema = z.union([\n schemas.MappingSchemas.ValueSchema,\n z.literal(false),\n]);\n\nexport const SettingsSchema = z\n .object({\n pixelCode: z\n .string()\n .min(1)\n .describe('TikTok Pixel Code from Events Manager (like C0ABCDEF12345)'),\n accessToken: z\n .string()\n .min(1)\n .describe('Events API access token from TikTok Events Manager'),\n url: z.string().url().describe('Custom Events API endpoint URL').optional(),\n test_event_code: z\n .string()\n .describe(\n 'Test event code for debugging in TikTok Events Manager (like TEST12345)',\n )\n .optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"User data fields to skip hashing (like ['email', 'phone_number'])\",\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\"Mapping for user data fields (like { email: 'user.email' })\")\n .optional(),\n partner_name: z\n .string()\n .describe('Partner name for TikTok attribution')\n .optional(),\n ip: InputSchema.describe(\n 'Client IP, sent as context.ip. Resolves against { ingest, event }. Default: [\"ingest.ip\", \"event.user.ip\"]. false switches it off.',\n ).optional(),\n userAgent: InputSchema.describe(\n 'Client user agent, sent as context.user_agent. Resolves against { ingest, event }. Default: [\"ingest.userAgent\", \"event.user.userAgent\"]. false switches it off.',\n ).optional(),\n })\n .strict();\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * TikTok Events API Mapping Schema\n * TikTok Events API has no event-level mapping configuration\n */\nexport const MappingSchema = z.object({});\n\n/**\n * Type inference from MappingSchema\n */\nexport type Mapping = z.infer<typeof MappingSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Standard TikTok Event Names\n * https://business-api.tiktok.com/portal/docs?id=1771100865818625\n */\nexport const StandardEventNameSchema = z.union([\n z.enum([\n 'ViewContent',\n 'ClickButton',\n 'Search',\n 'AddToWishlist',\n 'AddToCart',\n 'InitiateCheckout',\n 'AddPaymentInfo',\n 'CompletePayment',\n 'PlaceAnOrder',\n 'Contact',\n 'Download',\n 'SubmitForm',\n 'CompleteRegistration',\n 'Subscribe',\n ]),\n z.string(), // Allow custom event names\n]);\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for TikTok Events 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 TikTok API response\n return {\n data: {\n code: 0,\n message: 'OK',\n },\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing TikTok Events API events without making\n * actual HTTP requests to TikTok's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow } from '@walkeros/core';\nimport { createEvent, getEvent, isObject } from '@walkeros/core';\n\n/**\n * TikTok Events API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(url, body, { headers })` where `url` is the fixed\n * TikTok Events API endpoint and `body` is the JSON-stringified payload\n * `{ pixel_code, partner_name, data: [tiktokEvent] }`.\n *\n * The test fixture pins `accessToken = 's3cr3t'` and `pixelCode = 'PIXEL_CODE'`.\n *\n * Body fields are emitted in the order the destination constructs them\n * (insertion order matters for `JSON.stringify` string equality):\n * pixel_code, partner_name, data[] with { event, event_id, timestamp,\n * context: { user?, page }, properties }.\n *\n * User identity fields (`email`, `phone_number`, `external_id`) are hashed\n * with SHA-256.\n */\nconst ENDPOINT = 'https://business-api.tiktok.com/open_api/v1.3/event/track/';\nconst HEADERS = {\n headers: {\n 'Access-Token': 's3cr3t',\n 'Content-Type': 'application/json',\n },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Complete payment',\n description:\n 'A completed order is sent to the TikTok Events API as a CompletePayment with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'd1e2f3a4b5c60001',\n timestamp: 1700000900000,\n data: { id: 'ORD-300', value: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: { id: 'SKU-A1', name: 'Widget Pro', price: 124.99, quantity: 2 },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/checkout/complete',\n },\n }),\n mapping: {\n name: 'CompletePayment',\n data: {\n map: {\n value: 'data.value',\n currency: { key: 'data.currency', value: 'EUR' },\n order_id: 'data.id',\n content_type: { value: 'product' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n content_id: 'data.id',\n content_name: 'data.name',\n quantity: { key: 'data.quantity', value: 1 },\n price: 'data.price',\n },\n },\n ],\n },\n user_data: {\n map: {\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'CompletePayment',\n event_id: 'd1e2f3a4b5c60001',\n timestamp: '2023-11-14T22:28:20.000Z',\n context: {\n user: {\n external_id:\n 'fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8',\n },\n page: {\n url: 'https://shop.example.com/checkout/complete',\n },\n },\n properties: {\n value: 249.99,\n currency: 'EUR',\n order_id: 'ORD-300',\n content_type: 'product',\n contents: [\n {\n content_id: 'SKU-A1',\n content_name: 'Widget Pro',\n quantity: 2,\n price: 124.99,\n },\n ],\n },\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to TikTok as an AddToCart event with value, currency, and product contents.',\n in: getEvent('product add', {\n id: 'd1e2f3a4b5c60002',\n timestamp: 1700000901000,\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n color: 'blue',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n quantity: 1,\n },\n },\n ],\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products/running-shoes',\n },\n }),\n mapping: {\n name: 'AddToCart',\n data: {\n map: {\n content_type: { value: 'product' },\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n content_id: 'data.id',\n content_name: 'data.name',\n quantity: { key: 'data.quantity', value: 1 },\n price: 'data.price',\n },\n },\n ],\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'AddToCart',\n event_id: 'd1e2f3a4b5c60002',\n timestamp: '2023-11-14T22:28:21.000Z',\n context: {\n page: {\n url: 'https://shop.example.com/products/running-shoes',\n },\n },\n properties: {\n content_type: 'product',\n value: 89.99,\n currency: 'EUR',\n contents: [\n {\n content_id: 'SKU-B2',\n content_name: 'Running Shoes',\n quantity: 1,\n price: 89.99,\n },\n ],\n },\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const pageView: Flow.StepExample = {\n title: 'Page view',\n description:\n 'A page view is forwarded to TikTok as a page view event with the source URL in the page context.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60003',\n timestamp: 1700000902000,\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/docs/',\n },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'page view',\n event_id: 'd1e2f3a4b5c60003',\n timestamp: '2023-11-14T22:28:22.000Z',\n context: {\n page: {\n url: 'https://example.com/docs/',\n },\n },\n properties: {},\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Submit form',\n description:\n 'A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.',\n in: createEvent({\n name: 'form submit',\n id: 'd1e2f3a4b5c60004',\n timestamp: 1700000903000,\n data: { type: 'newsletter' },\n user: { email: 'user@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/contact',\n },\n }),\n mapping: {\n name: 'SubmitForm',\n data: {\n map: {\n user_data: {\n map: {\n email: 'user.email',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'SubmitForm',\n event_id: 'd1e2f3a4b5c60004',\n timestamp: '2023-11-14T22:28:23.000Z',\n context: {\n user: {\n // sha256('user@example.com')\n email:\n 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n page: {\n url: 'https://example.com/contact',\n },\n },\n properties: {},\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\n/** A silent rule sends nothing to TikTok. */\nexport const silentRule: Flow.StepExample = {\n public: false,\n description: 'A rule with silent: true sends no request to TikTok.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60005',\n timestamp: 1700000904000,\n }),\n mapping: { silent: true },\n out: [],\n};\n\n/** TikTok rejects the event in an HTTP 200 body. */\nexport const rejectedEvent: Flow.StepExample = {\n public: false,\n description:\n 'TikTok answers HTTP 200 with a non-zero code: the event was rejected, so the push fails with transport, not retryable, and the event goes to the DLQ.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60006',\n timestamp: 1700000905000,\n }),\n respond: {\n status: 200,\n body: { code: 40002, message: 'Invalid value for field event' },\n },\n outcome: { status: 'failed', code: 'transport', retryable: false },\n};\n\n/** TikTok is busy: a server error code in the HTTP 200 body. */\nexport const busy: Flow.StepExample = {\n public: false,\n description:\n 'TikTok answers HTTP 200 with a server error code: the push fails with transport, retryable.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60007',\n timestamp: 1700000906000,\n }),\n respond: { status: 200, body: { code: 50000, message: 'System error' } },\n outcome: { status: 'failed', code: 'transport', retryable: true },\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 n in a)e(t,n,{get:a[n],enumerable:!0})},a={};t(a,{MappingSchema:()=>d,SettingsSchema:()=>s,StandardEventNameSchema:()=>m,mapping:()=>l,settings:()=>u});import{zodToSchema as n}from"@walkeros/core/dev";import{schemas as r,z as i}from"@walkeros/core/dev";var o=i.union([r.MappingSchemas.ValueSchema,i.literal(!1)]),s=i.object({pixelCode:i.string().min(1).describe("TikTok Pixel Code from Events Manager (like C0ABCDEF12345)"),accessToken:i.string().min(1).describe("Events API access token from TikTok Events Manager"),url:i.string().url().describe("Custom Events API endpoint URL").optional(),test_event_code:i.string().describe("Test event code for debugging in TikTok Events Manager (like TEST12345)").optional(),doNotHash:i.array(i.string()).describe("User data fields to skip hashing (like ['email', 'phone_number'])").optional(),user_data:i.record(i.string(),i.string()).describe("Mapping for user data fields (like { email: 'user.email' })").optional(),partner_name:i.string().describe("Partner name for TikTok attribution").optional(),ip:o.describe('Client IP, sent as context.ip. Resolves against { ingest, event }. Default: ["ingest.ip", "event.user.ip"]. false switches it off.').optional(),userAgent:o.describe('Client user agent, sent as context.user_agent. Resolves against { ingest, event }. Default: ["ingest.userAgent", "event.user.userAgent"]. false switches it off.').optional()});import{z as c}from"@walkeros/core/dev";var d=c.object({});import{z as p}from"@walkeros/core/dev";var m=p.union([p.enum(["ViewContent","ClickButton","Search","AddToWishlist","AddToCart","InitiateCheckout","AddPaymentInfo","CompletePayment","PlaceAnOrder","Contact","Download","SubmitForm","CompleteRegistration","Subscribe"]),p.string()]),u=n(s),l=n(d),v={};t(v,{env:()=>g,step:()=>h});var g={};t(g,{push:()=>f,simulation:()=>b});var f={sendServer:async function(e,t,a){return{ok:!0,data:{code:0,message:"OK"}}}},b=["sendServer"],h={};t(h,{addToCart:()=>T,lead:()=>C,pageView:()=>x,purchase:()=>w});import{getEvent as y,isObject as k}from"@walkeros/core";var _="https://business-api.tiktok.com/open_api/v1.3/event/track/",S={headers:{"Access-Token":"s3cr3t","Content-Type":"application/json"}},w={title:"Complete payment",description:"A completed order is sent to the TikTok Events API as a CompletePayment with value, currency, and contents.",in:y("order complete",{id:"d1e2f3a4b5c60001",timestamp:17000009e5,data:{id:"ORD-300",total:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Widget Pro",price:124.99,quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/checkout/complete"}}),mapping:{name:"CompletePayment",data:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"},order_id:"data.id",content_type:{value:"product"},contents:{loop:["nested",{condition:e=>k(e)&&"product"===e.entity,map:{content_id:"data.id",content_name:"data.name",quantity:{key:"data.quantity",value:1},price:"data.price"}}]},user_data:{map:{external_id:"user.id"}}}}},out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"CompletePayment",event_id:"d1e2f3a4b5c60001",timestamp:"2023-11-14T22:28:20.000Z",context:{user:{external_id:"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"},page:{url:"https://shop.example.com/checkout/complete"}},properties:{value:249.99,currency:"EUR",order_id:"ORD-300",content_type:"product",contents:[{content_id:"SKU-A1",content_name:"Widget Pro",quantity:2,price:124.99}]}}]}),S]]},T={title:"Add to cart",description:"A product add is sent to TikTok as an AddToCart event with value, currency, and product contents.",in:y("product add",{id:"d1e2f3a4b5c60002",timestamp:1700000901e3,data:{id:"SKU-B2",name:"Running Shoes",price:89.99,color:"blue"},nested:[{entity:"product",data:{id:"SKU-B2",name:"Running Shoes",price:89.99,quantity:1}}],source:{type:"browser",platform:"web",url:"https://shop.example.com/products/running-shoes"}}),mapping:{name:"AddToCart",data:{map:{content_type:{value:"product"},value:"data.price",currency:{value:"EUR"},contents:{loop:["nested",{condition:e=>k(e)&&"product"===e.entity,map:{content_id:"data.id",content_name:"data.name",quantity:{key:"data.quantity",value:1},price:"data.price"}}]}}}},out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"AddToCart",event_id:"d1e2f3a4b5c60002",timestamp:"2023-11-14T22:28:21.000Z",context:{page:{url:"https://shop.example.com/products/running-shoes"}},properties:{content_type:"product",value:89.99,currency:"EUR",contents:[{content_id:"SKU-B2",content_name:"Running Shoes",quantity:1,price:89.99}]}}]}),S]]},x={title:"Page view",description:"A page view is forwarded to TikTok as a page view event with the source URL in the page context.",in:y("page view",{id:"d1e2f3a4b5c60003",timestamp:1700000902e3,source:{type:"browser",platform:"web",url:"https://example.com/docs/"}}),mapping:void 0,out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"page view",event_id:"d1e2f3a4b5c60003",timestamp:"2023-11-14T22:28:22.000Z",context:{page:{url:"https://example.com/docs/"}},properties:{}}]}),S]]},C={title:"Submit form",description:"A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.",in:y("form submit",{id:"d1e2f3a4b5c60004",timestamp:1700000903e3,data:{type:"newsletter"},user:{email:"user@example.com"},source:{type:"browser",platform:"web",url:"https://example.com/contact"}}),mapping:{name:"SubmitForm",data:{map:{user_data:{map:{email:"user.email"}}}}},out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"SubmitForm",event_id:"d1e2f3a4b5c60004",timestamp:"2023-11-14T22:28:23.000Z",context:{user:{email:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"},page:{url:"https://example.com/contact"}},properties:{}}]}),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 n in a)t(e,n,{get:a[n],enumerable:!0})},n={};a(n,{MappingSchema:()=>p,SettingsSchema:()=>d,StandardEventNameSchema:()=>u,mapping:()=>v,settings:()=>l});import{zodToSchema as r}from"@walkeros/core/dev";import{schemas as i,z as o}from"@walkeros/core/dev";var s=o.union([i.MappingSchemas.ValueSchema,o.literal(!1)]),d=o.object({pixelCode:o.string().min(1).describe("TikTok Pixel Code from Events Manager (like C0ABCDEF12345)"),accessToken:o.string().min(1).describe("Events API access token from TikTok Events Manager"),url:o.string().url().describe("Custom Events API endpoint URL").optional(),test_event_code:o.string().describe("Test event code for debugging in TikTok Events Manager (like TEST12345)").optional(),doNotHash:o.array(o.string()).describe("User data fields to skip hashing (like ['email', 'phone_number'])").optional(),user_data:o.record(o.string(),o.string()).describe("Mapping for user data fields (like { email: 'user.email' })").optional(),partner_name:o.string().describe("Partner name for TikTok attribution").optional(),ip:s.describe('Client IP, sent as context.ip. Resolves against { ingest, event }. Default: ["ingest.ip", "event.user.ip"]. false switches it off.').optional(),userAgent:s.describe('Client user agent, sent as context.user_agent. Resolves against { ingest, event }. Default: ["ingest.userAgent", "event.user.userAgent"]. false switches it off.').optional()}).strict();import{z as c}from"@walkeros/core/dev";var p=c.object({});import{z as m}from"@walkeros/core/dev";var u=m.union([m.enum(["ViewContent","ClickButton","Search","AddToWishlist","AddToCart","InitiateCheckout","AddPaymentInfo","CompletePayment","PlaceAnOrder","Contact","Download","SubmitForm","CompleteRegistration","Subscribe"]),m.string()]),l=r(d),v=r(p),g={};a(g,{env:()=>b,step:()=>y});var b={};a(b,{push:()=>f,simulation:()=>h});var f={sendServer:async function(e,t,a){return{data:{code:0,message:"OK"}}}},h=["sendServer"],y={};a(y,{addToCart:()=>C,busy:()=>R,lead:()=>E,pageView:()=>A,purchase:()=>x,rejectedEvent:()=>O,silentRule:()=>P});import{createEvent as k,getEvent as w,isObject as T}from"@walkeros/core";var _="https://business-api.tiktok.com/open_api/v1.3/event/track/",S={headers:{"Access-Token":"s3cr3t","Content-Type":"application/json"}},x={title:"Complete payment",description:"A completed order is sent to the TikTok Events API as a CompletePayment with value, currency, and contents.",in:w("order complete",{id:"d1e2f3a4b5c60001",timestamp:17000009e5,data:{id:"ORD-300",value:249.99,currency:"EUR"},nested:[{entity:"product",data:{id:"SKU-A1",name:"Widget Pro",price:124.99,quantity:2}}],user:{id:"user-123",device:"device-456"},source:{type:"browser",platform:"web",url:"https://shop.example.com/checkout/complete"}}),mapping:{name:"CompletePayment",data:{map:{value:"data.value",currency:{key:"data.currency",value:"EUR"},order_id:"data.id",content_type:{value:"product"},contents:{loop:["nested",{condition:e=>T(e)&&"product"===e.entity,map:{content_id:"data.id",content_name:"data.name",quantity:{key:"data.quantity",value:1},price:"data.price"}}]},user_data:{map:{external_id:"user.id"}}}}},out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"CompletePayment",event_id:"d1e2f3a4b5c60001",timestamp:"2023-11-14T22:28:20.000Z",context:{user:{external_id:"fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8"},page:{url:"https://shop.example.com/checkout/complete"}},properties:{value:249.99,currency:"EUR",order_id:"ORD-300",content_type:"product",contents:[{content_id:"SKU-A1",content_name:"Widget Pro",quantity:2,price:124.99}]}}]}),S]]},C={title:"Add to cart",description:"A product add is sent to TikTok as an AddToCart event with value, currency, and product contents.",in:w("product add",{id:"d1e2f3a4b5c60002",timestamp:1700000901e3,data:{id:"SKU-B2",name:"Running Shoes",price:89.99,color:"blue"},nested:[{entity:"product",data:{id:"SKU-B2",name:"Running Shoes",price:89.99,quantity:1}}],source:{type:"browser",platform:"web",url:"https://shop.example.com/products/running-shoes"}}),mapping:{name:"AddToCart",data:{map:{content_type:{value:"product"},value:"data.price",currency:{value:"EUR"},contents:{loop:["nested",{condition:e=>T(e)&&"product"===e.entity,map:{content_id:"data.id",content_name:"data.name",quantity:{key:"data.quantity",value:1},price:"data.price"}}]}}}},out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"AddToCart",event_id:"d1e2f3a4b5c60002",timestamp:"2023-11-14T22:28:21.000Z",context:{page:{url:"https://shop.example.com/products/running-shoes"}},properties:{content_type:"product",value:89.99,currency:"EUR",contents:[{content_id:"SKU-B2",content_name:"Running Shoes",quantity:1,price:89.99}]}}]}),S]]},A={title:"Page view",description:"A page view is forwarded to TikTok as a page view event with the source URL in the page context.",in:w("page view",{id:"d1e2f3a4b5c60003",timestamp:1700000902e3,source:{type:"browser",platform:"web",url:"https://example.com/docs/"}}),mapping:void 0,out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"page view",event_id:"d1e2f3a4b5c60003",timestamp:"2023-11-14T22:28:22.000Z",context:{page:{url:"https://example.com/docs/"}},properties:{}}]}),S]]},E={title:"Submit form",description:"A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.",in:k({name:"form submit",id:"d1e2f3a4b5c60004",timestamp:1700000903e3,data:{type:"newsletter"},user:{email:"user@example.com"},source:{type:"browser",platform:"web",url:"https://example.com/contact"}}),mapping:{name:"SubmitForm",data:{map:{user_data:{map:{email:"user.email"}}}}},out:[["sendServer",_,JSON.stringify({pixel_code:"PIXEL_CODE",partner_name:"walkerOS",data:[{event:"SubmitForm",event_id:"d1e2f3a4b5c60004",timestamp:"2023-11-14T22:28:23.000Z",context:{user:{email:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"},page:{url:"https://example.com/contact"}},properties:{}}]}),S]]},P={public:!1,description:"A rule with silent: true sends no request to TikTok.",in:w("page view",{id:"d1e2f3a4b5c60005",timestamp:1700000904e3}),mapping:{silent:!0},out:[]},O={public:!1,description:"TikTok answers HTTP 200 with a non-zero code: the event was rejected, so the push fails with transport, not retryable, and the event goes to the DLQ.",in:w("page view",{id:"d1e2f3a4b5c60006",timestamp:1700000905e3}),respond:{status:200,body:{code:40002,message:"Invalid value for field event"}},outcome:{status:"failed",code:"transport",retryable:!1}},R={public:!1,description:"TikTok answers HTTP 200 with a server error code: the push fails with transport, retryable.",in:w("page view",{id:"d1e2f3a4b5c60007",timestamp:1700000906e3}),respond:{status:200,body:{code:5e4,message:"System error"}},outcome:{status:"failed",code:"transport",retryable:!0}};export{g as examples,n as schemas};//# sourceMappingURL=dev.mjs.map
package/dist/dev.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { schemas, z } from '@walkeros/core/dev';\n\nconst InputSchema = z.union([\n schemas.MappingSchemas.ValueSchema,\n z.literal(false),\n]);\n\nexport const SettingsSchema = z.object({\n pixelCode: z\n .string()\n .min(1)\n .describe('TikTok Pixel Code from Events Manager (like C0ABCDEF12345)'),\n accessToken: z\n .string()\n .min(1)\n .describe('Events API access token from TikTok Events Manager'),\n url: z.string().url().describe('Custom Events API endpoint URL').optional(),\n test_event_code: z\n .string()\n .describe(\n 'Test event code for debugging in TikTok Events Manager (like TEST12345)',\n )\n .optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"User data fields to skip hashing (like ['email', 'phone_number'])\",\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\"Mapping for user data fields (like { email: 'user.email' })\")\n .optional(),\n partner_name: z\n .string()\n .describe('Partner name for TikTok attribution')\n .optional(),\n ip: InputSchema.describe(\n 'Client IP, sent as context.ip. Resolves against { ingest, event }. Default: [\"ingest.ip\", \"event.user.ip\"]. false switches it off.',\n ).optional(),\n userAgent: InputSchema.describe(\n 'Client user agent, sent as context.user_agent. Resolves against { ingest, event }. Default: [\"ingest.userAgent\", \"event.user.userAgent\"]. false switches it off.',\n ).optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * TikTok Events API Mapping Schema\n * TikTok Events API has no event-level mapping configuration\n */\nexport const MappingSchema = z.object({});\n\n/**\n * Type inference from MappingSchema\n */\nexport type Mapping = z.infer<typeof MappingSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Standard TikTok Event Names\n * https://business-api.tiktok.com/portal/docs?id=1771100865818625\n */\nexport const StandardEventNameSchema = z.union([\n z.enum([\n 'ViewContent',\n 'ClickButton',\n 'Search',\n 'AddToWishlist',\n 'AddToCart',\n 'InitiateCheckout',\n 'AddPaymentInfo',\n 'CompletePayment',\n 'PlaceAnOrder',\n 'Contact',\n 'Download',\n 'SubmitForm',\n 'CompleteRegistration',\n 'Subscribe',\n ]),\n z.string(), // Allow custom event names\n]);\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for TikTok Events 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 TikTok API response\n return {\n ok: true,\n data: {\n code: 0,\n message: 'OK',\n },\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing TikTok Events API events without making\n * actual HTTP requests to TikTok's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent, isObject } from '@walkeros/core';\n\n/**\n * TikTok Events API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(url, body, { headers })` where `url` is the fixed\n * TikTok Events API endpoint and `body` is the JSON-stringified payload\n * `{ pixel_code, partner_name, data: [tiktokEvent] }`.\n *\n * The test fixture pins `accessToken = 's3cr3t'` and `pixelCode = 'PIXEL_CODE'`.\n *\n * Body fields are emitted in the order the destination constructs them\n * (insertion order matters for `JSON.stringify` string equality):\n * pixel_code, partner_name, data[] with { event, event_id, timestamp,\n * context: { user?, page }, properties }.\n *\n * User identity fields (`email`, `phone_number`, `external_id`) are hashed\n * with SHA-256.\n */\nconst ENDPOINT = 'https://business-api.tiktok.com/open_api/v1.3/event/track/';\nconst HEADERS = {\n headers: {\n 'Access-Token': 's3cr3t',\n 'Content-Type': 'application/json',\n },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Complete payment',\n description:\n 'A completed order is sent to the TikTok Events API as a CompletePayment with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'd1e2f3a4b5c60001',\n timestamp: 1700000900000,\n data: { id: 'ORD-300', total: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: { id: 'SKU-A1', name: 'Widget Pro', price: 124.99, quantity: 2 },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/checkout/complete',\n },\n }),\n mapping: {\n name: 'CompletePayment',\n data: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n order_id: 'data.id',\n content_type: { value: 'product' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n content_id: 'data.id',\n content_name: 'data.name',\n quantity: { key: 'data.quantity', value: 1 },\n price: 'data.price',\n },\n },\n ],\n },\n user_data: {\n map: {\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'CompletePayment',\n event_id: 'd1e2f3a4b5c60001',\n timestamp: '2023-11-14T22:28:20.000Z',\n context: {\n user: {\n external_id:\n 'fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8',\n },\n page: {\n url: 'https://shop.example.com/checkout/complete',\n },\n },\n properties: {\n value: 249.99,\n currency: 'EUR',\n order_id: 'ORD-300',\n content_type: 'product',\n contents: [\n {\n content_id: 'SKU-A1',\n content_name: 'Widget Pro',\n quantity: 2,\n price: 124.99,\n },\n ],\n },\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to TikTok as an AddToCart event with value, currency, and product contents.',\n in: getEvent('product add', {\n id: 'd1e2f3a4b5c60002',\n timestamp: 1700000901000,\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n color: 'blue',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n quantity: 1,\n },\n },\n ],\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products/running-shoes',\n },\n }),\n mapping: {\n name: 'AddToCart',\n data: {\n map: {\n content_type: { value: 'product' },\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n content_id: 'data.id',\n content_name: 'data.name',\n quantity: { key: 'data.quantity', value: 1 },\n price: 'data.price',\n },\n },\n ],\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'AddToCart',\n event_id: 'd1e2f3a4b5c60002',\n timestamp: '2023-11-14T22:28:21.000Z',\n context: {\n page: {\n url: 'https://shop.example.com/products/running-shoes',\n },\n },\n properties: {\n content_type: 'product',\n value: 89.99,\n currency: 'EUR',\n contents: [\n {\n content_id: 'SKU-B2',\n content_name: 'Running Shoes',\n quantity: 1,\n price: 89.99,\n },\n ],\n },\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const pageView: Flow.StepExample = {\n title: 'Page view',\n description:\n 'A page view is forwarded to TikTok as a page view event with the source URL in the page context.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60003',\n timestamp: 1700000902000,\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/docs/',\n },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'page view',\n event_id: 'd1e2f3a4b5c60003',\n timestamp: '2023-11-14T22:28:22.000Z',\n context: {\n page: {\n url: 'https://example.com/docs/',\n },\n },\n properties: {},\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Submit form',\n description:\n 'A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.',\n in: getEvent('form submit', {\n id: 'd1e2f3a4b5c60004',\n timestamp: 1700000903000,\n data: { type: 'newsletter' },\n user: { email: 'user@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/contact',\n },\n }),\n mapping: {\n name: 'SubmitForm',\n data: {\n map: {\n user_data: {\n map: {\n email: 'user.email',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'SubmitForm',\n event_id: 'd1e2f3a4b5c60004',\n timestamp: '2023-11-14T22:28:23.000Z',\n context: {\n user: {\n // sha256('user@example.com')\n email:\n 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n page: {\n url: 'https://example.com/contact',\n },\n },\n properties: {},\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n"],"mappings":"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","names":["z","z"]}
1
+ {"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/schemas/primitives.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { schemas, z } from '@walkeros/core/dev';\n\nconst InputSchema = z.union([\n schemas.MappingSchemas.ValueSchema,\n z.literal(false),\n]);\n\nexport const SettingsSchema = z\n .object({\n pixelCode: z\n .string()\n .min(1)\n .describe('TikTok Pixel Code from Events Manager (like C0ABCDEF12345)'),\n accessToken: z\n .string()\n .min(1)\n .describe('Events API access token from TikTok Events Manager'),\n url: z.string().url().describe('Custom Events API endpoint URL').optional(),\n test_event_code: z\n .string()\n .describe(\n 'Test event code for debugging in TikTok Events Manager (like TEST12345)',\n )\n .optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"User data fields to skip hashing (like ['email', 'phone_number'])\",\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\"Mapping for user data fields (like { email: 'user.email' })\")\n .optional(),\n partner_name: z\n .string()\n .describe('Partner name for TikTok attribution')\n .optional(),\n ip: InputSchema.describe(\n 'Client IP, sent as context.ip. Resolves against { ingest, event }. Default: [\"ingest.ip\", \"event.user.ip\"]. false switches it off.',\n ).optional(),\n userAgent: InputSchema.describe(\n 'Client user agent, sent as context.user_agent. Resolves against { ingest, event }. Default: [\"ingest.userAgent\", \"event.user.userAgent\"]. false switches it off.',\n ).optional(),\n })\n .strict();\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * TikTok Events API Mapping Schema\n * TikTok Events API has no event-level mapping configuration\n */\nexport const MappingSchema = z.object({});\n\n/**\n * Type inference from MappingSchema\n */\nexport type Mapping = z.infer<typeof MappingSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * Standard TikTok Event Names\n * https://business-api.tiktok.com/portal/docs?id=1771100865818625\n */\nexport const StandardEventNameSchema = z.union([\n z.enum([\n 'ViewContent',\n 'ClickButton',\n 'Search',\n 'AddToWishlist',\n 'AddToCart',\n 'InitiateCheckout',\n 'AddPaymentInfo',\n 'CompletePayment',\n 'PlaceAnOrder',\n 'Contact',\n 'Download',\n 'SubmitForm',\n 'CompleteRegistration',\n 'Subscribe',\n ]),\n z.string(), // Allow custom event names\n]);\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for TikTok Events 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 TikTok API response\n return {\n data: {\n code: 0,\n message: 'OK',\n },\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing TikTok Events API events without making\n * actual HTTP requests to TikTok's servers.\n */\nexport const push: Env = {\n sendServer: mockSendServer,\n};\n\nexport const simulation = ['sendServer'];\n","import type { Flow } from '@walkeros/core';\nimport { createEvent, getEvent, isObject } from '@walkeros/core';\n\n/**\n * TikTok Events API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(url, body, { headers })` where `url` is the fixed\n * TikTok Events API endpoint and `body` is the JSON-stringified payload\n * `{ pixel_code, partner_name, data: [tiktokEvent] }`.\n *\n * The test fixture pins `accessToken = 's3cr3t'` and `pixelCode = 'PIXEL_CODE'`.\n *\n * Body fields are emitted in the order the destination constructs them\n * (insertion order matters for `JSON.stringify` string equality):\n * pixel_code, partner_name, data[] with { event, event_id, timestamp,\n * context: { user?, page }, properties }.\n *\n * User identity fields (`email`, `phone_number`, `external_id`) are hashed\n * with SHA-256.\n */\nconst ENDPOINT = 'https://business-api.tiktok.com/open_api/v1.3/event/track/';\nconst HEADERS = {\n headers: {\n 'Access-Token': 's3cr3t',\n 'Content-Type': 'application/json',\n },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Complete payment',\n description:\n 'A completed order is sent to the TikTok Events API as a CompletePayment with value, currency, and contents.',\n in: getEvent('order complete', {\n id: 'd1e2f3a4b5c60001',\n timestamp: 1700000900000,\n data: { id: 'ORD-300', value: 249.99, currency: 'EUR' },\n nested: [\n {\n entity: 'product',\n data: { id: 'SKU-A1', name: 'Widget Pro', price: 124.99, quantity: 2 },\n },\n ],\n user: { id: 'user-123', device: 'device-456' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/checkout/complete',\n },\n }),\n mapping: {\n name: 'CompletePayment',\n data: {\n map: {\n value: 'data.value',\n currency: { key: 'data.currency', value: 'EUR' },\n order_id: 'data.id',\n content_type: { value: 'product' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n content_id: 'data.id',\n content_name: 'data.name',\n quantity: { key: 'data.quantity', value: 1 },\n price: 'data.price',\n },\n },\n ],\n },\n user_data: {\n map: {\n external_id: 'user.id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'CompletePayment',\n event_id: 'd1e2f3a4b5c60001',\n timestamp: '2023-11-14T22:28:20.000Z',\n context: {\n user: {\n external_id:\n 'fcdec6df4d44dbc637c7c5b58efface52a7f8a88535423430255be0bb89bedd8',\n },\n page: {\n url: 'https://shop.example.com/checkout/complete',\n },\n },\n properties: {\n value: 249.99,\n currency: 'EUR',\n order_id: 'ORD-300',\n content_type: 'product',\n contents: [\n {\n content_id: 'SKU-A1',\n content_name: 'Widget Pro',\n quantity: 2,\n price: 124.99,\n },\n ],\n },\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const addToCart: Flow.StepExample = {\n title: 'Add to cart',\n description:\n 'A product add is sent to TikTok as an AddToCart event with value, currency, and product contents.',\n in: getEvent('product add', {\n id: 'd1e2f3a4b5c60002',\n timestamp: 1700000901000,\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n color: 'blue',\n },\n nested: [\n {\n entity: 'product',\n data: {\n id: 'SKU-B2',\n name: 'Running Shoes',\n price: 89.99,\n quantity: 1,\n },\n },\n ],\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://shop.example.com/products/running-shoes',\n },\n }),\n mapping: {\n name: 'AddToCart',\n data: {\n map: {\n content_type: { value: 'product' },\n value: 'data.price',\n currency: { value: 'EUR' },\n contents: {\n loop: [\n 'nested',\n {\n condition: (entity: unknown) =>\n isObject(entity) && entity.entity === 'product',\n map: {\n content_id: 'data.id',\n content_name: 'data.name',\n quantity: { key: 'data.quantity', value: 1 },\n price: 'data.price',\n },\n },\n ],\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'AddToCart',\n event_id: 'd1e2f3a4b5c60002',\n timestamp: '2023-11-14T22:28:21.000Z',\n context: {\n page: {\n url: 'https://shop.example.com/products/running-shoes',\n },\n },\n properties: {\n content_type: 'product',\n value: 89.99,\n currency: 'EUR',\n contents: [\n {\n content_id: 'SKU-B2',\n content_name: 'Running Shoes',\n quantity: 1,\n price: 89.99,\n },\n ],\n },\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const pageView: Flow.StepExample = {\n title: 'Page view',\n description:\n 'A page view is forwarded to TikTok as a page view event with the source URL in the page context.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60003',\n timestamp: 1700000902000,\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/docs/',\n },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'page view',\n event_id: 'd1e2f3a4b5c60003',\n timestamp: '2023-11-14T22:28:22.000Z',\n context: {\n page: {\n url: 'https://example.com/docs/',\n },\n },\n properties: {},\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Submit form',\n description:\n 'A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.',\n in: createEvent({\n name: 'form submit',\n id: 'd1e2f3a4b5c60004',\n timestamp: 1700000903000,\n data: { type: 'newsletter' },\n user: { email: 'user@example.com' },\n source: {\n type: 'browser',\n platform: 'web',\n url: 'https://example.com/contact',\n },\n }),\n mapping: {\n name: 'SubmitForm',\n data: {\n map: {\n user_data: {\n map: {\n email: 'user.email',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n pixel_code: 'PIXEL_CODE',\n partner_name: 'walkerOS',\n data: [\n {\n event: 'SubmitForm',\n event_id: 'd1e2f3a4b5c60004',\n timestamp: '2023-11-14T22:28:23.000Z',\n context: {\n user: {\n // sha256('user@example.com')\n email:\n 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n page: {\n url: 'https://example.com/contact',\n },\n },\n properties: {},\n },\n ],\n }),\n HEADERS,\n ],\n ],\n};\n\n/** A silent rule sends nothing to TikTok. */\nexport const silentRule: Flow.StepExample = {\n public: false,\n description: 'A rule with silent: true sends no request to TikTok.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60005',\n timestamp: 1700000904000,\n }),\n mapping: { silent: true },\n out: [],\n};\n\n/** TikTok rejects the event in an HTTP 200 body. */\nexport const rejectedEvent: Flow.StepExample = {\n public: false,\n description:\n 'TikTok answers HTTP 200 with a non-zero code: the event was rejected, so the push fails with transport, not retryable, and the event goes to the DLQ.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60006',\n timestamp: 1700000905000,\n }),\n respond: {\n status: 200,\n body: { code: 40002, message: 'Invalid value for field event' },\n },\n outcome: { status: 'failed', code: 'transport', retryable: false },\n};\n\n/** TikTok is busy: a server error code in the HTTP 200 body. */\nexport const busy: Flow.StepExample = {\n public: false,\n description:\n 'TikTok answers HTTP 200 with a server error code: the push fails with transport, retryable.',\n in: getEvent('page view', {\n id: 'd1e2f3a4b5c60007',\n timestamp: 1700000906000,\n }),\n respond: { status: 200, body: { code: 50000, message: 'System error' } },\n outcome: { status: 'failed', code: 'transport', retryable: true },\n};\n"],"mappings":"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","names":["z","z"]}
@@ -24,13 +24,22 @@ declare const purchase: Flow.StepExample;
24
24
  declare const addToCart: Flow.StepExample;
25
25
  declare const pageView: Flow.StepExample;
26
26
  declare const lead: Flow.StepExample;
27
+ /** A silent rule sends nothing to TikTok. */
28
+ declare const silentRule: Flow.StepExample;
29
+ /** TikTok rejects the event in an HTTP 200 body. */
30
+ declare const rejectedEvent: Flow.StepExample;
31
+ /** TikTok is busy: a server error code in the HTTP 200 body. */
32
+ declare const busy: Flow.StepExample;
27
33
 
28
34
  declare const step_addToCart: typeof addToCart;
35
+ declare const step_busy: typeof busy;
29
36
  declare const step_lead: typeof lead;
30
37
  declare const step_pageView: typeof pageView;
31
38
  declare const step_purchase: typeof purchase;
39
+ declare const step_rejectedEvent: typeof rejectedEvent;
40
+ declare const step_silentRule: typeof silentRule;
32
41
  declare namespace step {
33
- export { step_addToCart as addToCart, step_lead as lead, step_pageView as pageView, step_purchase as purchase };
42
+ export { step_addToCart as addToCart, step_busy as busy, step_lead as lead, step_pageView as pageView, step_purchase as purchase, step_rejectedEvent as rejectedEvent, step_silentRule as silentRule };
34
43
  }
35
44
 
36
45
  export { env, step };
@@ -24,13 +24,22 @@ declare const purchase: Flow.StepExample;
24
24
  declare const addToCart: Flow.StepExample;
25
25
  declare const pageView: Flow.StepExample;
26
26
  declare const lead: Flow.StepExample;
27
+ /** A silent rule sends nothing to TikTok. */
28
+ declare const silentRule: Flow.StepExample;
29
+ /** TikTok rejects the event in an HTTP 200 body. */
30
+ declare const rejectedEvent: Flow.StepExample;
31
+ /** TikTok is busy: a server error code in the HTTP 200 body. */
32
+ declare const busy: Flow.StepExample;
27
33
 
28
34
  declare const step_addToCart: typeof addToCart;
35
+ declare const step_busy: typeof busy;
29
36
  declare const step_lead: typeof lead;
30
37
  declare const step_pageView: typeof pageView;
31
38
  declare const step_purchase: typeof purchase;
39
+ declare const step_rejectedEvent: typeof rejectedEvent;
40
+ declare const step_silentRule: typeof silentRule;
32
41
  declare namespace step {
33
- export { step_addToCart as addToCart, step_lead as lead, step_pageView as pageView, step_purchase as purchase };
42
+ export { step_addToCart as addToCart, step_busy as busy, step_lead as lead, step_pageView as pageView, step_purchase as purchase, step_rejectedEvent as rejectedEvent, step_silentRule as silentRule };
34
43
  }
35
44
 
36
45
  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
  code: 0,
39
38
  message: "OK"
@@ -49,9 +48,12 @@ var simulation = ["sendServer"];
49
48
  var step_exports = {};
50
49
  __export(step_exports, {
51
50
  addToCart: () => addToCart,
51
+ busy: () => busy,
52
52
  lead: () => lead,
53
53
  pageView: () => pageView,
54
- purchase: () => purchase
54
+ purchase: () => purchase,
55
+ rejectedEvent: () => rejectedEvent,
56
+ silentRule: () => silentRule
55
57
  });
56
58
  var import_core = require("@walkeros/core");
57
59
  var ENDPOINT = "https://business-api.tiktok.com/open_api/v1.3/event/track/";
@@ -67,7 +69,7 @@ var purchase = {
67
69
  in: (0, import_core.getEvent)("order complete", {
68
70
  id: "d1e2f3a4b5c60001",
69
71
  timestamp: 17000009e5,
70
- data: { id: "ORD-300", total: 249.99, currency: "EUR" },
72
+ data: { id: "ORD-300", value: 249.99, currency: "EUR" },
71
73
  nested: [
72
74
  {
73
75
  entity: "product",
@@ -85,7 +87,7 @@ var purchase = {
85
87
  name: "CompletePayment",
86
88
  data: {
87
89
  map: {
88
- value: "data.total",
90
+ value: "data.value",
89
91
  currency: { key: "data.currency", value: "EUR" },
90
92
  order_id: "data.id",
91
93
  content_type: { value: "product" },
@@ -283,7 +285,8 @@ var pageView = {
283
285
  var lead = {
284
286
  title: "Submit form",
285
287
  description: "A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.",
286
- in: (0, import_core.getEvent)("form submit", {
288
+ in: (0, import_core.createEvent)({
289
+ name: "form submit",
287
290
  id: "d1e2f3a4b5c60004",
288
291
  timestamp: 1700000903e3,
289
292
  data: { type: "newsletter" },
@@ -335,6 +338,39 @@ var lead = {
335
338
  ]
336
339
  ]
337
340
  };
341
+ var silentRule = {
342
+ public: false,
343
+ description: "A rule with silent: true sends no request to TikTok.",
344
+ in: (0, import_core.getEvent)("page view", {
345
+ id: "d1e2f3a4b5c60005",
346
+ timestamp: 1700000904e3
347
+ }),
348
+ mapping: { silent: true },
349
+ out: []
350
+ };
351
+ var rejectedEvent = {
352
+ public: false,
353
+ description: "TikTok answers HTTP 200 with a non-zero code: the event was rejected, so the push fails with transport, not retryable, and the event goes to the DLQ.",
354
+ in: (0, import_core.getEvent)("page view", {
355
+ id: "d1e2f3a4b5c60006",
356
+ timestamp: 1700000905e3
357
+ }),
358
+ respond: {
359
+ status: 200,
360
+ body: { code: 40002, message: "Invalid value for field event" }
361
+ },
362
+ outcome: { status: "failed", code: "transport", retryable: false }
363
+ };
364
+ var busy = {
365
+ public: false,
366
+ description: "TikTok answers HTTP 200 with a server error code: the push fails with transport, retryable.",
367
+ in: (0, import_core.getEvent)("page view", {
368
+ id: "d1e2f3a4b5c60007",
369
+ timestamp: 1700000906e3
370
+ }),
371
+ respond: { status: 200, body: { code: 5e4, message: "System error" } },
372
+ outcome: { status: "failed", code: "transport", retryable: true }
373
+ };
338
374
  // Annotate the CommonJS export names for ESM import in node:
339
375
  0 && (module.exports = {
340
376
  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
  code: 0,
18
17
  message: "OK"
@@ -28,11 +27,14 @@ var simulation = ["sendServer"];
28
27
  var step_exports = {};
29
28
  __export(step_exports, {
30
29
  addToCart: () => addToCart,
30
+ busy: () => busy,
31
31
  lead: () => lead,
32
32
  pageView: () => pageView,
33
- purchase: () => purchase
33
+ purchase: () => purchase,
34
+ rejectedEvent: () => rejectedEvent,
35
+ silentRule: () => silentRule
34
36
  });
35
- import { getEvent, isObject } from "@walkeros/core";
37
+ import { createEvent, getEvent, isObject } from "@walkeros/core";
36
38
  var ENDPOINT = "https://business-api.tiktok.com/open_api/v1.3/event/track/";
37
39
  var HEADERS = {
38
40
  headers: {
@@ -46,7 +48,7 @@ var purchase = {
46
48
  in: getEvent("order complete", {
47
49
  id: "d1e2f3a4b5c60001",
48
50
  timestamp: 17000009e5,
49
- data: { id: "ORD-300", total: 249.99, currency: "EUR" },
51
+ data: { id: "ORD-300", value: 249.99, currency: "EUR" },
50
52
  nested: [
51
53
  {
52
54
  entity: "product",
@@ -64,7 +66,7 @@ var purchase = {
64
66
  name: "CompletePayment",
65
67
  data: {
66
68
  map: {
67
- value: "data.total",
69
+ value: "data.value",
68
70
  currency: { key: "data.currency", value: "EUR" },
69
71
  order_id: "data.id",
70
72
  content_type: { value: "product" },
@@ -262,7 +264,8 @@ var pageView = {
262
264
  var lead = {
263
265
  title: "Submit form",
264
266
  description: "A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.",
265
- in: getEvent("form submit", {
267
+ in: createEvent({
268
+ name: "form submit",
266
269
  id: "d1e2f3a4b5c60004",
267
270
  timestamp: 1700000903e3,
268
271
  data: { type: "newsletter" },
@@ -314,6 +317,39 @@ var lead = {
314
317
  ]
315
318
  ]
316
319
  };
320
+ var silentRule = {
321
+ public: false,
322
+ description: "A rule with silent: true sends no request to TikTok.",
323
+ in: getEvent("page view", {
324
+ id: "d1e2f3a4b5c60005",
325
+ timestamp: 1700000904e3
326
+ }),
327
+ mapping: { silent: true },
328
+ out: []
329
+ };
330
+ var rejectedEvent = {
331
+ public: false,
332
+ description: "TikTok answers HTTP 200 with a non-zero code: the event was rejected, so the push fails with transport, not retryable, and the event goes to the DLQ.",
333
+ in: getEvent("page view", {
334
+ id: "d1e2f3a4b5c60006",
335
+ timestamp: 1700000905e3
336
+ }),
337
+ respond: {
338
+ status: 200,
339
+ body: { code: 40002, message: "Invalid value for field event" }
340
+ },
341
+ outcome: { status: "failed", code: "transport", retryable: false }
342
+ };
343
+ var busy = {
344
+ public: false,
345
+ description: "TikTok answers HTTP 200 with a server error code: the push fails with transport, retryable.",
346
+ in: getEvent("page view", {
347
+ id: "d1e2f3a4b5c60007",
348
+ timestamp: 1700000906e3
349
+ }),
350
+ respond: { status: 200, body: { code: 5e4, message: "System error" } },
351
+ outcome: { status: "failed", code: "transport", retryable: true }
352
+ };
317
353
  export {
318
354
  env_exports as env,
319
355
  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,{DestinationTikTok:()=>types_exports,default:()=>index_default,destinationTikTok:()=>destinationTikTok}),module.exports=(mod=index_exports,((to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to})(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core"),import_server_core2=require("@walkeros/server-core"),import_server_core=require("@walkeros/server-core"),keysToHash=["email","phone_number","external_id"];async function hashUserData(userData,doNotHash=[]){const entries=await Promise.all(Object.entries(userData).map(async([key,value])=>void 0===value?[key,value]:function(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}(key,doNotHash)?[key,await(0,import_server_core.getHashServer)(String(value))]:[key,value]));return Object.fromEntries(entries)}var 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_core.getMappingValue)(root,setting??fallback,{collector:collector});return"string"==typeof value&&""!==value?value:void 0}var types_exports={},destinationTikTok={type:"tiktok",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,pixelCode:pixelCode}=settings;accessToken||logger.throw("Config settings accessToken missing"),pixelCode||logger.throw("Config settings pixelCode missing");const settingsConfig={partner_name:"walkerOS",...settings,accessToken:accessToken,pixelCode:pixelCode};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,ingest:ingest,collector:collector,env:env,logger:logger}){const{accessToken:accessToken,pixelCode:pixelCode,doNotHash:doNotHash,test_event_code:test_event_code,url:url="https://business-api.tiktok.com/open_api/v1.3/event/track/",user_data:user_data,partner_name:partner_name,ip:ip,userAgent:userAgent}=config.settings,eventData=(0,import_core.isObject)(data)?data:{},configData=config.data?await(0,import_core.getMappingValue)(event,config.data,{collector:collector}):{},userDataCustom=user_data?await(0,import_core.getMappingValue)(event,{map:user_data},{collector:collector}):{},userData={...(0,import_core.isObject)(configData)&&(0,import_core.isObject)(configData.user_data)?configData.user_data:{},...(0,import_core.isObject)(userDataCustom)?userDataCustom:{},...(0,import_core.isObject)(eventData.user_data)?eventData.user_data:{}},properties={};if((0,import_core.isObject)(eventData))for(const[key,value]of Object.entries(eventData))"user_data"!==key&&(properties[key]=value);const hashedUserData=await hashUserData(userData,doNotHash),context={},root=(0,import_core.createMappingRoot)(ingest,event),clientIp=await resolveClient(ip,DEFAULT_IP,root,collector),clientUserAgent=await resolveClient(userAgent,DEFAULT_USER_AGENT,root,collector);void 0!==clientIp&&(context.ip=clientIp),void 0!==clientUserAgent&&(context.user_agent=clientUserAgent),Object.keys(hashedUserData).length>0&&(context.user=hashedUserData),context.page={url:event.source?.url};const tiktokEvent={event:event.name,event_id:event.id,timestamp:new Date(event.timestamp).toISOString(),context:context,properties:properties},body={pixel_code:pixelCode,partner_name:partner_name,data:[tiktokEvent]};test_event_code&&(body.test_event_code=test_event_code),logger.debug("Calling TikTok Events API",{endpoint:url,method:"POST",eventName:tiktokEvent.event,eventId:tiktokEvent.event_id});const sendServerFn=env?.sendServer||import_server_core2.sendServer,result=await sendServerFn(url,JSON.stringify(body),{headers:{"Access-Token":accessToken,"Content-Type":"application/json"}});logger.debug("TikTok API response",{ok:!(0,import_core.isObject)(result)||result.ok}),(0,import_core.isObject)(result)&&!1===result.ok&&logger.throw(`TikTok API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationTikTok;//# 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,{DestinationTikTok:()=>types_exports,default:()=>index_default,destinationTikTok:()=>destinationTikTok}),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_core2=require("@walkeros/core"),import_server_core2=require("@walkeros/server-core"),import_server_core=require("@walkeros/server-core"),keysToHash=["email","phone_number","external_id"];async function hashUserData(userData,doNotHash=[]){const entries=await Promise.all(Object.entries(userData).map(async([key,value])=>void 0===value?[key,value]:function(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}(key,doNotHash)?[key,await(0,import_server_core.getHashServer)(String(value))]:[key,value]));return Object.fromEntries(entries)}var send=async function(event,{config:config,data:data,ingest:ingest,collector:collector,env:env,logger:logger}){const{accessToken:accessToken,pixelCode:pixelCode,doNotHash:doNotHash,test_event_code:test_event_code,url:url="https://business-api.tiktok.com/open_api/v1.3/event/track/",user_data:user_data,partner_name:partner_name,ip:ip,userAgent:userAgent}=config.settings??{};if(!accessToken||!pixelCode)throw new import_core2.StepError("TikTok settings missing, init() not run",{code:"not-ready"});const eventData=(0,import_core2.isObject)(data)?data:{},configData=config.data?await(0,import_core2.getMappingValue)(event,config.data,{collector:collector}):{},userDataCustom=user_data?await(0,import_core2.getMappingValue)(event,{map:user_data},{collector:collector}):{},userData={...(0,import_core2.isObject)(configData)&&(0,import_core2.isObject)(configData.user_data)?configData.user_data:{},...(0,import_core2.isObject)(userDataCustom)?userDataCustom:{},...(0,import_core2.isObject)(eventData.user_data)?eventData.user_data:{}},properties={};if((0,import_core2.isObject)(eventData))for(const[key,value]of Object.entries(eventData))"user_data"!==key&&(properties[key]=value);const hashedUserData=await hashUserData(userData,doNotHash),context={},root=(0,import_core2.createMappingRoot)(ingest,event),clientIp=await resolveClient(ip,DEFAULT_IP,root,collector),clientUserAgent=await resolveClient(userAgent,DEFAULT_USER_AGENT,root,collector);void 0!==clientIp&&(context.ip=clientIp),void 0!==clientUserAgent&&(context.user_agent=clientUserAgent),Object.keys(hashedUserData).length>0&&(context.user=hashedUserData),context.page={url:event.source?.url};const tiktokEvent={event:event.name,event_id:event.id,timestamp:new Date(event.timestamp).toISOString(),context:context,properties:properties},body={pixel_code:pixelCode,partner_name:partner_name,data:[tiktokEvent]};test_event_code&&(body.test_event_code=test_event_code),logger.debug("Calling TikTok Events API",{endpoint:url,method:"POST",eventName:tiktokEvent.event,eventId:tiktokEvent.event_id});const sendServerFn=env?.sendServer||import_server_core2.sendServer;!function(data){if(!(0,import_core2.isObject)(data)||"number"!=typeof data.code||0===data.code)return;throw new import_core2.StepError(`TikTok Events API rejected the event (code ${data.code})`,{code:"transport",retryable:40100===data.code||data.code>=5e4,body:data})}((await sendServerFn(url,JSON.stringify(body),{headers:{"Access-Token":accessToken,"Content-Type":"application/json"}})).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_core2.getMappingValue)(root,setting??fallback,{collector:collector});return"string"==typeof value&&""!==value?value:void 0}var types_exports={},destinationTikTok={type:"tiktok",config:{},init:async({config:partialConfig})=>function(partialConfig={}){const settings=partialConfig.settings||{},{accessToken:accessToken,pixelCode:pixelCode}=settings;if(!accessToken||!pixelCode){const missing=[...accessToken?[]:["accessToken"],...pixelCode?[]:["pixelCode"]];throw new import_core.StepError(`Config settings ${missing.join(", ")} missing`,{code:"config"})}const settingsConfig={partner_name:"walkerOS",...settings,accessToken:accessToken,pixelCode:pixelCode};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=destinationTikTok;//# 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 DestinationTikTok from './types';\n\nexport const destinationTikTok: Destination = {\n type: 'tiktok',\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 destinationTikTok;\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, pixelCode } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!pixelCode) logger.throw('Config settings pixelCode missing');\n\n const settingsConfig: Settings = {\n partner_name: 'walkerOS',\n ...settings,\n accessToken,\n pixelCode,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n EventData,\n EventContext,\n PushFn,\n RequestBody,\n UserData,\n Env,\n} 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 { hashUserData } from './hash';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, ingest, collector, env, logger },\n) {\n const {\n accessToken,\n pixelCode,\n doNotHash,\n test_event_code,\n url = 'https://business-api.tiktok.com/open_api/v1.3/event/track/',\n user_data,\n partner_name,\n ip,\n userAgent,\n } = config.settings as import('./types').Settings;\n\n const eventData = isObject(data) ? data : {};\n const configData = config.data\n ? await getMappingValue(event, config.data, { collector })\n : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Build user data from multiple sources\n const userData: UserData = {\n // Destination config data\n ...(isObject(configData) && isObject(configData.user_data)\n ? (configData.user_data as UserData)\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? (userDataCustom as UserData) : {}),\n // Event mapping data\n ...(isObject(eventData.user_data) ? (eventData.user_data as UserData) : {}),\n };\n\n // Build properties from event data, excluding user_data\n const properties: Record<string, unknown> = {};\n if (isObject(eventData)) {\n for (const [key, value] of Object.entries(eventData)) {\n if (key !== 'user_data') {\n properties[key] = value;\n }\n }\n }\n\n // Hash identity fields\n const hashedUserData = await hashUserData(userData, doNotHash);\n\n // Build context\n const context: EventContext = {};\n\n // Client IP and user agent auto-fill\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 if (clientIp !== undefined) context.ip = clientIp;\n if (clientUserAgent !== undefined) context.user_agent = clientUserAgent;\n\n // Add user data if non-empty\n if (Object.keys(hashedUserData).length > 0) {\n context.user = hashedUserData;\n }\n\n // Page context from event source\n context.page = {\n url: event.source?.url,\n };\n\n // Build event data\n const tiktokEvent: EventData = {\n event: event.name,\n event_id: event.id,\n timestamp: new Date(event.timestamp).toISOString(),\n context,\n properties,\n };\n\n // Build request body\n const body: RequestBody = {\n pixel_code: pixelCode,\n partner_name,\n data: [tiktokEvent],\n };\n\n // Test event code\n if (test_event_code) body.test_event_code = test_event_code;\n\n logger.debug('Calling TikTok Events API', {\n endpoint: url,\n method: 'POST',\n eventName: tiktokEvent.event,\n eventId: tiktokEvent.event_id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(url, JSON.stringify(body), {\n headers: {\n 'Access-Token': accessToken,\n 'Content-Type': 'application/json',\n },\n });\n\n logger.debug('TikTok API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`TikTok 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 type { UserData } from './types';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = ['email', 'phone_number', 'external_id'];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\nexport async function hashUserData(\n userData: UserData,\n doNotHash: string[] = [],\n): Promise<UserData> {\n const entries = await Promise.all(\n Object.entries(userData).map(async ([key, value]) => {\n if (value === undefined) return [key, value];\n if (shouldBeHashed(key, doNotHash)) {\n return [key, await getHashServer(String(value))];\n }\n return [key, value];\n }),\n );\n\n return Object.fromEntries(entries) as UserData;\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n pixelCode: string;\n accessToken: string;\n url?: string;\n test_event_code?: string;\n doNotHash?: string[];\n user_data?: WalkerOSMapping.Map;\n partner_name?: string;\n /**\n * Client IP, sent as context.ip. 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 context.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// TikTok Events API Request Body\nexport interface RequestBody {\n pixel_code: string;\n partner_name?: string;\n test_event_code?: string;\n data: EventData[];\n}\n\n// Individual event in the data array\nexport interface EventData {\n event: string;\n event_id: string;\n timestamp: string;\n context?: EventContext;\n properties?: Record<string, unknown>;\n}\n\n// Context object within each event\nexport interface EventContext {\n ip?: string;\n user_agent?: string;\n user?: UserData;\n page?: PageContext;\n ad?: AdContext;\n}\n\n// User identity fields\nexport interface UserData {\n email?: string;\n phone_number?: string;\n external_id?: string;\n ttp?: string;\n ttclid?: string;\n locale?: string;\n}\n\n// Page context\nexport interface PageContext {\n url?: string;\n referrer?: string;\n}\n\n// Ad attribution context\nexport interface AdContext {\n callback?: string;\n}\n\n// TikTok API response\nexport interface ResponseBody {\n code: number;\n message: string;\n data?: Record<string, unknown>;\n}\n\n// Standard TikTok event names\nexport type StandardEventName =\n | 'ViewContent'\n | 'ClickButton'\n | 'Search'\n | 'AddToWishlist'\n | 'AddToCart'\n | 'InitiateCheckout'\n | 'AddPaymentInfo'\n | 'CompletePayment'\n | 'PlaceAnOrder'\n | 'Contact'\n | 'Download'\n | 'SubmitForm'\n | 'CompleteRegistration'\n | 'Subscribe'\n | (string & {});\n"],"mappings":"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","names":["import_server_core"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/hash.ts","../src/types/index.ts"],"sourcesContent":["import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationTikTok from './types';\n\nexport const destinationTikTok: Destination = {\n type: 'tiktok',\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 destinationTikTok;\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, pixelCode } = settings;\n\n if (!accessToken || !pixelCode) {\n const missing = [\n ...(accessToken ? [] : ['accessToken']),\n ...(pixelCode ? [] : ['pixelCode']),\n ];\n throw new StepError(`Config settings ${missing.join(', ')} missing`, {\n code: 'config',\n });\n }\n\n const settingsConfig: Settings = {\n partner_name: 'walkerOS',\n ...settings,\n accessToken,\n pixelCode,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n EventData,\n EventContext,\n PushFn,\n RequestBody,\n UserData,\n Env,\n} 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 { hashUserData } from './hash';\n\n// A silent rule has no TikTok 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, collector, env, logger },\n) {\n const {\n accessToken,\n pixelCode,\n doNotHash,\n test_event_code,\n url = 'https://business-api.tiktok.com/open_api/v1.3/event/track/',\n user_data,\n partner_name,\n ip,\n userAgent,\n } = config.settings ?? {};\n if (!accessToken || !pixelCode)\n throw new StepError('TikTok settings missing, init() not run', {\n code: 'not-ready',\n });\n\n const eventData = isObject(data) ? data : {};\n const configData = config.data\n ? await getMappingValue(event, config.data, { collector })\n : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Build user data from multiple sources\n const userData: UserData = {\n // Destination config data\n ...(isObject(configData) && isObject(configData.user_data)\n ? (configData.user_data as UserData)\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? (userDataCustom as UserData) : {}),\n // Event mapping data\n ...(isObject(eventData.user_data) ? (eventData.user_data as UserData) : {}),\n };\n\n // Build properties from event data, excluding user_data\n const properties: Record<string, unknown> = {};\n if (isObject(eventData)) {\n for (const [key, value] of Object.entries(eventData)) {\n if (key !== 'user_data') {\n properties[key] = value;\n }\n }\n }\n\n // Hash identity fields\n const hashedUserData = await hashUserData(userData, doNotHash);\n\n // Build context\n const context: EventContext = {};\n\n // Client IP and user agent auto-fill\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 if (clientIp !== undefined) context.ip = clientIp;\n if (clientUserAgent !== undefined) context.user_agent = clientUserAgent;\n\n // Add user data if non-empty\n if (Object.keys(hashedUserData).length > 0) {\n context.user = hashedUserData;\n }\n\n // Page context from event source\n context.page = {\n url: event.source?.url,\n };\n\n // Build event data\n const tiktokEvent: EventData = {\n event: event.name,\n event_id: event.id,\n timestamp: new Date(event.timestamp).toISOString(),\n context,\n properties,\n };\n\n // Build request body\n const body: RequestBody = {\n pixel_code: pixelCode,\n partner_name,\n data: [tiktokEvent],\n };\n\n // Test event code\n if (test_event_code) body.test_event_code = test_event_code;\n\n logger.debug('Calling TikTok Events API', {\n endpoint: url,\n method: 'POST',\n eventName: tiktokEvent.event,\n eventId: tiktokEvent.event_id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const response = await sendServerFn(url, JSON.stringify(body), {\n headers: {\n 'Access-Token': accessToken,\n 'Content-Type': 'application/json',\n },\n });\n checkResponse(response.data);\n};\n\n/**\n * TikTok answers HTTP 200 with a non-zero `code` when it rejects the event\n * (`{ code: 0, message: 'OK' }` on success). A rejection fails the push; the\n * body stays on the error. Rate limiting (40100) and server errors (5xxxx)\n * can pass on a retry, a rejected event cannot.\n */\nfunction checkResponse(data: unknown): void {\n if (!isObject(data) || typeof data.code !== 'number' || data.code === 0)\n return;\n throw new StepError(\n `TikTok Events API rejected the event (code ${data.code})`,\n {\n code: 'transport',\n retryable: data.code === 40100 || data.code >= 50000,\n body: data,\n },\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 type { UserData } from './types';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = ['email', 'phone_number', 'external_id'];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\nexport async function hashUserData(\n userData: UserData,\n doNotHash: string[] = [],\n): Promise<UserData> {\n const entries = await Promise.all(\n Object.entries(userData).map(async ([key, value]) => {\n if (value === undefined) return [key, value];\n if (shouldBeHashed(key, doNotHash)) {\n return [key, await getHashServer(String(value))];\n }\n return [key, value];\n }),\n );\n\n return Object.fromEntries(entries) as UserData;\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n pixelCode: string;\n accessToken: string;\n url?: string;\n test_event_code?: string;\n doNotHash?: string[];\n user_data?: WalkerOSMapping.Map;\n partner_name?: string;\n /**\n * Client IP, sent as context.ip. 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 context.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// TikTok Events API Request Body\nexport interface RequestBody {\n pixel_code: string;\n partner_name?: string;\n test_event_code?: string;\n data: EventData[];\n}\n\n// Individual event in the data array\nexport interface EventData {\n event: string;\n event_id: string;\n timestamp: string;\n context?: EventContext;\n properties?: Record<string, unknown>;\n}\n\n// Context object within each event\nexport interface EventContext {\n ip?: string;\n user_agent?: string;\n user?: UserData;\n page?: PageContext;\n ad?: AdContext;\n}\n\n// User identity fields\nexport interface UserData {\n email?: string;\n phone_number?: string;\n external_id?: string;\n ttp?: string;\n ttclid?: string;\n locale?: string;\n}\n\n// Page context\nexport interface PageContext {\n url?: string;\n referrer?: string;\n}\n\n// Ad attribution context\nexport interface AdContext {\n callback?: string;\n}\n\n// TikTok API response\nexport interface ResponseBody {\n code: number;\n message: string;\n data?: Record<string, unknown>;\n}\n\n// Standard TikTok event names\nexport type StandardEventName =\n | 'ViewContent'\n | 'ClickButton'\n | 'Search'\n | 'AddToWishlist'\n | 'AddToCart'\n | 'InitiateCheckout'\n | 'AddPaymentInfo'\n | 'CompletePayment'\n | 'PlaceAnOrder'\n | 'Contact'\n | 'Download'\n | 'SubmitForm'\n | 'CompleteRegistration'\n | 'Subscribe'\n | (string & {});\n"],"mappings":"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","names":["import_core","import_server_core"]}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createMappingRoot,getMappingValue,isObject}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{getHashServer}from"@walkeros/server-core";var keysToHash=["email","phone_number","external_id"];async function hashUserData(userData,doNotHash=[]){const entries=await Promise.all(Object.entries(userData).map(async([key,value])=>void 0===value?[key,value]:function(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}(key,doNotHash)?[key,await getHashServer(String(value))]:[key,value]));return Object.fromEntries(entries)}var 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={},destinationTikTok={type:"tiktok",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,pixelCode:pixelCode}=settings;accessToken||logger.throw("Config settings accessToken missing"),pixelCode||logger.throw("Config settings pixelCode missing");const settingsConfig={partner_name:"walkerOS",...settings,accessToken:accessToken,pixelCode:pixelCode};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,ingest:ingest,collector:collector,env:env,logger:logger}){const{accessToken:accessToken,pixelCode:pixelCode,doNotHash:doNotHash,test_event_code:test_event_code,url:url="https://business-api.tiktok.com/open_api/v1.3/event/track/",user_data:user_data,partner_name:partner_name,ip:ip,userAgent:userAgent}=config.settings,eventData=isObject(data)?data:{},configData=config.data?await getMappingValue(event,config.data,{collector:collector}):{},userDataCustom=user_data?await getMappingValue(event,{map:user_data},{collector:collector}):{},userData={...isObject(configData)&&isObject(configData.user_data)?configData.user_data:{},...isObject(userDataCustom)?userDataCustom:{},...isObject(eventData.user_data)?eventData.user_data:{}},properties={};if(isObject(eventData))for(const[key,value]of Object.entries(eventData))"user_data"!==key&&(properties[key]=value);const hashedUserData=await hashUserData(userData,doNotHash),context={},root=createMappingRoot(ingest,event),clientIp=await resolveClient(ip,DEFAULT_IP,root,collector),clientUserAgent=await resolveClient(userAgent,DEFAULT_USER_AGENT,root,collector);void 0!==clientIp&&(context.ip=clientIp),void 0!==clientUserAgent&&(context.user_agent=clientUserAgent),Object.keys(hashedUserData).length>0&&(context.user=hashedUserData),context.page={url:event.source?.url};const tiktokEvent={event:event.name,event_id:event.id,timestamp:new Date(event.timestamp).toISOString(),context:context,properties:properties},body={pixel_code:pixelCode,partner_name:partner_name,data:[tiktokEvent]};test_event_code&&(body.test_event_code=test_event_code),logger.debug("Calling TikTok Events API",{endpoint:url,method:"POST",eventName:tiktokEvent.event,eventId:tiktokEvent.event_id});const sendServerFn=env?.sendServer||sendServer,result=await sendServerFn(url,JSON.stringify(body),{headers:{"Access-Token":accessToken,"Content-Type":"application/json"}});logger.debug("TikTok API response",{ok:!isObject(result)||result.ok}),isObject(result)&&!1===result.ok&&logger.throw(`TikTok API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationTikTok;export{types_exports as DestinationTikTok,index_default as default,destinationTikTok};//# sourceMappingURL=index.mjs.map
1
+ import{createRequire}from"module";createRequire(import.meta.url);import{StepError}from"@walkeros/core";import{createMappingRoot,getMappingValue,isObject,StepError as StepError2}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{getHashServer}from"@walkeros/server-core";var keysToHash=["email","phone_number","external_id"];async function hashUserData(userData,doNotHash=[]){const entries=await Promise.all(Object.entries(userData).map(async([key,value])=>void 0===value?[key,value]:function(key,doNotHash=[]){return keysToHash.includes(key)&&!doNotHash.includes(key)}(key,doNotHash)?[key,await getHashServer(String(value))]:[key,value]));return Object.fromEntries(entries)}var send=async function(event,{config:config,data:data,ingest:ingest,collector:collector,env:env,logger:logger}){const{accessToken:accessToken,pixelCode:pixelCode,doNotHash:doNotHash,test_event_code:test_event_code,url:url="https://business-api.tiktok.com/open_api/v1.3/event/track/",user_data:user_data,partner_name:partner_name,ip:ip,userAgent:userAgent}=config.settings??{};if(!accessToken||!pixelCode)throw new StepError2("TikTok settings missing, init() not run",{code:"not-ready"});const eventData=isObject(data)?data:{},configData=config.data?await getMappingValue(event,config.data,{collector:collector}):{},userDataCustom=user_data?await getMappingValue(event,{map:user_data},{collector:collector}):{},userData={...isObject(configData)&&isObject(configData.user_data)?configData.user_data:{},...isObject(userDataCustom)?userDataCustom:{},...isObject(eventData.user_data)?eventData.user_data:{}},properties={};if(isObject(eventData))for(const[key,value]of Object.entries(eventData))"user_data"!==key&&(properties[key]=value);const hashedUserData=await hashUserData(userData,doNotHash),context={},root=createMappingRoot(ingest,event),clientIp=await resolveClient(ip,DEFAULT_IP,root,collector),clientUserAgent=await resolveClient(userAgent,DEFAULT_USER_AGENT,root,collector);void 0!==clientIp&&(context.ip=clientIp),void 0!==clientUserAgent&&(context.user_agent=clientUserAgent),Object.keys(hashedUserData).length>0&&(context.user=hashedUserData),context.page={url:event.source?.url};const tiktokEvent={event:event.name,event_id:event.id,timestamp:new Date(event.timestamp).toISOString(),context:context,properties:properties},body={pixel_code:pixelCode,partner_name:partner_name,data:[tiktokEvent]};test_event_code&&(body.test_event_code=test_event_code),logger.debug("Calling TikTok Events API",{endpoint:url,method:"POST",eventName:tiktokEvent.event,eventId:tiktokEvent.event_id});const sendServerFn=env?.sendServer||sendServer;!function(data){if(!isObject(data)||"number"!=typeof data.code||0===data.code)return;throw new StepError2(`TikTok Events API rejected the event (code ${data.code})`,{code:"transport",retryable:40100===data.code||data.code>=5e4,body:data})}((await sendServerFn(url,JSON.stringify(body),{headers:{"Access-Token":accessToken,"Content-Type":"application/json"}})).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={},destinationTikTok={type:"tiktok",config:{},init:async({config:partialConfig})=>function(partialConfig={}){const settings=partialConfig.settings||{},{accessToken:accessToken,pixelCode:pixelCode}=settings;if(!accessToken||!pixelCode){const missing=[...accessToken?[]:["accessToken"],...pixelCode?[]:["pixelCode"]];throw new StepError(`Config settings ${missing.join(", ")} missing`,{code:"config"})}const settingsConfig={partner_name:"walkerOS",...settings,accessToken:accessToken,pixelCode:pixelCode};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=destinationTikTok;export{types_exports as DestinationTikTok,index_default as default,destinationTikTok};//# 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, pixelCode } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!pixelCode) logger.throw('Config settings pixelCode missing');\n\n const settingsConfig: Settings = {\n partner_name: 'walkerOS',\n ...settings,\n accessToken,\n pixelCode,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n EventData,\n EventContext,\n PushFn,\n RequestBody,\n UserData,\n Env,\n} 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 { hashUserData } from './hash';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, ingest, collector, env, logger },\n) {\n const {\n accessToken,\n pixelCode,\n doNotHash,\n test_event_code,\n url = 'https://business-api.tiktok.com/open_api/v1.3/event/track/',\n user_data,\n partner_name,\n ip,\n userAgent,\n } = config.settings as import('./types').Settings;\n\n const eventData = isObject(data) ? data : {};\n const configData = config.data\n ? await getMappingValue(event, config.data, { collector })\n : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Build user data from multiple sources\n const userData: UserData = {\n // Destination config data\n ...(isObject(configData) && isObject(configData.user_data)\n ? (configData.user_data as UserData)\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? (userDataCustom as UserData) : {}),\n // Event mapping data\n ...(isObject(eventData.user_data) ? (eventData.user_data as UserData) : {}),\n };\n\n // Build properties from event data, excluding user_data\n const properties: Record<string, unknown> = {};\n if (isObject(eventData)) {\n for (const [key, value] of Object.entries(eventData)) {\n if (key !== 'user_data') {\n properties[key] = value;\n }\n }\n }\n\n // Hash identity fields\n const hashedUserData = await hashUserData(userData, doNotHash);\n\n // Build context\n const context: EventContext = {};\n\n // Client IP and user agent auto-fill\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 if (clientIp !== undefined) context.ip = clientIp;\n if (clientUserAgent !== undefined) context.user_agent = clientUserAgent;\n\n // Add user data if non-empty\n if (Object.keys(hashedUserData).length > 0) {\n context.user = hashedUserData;\n }\n\n // Page context from event source\n context.page = {\n url: event.source?.url,\n };\n\n // Build event data\n const tiktokEvent: EventData = {\n event: event.name,\n event_id: event.id,\n timestamp: new Date(event.timestamp).toISOString(),\n context,\n properties,\n };\n\n // Build request body\n const body: RequestBody = {\n pixel_code: pixelCode,\n partner_name,\n data: [tiktokEvent],\n };\n\n // Test event code\n if (test_event_code) body.test_event_code = test_event_code;\n\n logger.debug('Calling TikTok Events API', {\n endpoint: url,\n method: 'POST',\n eventName: tiktokEvent.event,\n eventId: tiktokEvent.event_id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(url, JSON.stringify(body), {\n headers: {\n 'Access-Token': accessToken,\n 'Content-Type': 'application/json',\n },\n });\n\n logger.debug('TikTok API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`TikTok 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 type { UserData } from './types';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = ['email', 'phone_number', 'external_id'];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\nexport async function hashUserData(\n userData: UserData,\n doNotHash: string[] = [],\n): Promise<UserData> {\n const entries = await Promise.all(\n Object.entries(userData).map(async ([key, value]) => {\n if (value === undefined) return [key, value];\n if (shouldBeHashed(key, doNotHash)) {\n return [key, await getHashServer(String(value))];\n }\n return [key, value];\n }),\n );\n\n return Object.fromEntries(entries) as UserData;\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n pixelCode: string;\n accessToken: string;\n url?: string;\n test_event_code?: string;\n doNotHash?: string[];\n user_data?: WalkerOSMapping.Map;\n partner_name?: string;\n /**\n * Client IP, sent as context.ip. 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 context.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// TikTok Events API Request Body\nexport interface RequestBody {\n pixel_code: string;\n partner_name?: string;\n test_event_code?: string;\n data: EventData[];\n}\n\n// Individual event in the data array\nexport interface EventData {\n event: string;\n event_id: string;\n timestamp: string;\n context?: EventContext;\n properties?: Record<string, unknown>;\n}\n\n// Context object within each event\nexport interface EventContext {\n ip?: string;\n user_agent?: string;\n user?: UserData;\n page?: PageContext;\n ad?: AdContext;\n}\n\n// User identity fields\nexport interface UserData {\n email?: string;\n phone_number?: string;\n external_id?: string;\n ttp?: string;\n ttclid?: string;\n locale?: string;\n}\n\n// Page context\nexport interface PageContext {\n url?: string;\n referrer?: string;\n}\n\n// Ad attribution context\nexport interface AdContext {\n callback?: string;\n}\n\n// TikTok API response\nexport interface ResponseBody {\n code: number;\n message: string;\n data?: Record<string, unknown>;\n}\n\n// Standard TikTok event names\nexport type StandardEventName =\n | 'ViewContent'\n | 'ClickButton'\n | 'Search'\n | 'AddToWishlist'\n | 'AddToCart'\n | 'InitiateCheckout'\n | 'AddPaymentInfo'\n | 'CompletePayment'\n | 'PlaceAnOrder'\n | 'Contact'\n | 'Download'\n | 'SubmitForm'\n | 'CompleteRegistration'\n | 'Subscribe'\n | (string & {});\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationTikTok from './types';\n\nexport const destinationTikTok: Destination = {\n type: 'tiktok',\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 destinationTikTok;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/config.ts","../src/push.ts","../src/hash.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type { Config, Settings, PartialConfig } from './types';\nimport { StepError } from '@walkeros/core';\n\nexport function getConfig(partialConfig: PartialConfig = {}): Config {\n const settings: Partial<Settings> = partialConfig.settings || {};\n const { accessToken, pixelCode } = settings;\n\n if (!accessToken || !pixelCode) {\n const missing = [\n ...(accessToken ? [] : ['accessToken']),\n ...(pixelCode ? [] : ['pixelCode']),\n ];\n throw new StepError(`Config settings ${missing.join(', ')} missing`, {\n code: 'config',\n });\n }\n\n const settingsConfig: Settings = {\n partner_name: 'walkerOS',\n ...settings,\n accessToken,\n pixelCode,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n EventData,\n EventContext,\n PushFn,\n RequestBody,\n UserData,\n Env,\n} 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 { hashUserData } from './hash';\n\n// A silent rule has no TikTok 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, collector, env, logger },\n) {\n const {\n accessToken,\n pixelCode,\n doNotHash,\n test_event_code,\n url = 'https://business-api.tiktok.com/open_api/v1.3/event/track/',\n user_data,\n partner_name,\n ip,\n userAgent,\n } = config.settings ?? {};\n if (!accessToken || !pixelCode)\n throw new StepError('TikTok settings missing, init() not run', {\n code: 'not-ready',\n });\n\n const eventData = isObject(data) ? data : {};\n const configData = config.data\n ? await getMappingValue(event, config.data, { collector })\n : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Build user data from multiple sources\n const userData: UserData = {\n // Destination config data\n ...(isObject(configData) && isObject(configData.user_data)\n ? (configData.user_data as UserData)\n : {}),\n // Custom user_data from settings\n ...(isObject(userDataCustom) ? (userDataCustom as UserData) : {}),\n // Event mapping data\n ...(isObject(eventData.user_data) ? (eventData.user_data as UserData) : {}),\n };\n\n // Build properties from event data, excluding user_data\n const properties: Record<string, unknown> = {};\n if (isObject(eventData)) {\n for (const [key, value] of Object.entries(eventData)) {\n if (key !== 'user_data') {\n properties[key] = value;\n }\n }\n }\n\n // Hash identity fields\n const hashedUserData = await hashUserData(userData, doNotHash);\n\n // Build context\n const context: EventContext = {};\n\n // Client IP and user agent auto-fill\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 if (clientIp !== undefined) context.ip = clientIp;\n if (clientUserAgent !== undefined) context.user_agent = clientUserAgent;\n\n // Add user data if non-empty\n if (Object.keys(hashedUserData).length > 0) {\n context.user = hashedUserData;\n }\n\n // Page context from event source\n context.page = {\n url: event.source?.url,\n };\n\n // Build event data\n const tiktokEvent: EventData = {\n event: event.name,\n event_id: event.id,\n timestamp: new Date(event.timestamp).toISOString(),\n context,\n properties,\n };\n\n // Build request body\n const body: RequestBody = {\n pixel_code: pixelCode,\n partner_name,\n data: [tiktokEvent],\n };\n\n // Test event code\n if (test_event_code) body.test_event_code = test_event_code;\n\n logger.debug('Calling TikTok Events API', {\n endpoint: url,\n method: 'POST',\n eventName: tiktokEvent.event,\n eventId: tiktokEvent.event_id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const response = await sendServerFn(url, JSON.stringify(body), {\n headers: {\n 'Access-Token': accessToken,\n 'Content-Type': 'application/json',\n },\n });\n checkResponse(response.data);\n};\n\n/**\n * TikTok answers HTTP 200 with a non-zero `code` when it rejects the event\n * (`{ code: 0, message: 'OK' }` on success). A rejection fails the push; the\n * body stays on the error. Rate limiting (40100) and server errors (5xxxx)\n * can pass on a retry, a rejected event cannot.\n */\nfunction checkResponse(data: unknown): void {\n if (!isObject(data) || typeof data.code !== 'number' || data.code === 0)\n return;\n throw new StepError(\n `TikTok Events API rejected the event (code ${data.code})`,\n {\n code: 'transport',\n retryable: data.code === 40100 || data.code >= 50000,\n body: data,\n },\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 type { UserData } from './types';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = ['email', 'phone_number', 'external_id'];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\nexport async function hashUserData(\n userData: UserData,\n doNotHash: string[] = [],\n): Promise<UserData> {\n const entries = await Promise.all(\n Object.entries(userData).map(async ([key, value]) => {\n if (value === undefined) return [key, value];\n if (shouldBeHashed(key, doNotHash)) {\n return [key, await getHashServer(String(value))];\n }\n return [key, value];\n }),\n );\n\n return Object.fromEntries(entries) as UserData;\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n pixelCode: string;\n accessToken: string;\n url?: string;\n test_event_code?: string;\n doNotHash?: string[];\n user_data?: WalkerOSMapping.Map;\n partner_name?: string;\n /**\n * Client IP, sent as context.ip. 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 context.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// TikTok Events API Request Body\nexport interface RequestBody {\n pixel_code: string;\n partner_name?: string;\n test_event_code?: string;\n data: EventData[];\n}\n\n// Individual event in the data array\nexport interface EventData {\n event: string;\n event_id: string;\n timestamp: string;\n context?: EventContext;\n properties?: Record<string, unknown>;\n}\n\n// Context object within each event\nexport interface EventContext {\n ip?: string;\n user_agent?: string;\n user?: UserData;\n page?: PageContext;\n ad?: AdContext;\n}\n\n// User identity fields\nexport interface UserData {\n email?: string;\n phone_number?: string;\n external_id?: string;\n ttp?: string;\n ttclid?: string;\n locale?: string;\n}\n\n// Page context\nexport interface PageContext {\n url?: string;\n referrer?: string;\n}\n\n// Ad attribution context\nexport interface AdContext {\n callback?: string;\n}\n\n// TikTok API response\nexport interface ResponseBody {\n code: number;\n message: string;\n data?: Record<string, unknown>;\n}\n\n// Standard TikTok event names\nexport type StandardEventName =\n | 'ViewContent'\n | 'ClickButton'\n | 'Search'\n | 'AddToWishlist'\n | 'AddToCart'\n | 'InitiateCheckout'\n | 'AddPaymentInfo'\n | 'CompletePayment'\n | 'PlaceAnOrder'\n | 'Contact'\n | 'Download'\n | 'SubmitForm'\n | 'CompleteRegistration'\n | 'Subscribe'\n | (string & {});\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationTikTok from './types';\n\nexport const destinationTikTok: Destination = {\n type: 'tiktok',\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 destinationTikTok;\n"],"mappings":"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","names":["StepError","StepError"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/server-destination-tiktok",
4
- "version": "4.8.1-next-1792019907609",
4
+ "version": "4.8.2",
5
5
  "type": "destination",
6
6
  "platform": [
7
7
  "server"
@@ -247,7 +247,7 @@
247
247
  "env": {
248
248
  "push": {
249
249
  "sendServer": {
250
- "$code": "async function(e,t,a){return{ok:!0,data:{code:0,message:\"OK\"}}}"
250
+ "$code": "async function(e,t,a){return{data:{code:0,message:\"OK\"}}}"
251
251
  }
252
252
  },
253
253
  "simulation": [
@@ -327,7 +327,7 @@
327
327
  "nested",
328
328
  {
329
329
  "condition": {
330
- "$code": "e=>k(e)&&\"product\"===e.entity"
330
+ "$code": "e=>T(e)&&\"product\"===e.entity"
331
331
  },
332
332
  "map": {
333
333
  "content_id": "data.id",
@@ -358,6 +358,73 @@
358
358
  ]
359
359
  ]
360
360
  },
361
+ "busy": {
362
+ "public": false,
363
+ "description": "TikTok answers HTTP 200 with a server error code: the push fails with transport, retryable.",
364
+ "in": {
365
+ "name": "page view",
366
+ "data": {
367
+ "domain": "www.example.com",
368
+ "title": "walkerOS documentation",
369
+ "referrer": "https://www.walkeros.io/",
370
+ "search": "?foo=bar",
371
+ "hash": "#hash",
372
+ "id": "/docs/"
373
+ },
374
+ "context": {
375
+ "dev": [
376
+ "test",
377
+ 1
378
+ ]
379
+ },
380
+ "globals": {
381
+ "pagegroup": "docs"
382
+ },
383
+ "custom": {
384
+ "completely": "random"
385
+ },
386
+ "user": {
387
+ "id": "us3r",
388
+ "device": "c00k13",
389
+ "session": "s3ss10n"
390
+ },
391
+ "nested": [
392
+ {
393
+ "entity": "child",
394
+ "data": {
395
+ "is": "subordinated"
396
+ }
397
+ }
398
+ ],
399
+ "consent": {
400
+ "functional": true
401
+ },
402
+ "id": "d1e2f3a4b5c60007",
403
+ "trigger": "load",
404
+ "entity": "page",
405
+ "action": "view",
406
+ "timestamp": 1700000906000,
407
+ "timing": 3.14,
408
+ "source": {
409
+ "count": 1,
410
+ "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
411
+ "type": "collector",
412
+ "schema": "4"
413
+ }
414
+ },
415
+ "respond": {
416
+ "status": 200,
417
+ "body": {
418
+ "code": 50000,
419
+ "message": "System error"
420
+ }
421
+ },
422
+ "outcome": {
423
+ "status": "failed",
424
+ "code": "transport",
425
+ "retryable": true
426
+ }
427
+ },
361
428
  "lead": {
362
429
  "title": "Submit form",
363
430
  "description": "A newsletter form submission is sent to TikTok as a SubmitForm event with the hashed email in user context.",
@@ -508,7 +575,7 @@
508
575
  "name": "order complete",
509
576
  "data": {
510
577
  "id": "ORD-300",
511
- "total": 249.99,
578
+ "value": 249.99,
512
579
  "currency": "EUR"
513
580
  },
514
581
  "context": {
@@ -559,7 +626,7 @@
559
626
  "name": "CompletePayment",
560
627
  "data": {
561
628
  "map": {
562
- "value": "data.total",
629
+ "value": "data.value",
563
630
  "currency": {
564
631
  "key": "data.currency",
565
632
  "value": "EUR"
@@ -573,7 +640,7 @@
573
640
  "nested",
574
641
  {
575
642
  "condition": {
576
- "$code": "e=>k(e)&&\"product\"===e.entity"
643
+ "$code": "e=>T(e)&&\"product\"===e.entity"
577
644
  },
578
645
  "map": {
579
646
  "content_id": "data.id",
@@ -608,6 +675,132 @@
608
675
  }
609
676
  ]
610
677
  ]
678
+ },
679
+ "rejectedEvent": {
680
+ "public": false,
681
+ "description": "TikTok answers HTTP 200 with a non-zero code: the event was rejected, so the push fails with transport, not retryable, and the event goes to the DLQ.",
682
+ "in": {
683
+ "name": "page view",
684
+ "data": {
685
+ "domain": "www.example.com",
686
+ "title": "walkerOS documentation",
687
+ "referrer": "https://www.walkeros.io/",
688
+ "search": "?foo=bar",
689
+ "hash": "#hash",
690
+ "id": "/docs/"
691
+ },
692
+ "context": {
693
+ "dev": [
694
+ "test",
695
+ 1
696
+ ]
697
+ },
698
+ "globals": {
699
+ "pagegroup": "docs"
700
+ },
701
+ "custom": {
702
+ "completely": "random"
703
+ },
704
+ "user": {
705
+ "id": "us3r",
706
+ "device": "c00k13",
707
+ "session": "s3ss10n"
708
+ },
709
+ "nested": [
710
+ {
711
+ "entity": "child",
712
+ "data": {
713
+ "is": "subordinated"
714
+ }
715
+ }
716
+ ],
717
+ "consent": {
718
+ "functional": true
719
+ },
720
+ "id": "d1e2f3a4b5c60006",
721
+ "trigger": "load",
722
+ "entity": "page",
723
+ "action": "view",
724
+ "timestamp": 1700000905000,
725
+ "timing": 3.14,
726
+ "source": {
727
+ "count": 1,
728
+ "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
729
+ "type": "collector",
730
+ "schema": "4"
731
+ }
732
+ },
733
+ "respond": {
734
+ "status": 200,
735
+ "body": {
736
+ "code": 40002,
737
+ "message": "Invalid value for field event"
738
+ }
739
+ },
740
+ "outcome": {
741
+ "status": "failed",
742
+ "code": "transport",
743
+ "retryable": false
744
+ }
745
+ },
746
+ "silentRule": {
747
+ "public": false,
748
+ "description": "A rule with silent: true sends no request to TikTok.",
749
+ "in": {
750
+ "name": "page view",
751
+ "data": {
752
+ "domain": "www.example.com",
753
+ "title": "walkerOS documentation",
754
+ "referrer": "https://www.walkeros.io/",
755
+ "search": "?foo=bar",
756
+ "hash": "#hash",
757
+ "id": "/docs/"
758
+ },
759
+ "context": {
760
+ "dev": [
761
+ "test",
762
+ 1
763
+ ]
764
+ },
765
+ "globals": {
766
+ "pagegroup": "docs"
767
+ },
768
+ "custom": {
769
+ "completely": "random"
770
+ },
771
+ "user": {
772
+ "id": "us3r",
773
+ "device": "c00k13",
774
+ "session": "s3ss10n"
775
+ },
776
+ "nested": [
777
+ {
778
+ "entity": "child",
779
+ "data": {
780
+ "is": "subordinated"
781
+ }
782
+ }
783
+ ],
784
+ "consent": {
785
+ "functional": true
786
+ },
787
+ "id": "d1e2f3a4b5c60005",
788
+ "trigger": "load",
789
+ "entity": "page",
790
+ "action": "view",
791
+ "timestamp": 1700000904000,
792
+ "timing": 3.14,
793
+ "source": {
794
+ "count": 1,
795
+ "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
796
+ "type": "collector",
797
+ "schema": "4"
798
+ }
799
+ },
800
+ "mapping": {
801
+ "silent": true
802
+ },
803
+ "out": []
611
804
  }
612
805
  }
613
806
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@walkeros/server-destination-tiktok",
3
3
  "description": "TikTok Events API 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",