@walkeros/server-destination-linkedin 4.8.1 → 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,5 +1,28 @@
1
1
  # @walkeros/server-destination-linkedin
2
2
 
3
+ ## 4.8.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 2374f54: A failed request is reported as a failed push (dead-letter queue, one
8
+ ERROR line with the status) instead of counting as delivered or being logged
9
+ at debug. Events a destination cannot send, such as a missing user identifier,
10
+ fail with `missing-input`. Rules with `silent: true` send no event of their
11
+ own.
12
+ - Updated dependencies [2374f54]
13
+ - Updated dependencies [7e5fc27]
14
+ - Updated dependencies [2374f54]
15
+ - Updated dependencies [964590a]
16
+ - Updated dependencies [4100ede]
17
+ - Updated dependencies [2374f54]
18
+ - Updated dependencies [2374f54]
19
+ - Updated dependencies [15eb7b2]
20
+ - Updated dependencies [33a2779]
21
+ - Updated dependencies [33a2779]
22
+ - Updated dependencies [2374f54]
23
+ - @walkeros/core@4.8.2
24
+ - @walkeros/server-core@4.8.2
25
+
3
26
  ## 4.8.1
4
27
 
5
28
  ### Patch Changes
package/README.md CHANGED
@@ -32,7 +32,12 @@ npm install @walkeros/server-destination-linkedin
32
32
  "destinations": {
33
33
  "linkedin": {
34
34
  "package": "@walkeros/server-destination-linkedin",
35
- "config": {}
35
+ "config": {
36
+ "settings": {
37
+ "accessToken": "YOUR_ACCESS_TOKEN",
38
+ "conversionRuleId": "YOUR_CONVERSION_RULE_ID"
39
+ }
40
+ }
36
41
  }
37
42
  }
38
43
  }
package/dist/dev.d.mts CHANGED
@@ -26,7 +26,7 @@ declare const SettingsSchema: z.ZodObject<{
26
26
  doNotHash: z.ZodOptional<z.ZodArray<z.ZodString>>;
27
27
  url: z.ZodOptional<z.ZodString>;
28
28
  user_data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
29
- }, z.core.$strip>;
29
+ }, z.core.$strict>;
30
30
  type Settings = z.infer<typeof SettingsSchema>;
31
31
 
32
32
  /**
@@ -82,12 +82,19 @@ declare namespace env {
82
82
  declare const purchase: Flow.StepExample;
83
83
  declare const lead: Flow.StepExample;
84
84
  declare const purchaseWithLiFatId: Flow.StepExample;
85
+ /** A silent rule sends nothing to LinkedIn. */
86
+ declare const silentRule: Flow.StepExample;
87
+ declare const noIdentifierOrder: Flow.StepExample;
88
+ declare const noIdentifierForm: Flow.StepExample;
85
89
 
86
90
  declare const step_lead: typeof lead;
91
+ declare const step_noIdentifierForm: typeof noIdentifierForm;
92
+ declare const step_noIdentifierOrder: typeof noIdentifierOrder;
87
93
  declare const step_purchase: typeof purchase;
88
94
  declare const step_purchaseWithLiFatId: typeof purchaseWithLiFatId;
95
+ declare const step_silentRule: typeof silentRule;
89
96
  declare namespace step {
90
- export { step_lead as lead, step_purchase as purchase, step_purchaseWithLiFatId as purchaseWithLiFatId };
97
+ export { step_lead as lead, step_noIdentifierForm as noIdentifierForm, step_noIdentifierOrder as noIdentifierOrder, step_purchase as purchase, step_purchaseWithLiFatId as purchaseWithLiFatId, step_silentRule as silentRule };
91
98
  }
92
99
 
93
100
  declare const index_env: typeof env;
package/dist/dev.d.ts CHANGED
@@ -26,7 +26,7 @@ declare const SettingsSchema: z.ZodObject<{
26
26
  doNotHash: z.ZodOptional<z.ZodArray<z.ZodString>>;
27
27
  url: z.ZodOptional<z.ZodString>;
28
28
  user_data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
29
- }, z.core.$strip>;
29
+ }, z.core.$strict>;
30
30
  type Settings = z.infer<typeof SettingsSchema>;
31
31
 
32
32
  /**
@@ -82,12 +82,19 @@ declare namespace env {
82
82
  declare const purchase: Flow.StepExample;
83
83
  declare const lead: Flow.StepExample;
84
84
  declare const purchaseWithLiFatId: Flow.StepExample;
85
+ /** A silent rule sends nothing to LinkedIn. */
86
+ declare const silentRule: Flow.StepExample;
87
+ declare const noIdentifierOrder: Flow.StepExample;
88
+ declare const noIdentifierForm: Flow.StepExample;
85
89
 
86
90
  declare const step_lead: typeof lead;
91
+ declare const step_noIdentifierForm: typeof noIdentifierForm;
92
+ declare const step_noIdentifierOrder: typeof noIdentifierOrder;
87
93
  declare const step_purchase: typeof purchase;
88
94
  declare const step_purchaseWithLiFatId: typeof purchaseWithLiFatId;
95
+ declare const step_silentRule: typeof silentRule;
89
96
  declare namespace step {
90
- export { step_lead as lead, step_purchase as purchase, step_purchaseWithLiFatId as purchaseWithLiFatId };
97
+ export { step_lead as lead, step_noIdentifierForm as noIdentifierForm, step_noIdentifierOrder as noIdentifierOrder, step_purchase as purchase, step_purchaseWithLiFatId as purchaseWithLiFatId, step_silentRule as silentRule };
91
98
  }
92
99
 
93
100
  declare const index_env: typeof env;
