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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dev.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e,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:()=>b,settings:()=>h});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()}),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()}),h=(0,c.zodToSchema)(m),b=(0,c.zodToSchema)(f),I={};o(I,{env:()=>g,step:()=>A});var g={};o(g,{push:()=>y,simulation:()=>_});var y={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",{timestamp:17000009e5,data:{total:249.99,currency:"EUR"},user:{email:"jane@example.com"},source:{type:"server",id:"https://shop.example.com",previous_id:""}}),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:"1700000900000-gr0up-1",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",{timestamp:1700000901e3,user:{email:"user@example.com"},source:{type:"server",id:"https://example.com",previous_id:""}}),mapping:void 0,out:[["sendServer",k,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000901e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"}]},eventId:"1700000901000-gr0up-1"}]}),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",{timestamp:1700000902e3,data:{total:89.99,currency:"USD"},user:{email:"buyer@co.com"},context:{li_fat_id:["abc123-fat-id",0]},source:{type:"server",id:"https://shop.example.com",previous_id:""}}),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:"1700000902000-gr0up-1",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:()=>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
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 timestamp: 1700000900000,\n data: { total: 249.99, currency: 'EUR' },\n user: { email: 'jane@example.com' },\n source: { type: 'server', id: 'https://shop.example.com', previous_id: '' },\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: '1700000900000-gr0up-1',\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 timestamp: 1700000901000,\n user: { email: 'user@example.com' },\n source: { type: 'server', id: 'https://example.com', previous_id: '' },\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: '1700000901000-gr0up-1',\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 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: 'server', id: 'https://shop.example.com', previous_id: '' },\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: '1700000902000-gr0up-1',\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.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"]}
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:()=>a,mapping:()=>p,settings:()=>u});import{zodToSchema as n}from"@walkeros/core/dev";import{z as t}from"@walkeros/core/dev";import{z as o}from"@walkeros/core/dev";var a=o.enum(["SHA256_EMAIL","LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID","ACXIOM_ID","ORACLE_MOAT_ID"]),s=o.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:()=>y,purchase:()=>A,purchaseWithLiFatId:()=>k});import{getEvent as b}from"@walkeros/core";var _="https://api.linkedin.com/rest/conversionEvents",g={headers:{Authorization:"Bearer s3cr3t","Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0","X-RestLi-Method":"BATCH_CREATE","Linkedin-Version":"202604"}},A={title:"Purchase",description:"A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.",in:b("order complete",{timestamp:17000009e5,data:{total:249.99,currency:"EUR"},user:{email:"jane@example.com"},source:{type:"server",id:"https://shop.example.com",previous_id:""}}),mapping:{settings:{conversion:{map:{value:"data.total",currency:{key:"data.currency",value:"EUR"}}}}},out:[["sendServer",_,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:17000009e5,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d"}]},eventId:"1700000900000-gr0up-1",conversionValue:{currencyCode:"EUR",amount:"249.99"}}]}),g]]},y={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",{timestamp:1700000901e3,user:{email:"user@example.com"},source:{type:"server",id:"https://example.com",previous_id:""}}),mapping:void 0,out:[["sendServer",_,JSON.stringify({elements:[{conversion:"urn:lla:llaPartnerConversion:12345678",conversionHappenedAt:1700000901e3,user:{userIds:[{idType:"SHA256_EMAIL",idValue:"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514"}]},eventId:"1700000901000-gr0up-1"}]}),g]]},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",{timestamp:1700000902e3,data:{total:89.99,currency:"USD"},user:{email:"buyer@co.com"},context:{li_fat_id:["abc123-fat-id",0]},source:{type:"server",id:"https://shop.example.com",previous_id:""}}),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",_,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:"1700000902000-gr0up-1",conversionValue:{currencyCode:"USD",amount:"89.99"}}]}),g]]};export{m as examples,i as schemas};//# sourceMappingURL=dev.mjs.map
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
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 timestamp: 1700000900000,\n data: { total: 249.99, currency: 'EUR' },\n user: { email: 'jane@example.com' },\n source: { type: 'server', id: 'https://shop.example.com', previous_id: '' },\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: '1700000900000-gr0up-1',\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 timestamp: 1700000901000,\n user: { email: 'user@example.com' },\n source: { type: 'server', id: 'https://example.com', previous_id: '' },\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: '1700000901000-gr0up-1',\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 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: 'server', id: 'https://shop.example.com', previous_id: '' },\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: '1700000902000-gr0up-1',\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.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"]}
@@ -64,10 +64,11 @@ var purchase = {
64
64
  title: "Purchase",
65
65
  description: "A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.",
66
66
  in: (0, import_core.getEvent)("order complete", {
67
+ id: "ev-1700000900000",
67
68
  timestamp: 17000009e5,
68
69
  data: { total: 249.99, currency: "EUR" },
69
70
  user: { email: "jane@example.com" },
70
- source: { type: "server", id: "https://shop.example.com", previous_id: "" }
71
+ source: { type: "express", platform: "server" }
71
72
  }),
72
73
  mapping: {
73
74
  settings: {
@@ -97,7 +98,7 @@ var purchase = {
97
98
  }
98
99
  ]
99
100
  },
100
- eventId: "1700000900000-gr0up-1",
101
+ eventId: "ev-1700000900000",
101
102
  conversionValue: {
102
103
  currencyCode: "EUR",
103
104
  amount: "249.99"
@@ -113,9 +114,10 @@ var lead = {
113
114
  title: "Lead",
114
115
  description: "A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.",
115
116
  in: (0, import_core.getEvent)("form submit", {
117
+ id: "ev-1700000901000",
116
118
  timestamp: 1700000901e3,
117
119
  user: { email: "user@example.com" },
118
- source: { type: "server", id: "https://example.com", previous_id: "" }
120
+ source: { type: "express", platform: "server" }
119
121
  }),
120
122
  mapping: void 0,
121
123
  out: [
@@ -136,7 +138,7 @@ var lead = {
136
138
  }
137
139
  ]
138
140
  },
139
- eventId: "1700000901000-gr0up-1"
141
+ eventId: "ev-1700000901000"
140
142
  }
141
143
  ]
