@walkeros/server-destination-twitter 4.0.0-next-1777463920154 → 4.0.0
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/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/walkerOS.json +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var mod,__create=Object.create,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty,__copyProps=(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},__toESM=(mod,isNodeMode,target)=>(target=null!=mod?__create(__getProtoOf(mod)):{},__copyProps(!isNodeMode&&mod&&mod.__esModule?target:__defProp(target,"default",{value:mod,enumerable:!0}),mod)),index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationTwitter:()=>types_exports,default:()=>index_default,destinationTwitter:()=>destinationTwitter}),module.exports=(mod=index_exports,__copyProps(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core"),import_server_core=require("@walkeros/server-core"),import_oauth_1=__toESM(require("oauth-1.0a")),import_crypto=__toESM(require("crypto"));function normalizeString(value){return(0,import_core.isString)(value)&&value.length>0?value:(0,import_core.isArray)(value)&&(0,import_core.isString)(value[0])&&value[0].length>0?value[0]:void 0}var types_exports={},destinationTwitter={type:"twitter",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{pixelId:pixelId,eventId:eventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret}=settings;pixelId||logger.throw("Config settings pixelId missing"),eventId||logger.throw("Config settings eventId missing"),consumerKey||logger.throw("Config settings consumerKey missing"),consumerSecret||logger.throw("Config settings consumerSecret missing"),accessToken||logger.throw("Config settings accessToken missing"),accessTokenSecret||logger.throw("Config settings accessTokenSecret missing");const settingsConfig={...settings,pixelId:pixelId,eventId:eventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret,apiVersion:settings.apiVersion||"12"};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{pixelId:pixelId,eventId:defaultEventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret,apiVersion:apiVersion="12",doNotHash:doNotHash,url:url="https://ads-api.x.com/",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:{}},identifiers=[],emailRaw=(0,import_core.isString)(userData.email)?userData.email:(0,import_core.isString)(event.user.email)?event.user.email:void 0;if(emailRaw){const normalizedEmail=emailRaw.trim().toLowerCase(),idValue=doNotHash?.includes("email")?normalizedEmail:await(0,import_server_core.getHashServer)(normalizedEmail);identifiers.push({hashed_email:idValue})}const phoneRaw=(0,import_core.isString)(userData.phone)?userData.phone:(0,import_core.isString)(event.user.phone)?event.user.phone:void 0;if(phoneRaw){const normalizedPhone=phoneRaw.trim(),idValue=doNotHash?.includes("phone")?normalizedPhone:await(0,import_server_core.getHashServer)(normalizedPhone);identifiers.push({hashed_phone_number:idValue})}const twclid=normalizeString(userData.twclid);twclid&&identifiers.push({twclid:twclid});const ipAddress=normalizeString(userData.ip_address);ipAddress&&identifiers.push({ip_address:ipAddress});const userAgent=normalizeString(userData.user_agent);if(userAgent&&identifiers.push({user_agent:userAgent}),!identifiers.some(id=>"twclid"in id||"hashed_email"in id||"hashed_phone_number"in id))return;const mappingSettings=rule?.settings||{},eventIdResolved=mappingSettings.eventId?await(0,import_core.getMappingValue)(event,mappingSettings.eventId):void 0,valueResolved=void 0!==mappingSettings.value?await(0,import_core.getMappingValue)(event,mappingSettings.value):void 0,numberItemsResolved=void 0!==mappingSettings.number_items?await(0,import_core.getMappingValue)(event,mappingSettings.number_items):void 0,descriptionResolved=void 0!==mappingSettings.description?await(0,import_core.getMappingValue)(event,mappingSettings.description):void 0,resolvedEventId=(0,import_core.isString)(eventIdResolved)?eventIdResolved:defaultEventId,conversion={conversion_time:new Date(event.timestamp).toISOString(),event_id:resolvedEventId,identifiers:identifiers,conversion_id:event.id};null!=valueResolved&&(conversion.value=String(valueResolved)),(0,import_core.isNumber)(numberItemsResolved)&&(conversion.number_items=numberItemsResolved),(0,import_core.isString)(descriptionResolved)&&descriptionResolved.length>0&&(conversion.description=descriptionResolved);const body={conversions:[conversion]},endpoint=`${url}${apiVersion}/measurement/conversions/${pixelId}`,oauth=new import_oauth_1.default({consumer:{key:consumerKey,secret:consumerSecret},signature_method:"HMAC-SHA1",hash_function:(baseString,key)=>import_crypto.default.createHmac("sha1",key).update(baseString).digest("base64")}),authHeader=oauth.toHeader(oauth.authorize({url:endpoint,method:"POST"},{key:accessToken,secret:accessTokenSecret}));logger.debug("Calling X Conversions API",{endpoint:endpoint,method:"POST",event_id:resolvedEventId,conversion_id:event.id});const sendServerFn=env?.sendServer||import_server_core.sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:authHeader.Authorization,"Content-Type":"application/json"}});logger.debug("X Conversions API response",{ok:!(0,import_core.isObject)(result)||result.ok}),(0,import_core.isObject)(result)&&!1===result.ok&&logger.throw(`X Conversions API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationTwitter;//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";var mod,__create=Object.create,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty,__copyProps=(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},__toESM=(mod,isNodeMode,target)=>(target=null!=mod?__create(__getProtoOf(mod)):{},__copyProps(!isNodeMode&&mod&&mod.__esModule?target:__defProp(target,"default",{value:mod,enumerable:!0}),mod)),index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationTwitter:()=>types_exports,default:()=>index_default,destinationTwitter:()=>destinationTwitter}),module.exports=(mod=index_exports,__copyProps(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core"),import_server_core=require("@walkeros/server-core"),import_oauth_1=__toESM(require("oauth-1.0a")),import_crypto=__toESM(require("crypto"));function normalizeString(value){return(0,import_core.isString)(value)&&value.length>0?value:(0,import_core.isArray)(value)&&(0,import_core.isString)(value[0])&&value[0].length>0?value[0]:void 0}var types_exports={},destinationTwitter={type:"twitter",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{pixelId:pixelId,eventId:eventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret}=settings;pixelId||logger.throw("Config settings pixelId missing"),eventId||logger.throw("Config settings eventId missing"),consumerKey||logger.throw("Config settings consumerKey missing"),consumerSecret||logger.throw("Config settings consumerSecret missing"),accessToken||logger.throw("Config settings accessToken missing"),accessTokenSecret||logger.throw("Config settings accessTokenSecret missing");const settingsConfig={...settings,pixelId:pixelId,eventId:eventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret,apiVersion:settings.apiVersion||"12"};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{pixelId:pixelId,eventId:defaultEventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret,apiVersion:apiVersion="12",doNotHash:doNotHash,url:url="https://ads-api.x.com/",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:{}},identifiers=[],emailRaw=(0,import_core.isString)(userData.email)?userData.email:(0,import_core.isString)(event.user.email)?event.user.email:void 0;if(emailRaw){const normalizedEmail=emailRaw.trim().toLowerCase(),idValue=doNotHash?.includes("email")?normalizedEmail:await(0,import_server_core.getHashServer)(normalizedEmail);identifiers.push({hashed_email:idValue})}const phoneRaw=(0,import_core.isString)(userData.phone)?userData.phone:(0,import_core.isString)(event.user.phone)?event.user.phone:void 0;if(phoneRaw){const normalizedPhone=phoneRaw.trim(),idValue=doNotHash?.includes("phone")?normalizedPhone:await(0,import_server_core.getHashServer)(normalizedPhone);identifiers.push({hashed_phone_number:idValue})}const twclid=normalizeString(userData.twclid);twclid&&identifiers.push({twclid:twclid});const ipAddress=normalizeString(userData.ip_address);ipAddress&&identifiers.push({ip_address:ipAddress});const userAgent=normalizeString(userData.user_agent);if(userAgent&&identifiers.push({user_agent:userAgent}),!identifiers.some(id=>"twclid"in id||"hashed_email"in id||"hashed_phone_number"in id))return;const mappingSettings=rule?.settings||{},eventIdResolved=mappingSettings.eventId?await(0,import_core.getMappingValue)(event,mappingSettings.eventId,{collector:collector}):void 0,valueResolved=void 0!==mappingSettings.value?await(0,import_core.getMappingValue)(event,mappingSettings.value,{collector:collector}):void 0,numberItemsResolved=void 0!==mappingSettings.number_items?await(0,import_core.getMappingValue)(event,mappingSettings.number_items,{collector:collector}):void 0,descriptionResolved=void 0!==mappingSettings.description?await(0,import_core.getMappingValue)(event,mappingSettings.description,{collector:collector}):void 0,resolvedEventId=(0,import_core.isString)(eventIdResolved)?eventIdResolved:defaultEventId,conversion={conversion_time:new Date(event.timestamp).toISOString(),event_id:resolvedEventId,identifiers:identifiers,conversion_id:event.id};null!=valueResolved&&(conversion.value=String(valueResolved)),(0,import_core.isNumber)(numberItemsResolved)&&(conversion.number_items=numberItemsResolved),(0,import_core.isString)(descriptionResolved)&&descriptionResolved.length>0&&(conversion.description=descriptionResolved);const body={conversions:[conversion]},endpoint=`${url}${apiVersion}/measurement/conversions/${pixelId}`,oauth=new import_oauth_1.default({consumer:{key:consumerKey,secret:consumerSecret},signature_method:"HMAC-SHA1",hash_function:(baseString,key)=>import_crypto.default.createHmac("sha1",key).update(baseString).digest("base64")}),authHeader=oauth.toHeader(oauth.authorize({url:endpoint,method:"POST"},{key:accessToken,secret:accessTokenSecret}));logger.debug("Calling X Conversions API",{endpoint:endpoint,method:"POST",event_id:resolvedEventId,conversion_id:event.id});const sendServerFn=env?.sendServer||import_server_core.sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:authHeader.Authorization,"Content-Type":"application/json"}});logger.debug("X Conversions API response",{ok:!(0,import_core.isObject)(result)||result.ok}),(0,import_core.isObject)(result)&&!1===result.ok&&logger.throw(`X Conversions API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationTwitter;//# 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 DestinationTwitter from './types';\n\nexport const destinationTwitter: Destination = {\n type: 'twitter',\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 destinationTwitter;\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 {\n pixelId,\n eventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n } = settings;\n\n if (!pixelId) logger.throw('Config settings pixelId missing');\n if (!eventId) logger.throw('Config settings eventId missing');\n if (!consumerKey) logger.throw('Config settings consumerKey missing');\n if (!consumerSecret) logger.throw('Config settings consumerSecret missing');\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!accessTokenSecret)\n logger.throw('Config settings accessTokenSecret missing');\n\n const settingsConfig: Settings = {\n ...settings,\n pixelId,\n eventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n apiVersion: settings.apiVersion || '12',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n ConversionsRequest,\n Env,\n Identifier,\n Mapping,\n PushFn,\n Settings,\n} from './types';\nimport {\n getMappingValue,\n isArray,\n isNumber,\n isObject,\n isString,\n} from '@walkeros/core';\nimport { sendServer, getHashServer } from '@walkeros/server-core';\nimport OAuth from 'oauth-1.0a';\nimport crypto from 'crypto';\n\nfunction normalizeString(value: unknown): string | undefined {\n if (isString(value) && value.length > 0) return value;\n if (isArray(value) && isString(value[0]) && value[0].length > 0)\n return value[0];\n return undefined;\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, env, logger },\n) {\n const {\n pixelId,\n eventId: defaultEventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n apiVersion = '12',\n doNotHash,\n url = 'https://ads-api.x.com/',\n user_data,\n } = config.settings as 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 // Build identifiers array (each is a single-key object)\n const identifiers: Identifier[] = [];\n\n // hashed_email\n const emailRaw = isString(userData.email)\n ? userData.email\n : isString(event.user.email)\n ? event.user.email\n : undefined;\n if (emailRaw) {\n const normalizedEmail = emailRaw.trim().toLowerCase();\n const shouldHash = !doNotHash?.includes('email');\n const idValue = shouldHash\n ? await getHashServer(normalizedEmail)\n : normalizedEmail;\n identifiers.push({ hashed_email: idValue });\n }\n\n // hashed_phone_number\n const phoneRaw = isString(userData.phone)\n ? userData.phone\n : isString(event.user.phone)\n ? event.user.phone\n : undefined;\n if (phoneRaw) {\n const normalizedPhone = phoneRaw.trim();\n const shouldHash = !doNotHash?.includes('phone');\n const idValue = shouldHash\n ? await getHashServer(normalizedPhone)\n : normalizedPhone;\n identifiers.push({ hashed_phone_number: idValue });\n }\n\n // twclid (pass-through, handles context tuple [value, order])\n const twclid = normalizeString(userData.twclid);\n if (twclid) {\n identifiers.push({ twclid });\n }\n\n // ip_address (pass-through, secondary)\n const ipAddress = normalizeString(userData.ip_address);\n if (ipAddress) {\n identifiers.push({ ip_address: ipAddress });\n }\n\n // user_agent (pass-through, secondary)\n const userAgent = normalizeString(userData.user_agent);\n if (userAgent) {\n identifiers.push({ user_agent: userAgent });\n }\n\n // Skip event if no primary identifier is present\n const hasPrimary = identifiers.some(\n (id) =>\n 'twclid' in id || 'hashed_email' in id || 'hashed_phone_number' in id,\n );\n if (!hasPrimary) return;\n\n // Resolve per-event mapping settings\n const mappingSettings = (rule?.settings || {}) as Mapping;\n const eventIdResolved = mappingSettings.eventId\n ? await getMappingValue(event, mappingSettings.eventId)\n : undefined;\n const valueResolved =\n mappingSettings.value !== undefined\n ? await getMappingValue(event, mappingSettings.value)\n : undefined;\n const numberItemsResolved =\n mappingSettings.number_items !== undefined\n ? await getMappingValue(event, mappingSettings.number_items)\n : undefined;\n const descriptionResolved =\n mappingSettings.description !== undefined\n ? await getMappingValue(event, mappingSettings.description)\n : undefined;\n\n const resolvedEventId = isString(eventIdResolved)\n ? eventIdResolved\n : defaultEventId;\n\n // Construct conversion\n const conversion: ConversionEvent = {\n conversion_time: new Date(event.timestamp).toISOString(),\n event_id: resolvedEventId,\n identifiers,\n conversion_id: event.id,\n };\n\n if (valueResolved !== undefined && valueResolved !== null) {\n conversion.value = String(valueResolved);\n }\n\n if (isNumber(numberItemsResolved)) {\n conversion.number_items = numberItemsResolved;\n }\n\n if (isString(descriptionResolved) && descriptionResolved.length > 0) {\n conversion.description = descriptionResolved;\n }\n\n const body: ConversionsRequest = {\n conversions: [conversion],\n };\n\n const endpoint = `${url}${apiVersion}/measurement/conversions/${pixelId}`;\n\n // Generate OAuth 1.0a header (stateless, safe to create per-request)\n const oauth = new OAuth({\n consumer: { key: consumerKey, secret: consumerSecret },\n signature_method: 'HMAC-SHA1',\n hash_function(baseString: string, key: string) {\n return crypto.createHmac('sha1', key).update(baseString).digest('base64');\n },\n });\n\n const authHeader = oauth.toHeader(\n oauth.authorize(\n { url: endpoint, method: 'POST' },\n { key: accessToken, secret: accessTokenSecret },\n ),\n );\n\n logger.debug('Calling X Conversions API', {\n endpoint,\n method: 'POST',\n event_id: resolvedEventId,\n conversion_id: 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: authHeader.Authorization,\n 'Content-Type': 'application/json',\n },\n });\n\n logger.debug('X Conversions API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`X Conversions 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 pixelId: string;\n eventId: string;\n consumerKey: string;\n consumerSecret: string;\n accessToken: string;\n accessTokenSecret: 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 eventId?: WalkerOSMapping.Value;\n value?: WalkerOSMapping.Value;\n currency?: WalkerOSMapping.Value;\n number_items?: WalkerOSMapping.Value;\n description?: 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// X (Twitter) Conversions API types\n\n/**\n * User identifier -- each is a single-key object.\n * X requires at least one primary identifier (twclid, hashed_email, hashed_phone_number).\n * ip_address and user_agent are secondary identifiers.\n */\nexport type Identifier =\n | { twclid: string }\n | { hashed_email: string }\n | { hashed_phone_number: string }\n | { ip_address: string }\n | { user_agent: string };\n\n/** Product/content detail within a conversion */\nexport interface Content {\n content_id?: string;\n content_name?: string;\n content_type?: string;\n content_price?: number;\n num_items?: number;\n content_group_id?: string;\n}\n\n/** A single conversion event in the payload */\nexport interface ConversionEvent {\n conversion_time: string;\n event_id: string;\n identifiers: Identifier[];\n conversion_id?: string;\n value?: string;\n number_items?: number;\n description?: string;\n contents?: Content[];\n}\n\n/** Top-level request body for X Conversions API */\nexport interface ConversionsRequest {\n conversions: ConversionEvent[];\n}\n"],"mappings":"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","names":["OAuth","crypto"]}
|
|
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 DestinationTwitter from './types';\n\nexport const destinationTwitter: Destination = {\n type: 'twitter',\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 destinationTwitter;\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 {\n pixelId,\n eventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n } = settings;\n\n if (!pixelId) logger.throw('Config settings pixelId missing');\n if (!eventId) logger.throw('Config settings eventId missing');\n if (!consumerKey) logger.throw('Config settings consumerKey missing');\n if (!consumerSecret) logger.throw('Config settings consumerSecret missing');\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!accessTokenSecret)\n logger.throw('Config settings accessTokenSecret missing');\n\n const settingsConfig: Settings = {\n ...settings,\n pixelId,\n eventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n apiVersion: settings.apiVersion || '12',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n ConversionsRequest,\n Env,\n Identifier,\n Mapping,\n PushFn,\n Settings,\n} from './types';\nimport {\n getMappingValue,\n isArray,\n isNumber,\n isObject,\n isString,\n} from '@walkeros/core';\nimport { sendServer, getHashServer } from '@walkeros/server-core';\nimport OAuth from 'oauth-1.0a';\nimport crypto from 'crypto';\n\nfunction normalizeString(value: unknown): string | undefined {\n if (isString(value) && value.length > 0) return value;\n if (isArray(value) && isString(value[0]) && value[0].length > 0)\n return value[0];\n return undefined;\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, env, logger, collector },\n) {\n const {\n pixelId,\n eventId: defaultEventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n apiVersion = '12',\n doNotHash,\n url = 'https://ads-api.x.com/',\n user_data,\n } = config.settings as 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 // Build identifiers array (each is a single-key object)\n const identifiers: Identifier[] = [];\n\n // hashed_email\n const emailRaw = isString(userData.email)\n ? userData.email\n : isString(event.user.email)\n ? event.user.email\n : undefined;\n if (emailRaw) {\n const normalizedEmail = emailRaw.trim().toLowerCase();\n const shouldHash = !doNotHash?.includes('email');\n const idValue = shouldHash\n ? await getHashServer(normalizedEmail)\n : normalizedEmail;\n identifiers.push({ hashed_email: idValue });\n }\n\n // hashed_phone_number\n const phoneRaw = isString(userData.phone)\n ? userData.phone\n : isString(event.user.phone)\n ? event.user.phone\n : undefined;\n if (phoneRaw) {\n const normalizedPhone = phoneRaw.trim();\n const shouldHash = !doNotHash?.includes('phone');\n const idValue = shouldHash\n ? await getHashServer(normalizedPhone)\n : normalizedPhone;\n identifiers.push({ hashed_phone_number: idValue });\n }\n\n // twclid (pass-through, handles context tuple [value, order])\n const twclid = normalizeString(userData.twclid);\n if (twclid) {\n identifiers.push({ twclid });\n }\n\n // ip_address (pass-through, secondary)\n const ipAddress = normalizeString(userData.ip_address);\n if (ipAddress) {\n identifiers.push({ ip_address: ipAddress });\n }\n\n // user_agent (pass-through, secondary)\n const userAgent = normalizeString(userData.user_agent);\n if (userAgent) {\n identifiers.push({ user_agent: userAgent });\n }\n\n // Skip event if no primary identifier is present\n const hasPrimary = identifiers.some(\n (id) =>\n 'twclid' in id || 'hashed_email' in id || 'hashed_phone_number' in id,\n );\n if (!hasPrimary) return;\n\n // Resolve per-event mapping settings\n const mappingSettings = (rule?.settings || {}) as Mapping;\n const eventIdResolved = mappingSettings.eventId\n ? await getMappingValue(event, mappingSettings.eventId, { collector })\n : undefined;\n const valueResolved =\n mappingSettings.value !== undefined\n ? await getMappingValue(event, mappingSettings.value, { collector })\n : undefined;\n const numberItemsResolved =\n mappingSettings.number_items !== undefined\n ? await getMappingValue(event, mappingSettings.number_items, {\n collector,\n })\n : undefined;\n const descriptionResolved =\n mappingSettings.description !== undefined\n ? await getMappingValue(event, mappingSettings.description, {\n collector,\n })\n : undefined;\n\n const resolvedEventId = isString(eventIdResolved)\n ? eventIdResolved\n : defaultEventId;\n\n // Construct conversion\n const conversion: ConversionEvent = {\n conversion_time: new Date(event.timestamp).toISOString(),\n event_id: resolvedEventId,\n identifiers,\n conversion_id: event.id,\n };\n\n if (valueResolved !== undefined && valueResolved !== null) {\n conversion.value = String(valueResolved);\n }\n\n if (isNumber(numberItemsResolved)) {\n conversion.number_items = numberItemsResolved;\n }\n\n if (isString(descriptionResolved) && descriptionResolved.length > 0) {\n conversion.description = descriptionResolved;\n }\n\n const body: ConversionsRequest = {\n conversions: [conversion],\n };\n\n const endpoint = `${url}${apiVersion}/measurement/conversions/${pixelId}`;\n\n // Generate OAuth 1.0a header (stateless, safe to create per-request)\n const oauth = new OAuth({\n consumer: { key: consumerKey, secret: consumerSecret },\n signature_method: 'HMAC-SHA1',\n hash_function(baseString: string, key: string) {\n return crypto.createHmac('sha1', key).update(baseString).digest('base64');\n },\n });\n\n const authHeader = oauth.toHeader(\n oauth.authorize(\n { url: endpoint, method: 'POST' },\n { key: accessToken, secret: accessTokenSecret },\n ),\n );\n\n logger.debug('Calling X Conversions API', {\n endpoint,\n method: 'POST',\n event_id: resolvedEventId,\n conversion_id: 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: authHeader.Authorization,\n 'Content-Type': 'application/json',\n },\n });\n\n logger.debug('X Conversions API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`X Conversions 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 pixelId: string;\n eventId: string;\n consumerKey: string;\n consumerSecret: string;\n accessToken: string;\n accessTokenSecret: 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 eventId?: WalkerOSMapping.Value;\n value?: WalkerOSMapping.Value;\n currency?: WalkerOSMapping.Value;\n number_items?: WalkerOSMapping.Value;\n description?: 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// X (Twitter) Conversions API types\n\n/**\n * User identifier -- each is a single-key object.\n * X requires at least one primary identifier (twclid, hashed_email, hashed_phone_number).\n * ip_address and user_agent are secondary identifiers.\n */\nexport type Identifier =\n | { twclid: string }\n | { hashed_email: string }\n | { hashed_phone_number: string }\n | { ip_address: string }\n | { user_agent: string };\n\n/** Product/content detail within a conversion */\nexport interface Content {\n content_id?: string;\n content_name?: string;\n content_type?: string;\n content_price?: number;\n num_items?: number;\n content_group_id?: string;\n}\n\n/** A single conversion event in the payload */\nexport interface ConversionEvent {\n conversion_time: string;\n event_id: string;\n identifiers: Identifier[];\n conversion_id?: string;\n value?: string;\n number_items?: number;\n description?: string;\n contents?: Content[];\n}\n\n/** Top-level request body for X Conversions API */\nexport interface ConversionsRequest {\n conversions: ConversionEvent[];\n}\n"],"mappings":"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","names":["OAuth","crypto"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getMappingValue,isArray,isNumber,isObject,isString}from"@walkeros/core";import{sendServer,getHashServer}from"@walkeros/server-core";import OAuth from"oauth-1.0a";import crypto from"crypto";function normalizeString(value){return isString(value)&&value.length>0?value:isArray(value)&&isString(value[0])&&value[0].length>0?value[0]:void 0}var types_exports={},destinationTwitter={type:"twitter",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{pixelId:pixelId,eventId:eventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret}=settings;pixelId||logger.throw("Config settings pixelId missing"),eventId||logger.throw("Config settings eventId missing"),consumerKey||logger.throw("Config settings consumerKey missing"),consumerSecret||logger.throw("Config settings consumerSecret missing"),accessToken||logger.throw("Config settings accessToken missing"),accessTokenSecret||logger.throw("Config settings accessTokenSecret missing");const settingsConfig={...settings,pixelId:pixelId,eventId:eventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret,apiVersion:settings.apiVersion||"12"};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{pixelId:pixelId,eventId:defaultEventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret,apiVersion:apiVersion="12",doNotHash:doNotHash,url:url="https://ads-api.x.com/",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:{}},identifiers=[],emailRaw=isString(userData.email)?userData.email:isString(event.user.email)?event.user.email:void 0;if(emailRaw){const normalizedEmail=emailRaw.trim().toLowerCase(),idValue=doNotHash?.includes("email")?normalizedEmail:await getHashServer(normalizedEmail);identifiers.push({hashed_email:idValue})}const phoneRaw=isString(userData.phone)?userData.phone:isString(event.user.phone)?event.user.phone:void 0;if(phoneRaw){const normalizedPhone=phoneRaw.trim(),idValue=doNotHash?.includes("phone")?normalizedPhone:await getHashServer(normalizedPhone);identifiers.push({hashed_phone_number:idValue})}const twclid=normalizeString(userData.twclid);twclid&&identifiers.push({twclid:twclid});const ipAddress=normalizeString(userData.ip_address);ipAddress&&identifiers.push({ip_address:ipAddress});const userAgent=normalizeString(userData.user_agent);if(userAgent&&identifiers.push({user_agent:userAgent}),!identifiers.some(id=>"twclid"in id||"hashed_email"in id||"hashed_phone_number"in id))return;const mappingSettings=rule?.settings||{},eventIdResolved=mappingSettings.eventId?await getMappingValue(event,mappingSettings.eventId):void 0,valueResolved=void 0!==mappingSettings.value?await getMappingValue(event,mappingSettings.value):void 0,numberItemsResolved=void 0!==mappingSettings.number_items?await getMappingValue(event,mappingSettings.number_items):void 0,descriptionResolved=void 0!==mappingSettings.description?await getMappingValue(event,mappingSettings.description):void 0,resolvedEventId=isString(eventIdResolved)?eventIdResolved:defaultEventId,conversion={conversion_time:new Date(event.timestamp).toISOString(),event_id:resolvedEventId,identifiers:identifiers,conversion_id:event.id};null!=valueResolved&&(conversion.value=String(valueResolved)),isNumber(numberItemsResolved)&&(conversion.number_items=numberItemsResolved),isString(descriptionResolved)&&descriptionResolved.length>0&&(conversion.description=descriptionResolved);const body={conversions:[conversion]},endpoint=`${url}${apiVersion}/measurement/conversions/${pixelId}`,oauth=new OAuth({consumer:{key:consumerKey,secret:consumerSecret},signature_method:"HMAC-SHA1",hash_function:(baseString,key)=>crypto.createHmac("sha1",key).update(baseString).digest("base64")}),authHeader=oauth.toHeader(oauth.authorize({url:endpoint,method:"POST"},{key:accessToken,secret:accessTokenSecret}));logger.debug("Calling X Conversions API",{endpoint:endpoint,method:"POST",event_id:resolvedEventId,conversion_id:event.id});const sendServerFn=env?.sendServer||sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:authHeader.Authorization,"Content-Type":"application/json"}});logger.debug("X Conversions API response",{ok:!isObject(result)||result.ok}),isObject(result)&&!1===result.ok&&logger.throw(`X Conversions API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationTwitter;export{types_exports as DestinationTwitter,index_default as default,destinationTwitter};//# sourceMappingURL=index.mjs.map
|
|
1
|
+
import{getMappingValue,isArray,isNumber,isObject,isString}from"@walkeros/core";import{sendServer,getHashServer}from"@walkeros/server-core";import OAuth from"oauth-1.0a";import crypto from"crypto";function normalizeString(value){return isString(value)&&value.length>0?value:isArray(value)&&isString(value[0])&&value[0].length>0?value[0]:void 0}var types_exports={},destinationTwitter={type:"twitter",config:{},async init({config:partialConfig,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{pixelId:pixelId,eventId:eventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret}=settings;pixelId||logger.throw("Config settings pixelId missing"),eventId||logger.throw("Config settings eventId missing"),consumerKey||logger.throw("Config settings consumerKey missing"),consumerSecret||logger.throw("Config settings consumerSecret missing"),accessToken||logger.throw("Config settings accessToken missing"),accessTokenSecret||logger.throw("Config settings accessTokenSecret missing");const settingsConfig={...settings,pixelId:pixelId,eventId:eventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret,apiVersion:settings.apiVersion||"12"};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{pixelId:pixelId,eventId:defaultEventId,consumerKey:consumerKey,consumerSecret:consumerSecret,accessToken:accessToken,accessTokenSecret:accessTokenSecret,apiVersion:apiVersion="12",doNotHash:doNotHash,url:url="https://ads-api.x.com/",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:{}},identifiers=[],emailRaw=isString(userData.email)?userData.email:isString(event.user.email)?event.user.email:void 0;if(emailRaw){const normalizedEmail=emailRaw.trim().toLowerCase(),idValue=doNotHash?.includes("email")?normalizedEmail:await getHashServer(normalizedEmail);identifiers.push({hashed_email:idValue})}const phoneRaw=isString(userData.phone)?userData.phone:isString(event.user.phone)?event.user.phone:void 0;if(phoneRaw){const normalizedPhone=phoneRaw.trim(),idValue=doNotHash?.includes("phone")?normalizedPhone:await getHashServer(normalizedPhone);identifiers.push({hashed_phone_number:idValue})}const twclid=normalizeString(userData.twclid);twclid&&identifiers.push({twclid:twclid});const ipAddress=normalizeString(userData.ip_address);ipAddress&&identifiers.push({ip_address:ipAddress});const userAgent=normalizeString(userData.user_agent);if(userAgent&&identifiers.push({user_agent:userAgent}),!identifiers.some(id=>"twclid"in id||"hashed_email"in id||"hashed_phone_number"in id))return;const mappingSettings=rule?.settings||{},eventIdResolved=mappingSettings.eventId?await getMappingValue(event,mappingSettings.eventId,{collector:collector}):void 0,valueResolved=void 0!==mappingSettings.value?await getMappingValue(event,mappingSettings.value,{collector:collector}):void 0,numberItemsResolved=void 0!==mappingSettings.number_items?await getMappingValue(event,mappingSettings.number_items,{collector:collector}):void 0,descriptionResolved=void 0!==mappingSettings.description?await getMappingValue(event,mappingSettings.description,{collector:collector}):void 0,resolvedEventId=isString(eventIdResolved)?eventIdResolved:defaultEventId,conversion={conversion_time:new Date(event.timestamp).toISOString(),event_id:resolvedEventId,identifiers:identifiers,conversion_id:event.id};null!=valueResolved&&(conversion.value=String(valueResolved)),isNumber(numberItemsResolved)&&(conversion.number_items=numberItemsResolved),isString(descriptionResolved)&&descriptionResolved.length>0&&(conversion.description=descriptionResolved);const body={conversions:[conversion]},endpoint=`${url}${apiVersion}/measurement/conversions/${pixelId}`,oauth=new OAuth({consumer:{key:consumerKey,secret:consumerSecret},signature_method:"HMAC-SHA1",hash_function:(baseString,key)=>crypto.createHmac("sha1",key).update(baseString).digest("base64")}),authHeader=oauth.toHeader(oauth.authorize({url:endpoint,method:"POST"},{key:accessToken,secret:accessTokenSecret}));logger.debug("Calling X Conversions API",{endpoint:endpoint,method:"POST",event_id:resolvedEventId,conversion_id:event.id});const sendServerFn=env?.sendServer||sendServer,result=await sendServerFn(endpoint,JSON.stringify(body),{headers:{Authorization:authHeader.Authorization,"Content-Type":"application/json"}});logger.debug("X Conversions API response",{ok:!isObject(result)||result.ok}),isObject(result)&&!1===result.ok&&logger.throw(`X Conversions API error: ${JSON.stringify(result)}`)}(event,context)},index_default=destinationTwitter;export{types_exports as DestinationTwitter,index_default as default,destinationTwitter};//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -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 {\n pixelId,\n eventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n } = settings;\n\n if (!pixelId) logger.throw('Config settings pixelId missing');\n if (!eventId) logger.throw('Config settings eventId missing');\n if (!consumerKey) logger.throw('Config settings consumerKey missing');\n if (!consumerSecret) logger.throw('Config settings consumerSecret missing');\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!accessTokenSecret)\n logger.throw('Config settings accessTokenSecret missing');\n\n const settingsConfig: Settings = {\n ...settings,\n pixelId,\n eventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n apiVersion: settings.apiVersion || '12',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n ConversionsRequest,\n Env,\n Identifier,\n Mapping,\n PushFn,\n Settings,\n} from './types';\nimport {\n getMappingValue,\n isArray,\n isNumber,\n isObject,\n isString,\n} from '@walkeros/core';\nimport { sendServer, getHashServer } from '@walkeros/server-core';\nimport OAuth from 'oauth-1.0a';\nimport crypto from 'crypto';\n\nfunction normalizeString(value: unknown): string | undefined {\n if (isString(value) && value.length > 0) return value;\n if (isArray(value) && isString(value[0]) && value[0].length > 0)\n return value[0];\n return undefined;\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, env, logger },\n) {\n const {\n pixelId,\n eventId: defaultEventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n apiVersion = '12',\n doNotHash,\n url = 'https://ads-api.x.com/',\n user_data,\n } = config.settings as 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 // Build identifiers array (each is a single-key object)\n const identifiers: Identifier[] = [];\n\n // hashed_email\n const emailRaw = isString(userData.email)\n ? userData.email\n : isString(event.user.email)\n ? event.user.email\n : undefined;\n if (emailRaw) {\n const normalizedEmail = emailRaw.trim().toLowerCase();\n const shouldHash = !doNotHash?.includes('email');\n const idValue = shouldHash\n ? await getHashServer(normalizedEmail)\n : normalizedEmail;\n identifiers.push({ hashed_email: idValue });\n }\n\n // hashed_phone_number\n const phoneRaw = isString(userData.phone)\n ? userData.phone\n : isString(event.user.phone)\n ? event.user.phone\n : undefined;\n if (phoneRaw) {\n const normalizedPhone = phoneRaw.trim();\n const shouldHash = !doNotHash?.includes('phone');\n const idValue = shouldHash\n ? await getHashServer(normalizedPhone)\n : normalizedPhone;\n identifiers.push({ hashed_phone_number: idValue });\n }\n\n // twclid (pass-through, handles context tuple [value, order])\n const twclid = normalizeString(userData.twclid);\n if (twclid) {\n identifiers.push({ twclid });\n }\n\n // ip_address (pass-through, secondary)\n const ipAddress = normalizeString(userData.ip_address);\n if (ipAddress) {\n identifiers.push({ ip_address: ipAddress });\n }\n\n // user_agent (pass-through, secondary)\n const userAgent = normalizeString(userData.user_agent);\n if (userAgent) {\n identifiers.push({ user_agent: userAgent });\n }\n\n // Skip event if no primary identifier is present\n const hasPrimary = identifiers.some(\n (id) =>\n 'twclid' in id || 'hashed_email' in id || 'hashed_phone_number' in id,\n );\n if (!hasPrimary) return;\n\n // Resolve per-event mapping settings\n const mappingSettings = (rule?.settings || {}) as Mapping;\n const eventIdResolved = mappingSettings.eventId\n ? await getMappingValue(event, mappingSettings.eventId)\n : undefined;\n const valueResolved =\n mappingSettings.value !== undefined\n ? await getMappingValue(event, mappingSettings.value)\n : undefined;\n const numberItemsResolved =\n mappingSettings.number_items !== undefined\n ? await getMappingValue(event, mappingSettings.number_items)\n : undefined;\n const descriptionResolved =\n mappingSettings.description !== undefined\n ? await getMappingValue(event, mappingSettings.description)\n : undefined;\n\n const resolvedEventId = isString(eventIdResolved)\n ? eventIdResolved\n : defaultEventId;\n\n // Construct conversion\n const conversion: ConversionEvent = {\n conversion_time: new Date(event.timestamp).toISOString(),\n event_id: resolvedEventId,\n identifiers,\n conversion_id: event.id,\n };\n\n if (valueResolved !== undefined && valueResolved !== null) {\n conversion.value = String(valueResolved);\n }\n\n if (isNumber(numberItemsResolved)) {\n conversion.number_items = numberItemsResolved;\n }\n\n if (isString(descriptionResolved) && descriptionResolved.length > 0) {\n conversion.description = descriptionResolved;\n }\n\n const body: ConversionsRequest = {\n conversions: [conversion],\n };\n\n const endpoint = `${url}${apiVersion}/measurement/conversions/${pixelId}`;\n\n // Generate OAuth 1.0a header (stateless, safe to create per-request)\n const oauth = new OAuth({\n consumer: { key: consumerKey, secret: consumerSecret },\n signature_method: 'HMAC-SHA1',\n hash_function(baseString: string, key: string) {\n return crypto.createHmac('sha1', key).update(baseString).digest('base64');\n },\n });\n\n const authHeader = oauth.toHeader(\n oauth.authorize(\n { url: endpoint, method: 'POST' },\n { key: accessToken, secret: accessTokenSecret },\n ),\n );\n\n logger.debug('Calling X Conversions API', {\n endpoint,\n method: 'POST',\n event_id: resolvedEventId,\n conversion_id: 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: authHeader.Authorization,\n 'Content-Type': 'application/json',\n },\n });\n\n logger.debug('X Conversions API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`X Conversions 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 pixelId: string;\n eventId: string;\n consumerKey: string;\n consumerSecret: string;\n accessToken: string;\n accessTokenSecret: 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 eventId?: WalkerOSMapping.Value;\n value?: WalkerOSMapping.Value;\n currency?: WalkerOSMapping.Value;\n number_items?: WalkerOSMapping.Value;\n description?: 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// X (Twitter) Conversions API types\n\n/**\n * User identifier -- each is a single-key object.\n * X requires at least one primary identifier (twclid, hashed_email, hashed_phone_number).\n * ip_address and user_agent are secondary identifiers.\n */\nexport type Identifier =\n | { twclid: string }\n | { hashed_email: string }\n | { hashed_phone_number: string }\n | { ip_address: string }\n | { user_agent: string };\n\n/** Product/content detail within a conversion */\nexport interface Content {\n content_id?: string;\n content_name?: string;\n content_type?: string;\n content_price?: number;\n num_items?: number;\n content_group_id?: string;\n}\n\n/** A single conversion event in the payload */\nexport interface ConversionEvent {\n conversion_time: string;\n event_id: string;\n identifiers: Identifier[];\n conversion_id?: string;\n value?: string;\n number_items?: number;\n description?: string;\n contents?: Content[];\n}\n\n/** Top-level request body for X Conversions API */\nexport interface ConversionsRequest {\n conversions: ConversionEvent[];\n}\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationTwitter from './types';\n\nexport const destinationTwitter: Destination = {\n type: 'twitter',\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 destinationTwitter;\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 {\n pixelId,\n eventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n } = settings;\n\n if (!pixelId) logger.throw('Config settings pixelId missing');\n if (!eventId) logger.throw('Config settings eventId missing');\n if (!consumerKey) logger.throw('Config settings consumerKey missing');\n if (!consumerSecret) logger.throw('Config settings consumerSecret missing');\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!accessTokenSecret)\n logger.throw('Config settings accessTokenSecret missing');\n\n const settingsConfig: Settings = {\n ...settings,\n pixelId,\n eventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n apiVersion: settings.apiVersion || '12',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n ConversionsRequest,\n Env,\n Identifier,\n Mapping,\n PushFn,\n Settings,\n} from './types';\nimport {\n getMappingValue,\n isArray,\n isNumber,\n isObject,\n isString,\n} from '@walkeros/core';\nimport { sendServer, getHashServer } from '@walkeros/server-core';\nimport OAuth from 'oauth-1.0a';\nimport crypto from 'crypto';\n\nfunction normalizeString(value: unknown): string | undefined {\n if (isString(value) && value.length > 0) return value;\n if (isArray(value) && isString(value[0]) && value[0].length > 0)\n return value[0];\n return undefined;\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, env, logger, collector },\n) {\n const {\n pixelId,\n eventId: defaultEventId,\n consumerKey,\n consumerSecret,\n accessToken,\n accessTokenSecret,\n apiVersion = '12',\n doNotHash,\n url = 'https://ads-api.x.com/',\n user_data,\n } = config.settings as 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 // Build identifiers array (each is a single-key object)\n const identifiers: Identifier[] = [];\n\n // hashed_email\n const emailRaw = isString(userData.email)\n ? userData.email\n : isString(event.user.email)\n ? event.user.email\n : undefined;\n if (emailRaw) {\n const normalizedEmail = emailRaw.trim().toLowerCase();\n const shouldHash = !doNotHash?.includes('email');\n const idValue = shouldHash\n ? await getHashServer(normalizedEmail)\n : normalizedEmail;\n identifiers.push({ hashed_email: idValue });\n }\n\n // hashed_phone_number\n const phoneRaw = isString(userData.phone)\n ? userData.phone\n : isString(event.user.phone)\n ? event.user.phone\n : undefined;\n if (phoneRaw) {\n const normalizedPhone = phoneRaw.trim();\n const shouldHash = !doNotHash?.includes('phone');\n const idValue = shouldHash\n ? await getHashServer(normalizedPhone)\n : normalizedPhone;\n identifiers.push({ hashed_phone_number: idValue });\n }\n\n // twclid (pass-through, handles context tuple [value, order])\n const twclid = normalizeString(userData.twclid);\n if (twclid) {\n identifiers.push({ twclid });\n }\n\n // ip_address (pass-through, secondary)\n const ipAddress = normalizeString(userData.ip_address);\n if (ipAddress) {\n identifiers.push({ ip_address: ipAddress });\n }\n\n // user_agent (pass-through, secondary)\n const userAgent = normalizeString(userData.user_agent);\n if (userAgent) {\n identifiers.push({ user_agent: userAgent });\n }\n\n // Skip event if no primary identifier is present\n const hasPrimary = identifiers.some(\n (id) =>\n 'twclid' in id || 'hashed_email' in id || 'hashed_phone_number' in id,\n );\n if (!hasPrimary) return;\n\n // Resolve per-event mapping settings\n const mappingSettings = (rule?.settings || {}) as Mapping;\n const eventIdResolved = mappingSettings.eventId\n ? await getMappingValue(event, mappingSettings.eventId, { collector })\n : undefined;\n const valueResolved =\n mappingSettings.value !== undefined\n ? await getMappingValue(event, mappingSettings.value, { collector })\n : undefined;\n const numberItemsResolved =\n mappingSettings.number_items !== undefined\n ? await getMappingValue(event, mappingSettings.number_items, {\n collector,\n })\n : undefined;\n const descriptionResolved =\n mappingSettings.description !== undefined\n ? await getMappingValue(event, mappingSettings.description, {\n collector,\n })\n : undefined;\n\n const resolvedEventId = isString(eventIdResolved)\n ? eventIdResolved\n : defaultEventId;\n\n // Construct conversion\n const conversion: ConversionEvent = {\n conversion_time: new Date(event.timestamp).toISOString(),\n event_id: resolvedEventId,\n identifiers,\n conversion_id: event.id,\n };\n\n if (valueResolved !== undefined && valueResolved !== null) {\n conversion.value = String(valueResolved);\n }\n\n if (isNumber(numberItemsResolved)) {\n conversion.number_items = numberItemsResolved;\n }\n\n if (isString(descriptionResolved) && descriptionResolved.length > 0) {\n conversion.description = descriptionResolved;\n }\n\n const body: ConversionsRequest = {\n conversions: [conversion],\n };\n\n const endpoint = `${url}${apiVersion}/measurement/conversions/${pixelId}`;\n\n // Generate OAuth 1.0a header (stateless, safe to create per-request)\n const oauth = new OAuth({\n consumer: { key: consumerKey, secret: consumerSecret },\n signature_method: 'HMAC-SHA1',\n hash_function(baseString: string, key: string) {\n return crypto.createHmac('sha1', key).update(baseString).digest('base64');\n },\n });\n\n const authHeader = oauth.toHeader(\n oauth.authorize(\n { url: endpoint, method: 'POST' },\n { key: accessToken, secret: accessTokenSecret },\n ),\n );\n\n logger.debug('Calling X Conversions API', {\n endpoint,\n method: 'POST',\n event_id: resolvedEventId,\n conversion_id: 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: authHeader.Authorization,\n 'Content-Type': 'application/json',\n },\n });\n\n logger.debug('X Conversions API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`X Conversions 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 pixelId: string;\n eventId: string;\n consumerKey: string;\n consumerSecret: string;\n accessToken: string;\n accessTokenSecret: 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 eventId?: WalkerOSMapping.Value;\n value?: WalkerOSMapping.Value;\n currency?: WalkerOSMapping.Value;\n number_items?: WalkerOSMapping.Value;\n description?: 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// X (Twitter) Conversions API types\n\n/**\n * User identifier -- each is a single-key object.\n * X requires at least one primary identifier (twclid, hashed_email, hashed_phone_number).\n * ip_address and user_agent are secondary identifiers.\n */\nexport type Identifier =\n | { twclid: string }\n | { hashed_email: string }\n | { hashed_phone_number: string }\n | { ip_address: string }\n | { user_agent: string };\n\n/** Product/content detail within a conversion */\nexport interface Content {\n content_id?: string;\n content_name?: string;\n content_type?: string;\n content_price?: number;\n num_items?: number;\n content_group_id?: string;\n}\n\n/** A single conversion event in the payload */\nexport interface ConversionEvent {\n conversion_time: string;\n event_id: string;\n identifiers: Identifier[];\n conversion_id?: string;\n value?: string;\n number_items?: number;\n description?: string;\n contents?: Content[];\n}\n\n/** Top-level request body for X Conversions API */\nexport interface ConversionsRequest {\n conversions: ConversionEvent[];\n}\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationTwitter from './types';\n\nexport const destinationTwitter: Destination = {\n type: 'twitter',\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 destinationTwitter;\n"],"mappings":"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","names":[]}
|
package/dist/walkerOS.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkeros/server-destination-twitter",
|
|
3
3
|
"description": "X (Twitter) Conversions API server destination for walkerOS",
|
|
4
|
-
"version": "4.0.0
|
|
4
|
+
"version": "4.0.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"update": "npx npm-check-updates -u && npm update"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@walkeros/core": "4.0.0
|
|
38
|
-
"@walkeros/server-core": "4.0.0
|
|
37
|
+
"@walkeros/core": "4.0.0",
|
|
38
|
+
"@walkeros/server-core": "4.0.0",
|
|
39
39
|
"oauth-1.0a": "^2.2.6"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@walkeros/collector": "4.0.0
|
|
42
|
+
"@walkeros/collector": "4.0.0"
|
|
43
43
|
},
|
|
44
44
|
"repository": {
|
|
45
45
|
"url": "git+https://github.com/elbwalker/walkerOS.git",
|