package/dist/dev.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e,r=Object.defineProperty,i=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,t=Object.prototype.hasOwnProperty,o=(e,i)=>{for(var n in i)r(e,n,{get:i[n],enumerable:!0})},a={};o(a,{examples:()=>I,schemas:()=>s}),module.exports=(e=a,((e,o,a,s)=>{if(o&&"object"==typeof o||"function"==typeof o)for(let c of n(o))t.call(e,c)||c===a||r(e,c,{get:()=>o[c],enumerable:!(s=i(o,c))||s.enumerable});return e})(r({},"__esModule",{value:!0}),e));var s={};o(s,{ApiVersionSchema:()=>p,MappingSchema:()=>f,SettingsSchema:()=>v,UserIdTypeSchema:()=>u,mapping:()=>h,settings:()=>b});var c=require("@walkeros/core/dev"),d=require("@walkeros/core/dev"),l=require("@walkeros/core/dev"),u=l.z.enum(["SHA256_EMAIL","LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID","ACXIOM_ID","ORACLE_MOAT_ID"]),p=l.z.string().regex(/^\d{6}$/,"API version must be in YYYYMM format (e.g. 202604)"),v=d.z.object({accessToken:d.z.string().min(1).describe("LinkedIn OAuth 2.0 Bearer token for Conversions API authentication (like AQX...)"),conversionRuleId:d.z.string().regex(/^[0-9]+$/,"Conversion rule ID must contain only digits").describe("Default LinkedIn conversion rule ID from Campaign Manager (like 12345678)"),apiVersion:p.describe("Linkedin-Version header value in YYYYMM format (like 202604)").optional(),doNotHash:d.z.array(d.z.string()).describe("Array of user data fields that should not be hashed (like ['email'])").optional(),url:d.z.string().url().describe("Custom URL for LinkedIn Conversions API endpoint (like https://api.linkedin.com/rest/)").optional(),user_data:d.z.record(d.z.string(),d.z.string()).describe("Mapping configuration for user data fields (like { email: 'user.email', li_fat_id: 'context.li_fat_id' })").optional()}),m=require("@walkeros/core/dev"),f=m.z.object({conversion:m.z.object({ruleId:m.z.string().describe("Override conversion rule ID for this event").optional(),value:m.z.union([m.z.string(),m.z.number()]).describe("Conversion monetary value").optional(),currency:m.z.string().describe("ISO 4217 currency code (like USD, EUR)").optional()}).describe("Per-event conversion override with ruleId, value, and currency").optional()}),b=(0,c.zodToSchema)(v),h=(0,c.zodToSchema)(f),I={};o(I,{env:()=>y,step:()=>A});var y={};o(y,{push:()=>g,simulation:()=>_});var g={sendServer:async function(e,r,i){return{ok:!0,data:{}}}},_=["sendServer"],A={};o(A,{lead:()=>L,purchase:()=>C,purchaseWithLiFatId:()=>T});var S=require("@walkeros/core"),k="https://api.linkedin.com/rest/conversionEvents",z={headers:{Authorization:"Bearer s3cr3t","Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0","X-RestLi-Method":"BATCH_CREATE","Linkedin-Version":"202604"}},C={title:"Purchase",description:"A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.",in:(0,S.getEvent)("order complete",{id:"ev-1700000900000",timestamp:17000009e5,data:{total:249.99,currency:"EUR"},user:{email:"jane@example.com"},source:{type:"express",platform:"server"}}),mapping:{settings:{conversion:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"}}}}},out:[["sendServer",k,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:17000009e5,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d"}]},eventId:"ev-1700000900000",conversionValue:{currencyCode:"EUR",amount:"249.99"}}]}),z]]},L={title:"Lead",description:"A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.",in:(0,S.getEvent)("form submit",{id:"ev-1700000901000",timestamp:1700000901e3,user:{email:"user@example.com"},source:{type:"express",platform:"server"}}),mapping:void 0,out:[["sendServer",k,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000901e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"}]},eventId:"ev-1700000901000"}]}),z]]},T={title:"Purchase with li_fat_id",description:"A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.",in:(0,S.getEvent)("order complete",{id:"ev-1700000902000",timestamp:1700000902e3,data:{total:89.99,currency:"USD"},user:{email:"buyer@co.com"},context:{li_fat_id:["abc123-fat-id",0]},source:{type:"express",platform:"server"}}),mapping:{settings:{conversion:{map:{value:"data.total",currency:{key:"data.currency",value:"USD"}}}},data:{map:{user_data:{map:{li_fat_id:"context.li_fat_id"}}}}},out:[["sendServer",k,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000902e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66"},{idType:"LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID",idValue:"abc123-fat-id"}]},eventId:"ev-1700000902000",conversionValue:{currencyCode:"USD",amount:"89.99"}}]}),z]]};//# sourceMappingURL=dev.js.map
1
+ "use strict";var e,r=Object.defineProperty,i=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,t=Object.prototype.hasOwnProperty,o=(e,i)=>{for(var n in i)r(e,n,{get:i[n],enumerable:!0})},a={};o(a,{examples:()=>I,schemas:()=>s}),module.exports=(e=a,((e,o,a,s)=>{if(o&&"object"==typeof o||"function"==typeof o)for(let c of n(o))t.call(e,c)||c===a||r(e,c,{get:()=>o[c],enumerable:!(s=i(o,c))||s.enumerable});return e})(r({},"__esModule",{value:!0}),e));var s={};o(s,{ApiVersionSchema:()=>p,MappingSchema:()=>f,SettingsSchema:()=>m,UserIdTypeSchema:()=>u,mapping:()=>h,settings:()=>b});var c=require("@walkeros/core/dev"),d=require("@walkeros/core/dev"),l=require("@walkeros/core/dev"),u=l.z.enum(["SHA256_EMAIL","LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID","ACXIOM_ID","ORACLE_MOAT_ID"]),p=l.z.string().regex(/^\d{6}$/,"API version must be in YYYYMM format (e.g. 202604)"),m=d.z.object({accessToken:d.z.string().min(1).describe("LinkedIn OAuth 2.0 Bearer token for Conversions API authentication (like AQX...)"),conversionRuleId:d.z.string().regex(/^[0-9]+$/,"Conversion rule ID must contain only digits").describe("Default LinkedIn conversion rule ID from Campaign Manager (like 12345678)"),apiVersion:p.describe("Linkedin-Version header value in YYYYMM format (like 202604)").optional(),doNotHash:d.z.array(d.z.string()).describe("Array of user data fields that should not be hashed (like ['email'])").optional(),url:d.z.string().url().describe("Custom URL for LinkedIn Conversions API endpoint (like https://api.linkedin.com/rest/)").optional(),user_data:d.z.record(d.z.string(),d.z.string()).describe("Mapping configuration for user data fields (like { email: 'user.email', li_fat_id: 'context.li_fat_id' })").optional()}).strict(),v=require("@walkeros/core/dev"),f=v.z.object({conversion:v.z.object({ruleId:v.z.string().describe("Override conversion rule ID for this event").optional(),value:v.z.union([v.z.string(),v.z.number()]).describe("Conversion monetary value").optional(),currency:v.z.string().describe("ISO 4217 currency code (like USD, EUR)").optional()}).describe("Per-event conversion override with ruleId, value, and currency").optional()}),b=(0,c.zodToSchema)(m),h=(0,c.zodToSchema)(f),I={};o(I,{env:()=>g,step:()=>_});var g={};o(g,{push:()=>y,simulation:()=>A});var y={sendServer:async function(e,r,i){return{data:{}}}},A=["sendServer"],_={};o(_,{lead:()=>C,noIdentifierForm:()=>O,noIdentifierOrder:()=>D,purchase:()=>L,purchaseWithLiFatId:()=>E,silentRule:()=>T});var k=require("@walkeros/core"),S="https://api.linkedin.com/rest/conversionEvents",z={headers:{Authorization:"Bearer s3cr3t","Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0","X-RestLi-Method":"BATCH_CREATE","Linkedin-Version":"202604"}},L={title:"Purchase",description:"A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.",in:(0,k.getEvent)("order complete",{id:"ev-1700000900000",timestamp:17000009e5,data:{value:249.99,currency:"EUR"},user:{email:"jane@example.com"},source:{type:"express",platform:"server"}}),mapping:{settings:{conversion:{map:{value:"data.value",currency:{key:"data.currency",value:"EUR"}}}}},out:[["sendServer",S,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:17000009e5,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d"}]},eventId:"ev-1700000900000",conversionValue:{currencyCode:"EUR",amount:"249.99"}}]}),z]]},C={title:"Lead",description:"A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.",in:(0,k.createEvent)({name:"form submit",id:"ev-1700000901000",timestamp:1700000901e3,user:{email:"user@example.com"},source:{type:"express",platform:"server"}}),mapping:void 0,out:[["sendServer",S,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000901e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"}]},eventId:"ev-1700000901000"}]}),z]]},E={title:"Purchase with li_fat_id",description:"A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.",in:(0,k.getEvent)("order complete",{id:"ev-1700000902000",timestamp:1700000902e3,data:{value:89.99,currency:"USD"},user:{email:"buyer@co.com"},context:{li_fat_id:["abc123-fat-id",0]},source:{type:"express",platform:"server"}}),mapping:{settings:{conversion:{map:{value:"data.value",currency:{key:"data.currency",value:"USD"}}}},data:{map:{user_data:{map:{li_fat_id:"context.li_fat_id"}}}}},out:[["sendServer",S,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000902e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66"},{idType:"LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID",idValue:"abc123-fat-id"}]},eventId:"ev-1700000902000",conversionValue:{currencyCode:"USD",amount:"89.99"}}]}),z]]},T={public:!1,description:"A rule with silent: true sends no request to LinkedIn.",in:(0,k.getEvent)("page view",{timestamp:170000099e4}),mapping:{silent:!0},out:[]};function w(e,r){const[i,n]=e.split(" ");return{public:!1,description:`A ${e} event without a user identifier cannot be sent to LinkedIn: the push fails with missing-input instead of counting as delivered.`,in:{name:e,entity:i,action:n,timestamp:r},out:[],outcome:{status:"failed",code:"missing-input",retryable:!1}}}var D=w("order complete",1700000991e3),O=w("form submit",1700000992e3);//# sourceMappingURL=dev.js.map
package/dist/dev.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\nimport { ApiVersionSchema } from './primitives';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'LinkedIn OAuth 2.0 Bearer token for Conversions API authentication (like AQX...)',\n ),\n conversionRuleId: z\n .string()\n .regex(/^[0-9]+$/, 'Conversion rule ID must contain only digits')\n .describe(\n 'Default LinkedIn conversion rule ID from Campaign Manager (like 12345678)',\n ),\n apiVersion: ApiVersionSchema.describe(\n 'Linkedin-Version header value in YYYYMM format (like 202604)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"Array of user data fields that should not be hashed (like ['email'])\",\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for LinkedIn Conversions API endpoint (like https://api.linkedin.com/rest/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user data fields (like { email: 'user.email', li_fat_id: 'context.li_fat_id' })\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * LinkedIn User ID Type Enum\n * Types of user identifiers supported by LinkedIn Conversions API\n */\nexport const UserIdTypeSchema = z.enum([\n 'SHA256_EMAIL',\n 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n 'ACXIOM_ID',\n 'ORACLE_MOAT_ID',\n]);\n\n/**\n * API Version Schema\n * LinkedIn-Version header value in YYYYMM format\n */\nexport const ApiVersionSchema = z\n .string()\n .regex(/^\\d{6}$/, 'API version must be in YYYYMM format (e.g. 202604)');\n","import { z } from '@walkeros/core/dev';\n\n/**\n * LinkedIn Conversions API Mapping Schema\n *\n * Per-event override for conversion rule, value, and currency.\n * The `conversion` field is a mapping value that resolves to an object\n * with optional `ruleId`, `value`, and `currency` keys.\n */\nexport const MappingSchema = z.object({\n conversion: z\n .object({\n ruleId: z\n .string()\n .describe('Override conversion rule ID for this event')\n .optional(),\n value: z\n .union([z.string(), z.number()])\n .describe('Conversion monetary value')\n .optional(),\n currency: z\n .string()\n .describe('ISO 4217 currency code (like USD, EUR)')\n .optional(),\n })\n .describe('Per-event conversion override with ruleId, value, and currency')\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for LinkedIn Conversions API destination\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nasync function mockSendServer(\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n): Promise<SendResponse> {\n return {\n ok: true,\n data: {},\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing LinkedIn Conversions API events without making\n * actual HTTP requests to LinkedIn'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 } from '@walkeros/core';\n\n/**\n * LinkedIn Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), options)` where\n * endpoint = `${settings.url}conversionEvents`\n * body = `{ elements: [conversionEvent] }`\n *\n * Test fixture pins `conversionRuleId = '12345678'` and the default url, so\n * every call targets:\n * https://api.linkedin.com/rest/conversionEvents\n *\n * Each conversion event is emitted with keys in the destination's build order:\n * 1. conversion (`urn:lla:llaPartnerConversion:<ruleId>`)\n * 2. conversionHappenedAt (raw `event.timestamp` in ms)\n * 3. user\n * 4. eventId\n * 5. conversionValue (only when mapping provides a value)\n *\n * `options` carries the Authorization + LinkedIn-specific headers.\n */\nconst ENDPOINT = 'https://api.linkedin.com/rest/conversionEvents';\nconst OPTIONS = {\n headers: {\n Authorization: 'Bearer s3cr3t',\n 'Content-Type': 'application/json',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n 'Linkedin-Version': '202604',\n },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.',\n in: getEvent('order complete', {\n id: 'ev-1700000900000',\n timestamp: 1700000900000,\n data: { total: 249.99, currency: 'EUR' },\n user: { email: 'jane@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n settings: {\n conversion: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000900000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('jane@example.com')\n idValue:\n '8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d',\n },\n ],\n },\n eventId: 'ev-1700000900000',\n conversionValue: {\n currencyCode: 'EUR',\n amount: '249.99',\n },\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Lead',\n description:\n 'A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.',\n in: getEvent('form submit', {\n id: 'ev-1700000901000',\n timestamp: 1700000901000,\n user: { email: 'user@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000901000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('user@example.com')\n idValue:\n 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n ],\n },\n eventId: 'ev-1700000901000',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const purchaseWithLiFatId: Flow.StepExample = {\n title: 'Purchase with li_fat_id',\n description:\n 'A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.',\n in: getEvent('order complete', {\n id: 'ev-1700000902000',\n timestamp: 1700000902000,\n data: { total: 89.99, currency: 'USD' },\n user: { email: 'buyer@co.com' },\n context: { li_fat_id: ['abc123-fat-id', 0] },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n settings: {\n conversion: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'USD' },\n },\n },\n },\n data: {\n map: {\n user_data: {\n map: {\n li_fat_id: 'context.li_fat_id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000902000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('buyer@co.com')\n idValue:\n '484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66',\n },\n {\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: 'abc123-fat-id',\n },\n ],\n },\n eventId: 'ev-1700000902000',\n conversionValue: {\n currencyCode: 'USD',\n amount: '89.99',\n },\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n"],"mappings":"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","names":["import_dev","import_dev","import_dev"]}
1
+ {"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\nimport { ApiVersionSchema } from './primitives';\n\nexport const SettingsSchema = z\n .object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'LinkedIn OAuth 2.0 Bearer token for Conversions API authentication (like AQX...)',\n ),\n conversionRuleId: z\n .string()\n .regex(/^[0-9]+$/, 'Conversion rule ID must contain only digits')\n .describe(\n 'Default LinkedIn conversion rule ID from Campaign Manager (like 12345678)',\n ),\n apiVersion: ApiVersionSchema.describe(\n 'Linkedin-Version header value in YYYYMM format (like 202604)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"Array of user data fields that should not be hashed (like ['email'])\",\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for LinkedIn Conversions API endpoint (like https://api.linkedin.com/rest/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user data fields (like { email: 'user.email', li_fat_id: 'context.li_fat_id' })\",\n )\n .optional(),\n })\n .strict();\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * LinkedIn User ID Type Enum\n * Types of user identifiers supported by LinkedIn Conversions API\n */\nexport const UserIdTypeSchema = z.enum([\n 'SHA256_EMAIL',\n 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n 'ACXIOM_ID',\n 'ORACLE_MOAT_ID',\n]);\n\n/**\n * API Version Schema\n * LinkedIn-Version header value in YYYYMM format\n */\nexport const ApiVersionSchema = z\n .string()\n .regex(/^\\d{6}$/, 'API version must be in YYYYMM format (e.g. 202604)');\n","import { z } from '@walkeros/core/dev';\n\n/**\n * LinkedIn Conversions API Mapping Schema\n *\n * Per-event override for conversion rule, value, and currency.\n * The `conversion` field is a mapping value that resolves to an object\n * with optional `ruleId`, `value`, and `currency` keys.\n */\nexport const MappingSchema = z.object({\n conversion: z\n .object({\n ruleId: z\n .string()\n .describe('Override conversion rule ID for this event')\n .optional(),\n value: z\n .union([z.string(), z.number()])\n .describe('Conversion monetary value')\n .optional(),\n currency: z\n .string()\n .describe('ISO 4217 currency code (like USD, EUR)')\n .optional(),\n })\n .describe('Per-event conversion override with ruleId, value, and currency')\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for LinkedIn Conversions API destination\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nasync function mockSendServer(\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n): Promise<SendResponse> {\n return {\n data: {},\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing LinkedIn Conversions API events without making\n * actual HTTP requests to LinkedIn'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 } from '@walkeros/core';\n\n/**\n * LinkedIn Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), options)` where\n * endpoint = `${settings.url}conversionEvents`\n * body = `{ elements: [conversionEvent] }`\n *\n * Test fixture pins `conversionRuleId = '12345678'` and the default url, so\n * every call targets:\n * https://api.linkedin.com/rest/conversionEvents\n *\n * Each conversion event is emitted with keys in the destination's build order:\n * 1. conversion (`urn:lla:llaPartnerConversion:<ruleId>`)\n * 2. conversionHappenedAt (raw `event.timestamp` in ms)\n * 3. user\n * 4. eventId\n * 5. conversionValue (only when mapping provides a value)\n *\n * `options` carries the Authorization + LinkedIn-specific headers.\n */\nconst ENDPOINT = 'https://api.linkedin.com/rest/conversionEvents';\nconst OPTIONS = {\n headers: {\n Authorization: 'Bearer s3cr3t',\n 'Content-Type': 'application/json',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n 'Linkedin-Version': '202604',\n },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.',\n in: getEvent('order complete', {\n id: 'ev-1700000900000',\n timestamp: 1700000900000,\n data: { value: 249.99, currency: 'EUR' },\n user: { email: 'jane@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n settings: {\n conversion: {\n map: {\n value: 'data.value',\n currency: { key: 'data.currency', value: 'EUR' },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000900000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('jane@example.com')\n idValue:\n '8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d',\n },\n ],\n },\n eventId: 'ev-1700000900000',\n conversionValue: {\n currencyCode: 'EUR',\n amount: '249.99',\n },\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Lead',\n description:\n 'A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.',\n in: createEvent({\n name: 'form submit',\n id: 'ev-1700000901000',\n timestamp: 1700000901000,\n user: { email: 'user@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000901000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('user@example.com')\n idValue:\n 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n ],\n },\n eventId: 'ev-1700000901000',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const purchaseWithLiFatId: Flow.StepExample = {\n title: 'Purchase with li_fat_id',\n description:\n 'A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.',\n in: getEvent('order complete', {\n id: 'ev-1700000902000',\n timestamp: 1700000902000,\n data: { value: 89.99, currency: 'USD' },\n user: { email: 'buyer@co.com' },\n context: { li_fat_id: ['abc123-fat-id', 0] },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n settings: {\n conversion: {\n map: {\n value: 'data.value',\n currency: { key: 'data.currency', value: 'USD' },\n },\n },\n },\n data: {\n map: {\n user_data: {\n map: {\n li_fat_id: 'context.li_fat_id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000902000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('buyer@co.com')\n idValue:\n '484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66',\n },\n {\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: 'abc123-fat-id',\n },\n ],\n },\n eventId: 'ev-1700000902000',\n conversionValue: {\n currencyCode: 'USD',\n amount: '89.99',\n },\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\n/** A silent rule sends nothing to LinkedIn. */\nexport const silentRule: Flow.StepExample = {\n public: false,\n description: 'A rule with silent: true sends no request to LinkedIn.',\n in: getEvent('page view', { timestamp: 1700000990000 }),\n mapping: { silent: true },\n out: [],\n};\n\n/**\n * No user identifier -- LinkedIn cannot match the event to a person, so the push\n * fails with missing-input instead of counting as delivered. One per event\n * name above, so every example's event without identifiers has its declared\n * outcome.\n */\nfunction withoutIdentifier(name: string, timestamp: number): Flow.StepExample {\n const [entity, action] = name.split(' ');\n return {\n public: false,\n description: `A ${name} event without a user identifier cannot be sent to LinkedIn: the push fails with missing-input instead of counting as delivered.`,\n in: { name, entity, action, timestamp },\n out: [],\n outcome: { status: 'failed', code: 'missing-input', retryable: false },\n };\n}\n\nexport const noIdentifierOrder = withoutIdentifier(\n 'order complete',\n 1700000991000,\n);\nexport const noIdentifierForm = withoutIdentifier('form submit', 1700000992000);\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,r=(r,i)=>{for(var n in i)e(r,n,{get:i[n],enumerable:!0})},i={};r(i,{ApiVersionSchema:()=>s,MappingSchema:()=>l,SettingsSchema:()=>c,UserIdTypeSchema:()=>o,mapping:()=>p,settings:()=>u});import{zodToSchema as n}from"@walkeros/core/dev";import{z as t}from"@walkeros/core/dev";import{z as a}from"@walkeros/core/dev";var o=a.enum(["SHA256_EMAIL","LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID","ACXIOM_ID","ORACLE_MOAT_ID"]),s=a.string().regex(/^\d{6}$/,"API version must be in YYYYMM format (e.g. 202604)"),c=t.object({accessToken:t.string().min(1).describe("LinkedIn OAuth 2.0 Bearer token for Conversions API authentication (like AQX...)"),conversionRuleId:t.string().regex(/^[0-9]+$/,"Conversion rule ID must contain only digits").describe("Default LinkedIn conversion rule ID from Campaign Manager (like 12345678)"),apiVersion:s.describe("Linkedin-Version header value in YYYYMM format (like 202604)").optional(),doNotHash:t.array(t.string()).describe("Array of user data fields that should not be hashed (like ['email'])").optional(),url:t.string().url().describe("Custom URL for LinkedIn Conversions API endpoint (like https://api.linkedin.com/rest/)").optional(),user_data:t.record(t.string(),t.string()).describe("Mapping configuration for user data fields (like { email: 'user.email', li_fat_id: 'context.li_fat_id' })").optional()});import{z as d}from"@walkeros/core/dev";var l=d.object({conversion:d.object({ruleId:d.string().describe("Override conversion rule ID for this event").optional(),value:d.union([d.string(),d.number()]).describe("Conversion monetary value").optional(),currency:d.string().describe("ISO 4217 currency code (like USD, EUR)").optional()}).describe("Per-event conversion override with ruleId, value, and currency").optional()}),u=n(c),p=n(l),m={};r(m,{env:()=>v,step:()=>I});var v={};r(v,{push:()=>f,simulation:()=>h});var f={sendServer:async function(e,r,i){return{ok:!0,data:{}}}},h=["sendServer"],I={};r(I,{lead:()=>g,purchase:()=>_,purchaseWithLiFatId:()=>k});import{getEvent as b}from"@walkeros/core";var A="https://api.linkedin.com/rest/conversionEvents",y={headers:{Authorization:"Bearer s3cr3t","Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0","X-RestLi-Method":"BATCH_CREATE","Linkedin-Version":"202604"}},_={title:"Purchase",description:"A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.",in:b("order complete",{id:"ev-1700000900000",timestamp:17000009e5,data:{total:249.99,currency:"EUR"},user:{email:"jane@example.com"},source:{type:"express",platform:"server"}}),mapping:{settings:{conversion:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"}}}}},out:[["sendServer",A,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:17000009e5,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d"}]},eventId:"ev-1700000900000",conversionValue:{currencyCode:"EUR",amount:"249.99"}}]}),y]]},g={title:"Lead",description:"A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.",in:b("form submit",{id:"ev-1700000901000",timestamp:1700000901e3,user:{email:"user@example.com"},source:{type:"express",platform:"server"}}),mapping:void 0,out:[["sendServer",A,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000901e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"}]},eventId:"ev-1700000901000"}]}),y]]},k={title:"Purchase with li_fat_id",description:"A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.",in:b("order complete",{id:"ev-1700000902000",timestamp:1700000902e3,data:{total:89.99,currency:"USD"},user:{email:"buyer@co.com"},context:{li_fat_id:["abc123-fat-id",0]},source:{type:"express",platform:"server"}}),mapping:{settings:{conversion:{map:{value:"data.total",currency:{key:"data.currency",value:"USD"}}}},data:{map:{user_data:{map:{li_fat_id:"context.li_fat_id"}}}}},out:[["sendServer",A,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000902e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66"},{idType:"LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID",idValue:"abc123-fat-id"}]},eventId:"ev-1700000902000",conversionValue:{currencyCode:"USD",amount:"89.99"}}]}),y]]};export{m as examples,i as schemas};//# sourceMappingURL=dev.mjs.map
1
+ import{createRequire as e}from"module";e(import.meta.url);var i=Object.defineProperty,r=(e,r)=>{for(var n in r)i(e,n,{get:r[n],enumerable:!0})},n={};r(n,{ApiVersionSchema:()=>d,MappingSchema:()=>u,SettingsSchema:()=>c,UserIdTypeSchema:()=>s,mapping:()=>m,settings:()=>p});import{zodToSchema as t}from"@walkeros/core/dev";import{z as o}from"@walkeros/core/dev";import{z as a}from"@walkeros/core/dev";var s=a.enum(["SHA256_EMAIL","LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID","ACXIOM_ID","ORACLE_MOAT_ID"]),d=a.string().regex(/^\d{6}$/,"API version must be in YYYYMM format (e.g. 202604)"),c=o.object({accessToken:o.string().min(1).describe("LinkedIn OAuth 2.0 Bearer token for Conversions API authentication (like AQX...)"),conversionRuleId:o.string().regex(/^[0-9]+$/,"Conversion rule ID must contain only digits").describe("Default LinkedIn conversion rule ID from Campaign Manager (like 12345678)"),apiVersion:d.describe("Linkedin-Version header value in YYYYMM format (like 202604)").optional(),doNotHash:o.array(o.string()).describe("Array of user data fields that should not be hashed (like ['email'])").optional(),url:o.string().url().describe("Custom URL for LinkedIn Conversions API endpoint (like https://api.linkedin.com/rest/)").optional(),user_data:o.record(o.string(),o.string()).describe("Mapping configuration for user data fields (like { email: 'user.email', li_fat_id: 'context.li_fat_id' })").optional()}).strict();import{z as l}from"@walkeros/core/dev";var u=l.object({conversion:l.object({ruleId:l.string().describe("Override conversion rule ID for this event").optional(),value:l.union([l.string(),l.number()]).describe("Conversion monetary value").optional(),currency:l.string().describe("ISO 4217 currency code (like USD, EUR)").optional()}).describe("Per-event conversion override with ruleId, value, and currency").optional()}),p=t(c),m=t(u),v={};r(v,{env:()=>f,step:()=>I});var f={};r(f,{push:()=>h,simulation:()=>b});var h={sendServer:async function(e,i,r){return{data:{}}}},b=["sendServer"],I={};r(I,{lead:()=>S,noIdentifierForm:()=>T,noIdentifierOrder:()=>D,purchase:()=>k,purchaseWithLiFatId:()=>L,silentRule:()=>C});import{createEvent as g,getEvent as A}from"@walkeros/core";var y="https://api.linkedin.com/rest/conversionEvents",_={headers:{Authorization:"Bearer s3cr3t","Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0","X-RestLi-Method":"BATCH_CREATE","Linkedin-Version":"202604"}},k={title:"Purchase",description:"A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.",in:A("order complete",{id:"ev-1700000900000",timestamp:17000009e5,data:{value:249.99,currency:"EUR"},user:{email:"jane@example.com"},source:{type:"express",platform:"server"}}),mapping:{settings:{conversion:{map:{value:"data.value",currency:{key:"data.currency",value:"EUR"}}}}},out:[["sendServer",y,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:17000009e5,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d"}]},eventId:"ev-1700000900000",conversionValue:{currencyCode:"EUR",amount:"249.99"}}]}),_]]},S={title:"Lead",description:"A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.",in:g({name:"form submit",id:"ev-1700000901000",timestamp:1700000901e3,user:{email:"user@example.com"},source:{type:"express",platform:"server"}}),mapping:void 0,out:[["sendServer",y,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000901e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"}]},eventId:"ev-1700000901000"}]}),_]]},L={title:"Purchase with li_fat_id",description:"A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.",in:A("order complete",{id:"ev-1700000902000",timestamp:1700000902e3,data:{value:89.99,currency:"USD"},user:{email:"buyer@co.com"},context:{li_fat_id:["abc123-fat-id",0]},source:{type:"express",platform:"server"}}),mapping:{settings:{conversion:{map:{value:"data.value",currency:{key:"data.currency",value:"USD"}}}},data:{map:{user_data:{map:{li_fat_id:"context.li_fat_id"}}}}},out:[["sendServer",y,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000902e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66"},{idType:"LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID",idValue:"abc123-fat-id"}]},eventId:"ev-1700000902000",conversionValue:{currencyCode:"USD",amount:"89.99"}}]}),_]]},C={public:!1,description:"A rule with silent: true sends no request to LinkedIn.",in:A("page view",{timestamp:170000099e4}),mapping:{silent:!0},out:[]};function R(e,i){const[r,n]=e.split(" ");return{public:!1,description:`A ${e} event without a user identifier cannot be sent to LinkedIn: the push fails with missing-input instead of counting as delivered.`,in:{name:e,entity:r,action:n,timestamp:i},out:[],outcome:{status:"failed",code:"missing-input",retryable:!1}}}var D=R("order complete",1700000991e3),T=R("form submit",1700000992e3);export{v 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/primitives.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\nimport { ApiVersionSchema } from './primitives';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'LinkedIn OAuth 2.0 Bearer token for Conversions API authentication (like AQX...)',\n ),\n conversionRuleId: z\n .string()\n .regex(/^[0-9]+$/, 'Conversion rule ID must contain only digits')\n .describe(\n 'Default LinkedIn conversion rule ID from Campaign Manager (like 12345678)',\n ),\n apiVersion: ApiVersionSchema.describe(\n 'Linkedin-Version header value in YYYYMM format (like 202604)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"Array of user data fields that should not be hashed (like ['email'])\",\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for LinkedIn Conversions API endpoint (like https://api.linkedin.com/rest/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user data fields (like { email: 'user.email', li_fat_id: 'context.li_fat_id' })\",\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * LinkedIn User ID Type Enum\n * Types of user identifiers supported by LinkedIn Conversions API\n */\nexport const UserIdTypeSchema = z.enum([\n 'SHA256_EMAIL',\n 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n 'ACXIOM_ID',\n 'ORACLE_MOAT_ID',\n]);\n\n/**\n * API Version Schema\n * LinkedIn-Version header value in YYYYMM format\n */\nexport const ApiVersionSchema = z\n .string()\n .regex(/^\\d{6}$/, 'API version must be in YYYYMM format (e.g. 202604)');\n","import { z } from '@walkeros/core/dev';\n\n/**\n * LinkedIn Conversions API Mapping Schema\n *\n * Per-event override for conversion rule, value, and currency.\n * The `conversion` field is a mapping value that resolves to an object\n * with optional `ruleId`, `value`, and `currency` keys.\n */\nexport const MappingSchema = z.object({\n conversion: z\n .object({\n ruleId: z\n .string()\n .describe('Override conversion rule ID for this event')\n .optional(),\n value: z\n .union([z.string(), z.number()])\n .describe('Conversion monetary value')\n .optional(),\n currency: z\n .string()\n .describe('ISO 4217 currency code (like USD, EUR)')\n .optional(),\n })\n .describe('Per-event conversion override with ruleId, value, and currency')\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for LinkedIn Conversions API destination\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nasync function mockSendServer(\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n): Promise<SendResponse> {\n return {\n ok: true,\n data: {},\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing LinkedIn Conversions API events without making\n * actual HTTP requests to LinkedIn'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 } from '@walkeros/core';\n\n/**\n * LinkedIn Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), options)` where\n * endpoint = `${settings.url}conversionEvents`\n * body = `{ elements: [conversionEvent] }`\n *\n * Test fixture pins `conversionRuleId = '12345678'` and the default url, so\n * every call targets:\n * https://api.linkedin.com/rest/conversionEvents\n *\n * Each conversion event is emitted with keys in the destination's build order:\n * 1. conversion (`urn:lla:llaPartnerConversion:<ruleId>`)\n * 2. conversionHappenedAt (raw `event.timestamp` in ms)\n * 3. user\n * 4. eventId\n * 5. conversionValue (only when mapping provides a value)\n *\n * `options` carries the Authorization + LinkedIn-specific headers.\n */\nconst ENDPOINT = 'https://api.linkedin.com/rest/conversionEvents';\nconst OPTIONS = {\n headers: {\n Authorization: 'Bearer s3cr3t',\n 'Content-Type': 'application/json',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n 'Linkedin-Version': '202604',\n },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.',\n in: getEvent('order complete', {\n id: 'ev-1700000900000',\n timestamp: 1700000900000,\n data: { total: 249.99, currency: 'EUR' },\n user: { email: 'jane@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n settings: {\n conversion: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'EUR' },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000900000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('jane@example.com')\n idValue:\n '8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d',\n },\n ],\n },\n eventId: 'ev-1700000900000',\n conversionValue: {\n currencyCode: 'EUR',\n amount: '249.99',\n },\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Lead',\n description:\n 'A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.',\n in: getEvent('form submit', {\n id: 'ev-1700000901000',\n timestamp: 1700000901000,\n user: { email: 'user@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000901000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('user@example.com')\n idValue:\n 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n ],\n },\n eventId: 'ev-1700000901000',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const purchaseWithLiFatId: Flow.StepExample = {\n title: 'Purchase with li_fat_id',\n description:\n 'A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.',\n in: getEvent('order complete', {\n id: 'ev-1700000902000',\n timestamp: 1700000902000,\n data: { total: 89.99, currency: 'USD' },\n user: { email: 'buyer@co.com' },\n context: { li_fat_id: ['abc123-fat-id', 0] },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n settings: {\n conversion: {\n map: {\n value: 'data.total',\n currency: { key: 'data.currency', value: 'USD' },\n },\n },\n },\n data: {\n map: {\n user_data: {\n map: {\n li_fat_id: 'context.li_fat_id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000902000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('buyer@co.com')\n idValue:\n '484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66',\n },\n {\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: 'abc123-fat-id',\n },\n ],\n },\n eventId: 'ev-1700000902000',\n conversionValue: {\n currencyCode: 'USD',\n amount: '89.99',\n },\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n"],"mappings":"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","names":["z","z","z"]}
1
+ {"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/primitives.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport * from './primitives';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\nimport { ApiVersionSchema } from './primitives';\n\nexport const SettingsSchema = z\n .object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'LinkedIn OAuth 2.0 Bearer token for Conversions API authentication (like AQX...)',\n ),\n conversionRuleId: z\n .string()\n .regex(/^[0-9]+$/, 'Conversion rule ID must contain only digits')\n .describe(\n 'Default LinkedIn conversion rule ID from Campaign Manager (like 12345678)',\n ),\n apiVersion: ApiVersionSchema.describe(\n 'Linkedin-Version header value in YYYYMM format (like 202604)',\n ).optional(),\n doNotHash: z\n .array(z.string())\n .describe(\n \"Array of user data fields that should not be hashed (like ['email'])\",\n )\n .optional(),\n url: z\n .string()\n .url()\n .describe(\n 'Custom URL for LinkedIn Conversions API endpoint (like https://api.linkedin.com/rest/)',\n )\n .optional(),\n user_data: z\n .record(z.string(), z.string())\n .describe(\n \"Mapping configuration for user data fields (like { email: 'user.email', li_fat_id: 'context.li_fat_id' })\",\n )\n .optional(),\n })\n .strict();\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\n/**\n * LinkedIn User ID Type Enum\n * Types of user identifiers supported by LinkedIn Conversions API\n */\nexport const UserIdTypeSchema = z.enum([\n 'SHA256_EMAIL',\n 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n 'ACXIOM_ID',\n 'ORACLE_MOAT_ID',\n]);\n\n/**\n * API Version Schema\n * LinkedIn-Version header value in YYYYMM format\n */\nexport const ApiVersionSchema = z\n .string()\n .regex(/^\\d{6}$/, 'API version must be in YYYYMM format (e.g. 202604)');\n","import { z } from '@walkeros/core/dev';\n\n/**\n * LinkedIn Conversions API Mapping Schema\n *\n * Per-event override for conversion rule, value, and currency.\n * The `conversion` field is a mapping value that resolves to an object\n * with optional `ruleId`, `value`, and `currency` keys.\n */\nexport const MappingSchema = z.object({\n conversion: z\n .object({\n ruleId: z\n .string()\n .describe('Override conversion rule ID for this event')\n .optional(),\n value: z\n .union([z.string(), z.number()])\n .describe('Conversion monetary value')\n .optional(),\n currency: z\n .string()\n .describe('ISO 4217 currency code (like USD, EUR)')\n .optional(),\n })\n .describe('Per-event conversion override with ruleId, value, and currency')\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { SendDataValue, SendResponse } from '@walkeros/core';\nimport type { SendServerOptions } from '@walkeros/server-core';\nimport type { Env } from '../types';\n\n/**\n * Example environment configurations for LinkedIn Conversions API destination\n *\n * These environments provide standardized mock structures for testing\n * and development without requiring actual HTTP requests.\n */\n\n/**\n * Mock sendServer function that simulates successful HTTP responses\n */\nasync function mockSendServer(\n url: string,\n data?: SendDataValue,\n options?: SendServerOptions,\n): Promise<SendResponse> {\n return {\n data: {},\n };\n}\n\n/**\n * Standard mock environment for push operations\n *\n * Use this for testing LinkedIn Conversions API events without making\n * actual HTTP requests to LinkedIn'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 } from '@walkeros/core';\n\n/**\n * LinkedIn Conversions API step examples.\n *\n * At push time, the destination calls\n * `env.sendServer(endpoint, JSON.stringify(body), options)` where\n * endpoint = `${settings.url}conversionEvents`\n * body = `{ elements: [conversionEvent] }`\n *\n * Test fixture pins `conversionRuleId = '12345678'` and the default url, so\n * every call targets:\n * https://api.linkedin.com/rest/conversionEvents\n *\n * Each conversion event is emitted with keys in the destination's build order:\n * 1. conversion (`urn:lla:llaPartnerConversion:<ruleId>`)\n * 2. conversionHappenedAt (raw `event.timestamp` in ms)\n * 3. user\n * 4. eventId\n * 5. conversionValue (only when mapping provides a value)\n *\n * `options` carries the Authorization + LinkedIn-specific headers.\n */\nconst ENDPOINT = 'https://api.linkedin.com/rest/conversionEvents';\nconst OPTIONS = {\n headers: {\n Authorization: 'Bearer s3cr3t',\n 'Content-Type': 'application/json',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n 'Linkedin-Version': '202604',\n },\n};\n\nexport const purchase: Flow.StepExample = {\n title: 'Purchase',\n description:\n 'A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.',\n in: getEvent('order complete', {\n id: 'ev-1700000900000',\n timestamp: 1700000900000,\n data: { value: 249.99, currency: 'EUR' },\n user: { email: 'jane@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n settings: {\n conversion: {\n map: {\n value: 'data.value',\n currency: { key: 'data.currency', value: 'EUR' },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000900000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('jane@example.com')\n idValue:\n '8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d',\n },\n ],\n },\n eventId: 'ev-1700000900000',\n conversionValue: {\n currencyCode: 'EUR',\n amount: '249.99',\n },\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const lead: Flow.StepExample = {\n title: 'Lead',\n description:\n 'A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.',\n in: createEvent({\n name: 'form submit',\n id: 'ev-1700000901000',\n timestamp: 1700000901000,\n user: { email: 'user@example.com' },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: undefined,\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000901000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('user@example.com')\n idValue:\n 'b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514',\n },\n ],\n },\n eventId: 'ev-1700000901000',\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\nexport const purchaseWithLiFatId: Flow.StepExample = {\n title: 'Purchase with li_fat_id',\n description:\n 'A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.',\n in: getEvent('order complete', {\n id: 'ev-1700000902000',\n timestamp: 1700000902000,\n data: { value: 89.99, currency: 'USD' },\n user: { email: 'buyer@co.com' },\n context: { li_fat_id: ['abc123-fat-id', 0] },\n source: { type: 'express', platform: 'server' },\n }),\n mapping: {\n settings: {\n conversion: {\n map: {\n value: 'data.value',\n currency: { key: 'data.currency', value: 'USD' },\n },\n },\n },\n data: {\n map: {\n user_data: {\n map: {\n li_fat_id: 'context.li_fat_id',\n },\n },\n },\n },\n },\n out: [\n [\n 'sendServer',\n ENDPOINT,\n JSON.stringify({\n elements: [\n {\n conversion: 'urn:lla:llaPartnerConversion:12345678',\n conversionHappenedAt: 1700000902000,\n user: {\n userIds: [\n {\n idType: 'SHA256_EMAIL',\n // sha256('buyer@co.com')\n idValue:\n '484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66',\n },\n {\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: 'abc123-fat-id',\n },\n ],\n },\n eventId: 'ev-1700000902000',\n conversionValue: {\n currencyCode: 'USD',\n amount: '89.99',\n },\n },\n ],\n }),\n OPTIONS,\n ],\n ],\n};\n\n/** A silent rule sends nothing to LinkedIn. */\nexport const silentRule: Flow.StepExample = {\n public: false,\n description: 'A rule with silent: true sends no request to LinkedIn.',\n in: getEvent('page view', { timestamp: 1700000990000 }),\n mapping: { silent: true },\n out: [],\n};\n\n/**\n * No user identifier -- LinkedIn cannot match the event to a person, so the push\n * fails with missing-input instead of counting as delivered. One per event\n * name above, so every example's event without identifiers has its declared\n * outcome.\n */\nfunction withoutIdentifier(name: string, timestamp: number): Flow.StepExample {\n const [entity, action] = name.split(' ');\n return {\n public: false,\n description: `A ${name} event without a user identifier cannot be sent to LinkedIn: the push fails with missing-input instead of counting as delivered.`,\n in: { name, entity, action, timestamp },\n out: [],\n outcome: { status: 'failed', code: 'missing-input', retryable: false },\n };\n}\n\nexport const noIdentifierOrder = withoutIdentifier(\n 'order complete',\n 1700000991000,\n);\nexport const noIdentifierForm = withoutIdentifier('form submit', 1700000992000);\n"],"mappings":"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","names":["z","z","z"]}
@@ -23,12 +23,19 @@ declare namespace env {
23
23
  declare const purchase: Flow.StepExample;
24
24
  declare const lead: Flow.StepExample;
25
25
  declare const purchaseWithLiFatId: Flow.StepExample;
26
+ /** A silent rule sends nothing to LinkedIn. */
27
+ declare const silentRule: Flow.StepExample;
28
+ declare const noIdentifierOrder: Flow.StepExample;
29
+ declare const noIdentifierForm: Flow.StepExample;
26
30
 
27
31
  declare const step_lead: typeof lead;
32
+ declare const step_noIdentifierForm: typeof noIdentifierForm;
33
+ declare const step_noIdentifierOrder: typeof noIdentifierOrder;
28
34
  declare const step_purchase: typeof purchase;
29
35
  declare const step_purchaseWithLiFatId: typeof purchaseWithLiFatId;
36
+ declare const step_silentRule: typeof silentRule;
30
37
  declare namespace step {
31
- export { step_lead as lead, step_purchase as purchase, step_purchaseWithLiFatId as purchaseWithLiFatId };
38
+ export { step_lead as lead, step_noIdentifierForm as noIdentifierForm, step_noIdentifierOrder as noIdentifierOrder, step_purchase as purchase, step_purchaseWithLiFatId as purchaseWithLiFatId, step_silentRule as silentRule };
32
39
  }
33
40
 
34
41
  export { env, step };
@@ -23,12 +23,19 @@ declare namespace env {
23
23
  declare const purchase: Flow.StepExample;
24
24
  declare const lead: Flow.StepExample;
25
25
  declare const purchaseWithLiFatId: Flow.StepExample;
26
+ /** A silent rule sends nothing to LinkedIn. */
27
+ declare const silentRule: Flow.StepExample;
28
+ declare const noIdentifierOrder: Flow.StepExample;
29
+ declare const noIdentifierForm: Flow.StepExample;
26
30
 
27
31
  declare const step_lead: typeof lead;
32
+ declare const step_noIdentifierForm: typeof noIdentifierForm;
33
+ declare const step_noIdentifierOrder: typeof noIdentifierOrder;
28
34
  declare const step_purchase: typeof purchase;
29
35
  declare const step_purchaseWithLiFatId: typeof purchaseWithLiFatId;
36
+ declare const step_silentRule: typeof silentRule;
30
37
  declare namespace step {
31
- export { step_lead as lead, step_purchase as purchase, step_purchaseWithLiFatId as purchaseWithLiFatId };
38
+ export { step_lead as lead, step_noIdentifierForm as noIdentifierForm, step_noIdentifierOrder as noIdentifierOrder, step_purchase as purchase, step_purchaseWithLiFatId as purchaseWithLiFatId, step_silentRule as silentRule };
32
39
  }
33
40
 
34
41
  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
  };
39
38
  }