142
144
  }),
@@ -148,11 +150,12 @@ var purchaseWithLiFatId = {
148
150
  title: "Purchase with li_fat_id",
149
151
  description: "A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.",
150
152
  in: (0, import_core.getEvent)("order complete", {
153
+ id: "ev-1700000902000",
151
154
  timestamp: 1700000902e3,
152
155
  data: { total: 89.99, currency: "USD" },
153
156
  user: { email: "buyer@co.com" },
154
157
  context: { li_fat_id: ["abc123-fat-id", 0] },
155
- source: { type: "server", id: "https://shop.example.com", previous_id: "" }
158
+ source: { type: "express", platform: "server" }
156
159
  }),
157
160
  mapping: {
158
161
  settings: {
@@ -195,7 +198,7 @@ var purchaseWithLiFatId = {
195
198
  }
196
199
  ]
197
200
  },
198
- eventId: "1700000902000-gr0up-1",
201
+ eventId: "ev-1700000902000",
199
202
  conversionValue: {
200
203
  currencyCode: "USD",
201
204
  amount: "89.99"
@@ -43,10 +43,11 @@ var purchase = {
43
43
  title: "Purchase",
44
44
  description: "A completed order is sent to the LinkedIn Conversions API with conversion value, currency, and hashed email.",
45
45
  in: getEvent("order complete", {
46
+ id: "ev-1700000900000",
46
47
  timestamp: 17000009e5,
47
48
  data: { total: 249.99, currency: "EUR" },
48
49
  user: { email: "jane@example.com" },
49
- source: { type: "server", id: "https://shop.example.com", previous_id: "" }
50
+ source: { type: "express", platform: "server" }
50
51
  }),
51
52
  mapping: {
52
53
  settings: {
@@ -76,7 +77,7 @@ var purchase = {
76
77
  }
77
78
  ]
78
79
  },
79
- eventId: "1700000900000-gr0up-1",
80
+ eventId: "ev-1700000900000",
80
81
  conversionValue: {
81
82
  currencyCode: "EUR",
82
83
  amount: "249.99"
@@ -92,9 +93,10 @@ var lead = {
92
93
  title: "Lead",
93
94
  description: "A form submission is posted to LinkedIn as a conversion with the SHA-256 hashed email as the user identifier.",
94
95
  in: getEvent("form submit", {
96
+ id: "ev-1700000901000",
95
97
  timestamp: 1700000901e3,
96
98
  user: { email: "user@example.com" },
97
- source: { type: "server", id: "https://example.com", previous_id: "" }
99
+ source: { type: "express", platform: "server" }
98
100
  }),
99
101
  mapping: void 0,
100
102
  out: [
@@ -115,7 +117,7 @@ var lead = {
115
117
  }
116
118
  ]
117
119
  },
118
- eventId: "1700000901000-gr0up-1"
120
+ eventId: "ev-1700000901000"
119
121
  }
120
122
  ]
121
123
  }),
@@ -127,11 +129,12 @@ var purchaseWithLiFatId = {
127
129
  title: "Purchase with li_fat_id",
128
130
  description: "A purchase is sent to LinkedIn with both the hashed email and the first-party li_fat_id tracking identifier.",
129
131
  in: getEvent("order complete", {
132
+ id: "ev-1700000902000",
130
133
  timestamp: 1700000902e3,
131
134
  data: { total: 89.99, currency: "USD" },
132
135
  user: { email: "buyer@co.com" },
133
136
  context: { li_fat_id: ["abc123-fat-id", 0] },
134
- source: { type: "server", id: "https://shop.example.com", previous_id: "" }
137
+ source: { type: "express", platform: "server" }
135
138
  }),
136
139
  mapping: {
137
140
  settings: {
@@ -174,7 +177,7 @@ var purchaseWithLiFatId = {
174
177
  }
175
178
  ]
176
179
  },
177
- eventId: "1700000902000-gr0up-1",
180
+ eventId: "ev-1700000902000",
178
181
  conversionValue: {
179
182
  currencyCode: "USD",
180
183
  amount: "89.99"
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}){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}):{},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=(null==doNotHash?void 0: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=(null==rule?void 0:rule.settings)||{},conversionResolved=mappingSettings.conversion?await(0,import_core.getMappingValue)(event,mappingSettings.conversion):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=(null==env?void 0: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"),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
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 },\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 })\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)\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGO,SAAS,UACd,gBAA+B,CAAC,GAChC,QACQ;AACR,QAAM,WAAY,cAAc,YAAY,CAAC;AAC7C,QAAM,EAAE,aAAa,iBAAiB,IAAI;AAE1C,MAAI,CAAC,YAAa,QAAO,MAAM,qCAAqC;AACpE,MAAI,CAAC;AACH,WAAO,MAAM,0CAA0C;AAEzD,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;;;ACZA,kBAA6D;AAC7D,yBAA2B;AAC3B,IAAAA,sBAA8B;AAEvB,IAAM,OAAe,eAC1B,OACA,EAAE,QAAQ,MAAM,MAAM,KAAK,OAAO,GAClC;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA,MAAM;AAAA,IACN;AAAA,EACF,IAAI,OAAO;AAGX,QAAM,iBAAiB,YACnB,UAAM,6BAAgB,OAAO,EAAE,KAAK,UAAU,CAAC,IAC/C,CAAC;AAGL,QAAM,gBAAY,sBAAS,IAAI,IAAI,OAAO,CAAC;AAC3C,QAAM,WAAoC;AAAA,IACxC,OAAI,sBAAS,cAAc,IAAI,iBAAiB,CAAC;AAAA,IACjD,OAAI,sBAAS,UAAU,SAAS,IAAI,UAAU,YAAY,CAAC;AAAA,EAC7D;AAGA,QAAM,YAAQ,sBAAS,SAAS,KAAK,IACjC,SAAS,YACT,sBAAS,MAAM,KAAK,KAAK,IACvB,MAAM,KAAK,QACX;AAGN,QAAM,UAA4B,CAAC;AAGnC,MAAI,OAAO;AACT,UAAM,kBAAkB,MAAM,KAAK,EAAE,YAAY;AACjD,UAAM,aAAa,EAAC,uCAAW,SAAS;AACxC,UAAM,UAAU,aACZ,UAAM,mCAAc,eAAe,IACnC;AAEJ,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAIA,QAAM,aAAa,SAAS;AAC5B,QAAM,cAAU,sBAAS,UAAU,IAC/B,iBACA,qBAAQ,UAAU,SAAK,sBAAS,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,EAAG;AAG1B,MAAI;AACJ,QAAM,YAAY,SAAS;AAC3B,QAAM,WAAW,SAAS;AAC1B,UAAI,sBAAS,SAAS,SAAK,sBAAS,QAAQ,KAAK,aAAa,UAAU;AACtE,eAAW,EAAE,WAAW,SAAS;AACjC,YAAI,sBAAS,SAAS,KAAK,KAAK,SAAS;AACvC,eAAS,QAAQ,SAAS;AAC5B,YAAI,sBAAS,SAAS,WAAW,KAAK,SAAS;AAC7C,eAAS,cAAc,SAAS;AAClC,YAAI,sBAAS,SAAS,WAAW,KAAK,SAAS;AAC7C,eAAS,cAAc,SAAS;AAAA,EACpC;AAGA,QAAM,mBAAmB,6BAAM,aAAY,CAAC;AAC5C,QAAM,qBAAqB,gBAAgB,aACvC,UAAM,6BAAgB,OAAO,gBAAgB,UAAU,IACvD;AACJ,QAAM,yBAAqB,sBAAS,kBAAkB,IAClD,qBACA,CAAC;AAGL,QAAM,aAAS,sBAAS,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,kBAAc,sBAAS,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,gBAAgB,2BAAa,eAAc;AACjD,QAAM,SAAS,MAAM,aAAa,UAAU,KAAK,UAAU,IAAI,GAAG;AAAA,IAChE,SAAS;AAAA,MACP,eAAe,UAAU,WAAW;AAAA,MACpC,gBAAgB;AAAA,MAChB,6BAA6B;AAAA,MAC7B,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,IACtB;AAAA,EACF,CAAC;AAED,SAAO,MAAM,yBAAyB;AAAA,IACpC,QAAI,sBAAS,MAAM,IAAI,OAAO,KAAK;AAAA,EACrC,CAAC;AAED,UAAI,sBAAS,MAAM,KAAK,OAAO,OAAO,OAAO;AAC3C,WAAO,MAAM,uBAAuB,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,EAC9D;AACF;;;ACxKA;;;AHOO,IAAM,sBAAmC;AAAA,EAC9C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,OAAO,GAAG;AAC5C,UAAM,SAAS,UAAU,eAAe,MAAM;AAC9C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AACF;AAEA,IAAO,gBAAQ;","names":["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, 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"]}
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}){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}):{},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=(null==doNotHash?void 0: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=(null==rule?void 0:rule.settings)||{},conversionResolved=mappingSettings.conversion?await getMappingValue(event,mappingSettings.conversion):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=(null==env?void 0: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{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 +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 },\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 })\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)\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 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,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/server-destination-linkedin",
4
- "version": "3.4.2",
4
+ "version": "4.0.0-next-1777882869103",
5
5
  "type": "destination",