@@ -46,8 +45,11 @@ var simulation = ["sendServer"];
46
45
  var step_exports = {};
47
46
  __export(step_exports, {
48
47
  lead: () => lead,
48
+ noIdentifierForm: () => noIdentifierForm,
49
+ noIdentifierOrder: () => noIdentifierOrder,
49
50
  purchase: () => purchase,
50
- purchaseWithLiFatId: () => purchaseWithLiFatId
51
+ purchaseWithLiFatId: () => purchaseWithLiFatId,
52
+ silentRule: () => silentRule
51
53
  });
52
54
  var import_core = require("@walkeros/core");
53
55
  var ENDPOINT = "https://api.linkedin.com/rest/conversionEvents";
@@ -66,7 +68,7 @@ var purchase = {
66
68
  in: (0, import_core.getEvent)("order complete", {
67
69
  id: "ev-1700000900000",
68
70
  timestamp: 17000009e5,
69
- data: { total: 249.99, currency: "EUR" },
71
+ data: { value: 249.99, currency: "EUR" },
70
72
  user: { email: "jane@example.com" },
71
73
  source: { type: "express", platform: "server" }
72
74
  }),
@@ -74,7 +76,7 @@ var purchase = {
74
76
  settings: {
75
77
  conversion: {
76
78
  map: {
77
- value: "data.total",
79
+ value: "data.value",
78
80
  currency: { key: "data.currency", value: "EUR" }
79
81
  }
80
82
  }
@@ -113,7 +115,8 @@ var purchase = {
113
115
  var lead = {
114
116
  title: "Lead",
115
117
  description: "A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.",
116
- in: (0, import_core.getEvent)("form submit", {
118
+ in: (0, import_core.createEvent)({
119
+ name: "form submit",
117
120
  id: "ev-1700000901000",
118
121
  timestamp: 1700000901e3,
119
122
  user: { email: "user@example.com" },
@@ -152,7 +155,7 @@ var purchaseWithLiFatId = {
152
155
  in: (0, import_core.getEvent)("order complete", {
153
156
  id: "ev-1700000902000",
154
157
  timestamp: 1700000902e3,
155
- data: { total: 89.99, currency: "USD" },
158
+ data: { value: 89.99, currency: "USD" },
156
159
  user: { email: "buyer@co.com" },
157
160
  context: { li_fat_id: ["abc123-fat-id", 0] },
158
161
  source: { type: "express", platform: "server" }
@@ -161,7 +164,7 @@ var purchaseWithLiFatId = {
161
164
  settings: {
162
165
  conversion: {
163
166
  map: {
164
- value: "data.total",
167
+ value: "data.value",
165
168
  currency: { key: "data.currency", value: "USD" }
166
169
  }
167
170
  }
@@ -210,6 +213,28 @@ var purchaseWithLiFatId = {
210
213
  ]
211
214
  ]
212
215
  };
216
+ var silentRule = {
217
+ public: false,
218
+ description: "A rule with silent: true sends no request to LinkedIn.",
219
+ in: (0, import_core.getEvent)("page view", { timestamp: 170000099e4 }),
220
+ mapping: { silent: true },
221
+ out: []
222
+ };
223
+ function withoutIdentifier(name, timestamp) {
224
+ const [entity, action] = name.split(" ");
225
+ return {
226
+ public: false,
227
+ description: `A ${name} event without a user identifier cannot be sent to LinkedIn: the push fails with missing-input instead of counting as delivered.`,
228
+ in: { name, entity, action, timestamp },
229
+ out: [],
230
+ outcome: { status: "failed", code: "missing-input", retryable: false }
231
+ };
232
+ }
233
+ var noIdentifierOrder = withoutIdentifier(
234
+ "order complete",
235
+ 1700000991e3
236
+ );
237
+ var noIdentifierForm = withoutIdentifier("form submit", 1700000992e3);
213
238
  // Annotate the CommonJS export names for ESM import in node:
214
239
  0 && (module.exports = {
215
240
  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
  };
18
17
  }
@@ -25,10 +24,13 @@ var simulation = ["sendServer"];
25
24
  var step_exports = {};
26
25
  __export(step_exports, {
27
26
  lead: () => lead,
27
+ noIdentifierForm: () => noIdentifierForm,
28
+ noIdentifierOrder: () => noIdentifierOrder,
28
29
  purchase: () => purchase,
29
- purchaseWithLiFatId: () => purchaseWithLiFatId
30
+ purchaseWithLiFatId: () => purchaseWithLiFatId,
31
+ silentRule: () => silentRule
30
32
  });
31
- import { getEvent } from "@walkeros/core";
33
+ import { createEvent, getEvent } from "@walkeros/core";
32
34
  var ENDPOINT = "https://api.linkedin.com/rest/conversionEvents";
33
35
  var OPTIONS = {
34
36
  headers: {
@@ -45,7 +47,7 @@ var purchase = {
45
47
  in: getEvent("order complete", {
46
48
  id: "ev-1700000900000",
47
49
  timestamp: 17000009e5,
48
- data: { total: 249.99, currency: "EUR" },
50
+ data: { value: 249.99, currency: "EUR" },
49
51
  user: { email: "jane@example.com" },
50
52
  source: { type: "express", platform: "server" }
51
53
  }),
@@ -53,7 +55,7 @@ var purchase = {
53
55
  settings: {
54
56
  conversion: {
55
57
  map: {
56
- value: "data.total",
58
+ value: "data.value",
57
59
  currency: { key: "data.currency", value: "EUR" }
58
60
  }
59
61
  }
@@ -92,7 +94,8 @@ var purchase = {
92
94
  var lead = {
93
95
  title: "Lead",
94
96
  description: "A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.",
95
- in: getEvent("form submit", {
97
+ in: createEvent({
98
+ name: "form submit",
96
99
  id: "ev-1700000901000",
97
100
  timestamp: 1700000901e3,
98
101
  user: { email: "user@example.com" },
@@ -131,7 +134,7 @@ var purchaseWithLiFatId = {
131
134
  in: getEvent("order complete", {
132
135
  id: "ev-1700000902000",
133
136
  timestamp: 1700000902e3,
134
- data: { total: 89.99, currency: "USD" },
137
+ data: { value: 89.99, currency: "USD" },
135
138
  user: { email: "buyer@co.com" },
136
139
  context: { li_fat_id: ["abc123-fat-id", 0] },
137
140
  source: { type: "express", platform: "server" }
@@ -140,7 +143,7 @@ var purchaseWithLiFatId = {
140
143
  settings: {
141
144
  conversion: {
142
145
  map: {
143
- value: "data.total",
146
+ value: "data.value",
144
147
  currency: { key: "data.currency", value: "USD" }
145
148
  }
146
149
  }
@@ -189,6 +192,28 @@ var purchaseWithLiFatId = {
189
192
  ]
190
193
  ]
191
194
  };
195
+ var silentRule = {
196
+ public: false,
197
+ description: "A rule with silent: true sends no request to LinkedIn.",
198
+ in: getEvent("page view", { timestamp: 170000099e4 }),
199
+ mapping: { silent: true },
200
+ out: []
201
+ };
202
+ function withoutIdentifier(name, timestamp) {
203
+ const [entity, action] = name.split(" ");
204
+ return {
205
+ public: false,
206
+ description: `A ${name} event without a user identifier cannot be sent to LinkedIn: the push fails with missing-input instead of counting as delivered.`,
207
+ in: { name, entity, action, timestamp },
208
+ out: [],
209
+ outcome: { status: "failed", code: "missing-input", retryable: false }
210
+ };
211
+ }
212
+ var noIdentifierOrder = withoutIdentifier(
213
+ "order complete",
214
+ 1700000991e3
215
+ );
216
+ var noIdentifierForm = withoutIdentifier("form submit", 1700000992e3);
192
217
  export {
193
218
  env_exports as env,
194
219
  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,{DestinationLinkedIn:()=>types_exports,default:()=>index_default,destinationLinkedIn:()=>destinationLinkedIn}),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_core=require("@walkeros/server-core"),import_server_core2=require("@walkeros/server-core"),types_exports={},destinationLinkedIn={type:"linkedin",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,conversionRuleId:conversionRuleId}=settings;accessToken||logger.throw("Config settings accessToken missing"),conversionRuleId||logger.throw("Config settings conversionRuleId missing");const settingsConfig={...settings,accessToken:accessToken,conversionRuleId:conversionRuleId,apiVersion:settings.apiVersion||"202604"};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,env:env,logger:logger,collector:collector}){const{accessToken:accessToken,conversionRuleId:conversionRuleId,apiVersion:apiVersion="202604",doNotHash:doNotHash,url:url="https://api.linkedin.com/rest/",user_data:user_data}=config.settings,userDataCustom=user_data?await(0,import_core.getMappingValue)(event,{map:user_data},{collector:collector}):{},eventData=(0,import_core.isObject)(data)?data:{},userData={...(0,import_core.isObject)(userDataCustom)?userDataCustom:{},...(0,import_core.isObject)(eventData.user_data)?eventData.user_data:{}},email=(0,import_core.isString)(userData.email)?userData.email:(0,import_core.isString)(event.user.email)?event.user.email:void 0,userIds=[];if(email){const normalizedEmail=email.trim().toLowerCase(),idValue=doNotHash?.includes("email")?normalizedEmail:await(0,import_server_core2.getHashServer)(normalizedEmail);userIds.push({idType:"SHA256_EMAIL",idValue:idValue})}const liFatIdRaw=userData.li_fat_id,liFatId=(0,import_core.isString)(liFatIdRaw)?liFatIdRaw:(0,import_core.isArray)(liFatIdRaw)&&(0,import_core.isString)(liFatIdRaw[0])?liFatIdRaw[0]:void 0;if(liFatId&&userIds.push({idType:"LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID",idValue:liFatId}),0===userIds.length)return;let userInfo;const firstName=userData.firstName,lastName=userData.lastName;(0,import_core.isString)(firstName)&&(0,import_core.isString)(lastName)&&firstName&&lastName&&(userInfo={firstName:firstName,lastName:lastName},(0,import_core.isString)(userData.title)&&userData.title&&(userInfo.title=userData.title),(0,import_core.isString)(userData.companyName)&&userData.companyName&&(userInfo.companyName=userData.companyName),(0,import_core.isString)(userData.countryCode)&&userData.countryCode&&(userInfo.countryCode=userData.countryCode));const mappingSettings=rule?.settings||{},conversionResolved=mappingSettings.conversion?await(0,import_core.getMappingValue)(event,mappingSettings.conversion,{collector:collector}):void 0,conversionOverride=(0,import_core.isObject)(conversionResolved)?conversionResolved:{},conversion=`urn:lla:llaPartnerConversion:${(0,import_core.isString)(conversionOverride.ruleId)?conversionOverride.ruleId:conversionRuleId}`;let conversionValue;const valueRaw=conversionOverride.value,currencyRaw=conversionOverride.currency;null!=valueRaw&&(conversionValue={currencyCode:(0,import_core.isString)(currencyRaw)?currencyRaw:"USD",amount:String(valueRaw)});const conversionEvent={conversion:conversion,conversionHappenedAt:event.timestamp,user:{userIds:userIds,...userInfo?{userInfo:userInfo}:{}},eventId:event.id};conversionValue&&(conversionEvent.conversionValue=conversionValue);const body={elements:[conversionEvent]},endpoint=`${url}conversionEvents`;logger.debug("Calling LinkedIn API",{endpoint:endpoint,method:"POST",conversion:conversion,eventId:event.id});const sendServerFn=env?.sendServer||import_server_core.sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`,"Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0","X-RestLi-Method":"BATCH_CREATE","Linkedin-Version":apiVersion}});logger.debug("LinkedIn API response",{ok:!(0,import_core.isObject)(result)||result.ok}),(0,import_core.isObject)(result)&&!1===result.ok&&logger.throw(`LinkedIn API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationLinkedIn;//# 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,{DestinationLinkedIn:()=>types_exports,default:()=>index_default,destinationLinkedIn:()=>destinationLinkedIn}),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_core=require("@walkeros/server-core"),import_server_core2=require("@walkeros/server-core"),send=async function(event,{config:config,rule:rule,data:data,env:env,logger:logger,collector:collector}){const{accessToken:accessToken,conversionRuleId:conversionRuleId,apiVersion:apiVersion="202604",doNotHash:doNotHash,url:url="https://api.linkedin.com/rest/",user_data:user_data}=config.settings,userDataCustom=user_data?await(0,import_core2.getMappingValue)(event,{map:user_data},{collector:collector}):{},eventData=(0,import_core2.isObject)(data)?data:{},userData={...(0,import_core2.isObject)(userDataCustom)?userDataCustom:{},...(0,import_core2.isObject)(eventData.user_data)?eventData.user_data:{}},email=(0,import_core2.isString)(userData.email)?userData.email:(0,import_core2.isString)(event.user.email)?event.user.email:void 0,userIds=[];if(email){const normalizedEmail=email.trim().toLowerCase(),idValue=!doNotHash?.includes("email")?await(0,import_server_core2.getHashServer)(normalizedEmail):normalizedEmail;userIds.push({idType:"SHA256_EMAIL",idValue:idValue})}const liFatIdRaw=userData.li_fat_id,liFatId=(0,import_core2.isString)(liFatIdRaw)?liFatIdRaw:(0,import_core2.isArray)(liFatIdRaw)&&(0,import_core2.isString)(liFatIdRaw[0])?liFatIdRaw[0]:void 0;if(liFatId&&userIds.push({idType:"LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID",idValue:liFatId}),0===userIds.length)throw new import_core2.StepError("No user identifier to send the event with",{code:"missing-input"});let userInfo;const firstName=userData.firstName,lastName=userData.lastName;(0,import_core2.isString)(firstName)&&(0,import_core2.isString)(lastName)&&firstName&&lastName&&(userInfo={firstName:firstName,lastName:lastName},(0,import_core2.isString)(userData.title)&&userData.title&&(userInfo.title=userData.title),(0,import_core2.isString)(userData.companyName)&&userData.companyName&&(userInfo.companyName=userData.companyName),(0,import_core2.isString)(userData.countryCode)&&userData.countryCode&&(userInfo.countryCode=userData.countryCode));const mappingSettings=rule?.settings||{},conversionResolved=mappingSettings.conversion?await(0,import_core2.getMappingValue)(event,mappingSettings.conversion,{collector:collector}):void 0,conversionOverride=(0,import_core2.isObject)(conversionResolved)?conversionResolved:{},conversion=`urn:lla:llaPartnerConversion:${(0,import_core2.isString)(conversionOverride.ruleId)?conversionOverride.ruleId:conversionRuleId}`;let conversionValue;const valueRaw=conversionOverride.value,currencyRaw=conversionOverride.currency;null!=valueRaw&&(conversionValue={currencyCode:(0,import_core2.isString)(currencyRaw)?currencyRaw:"USD",amount:String(valueRaw)});const conversionEvent={conversion:conversion,conversionHappenedAt:event.timestamp,user:{userIds:userIds,...userInfo?{userInfo:userInfo}:{}},eventId:event.id};conversionValue&&(conversionEvent.conversionValue=conversionValue);const body={elements:[conversionEvent]},endpoint=`${url}conversionEvents`;logger.debug("Calling LinkedIn API",{endpoint:endpoint,method:"POST",conversion:conversion,eventId:event.id});const sendServerFn=env?.sendServer||import_server_core.sendServer;await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`,"Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0","X-RestLi-Method":"BATCH_CREATE","Linkedin-Version":apiVersion}})},types_exports={},destinationLinkedIn={type:"linkedin",config:{},async init({config:partialConfig}){const config=function(partialConfig={}){const settings=partialConfig.settings||{},{accessToken:accessToken,conversionRuleId:conversionRuleId}=settings;if(!accessToken||!conversionRuleId){const missing=[...accessToken?[]:["accessToken"],...conversionRuleId?[]:["conversionRuleId"]];throw new import_core.StepError(`Config settings ${missing.join(", ")} missing`,{code:"config"})}const settingsConfig={...settings,accessToken:accessToken,conversionRuleId:conversionRuleId,apiVersion:settings.apiVersion||"202604"};return{...partialConfig,settings:settingsConfig}}(partialConfig);return config},push:async(event,context)=>await async function(event,context){context.rule?.silent||await send(event,context)}(event,context)},index_default=destinationLinkedIn;//# 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/types/index.ts"],"sourcesContent":["import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationLinkedIn from './types';\n\nexport const destinationLinkedIn: Destination = {\n type: 'linkedin',\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 destinationLinkedIn;\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, conversionRuleId } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!conversionRuleId)\n logger.throw('Config settings conversionRuleId missing');\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n conversionRuleId,\n apiVersion: settings.apiVersion || '202604',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n ConversionEventsRequest,\n ConversionValue,\n Env,\n Mapping,\n PushFn,\n UserIdentifier,\n UserInfo,\n} from './types';\nimport { getMappingValue, isArray, isObject, isString } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { getHashServer } from '@walkeros/server-core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, env, logger, collector },\n) {\n const {\n accessToken,\n conversionRuleId,\n apiVersion = '202604',\n doNotHash,\n url = 'https://api.linkedin.com/rest/',\n user_data,\n } = config.settings!;\n\n // Resolve user data from settings-level mapping\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Merge user data sources: config mapping + event mapping data\n const eventData = isObject(data) ? data : {};\n const userData: Record<string, unknown> = {\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n ...(isObject(eventData.user_data) ? eventData.user_data : {}),\n };\n\n // Always try to get email from event.user.email if not already mapped\n const email = isString(userData.email)\n ? userData.email\n : isString(event.user.email)\n ? event.user.email\n : undefined;\n\n // Build userIds array\n const userIds: UserIdentifier[] = [];\n\n // SHA256_EMAIL\n if (email) {\n const normalizedEmail = email.trim().toLowerCase();\n const shouldHash = !doNotHash?.includes('email');\n const idValue = shouldHash\n ? await getHashServer(normalizedEmail)\n : normalizedEmail;\n\n userIds.push({\n idType: 'SHA256_EMAIL',\n idValue,\n });\n }\n\n // LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID from li_fat_id\n // Handle both string and context tuple [value, order] formats\n const liFatIdRaw = userData.li_fat_id;\n const liFatId = isString(liFatIdRaw)\n ? liFatIdRaw\n : isArray(liFatIdRaw) && isString(liFatIdRaw[0])\n ? liFatIdRaw[0]\n : undefined;\n if (liFatId) {\n userIds.push({\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: liFatId,\n });\n }\n\n // Skip event if no user identifiers\n if (userIds.length === 0) return;\n\n // Build optional userInfo\n let userInfo: UserInfo | undefined;\n const firstName = userData.firstName;\n const lastName = userData.lastName;\n if (isString(firstName) && isString(lastName) && firstName && lastName) {\n userInfo = { firstName, lastName };\n if (isString(userData.title) && userData.title)\n userInfo.title = userData.title;\n if (isString(userData.companyName) && userData.companyName)\n userInfo.companyName = userData.companyName;\n if (isString(userData.countryCode) && userData.countryCode)\n userInfo.countryCode = userData.countryCode;\n }\n\n // Resolve per-event conversion override\n const mappingSettings = (rule?.settings || {}) as Mapping;\n const conversionResolved = mappingSettings.conversion\n ? await getMappingValue(event, mappingSettings.conversion, { collector })\n : undefined;\n const conversionOverride = isObject(conversionResolved)\n ? conversionResolved\n : {};\n\n // Build conversion URN\n const ruleId = isString(conversionOverride.ruleId)\n ? conversionOverride.ruleId\n : conversionRuleId;\n const conversion = `urn:lla:llaPartnerConversion:${ruleId}`;\n\n // Build conversion value\n let conversionValue: ConversionValue | undefined;\n const valueRaw = conversionOverride.value;\n const currencyRaw = conversionOverride.currency;\n if (valueRaw !== undefined && valueRaw !== null) {\n conversionValue = {\n currencyCode: isString(currencyRaw) ? currencyRaw : 'USD',\n amount: String(valueRaw),\n };\n }\n\n // Construct the conversion event\n const conversionEvent: ConversionEvent = {\n conversion,\n conversionHappenedAt: event.timestamp,\n user: {\n userIds,\n ...(userInfo ? { userInfo } : {}),\n },\n eventId: event.id,\n };\n\n if (conversionValue) {\n conversionEvent.conversionValue = conversionValue;\n }\n\n // Construct request body\n const body: ConversionEventsRequest = {\n elements: [conversionEvent],\n };\n\n const endpoint = `${url}conversionEvents`;\n\n logger.debug('Calling LinkedIn API', {\n endpoint,\n method: 'POST',\n conversion,\n eventId: event.id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body), {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n 'Linkedin-Version': apiVersion,\n },\n });\n\n logger.debug('LinkedIn API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`LinkedIn API error: ${JSON.stringify(result)}`);\n }\n};\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n accessToken: string;\n conversionRuleId: string;\n apiVersion?: string;\n doNotHash?: string[];\n url?: string;\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n conversion?: WalkerOSMapping.Value;\n}\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// LinkedIn API types\n\nexport type UserIdType =\n | 'SHA256_EMAIL'\n | 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID'\n | 'ACXIOM_ID'\n | 'ORACLE_MOAT_ID';\n\nexport interface UserIdentifier {\n idType: UserIdType;\n idValue: string;\n}\n\nexport interface UserInfo {\n firstName: string;\n lastName: string;\n title?: string;\n companyName?: string;\n countryCode?: string;\n}\n\nexport interface ConversionUser {\n userIds: UserIdentifier[];\n userInfo?: UserInfo;\n}\n\nexport interface ConversionValue {\n currencyCode: string;\n amount: string;\n}\n\nexport interface ConversionEvent {\n conversion: string;\n conversionHappenedAt: number;\n conversionValue?: ConversionValue;\n user: ConversionUser;\n eventId?: string;\n}\n\nexport interface ConversionEventsRequest {\n elements: ConversionEvent[];\n}\n"],"mappings":"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","names":["import_server_core"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationLinkedIn from './types';\n\nexport const destinationLinkedIn: Destination = {\n type: 'linkedin',\n\n config: {},\n\n async init({ config: partialConfig }) {\n const config = getConfig(partialConfig);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationLinkedIn;\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, conversionRuleId } = settings;\n\n if (!accessToken || !conversionRuleId) {\n const missing = [\n ...(accessToken ? [] : ['accessToken']),\n ...(conversionRuleId ? [] : ['conversionRuleId']),\n ];\n throw new StepError(`Config settings ${missing.join(', ')} missing`, {\n code: 'config',\n });\n }\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n conversionRuleId,\n apiVersion: settings.apiVersion || '202604',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n ConversionEventsRequest,\n ConversionValue,\n Env,\n Mapping,\n PushFn,\n UserIdentifier,\n UserInfo,\n} from './types';\nimport {\n getMappingValue,\n isArray,\n isObject,\n isString,\n StepError,\n} from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { getHashServer } from '@walkeros/server-core';\n\n// A silent rule has no linkedin 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, rule, data, env, logger, collector },\n) {\n const {\n accessToken,\n conversionRuleId,\n apiVersion = '202604',\n doNotHash,\n url = 'https://api.linkedin.com/rest/',\n user_data,\n } = config.settings!;\n\n // Resolve user data from settings-level mapping\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Merge user data sources: config mapping + event mapping data\n const eventData = isObject(data) ? data : {};\n const userData: Record<string, unknown> = {\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n ...(isObject(eventData.user_data) ? eventData.user_data : {}),\n };\n\n // Always try to get email from event.user.email if not already mapped\n const email = isString(userData.email)\n ? userData.email\n : isString(event.user.email)\n ? event.user.email\n : undefined;\n\n // Build userIds array\n const userIds: UserIdentifier[] = [];\n\n // SHA256_EMAIL\n if (email) {\n const normalizedEmail = email.trim().toLowerCase();\n const shouldHash = !doNotHash?.includes('email');\n const idValue = shouldHash\n ? await getHashServer(normalizedEmail)\n : normalizedEmail;\n\n userIds.push({\n idType: 'SHA256_EMAIL',\n idValue,\n });\n }\n\n // LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID from li_fat_id\n // Handle both string and context tuple [value, order] formats\n const liFatIdRaw = userData.li_fat_id;\n const liFatId = isString(liFatIdRaw)\n ? liFatIdRaw\n : isArray(liFatIdRaw) && isString(liFatIdRaw[0])\n ? liFatIdRaw[0]\n : undefined;\n if (liFatId) {\n userIds.push({\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: liFatId,\n });\n }\n\n // An event without a user identifier cannot be matched by LinkedIn\n if (userIds.length === 0)\n throw new StepError('No user identifier to send the event with', {\n code: 'missing-input',\n });\n\n // Build optional userInfo\n let userInfo: UserInfo | undefined;\n const firstName = userData.firstName;\n const lastName = userData.lastName;\n if (isString(firstName) && isString(lastName) && firstName && lastName) {\n userInfo = { firstName, lastName };\n if (isString(userData.title) && userData.title)\n userInfo.title = userData.title;\n if (isString(userData.companyName) && userData.companyName)\n userInfo.companyName = userData.companyName;\n if (isString(userData.countryCode) && userData.countryCode)\n userInfo.countryCode = userData.countryCode;\n }\n\n // Resolve per-event conversion override\n const mappingSettings = (rule?.settings || {}) as Mapping;\n const conversionResolved = mappingSettings.conversion\n ? await getMappingValue(event, mappingSettings.conversion, { collector })\n : undefined;\n const conversionOverride = isObject(conversionResolved)\n ? conversionResolved\n : {};\n\n // Build conversion URN\n const ruleId = isString(conversionOverride.ruleId)\n ? conversionOverride.ruleId\n : conversionRuleId;\n const conversion = `urn:lla:llaPartnerConversion:${ruleId}`;\n\n // Build conversion value\n let conversionValue: ConversionValue | undefined;\n const valueRaw = conversionOverride.value;\n const currencyRaw = conversionOverride.currency;\n if (valueRaw !== undefined && valueRaw !== null) {\n conversionValue = {\n currencyCode: isString(currencyRaw) ? currencyRaw : 'USD',\n amount: String(valueRaw),\n };\n }\n\n // Construct the conversion event\n const conversionEvent: ConversionEvent = {\n conversion,\n conversionHappenedAt: event.timestamp,\n user: {\n userIds,\n ...(userInfo ? { userInfo } : {}),\n },\n eventId: event.id,\n };\n\n if (conversionValue) {\n conversionEvent.conversionValue = conversionValue;\n }\n\n // Construct request body\n const body: ConversionEventsRequest = {\n elements: [conversionEvent],\n };\n\n const endpoint = `${url}conversionEvents`;\n\n logger.debug('Calling LinkedIn API', {\n endpoint,\n method: 'POST',\n conversion,\n eventId: event.id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n await sendServerFn(endpoint, JSON.stringify(body), {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n 'Linkedin-Version': apiVersion,\n },\n });\n};\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n accessToken: string;\n conversionRuleId: string;\n apiVersion?: string;\n doNotHash?: string[];\n url?: string;\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n conversion?: WalkerOSMapping.Value;\n}\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// LinkedIn API types\n\nexport type UserIdType =\n | 'SHA256_EMAIL'\n | 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID'\n | 'ACXIOM_ID'\n | 'ORACLE_MOAT_ID';\n\nexport interface UserIdentifier {\n idType: UserIdType;\n idValue: string;\n}\n\nexport interface UserInfo {\n firstName: string;\n lastName: string;\n title?: string;\n companyName?: string;\n countryCode?: string;\n}\n\nexport interface ConversionUser {\n userIds: UserIdentifier[];\n userInfo?: UserInfo;\n}\n\nexport interface ConversionValue {\n currencyCode: string;\n amount: string;\n}\n\nexport interface ConversionEvent {\n conversion: string;\n conversionHappenedAt: number;\n conversionValue?: ConversionValue;\n user: ConversionUser;\n eventId?: string;\n}\n\nexport interface ConversionEventsRequest {\n elements: ConversionEvent[];\n}\n"],"mappings":"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","names":["import_core","import_server_core"]}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{getMappingValue,isArray,isObject,isString}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{getHashServer}from"@walkeros/server-core";var types_exports={},destinationLinkedIn={type:"linkedin",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{accessToken:accessToken,conversionRuleId:conversionRuleId}=settings;accessToken||logger.throw("Config settings accessToken missing"),conversionRuleId||logger.throw("Config settings conversionRuleId missing");const settingsConfig={...settings,accessToken:accessToken,conversionRuleId:conversionRuleId,apiVersion:settings.apiVersion||"202604"};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,env:env,logger:logger,collector:collector}){const{accessToken:accessToken,conversionRuleId:conversionRuleId,apiVersion:apiVersion="202604",doNotHash:doNotHash,url:url="https://api.linkedin.com/rest/",user_data:user_data}=config.settings,userDataCustom=user_data?await getMappingValue(event,{map:user_data},{collector:collector}):{},eventData=isObject(data)?data:{},userData={...isObject(userDataCustom)?userDataCustom:{},...isObject(eventData.user_data)?eventData.user_data:{}},email=isString(userData.email)?userData.email:isString(event.user.email)?event.user.email:void 0,userIds=[];if(email){const normalizedEmail=email.trim().toLowerCase(),idValue=doNotHash?.includes("email")?normalizedEmail:await getHashServer(normalizedEmail);userIds.push({idType:"SHA256_EMAIL",idValue:idValue})}const liFatIdRaw=userData.li_fat_id,liFatId=isString(liFatIdRaw)?liFatIdRaw:isArray(liFatIdRaw)&&isString(liFatIdRaw[0])?liFatIdRaw[0]:void 0;if(liFatId&&userIds.push({idType:"LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID",idValue:liFatId}),0===userIds.length)return;let userInfo;const firstName=userData.firstName,lastName=userData.lastName;isString(firstName)&&isString(lastName)&&firstName&&lastName&&(userInfo={firstName:firstName,lastName:lastName},isString(userData.title)&&userData.title&&(userInfo.title=userData.title),isString(userData.companyName)&&userData.companyName&&(userInfo.companyName=userData.companyName),isString(userData.countryCode)&&userData.countryCode&&(userInfo.countryCode=userData.countryCode));const mappingSettings=rule?.settings||{},conversionResolved=mappingSettings.conversion?await getMappingValue(event,mappingSettings.conversion,{collector:collector}):void 0,conversionOverride=isObject(conversionResolved)?conversionResolved:{},conversion=`urn:lla:llaPartnerConversion:${isString(conversionOverride.ruleId)?conversionOverride.ruleId:conversionRuleId}`;let conversionValue;const valueRaw=conversionOverride.value,currencyRaw=conversionOverride.currency;null!=valueRaw&&(conversionValue={currencyCode:isString(currencyRaw)?currencyRaw:"USD",amount:String(valueRaw)});const conversionEvent={conversion:conversion,conversionHappenedAt:event.timestamp,user:{userIds:userIds,...userInfo?{userInfo:userInfo}:{}},eventId:event.id};conversionValue&&(conversionEvent.conversionValue=conversionValue);const body={elements:[conversionEvent]},endpoint=`${url}conversionEvents`;logger.debug("Calling LinkedIn API",{endpoint:endpoint,method:"POST",conversion:conversion,eventId:event.id});const sendServerFn=env?.sendServer||sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`,"Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0","X-RestLi-Method":"BATCH_CREATE","Linkedin-Version":apiVersion}});logger.debug("LinkedIn API response",{ok:!isObject(result)||result.ok}),isObject(result)&&!1===result.ok&&logger.throw(`LinkedIn API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationLinkedIn;export{types_exports as DestinationLinkedIn,index_default as default,destinationLinkedIn};//# sourceMappingURL=index.mjs.map
1
+ import{createRequire}from"module";createRequire(import.meta.url);import{StepError}from"@walkeros/core";import{getMappingValue,isArray,isObject,isString,StepError as StepError2}from"@walkeros/core";import{sendServer}from"@walkeros/server-core";import{getHashServer}from"@walkeros/server-core";var send=async function(event,{config:config,rule:rule,data:data,env:env,logger:logger,collector:collector}){const{accessToken:accessToken,conversionRuleId:conversionRuleId,apiVersion:apiVersion="202604",doNotHash:doNotHash,url:url="https://api.linkedin.com/rest/",user_data:user_data}=config.settings,userDataCustom=user_data?await getMappingValue(event,{map:user_data},{collector:collector}):{},eventData=isObject(data)?data:{},userData={...isObject(userDataCustom)?userDataCustom:{},...isObject(eventData.user_data)?eventData.user_data:{}},email=isString(userData.email)?userData.email:isString(event.user.email)?event.user.email:void 0,userIds=[];if(email){const normalizedEmail=email.trim().toLowerCase(),idValue=!doNotHash?.includes("email")?await getHashServer(normalizedEmail):normalizedEmail;userIds.push({idType:"SHA256_EMAIL",idValue:idValue})}const liFatIdRaw=userData.li_fat_id,liFatId=isString(liFatIdRaw)?liFatIdRaw:isArray(liFatIdRaw)&&isString(liFatIdRaw[0])?liFatIdRaw[0]:void 0;if(liFatId&&userIds.push({idType:"LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID",idValue:liFatId}),0===userIds.length)throw new StepError2("No user identifier to send the event with",{code:"missing-input"});let userInfo;const firstName=userData.firstName,lastName=userData.lastName;isString(firstName)&&isString(lastName)&&firstName&&lastName&&(userInfo={firstName:firstName,lastName:lastName},isString(userData.title)&&userData.title&&(userInfo.title=userData.title),isString(userData.companyName)&&userData.companyName&&(userInfo.companyName=userData.companyName),isString(userData.countryCode)&&userData.countryCode&&(userInfo.countryCode=userData.countryCode));const mappingSettings=rule?.settings||{},conversionResolved=mappingSettings.conversion?await getMappingValue(event,mappingSettings.conversion,{collector:collector}):void 0,conversionOverride=isObject(conversionResolved)?conversionResolved:{},conversion=`urn:lla:llaPartnerConversion:${isString(conversionOverride.ruleId)?conversionOverride.ruleId:conversionRuleId}`;let conversionValue;const valueRaw=conversionOverride.value,currencyRaw=conversionOverride.currency;null!=valueRaw&&(conversionValue={currencyCode:isString(currencyRaw)?currencyRaw:"USD",amount:String(valueRaw)});const conversionEvent={conversion:conversion,conversionHappenedAt:event.timestamp,user:{userIds:userIds,...userInfo?{userInfo:userInfo}:{}},eventId:event.id};conversionValue&&(conversionEvent.conversionValue=conversionValue);const body={elements:[conversionEvent]},endpoint=`${url}conversionEvents`;logger.debug("Calling LinkedIn API",{endpoint:endpoint,method:"POST",conversion:conversion,eventId:event.id});const sendServerFn=env?.sendServer||sendServer;await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:`Bearer ${accessToken}`,"Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0","X-RestLi-Method":"BATCH_CREATE","Linkedin-Version":apiVersion}})},types_exports={},destinationLinkedIn={type:"linkedin",config:{},async init({config:partialConfig}){const config=function(partialConfig={}){const settings=partialConfig.settings||{},{accessToken:accessToken,conversionRuleId:conversionRuleId}=settings;if(!accessToken||!conversionRuleId){const missing=[...accessToken?[]:["accessToken"],...conversionRuleId?[]:["conversionRuleId"]];throw new StepError(`Config settings ${missing.join(", ")} missing`,{code:"config"})}const settingsConfig={...settings,accessToken:accessToken,conversionRuleId:conversionRuleId,apiVersion:settings.apiVersion||"202604"};return{...partialConfig,settings:settingsConfig}}(partialConfig);return config},push:async(event,context)=>await async function(event,context){context.rule?.silent||await send(event,context)}(event,context)},index_default=destinationLinkedIn;export{types_exports as DestinationLinkedIn,index_default as default,destinationLinkedIn};//# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, conversionRuleId } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!conversionRuleId)\n logger.throw('Config settings conversionRuleId missing');\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n conversionRuleId,\n apiVersion: settings.apiVersion || '202604',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n ConversionEventsRequest,\n ConversionValue,\n Env,\n Mapping,\n PushFn,\n UserIdentifier,\n UserInfo,\n} from './types';\nimport { getMappingValue, isArray, isObject, isString } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { getHashServer } from '@walkeros/server-core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, env, logger, collector },\n) {\n const {\n accessToken,\n conversionRuleId,\n apiVersion = '202604',\n doNotHash,\n url = 'https://api.linkedin.com/rest/',\n user_data,\n } = config.settings!;\n\n // Resolve user data from settings-level mapping\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Merge user data sources: config mapping + event mapping data\n const eventData = isObject(data) ? data : {};\n const userData: Record<string, unknown> = {\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n ...(isObject(eventData.user_data) ? eventData.user_data : {}),\n };\n\n // Always try to get email from event.user.email if not already mapped\n const email = isString(userData.email)\n ? userData.email\n : isString(event.user.email)\n ? event.user.email\n : undefined;\n\n // Build userIds array\n const userIds: UserIdentifier[] = [];\n\n // SHA256_EMAIL\n if (email) {\n const normalizedEmail = email.trim().toLowerCase();\n const shouldHash = !doNotHash?.includes('email');\n const idValue = shouldHash\n ? await getHashServer(normalizedEmail)\n : normalizedEmail;\n\n userIds.push({\n idType: 'SHA256_EMAIL',\n idValue,\n });\n }\n\n // LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID from li_fat_id\n // Handle both string and context tuple [value, order] formats\n const liFatIdRaw = userData.li_fat_id;\n const liFatId = isString(liFatIdRaw)\n ? liFatIdRaw\n : isArray(liFatIdRaw) && isString(liFatIdRaw[0])\n ? liFatIdRaw[0]\n : undefined;\n if (liFatId) {\n userIds.push({\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: liFatId,\n });\n }\n\n // Skip event if no user identifiers\n if (userIds.length === 0) return;\n\n // Build optional userInfo\n let userInfo: UserInfo | undefined;\n const firstName = userData.firstName;\n const lastName = userData.lastName;\n if (isString(firstName) && isString(lastName) && firstName && lastName) {\n userInfo = { firstName, lastName };\n if (isString(userData.title) && userData.title)\n userInfo.title = userData.title;\n if (isString(userData.companyName) && userData.companyName)\n userInfo.companyName = userData.companyName;\n if (isString(userData.countryCode) && userData.countryCode)\n userInfo.countryCode = userData.countryCode;\n }\n\n // Resolve per-event conversion override\n const mappingSettings = (rule?.settings || {}) as Mapping;\n const conversionResolved = mappingSettings.conversion\n ? await getMappingValue(event, mappingSettings.conversion, { collector })\n : undefined;\n const conversionOverride = isObject(conversionResolved)\n ? conversionResolved\n : {};\n\n // Build conversion URN\n const ruleId = isString(conversionOverride.ruleId)\n ? conversionOverride.ruleId\n : conversionRuleId;\n const conversion = `urn:lla:llaPartnerConversion:${ruleId}`;\n\n // Build conversion value\n let conversionValue: ConversionValue | undefined;\n const valueRaw = conversionOverride.value;\n const currencyRaw = conversionOverride.currency;\n if (valueRaw !== undefined && valueRaw !== null) {\n conversionValue = {\n currencyCode: isString(currencyRaw) ? currencyRaw : 'USD',\n amount: String(valueRaw),\n };\n }\n\n // Construct the conversion event\n const conversionEvent: ConversionEvent = {\n conversion,\n conversionHappenedAt: event.timestamp,\n user: {\n userIds,\n ...(userInfo ? { userInfo } : {}),\n },\n eventId: event.id,\n };\n\n if (conversionValue) {\n conversionEvent.conversionValue = conversionValue;\n }\n\n // Construct request body\n const body: ConversionEventsRequest = {\n elements: [conversionEvent],\n };\n\n const endpoint = `${url}conversionEvents`;\n\n logger.debug('Calling LinkedIn API', {\n endpoint,\n method: 'POST',\n conversion,\n eventId: event.id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body), {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n 'Linkedin-Version': apiVersion,\n },\n });\n\n logger.debug('LinkedIn API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`LinkedIn API error: ${JSON.stringify(result)}`);\n }\n};\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n accessToken: string;\n conversionRuleId: string;\n apiVersion?: string;\n doNotHash?: string[];\n url?: string;\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n conversion?: WalkerOSMapping.Value;\n}\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// LinkedIn API types\n\nexport type UserIdType =\n | 'SHA256_EMAIL'\n | 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID'\n | 'ACXIOM_ID'\n | 'ORACLE_MOAT_ID';\n\nexport interface UserIdentifier {\n idType: UserIdType;\n idValue: string;\n}\n\nexport interface UserInfo {\n firstName: string;\n lastName: string;\n title?: string;\n companyName?: string;\n countryCode?: string;\n}\n\nexport interface ConversionUser {\n userIds: UserIdentifier[];\n userInfo?: UserInfo;\n}\n\nexport interface ConversionValue {\n currencyCode: string;\n amount: string;\n}\n\nexport interface ConversionEvent {\n conversion: string;\n conversionHappenedAt: number;\n conversionValue?: ConversionValue;\n user: ConversionUser;\n eventId?: string;\n}\n\nexport interface ConversionEventsRequest {\n elements: ConversionEvent[];\n}\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationLinkedIn from './types';\n\nexport const destinationLinkedIn: Destination = {\n type: 'linkedin',\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 destinationLinkedIn;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type { Config, Settings, PartialConfig } from './types';\nimport { StepError } from '@walkeros/core';\n\nexport function getConfig(partialConfig: PartialConfig = {}): Config {\n const settings: Partial<Settings> = partialConfig.settings || {};\n const { accessToken, conversionRuleId } = settings;\n\n if (!accessToken || !conversionRuleId) {\n const missing = [\n ...(accessToken ? [] : ['accessToken']),\n ...(conversionRuleId ? [] : ['conversionRuleId']),\n ];\n throw new StepError(`Config settings ${missing.join(', ')} missing`, {\n code: 'config',\n });\n }\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n conversionRuleId,\n apiVersion: settings.apiVersion || '202604',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n ConversionEventsRequest,\n ConversionValue,\n Env,\n Mapping,\n PushFn,\n UserIdentifier,\n UserInfo,\n} from './types';\nimport {\n getMappingValue,\n isArray,\n isObject,\n isString,\n StepError,\n} from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { getHashServer } from '@walkeros/server-core';\n\n// A silent rule has no linkedin 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, rule, data, env, logger, collector },\n) {\n const {\n accessToken,\n conversionRuleId,\n apiVersion = '202604',\n doNotHash,\n url = 'https://api.linkedin.com/rest/',\n user_data,\n } = config.settings!;\n\n // Resolve user data from settings-level mapping\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data }, { collector })\n : {};\n\n // Merge user data sources: config mapping + event mapping data\n const eventData = isObject(data) ? data : {};\n const userData: Record<string, unknown> = {\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n ...(isObject(eventData.user_data) ? eventData.user_data : {}),\n };\n\n // Always try to get email from event.user.email if not already mapped\n const email = isString(userData.email)\n ? userData.email\n : isString(event.user.email)\n ? event.user.email\n : undefined;\n\n // Build userIds array\n const userIds: UserIdentifier[] = [];\n\n // SHA256_EMAIL\n if (email) {\n const normalizedEmail = email.trim().toLowerCase();\n const shouldHash = !doNotHash?.includes('email');\n const idValue = shouldHash\n ? await getHashServer(normalizedEmail)\n : normalizedEmail;\n\n userIds.push({\n idType: 'SHA256_EMAIL',\n idValue,\n });\n }\n\n // LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID from li_fat_id\n // Handle both string and context tuple [value, order] formats\n const liFatIdRaw = userData.li_fat_id;\n const liFatId = isString(liFatIdRaw)\n ? liFatIdRaw\n : isArray(liFatIdRaw) && isString(liFatIdRaw[0])\n ? liFatIdRaw[0]\n : undefined;\n if (liFatId) {\n userIds.push({\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: liFatId,\n });\n }\n\n // An event without a user identifier cannot be matched by LinkedIn\n if (userIds.length === 0)\n throw new StepError('No user identifier to send the event with', {\n code: 'missing-input',\n });\n\n // Build optional userInfo\n let userInfo: UserInfo | undefined;\n const firstName = userData.firstName;\n const lastName = userData.lastName;\n if (isString(firstName) && isString(lastName) && firstName && lastName) {\n userInfo = { firstName, lastName };\n if (isString(userData.title) && userData.title)\n userInfo.title = userData.title;\n if (isString(userData.companyName) && userData.companyName)\n userInfo.companyName = userData.companyName;\n if (isString(userData.countryCode) && userData.countryCode)\n userInfo.countryCode = userData.countryCode;\n }\n\n // Resolve per-event conversion override\n const mappingSettings = (rule?.settings || {}) as Mapping;\n const conversionResolved = mappingSettings.conversion\n ? await getMappingValue(event, mappingSettings.conversion, { collector })\n : undefined;\n const conversionOverride = isObject(conversionResolved)\n ? conversionResolved\n : {};\n\n // Build conversion URN\n const ruleId = isString(conversionOverride.ruleId)\n ? conversionOverride.ruleId\n : conversionRuleId;\n const conversion = `urn:lla:llaPartnerConversion:${ruleId}`;\n\n // Build conversion value\n let conversionValue: ConversionValue | undefined;\n const valueRaw = conversionOverride.value;\n const currencyRaw = conversionOverride.currency;\n if (valueRaw !== undefined && valueRaw !== null) {\n conversionValue = {\n currencyCode: isString(currencyRaw) ? currencyRaw : 'USD',\n amount: String(valueRaw),\n };\n }\n\n // Construct the conversion event\n const conversionEvent: ConversionEvent = {\n conversion,\n conversionHappenedAt: event.timestamp,\n user: {\n userIds,\n ...(userInfo ? { userInfo } : {}),\n },\n eventId: event.id,\n };\n\n if (conversionValue) {\n conversionEvent.conversionValue = conversionValue;\n }\n\n // Construct request body\n const body: ConversionEventsRequest = {\n elements: [conversionEvent],\n };\n\n const endpoint = `${url}conversionEvents`;\n\n logger.debug('Calling LinkedIn API', {\n endpoint,\n method: 'POST',\n conversion,\n eventId: event.id,\n });\n\n const sendServerFn = (env as Env)?.sendServer || sendServer;\n await sendServerFn(endpoint, JSON.stringify(body), {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n 'Linkedin-Version': apiVersion,\n },\n });\n};\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n accessToken: string;\n conversionRuleId: string;\n apiVersion?: string;\n doNotHash?: string[];\n url?: string;\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n conversion?: WalkerOSMapping.Value;\n}\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// LinkedIn API types\n\nexport type UserIdType =\n | 'SHA256_EMAIL'\n | 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID'\n | 'ACXIOM_ID'\n | 'ORACLE_MOAT_ID';\n\nexport interface UserIdentifier {\n idType: UserIdType;\n idValue: string;\n}\n\nexport interface UserInfo {\n firstName: string;\n lastName: string;\n title?: string;\n companyName?: string;\n countryCode?: string;\n}\n\nexport interface ConversionUser {\n userIds: UserIdentifier[];\n userInfo?: UserInfo;\n}\n\nexport interface ConversionValue {\n currencyCode: string;\n amount: string;\n}\n\nexport interface ConversionEvent {\n conversion: string;\n conversionHappenedAt: number;\n conversionValue?: ConversionValue;\n user: ConversionUser;\n eventId?: string;\n}\n\nexport interface ConversionEventsRequest {\n elements: ConversionEvent[];\n}\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationLinkedIn from './types';\n\nexport const destinationLinkedIn: Destination = {\n type: 'linkedin',\n\n config: {},\n\n async init({ config: partialConfig }) {\n const config = getConfig(partialConfig);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationLinkedIn;\n"],"mappings":";;;AACA,SAAS,iBAAiB;AAEnB,SAAS,UAAU,gBAA+B,CAAC,GAAW;AACnE,QAAM,WAA8B,cAAc,YAAY,CAAC;AAC/D,QAAM,EAAE,aAAa,iBAAiB,IAAI;AAE1C,MAAI,CAAC,eAAe,CAAC,kBAAkB;AACrC,UAAM,UAAU;AAAA,MACd,GAAI,cAAc,CAAC,IAAI,CAAC,aAAa;AAAA,MACrC,GAAI,mBAAmB,CAAC,IAAI,CAAC,kBAAkB;AAAA,IACjD;AACA,UAAM,IAAI,UAAU,mBAAmB,QAAQ,KAAK,IAAI,CAAC,YAAY;AAAA,MACnE,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,QAAM,iBAA2B;AAAA,IAC/B,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA,YAAY,SAAS,cAAc;AAAA,EACrC;AAEA,SAAO,EAAE,GAAG,eAAe,UAAU,eAAe;AACtD;;;ACfA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAAA;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAGvB,IAAM,OAAe,eAAgB,OAAO,SAAS;AAC1D,MAAI,CAAC,QAAQ,MAAM,OAAQ,OAAM,KAAK,OAAO,OAAO;AACtD;AAEA,IAAM,OAAe,eACnB,OACA,EAAE,QAAQ,MAAM,MAAM,KAAK,QAAQ,UAAU,GAC7C;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA,MAAM;AAAA,IACN;AAAA,EACF,IAAI,OAAO;AAGX,QAAM,iBAAiB,YACnB,MAAM,gBAAgB,OAAO,EAAE,KAAK,UAAU,GAAG,EAAE,UAAU,CAAC,IAC9D,CAAC;AAGL,QAAM,YAAY,SAAS,IAAI,IAAI,OAAO,CAAC;AAC3C,QAAM,WAAoC;AAAA,IACxC,GAAI,SAAS,cAAc,IAAI,iBAAiB,CAAC;AAAA,IACjD,GAAI,SAAS,UAAU,SAAS,IAAI,UAAU,YAAY,CAAC;AAAA,EAC7D;AAGA,QAAM,QAAQ,SAAS,SAAS,KAAK,IACjC,SAAS,QACT,SAAS,MAAM,KAAK,KAAK,IACvB,MAAM,KAAK,QACX;AAGN,QAAM,UAA4B,CAAC;AAGnC,MAAI,OAAO;AACT,UAAM,kBAAkB,MAAM,KAAK,EAAE,YAAY;AACjD,UAAM,aAAa,CAAC,WAAW,SAAS,OAAO;AAC/C,UAAM,UAAU,aACZ,MAAM,cAAc,eAAe,IACnC;AAEJ,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAIA,QAAM,aAAa,SAAS;AAC5B,QAAM,UAAU,SAAS,UAAU,IAC/B,aACA,QAAQ,UAAU,KAAK,SAAS,WAAW,CAAC,CAAC,IAC3C,WAAW,CAAC,IACZ;AACN,MAAI,SAAS;AACX,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAGA,MAAI,QAAQ,WAAW;AACrB,UAAM,IAAIA,WAAU,6CAA6C;AAAA,MAC/D,MAAM;AAAA,IACR,CAAC;AAGH,MAAI;AACJ,QAAM,YAAY,SAAS;AAC3B,QAAM,WAAW,SAAS;AAC1B,MAAI,SAAS,SAAS,KAAK,SAAS,QAAQ,KAAK,aAAa,UAAU;AACtE,eAAW,EAAE,WAAW,SAAS;AACjC,QAAI,SAAS,SAAS,KAAK,KAAK,SAAS;AACvC,eAAS,QAAQ,SAAS;AAC5B,QAAI,SAAS,SAAS,WAAW,KAAK,SAAS;AAC7C,eAAS,cAAc,SAAS;AAClC,QAAI,SAAS,SAAS,WAAW,KAAK,SAAS;AAC7C,eAAS,cAAc,SAAS;AAAA,EACpC;AAGA,QAAM,kBAAmB,MAAM,YAAY,CAAC;AAC5C,QAAM,qBAAqB,gBAAgB,aACvC,MAAM,gBAAgB,OAAO,gBAAgB,YAAY,EAAE,UAAU,CAAC,IACtE;AACJ,QAAM,qBAAqB,SAAS,kBAAkB,IAClD,qBACA,CAAC;AAGL,QAAM,SAAS,SAAS,mBAAmB,MAAM,IAC7C,mBAAmB,SACnB;AACJ,QAAM,aAAa,gCAAgC,MAAM;AAGzD,MAAI;AACJ,QAAM,WAAW,mBAAmB;AACpC,QAAM,cAAc,mBAAmB;AACvC,MAAI,aAAa,UAAa,aAAa,MAAM;AAC/C,sBAAkB;AAAA,MAChB,cAAc,SAAS,WAAW,IAAI,cAAc;AAAA,MACpD,QAAQ,OAAO,QAAQ;AAAA,IACzB;AAAA,EACF;AAGA,QAAM,kBAAmC;AAAA,IACvC;AAAA,IACA,sBAAsB,MAAM;AAAA,IAC5B,MAAM;AAAA,MACJ;AAAA,MACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,IACjC;AAAA,IACA,SAAS,MAAM;AAAA,EACjB;AAEA,MAAI,iBAAiB;AACnB,oBAAgB,kBAAkB;AAAA,EACpC;AAGA,QAAM,OAAgC;AAAA,IACpC,UAAU,CAAC,eAAe;AAAA,EAC5B;AAEA,QAAM,WAAW,GAAG,GAAG;AAEvB,SAAO,MAAM,wBAAwB;AAAA,IACnC;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,SAAS,MAAM;AAAA,EACjB,CAAC;AAED,QAAM,eAAgB,KAAa,cAAc;AACjD,QAAM,aAAa,UAAU,KAAK,UAAU,IAAI,GAAG;AAAA,IACjD,SAAS;AAAA,MACP,eAAe,UAAU,WAAW;AAAA,MACpC,gBAAgB;AAAA,MAChB,6BAA6B;AAAA,MAC7B,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,IACtB;AAAA,EACF,CAAC;AACH;;;AC9KA;;;ACOO,IAAM,sBAAmC;AAAA,EAC9C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,cAAc,GAAG;AACpC,UAAM,SAAS,UAAU,aAAa;AACtC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AACF;AAEA,IAAO,gBAAQ;","names":["StepError"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/server-destination-linkedin",
4
- "version": "4.8.1",
4
+ "version": "4.8.2",
5
5
  "type": "destination",
6
6
  "platform": [
7
7
  "server"
@@ -98,7 +98,7 @@
98
98
  "env": {
99
99
  "push": {
100
100
  "sendServer": {
101
- "$code": "async function(e,r,i){return{ok:!0,data:{}}}"
101
+ "$code": "async function(e,i,r){return{data:{}}}"
102
102
  }
103
103
  },
104
104
  "simulation": [
@@ -177,13 +177,45 @@
177
177
  ]
178
178
  ]
179
179
  },
180
+ "noIdentifierForm": {
181
+ "public": false,
182
+ "description": "A form submit event without a user identifier cannot be sent to LinkedIn: the push fails with missing-input instead of counting as delivered.",
183
+ "in": {
184
+ "name": "form submit",
185
+ "entity": "form",
186
+ "action": "submit",
187
+ "timestamp": 1700000992000
188
+ },
189
+ "out": [],
190
+ "outcome": {
191
+ "status": "failed",
192
+ "code": "missing-input",
193
+ "retryable": false
194
+ }
195
+ },
196
+ "noIdentifierOrder": {
197
+ "public": false,
198
+ "description": "A order complete event without a user identifier cannot be sent to LinkedIn: the push fails with missing-input instead of counting as delivered.",
199
+ "in": {
200
+ "name": "order complete",
201
+ "entity": "order",
202
+ "action": "complete",
203
+ "timestamp": 1700000991000
204
+ },
205
+ "out": [],
206
+ "outcome": {
207
+ "status": "failed",
208
+ "code": "missing-input",
209
+ "retryable": false
210
+ }
211
+ },
180
212
  "purchase": {
181
213
  "title": "Purchase",
182
214
  "description": "A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.",
183
215
  "in": {
184
216
  "name": "order complete",
185
217
  "data": {
186
- "total": 249.99,
218
+ "value": 249.99,
187
219
  "currency": "EUR"
188
220
  },
189
221
  "context": {
@@ -269,7 +301,7 @@
269
301
  "settings": {
270
302
  "conversion": {
271
303
  "map": {
272
- "value": "data.total",
304
+ "value": "data.value",
273
305
  "currency": {
274
306
  "key": "data.currency",
275
307
  "value": "EUR"
@@ -301,7 +333,7 @@
301
333
  "in": {
302
334
  "name": "order complete",
303
335
  "data": {
304
- "total": 89.99,
336
+ "value": 89.99,
305
337
  "currency": "USD"
306
338
  },
307
339
  "context": {
@@ -387,7 +419,7 @@
387
419
  "settings": {
388
420
  "conversion": {
389
421
  "map": {
390
- "value": "data.total",
422
+ "value": "data.value",
391
423
  "currency": {
392
424
  "key": "data.currency",
393
425
  "value": "USD"
@@ -421,6 +453,65 @@
421
453
  }
422
454
  ]
423
455
  ]
456
+ },
457
+ "silentRule": {
458
+ "public": false,
459
+ "description": "A rule with silent: true sends no request to LinkedIn.",
460
+ "in": {
461
+ "name": "page view",
462
+ "data": {
463
+ "domain": "www.example.com",
464
+ "title": "walkerOS documentation",
465
+ "referrer": "https://www.walkeros.io/",
466
+ "search": "?foo=bar",
467
+ "hash": "#hash",
468
+ "id": "/docs/"
469
+ },
470
+ "context": {
471
+ "dev": [
472
+ "test",
473
+ 1
474
+ ]
475
+ },
476
+ "globals": {
477
+ "pagegroup": "docs"
478
+ },
479
+ "custom": {
480
+ "completely": "random"
481
+ },
482
+ "user": {
483
+ "id": "us3r",
484
+ "device": "c00k13",
485
+ "session": "s3ss10n"
486
+ },
487
+ "nested": [
488
+ {
489
+ "entity": "child",
490
+ "data": {
491
+ "is": "subordinated"
492
+ }
493
+ }
494
+ ],
495
+ "consent": {
496
+ "functional": true
497
+ },
498
+ "id": "f0cc5f6fec3d8eeb",
499
+ "trigger": "load",
500
+ "entity": "page",
501
+ "action": "view",
502
+ "timestamp": 1700000990000,
503
+ "timing": 3.14,
504
+ "source": {
505
+ "count": 1,
506
+ "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
507
+ "type": "collector",
508
+ "schema": "4"
509
+ }
510
+ },
511
+ "mapping": {
512
+ "silent": true
513
+ },
514
+ "out": []
424
515
  }
425
516
  }
426
517
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@walkeros/server-destination-linkedin",
3
3
  "description": "LinkedIn Conversions API server destination for walkerOS",
4
- "version": "4.8.1",
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",
39
- "@walkeros/server-core": "4.8.1"
38
+ "@walkeros/core": "4.8.2",
39
+ "@walkeros/server-core": "4.8.2"
40
40
  },
41
41
  "devDependencies": {
42
- "@walkeros/collector": "4.8.1"
42
+ "@walkeros/collector": "4.8.2"
43
43
  },
44
44
  "repository": {
45
45
  "url": "git+https://github.com/elbwalker/walkerOS.git",