6
6
  "platform": [
7
7
  "server"
@@ -139,42 +139,28 @@
139
139
  "entity": "child",
140
140
  "data": {
141
141
  "is": "subordinated"
142
- },
143
- "nested": [],
144
- "context": {
145
- "element": [
146
- "child",
147
- 0
148
- ]
149
142
  }
150
143
  }
151
144
  ],
152
145
  "consent": {
153
146
  "functional": true
154
147
  },
155
- "id": "1700000901000-gr0up-1",
148
+ "id": "ev-1700000901000",
156
149
  "trigger": "test",
157
150
  "entity": "form",
158
151
  "action": "submit",
159
152
  "timestamp": 1700000901000,
160
153
  "timing": 3.14,
161
- "group": "gr0up",
162
- "count": 1,
163
- "version": {
164
- "source": "3.4.2",
165
- "tagging": 1
166
- },
167
154
  "source": {
168
- "type": "server",
169
- "id": "https://example.com",
170
- "previous_id": ""
155
+ "type": "express",
156
+ "platform": "server"
171
157
  }
172
158
  },
173
159
  "out": [
174
160
  [
175
161
  "sendServer",
176
162
  "https://api.linkedin.com/rest/conversionEvents",
177
- "{\"elements\":[{\"conversion\":\"urn:lla:llaPartnerConversion:12345678\",\"conversionHappenedAt\":1700000901000,\"user\":{\"userIds\":[{\"idType\":\"SHA256_EMAIL\",\"idValue\":\"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514\"}]},\"eventId\":\"1700000901000-gr0up-1\"}]}",
163
+ "{\"elements\":[{\"conversion\":\"urn:lla:llaPartnerConversion:12345678\",\"conversionHappenedAt\":1700000901000,\"user\":{\"userIds\":[{\"idType\":\"SHA256_EMAIL\",\"idValue\":\"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514\"}]},\"eventId\":\"ev-1700000901000\"}]}",
178
164
  {
179
165
  "headers": {
180
166
  "Authorization": "Bearer s3cr3t",
@@ -262,22 +248,15 @@
262
248
  "consent": {
263
249
  "functional": true
264
250
  },
265
- "id": "1700000900000-gr0up-1",
251
+ "id": "ev-1700000900000",
266
252
  "trigger": "load",
267
253
  "entity": "order",
268
254
  "action": "complete",
269
255
  "timestamp": 1700000900000,
270
256
  "timing": 3.14,
271
- "group": "gr0up",
272
- "count": 1,
273
- "version": {
274
- "source": "3.4.2",
275
- "tagging": 1
276
- },
277
257
  "source": {
278
- "type": "server",
279
- "id": "https://shop.example.com",
280
- "previous_id": ""
258
+ "type": "express",
259
+ "platform": "server"
281
260
  }
282
261
  },
283
262
  "mapping": {
@@ -297,7 +276,7 @@
297
276
  [
298
277
  "sendServer",
299
278
  "https://api.linkedin.com/rest/conversionEvents",
300
- "{\"elements\":[{\"conversion\":\"urn:lla:llaPartnerConversion:12345678\",\"conversionHappenedAt\":1700000900000,\"user\":{\"userIds\":[{\"idType\":\"SHA256_EMAIL\",\"idValue\":\"8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d\"}]},\"eventId\":\"1700000900000-gr0up-1\",\"conversionValue\":{\"currencyCode\":\"EUR\",\"amount\":\"249.99\"}}]}",
279
+ "{\"elements\":[{\"conversion\":\"urn:lla:llaPartnerConversion:12345678\",\"conversionHappenedAt\":1700000900000,\"user\":{\"userIds\":[{\"idType\":\"SHA256_EMAIL\",\"idValue\":\"8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d\"}]},\"eventId\":\"ev-1700000900000\",\"conversionValue\":{\"currencyCode\":\"EUR\",\"amount\":\"249.99\"}}]}",
301
280
  {
302
281
  "headers": {
303
282
  "Authorization": "Bearer s3cr3t",
@@ -385,22 +364,15 @@
385
364
  "consent": {
386
365
  "functional": true
387
366
  },
388
- "id": "1700000902000-gr0up-1",
367
+ "id": "ev-1700000902000",
389
368
  "trigger": "load",
390
369
  "entity": "order",
391
370
  "action": "complete",
392
371
  "timestamp": 1700000902000,
393
372
  "timing": 3.14,
394
- "group": "gr0up",
395
- "count": 1,
396
- "version": {
397
- "source": "3.4.2",
398
- "tagging": 1
399
- },
400
373
  "source": {
401
- "type": "server",
402
- "id": "https://shop.example.com",
403
- "previous_id": ""
374
+ "type": "express",
375
+ "platform": "server"
404
376
  }
405
377
  },
406
378
  "mapping": {
@@ -429,7 +401,7 @@
429
401
  [
430
402
  "sendServer",
431
403
  "https://api.linkedin.com/rest/conversionEvents",
432
- "{\"elements\":[{\"conversion\":\"urn:lla:llaPartnerConversion:12345678\",\"conversionHappenedAt\":1700000902000,\"user\":{\"userIds\":[{\"idType\":\"SHA256_EMAIL\",\"idValue\":\"484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66\"},{\"idType\":\"LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID\",\"idValue\":\"abc123-fat-id\"}]},\"eventId\":\"1700000902000-gr0up-1\",\"conversionValue\":{\"currencyCode\":\"USD\",\"amount\":\"89.99\"}}]}",
404
+ "{\"elements\":[{\"conversion\":\"urn:lla:llaPartnerConversion:12345678\",\"conversionHappenedAt\":1700000902000,\"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\"}}]}",
433
405
  {
434
406
  "headers": {
435
407
  "Authorization": "Bearer s3cr3t",
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": "3.4.2",
4
+ "version": "4.0.0-next-1777882869103",
5
5
  "license": "MIT",
6
6
  "exports": {
7
7
  ".": {
@@ -34,11 +34,11 @@
34
34
  "update": "npx npm-check-updates -u && npm update"
35
35
  },
36
36
  "dependencies": {
37
- "@walkeros/core": "3.4.2",
38
- "@walkeros/server-core": "3.4.2"
37
+ "@walkeros/core": "4.0.0-next-1777882869103",
38
+ "@walkeros/server-core": "4.0.0-next-1777882869103"
39
39
  },
40
40
  "devDependencies": {
41
- "@walkeros/collector": "3.4.2"
41
+ "@walkeros/collector": "4.0.0-next-1777882869103"
42
42
  },
43
43
  "repository": {
44
44
  "url": "git+https://github.com/elbwalker/walkerOS.git",