@walkeros/server-destination-customerio 3.4.0-next-1776749829492

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.
@@ -0,0 +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 { siteId, apiKey } = settings;\n\n if (!siteId) logger.throw('Config settings siteId missing');\n if (!apiKey) logger.throw('Config settings apiKey missing');\n\n const settingsConfig: Settings = {\n ...settings,\n siteId: siteId as string,\n apiKey: apiKey as string,\n // Default identity resolution paths\n customerId: settings.customerId ?? 'user.id',\n anonymousId: settings.anonymousId ?? 'user.session',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n PushFn,\n Settings,\n RuntimeState,\n CustomerIoTrackClientMock,\n CustomerIoApiClientMock,\n} from './types';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const settings = config.settings as Settings;\n const envTyped = env as\n | {\n trackClient?: CustomerIoTrackClientMock;\n apiClient?: CustomerIoApiClientMock;\n }\n | undefined;\n const trackClient = envTyped?.trackClient || settings._trackClient;\n const apiClient = envTyped?.apiClient || settings._apiClient;\n\n if (!trackClient) {\n logger.warn('Customer.io TrackClient not initialized');\n return;\n }\n\n const state: RuntimeState = settings._state || {};\n const mappingSettings = rule?.settings || {};\n\n // Convert ms timestamp to Unix seconds\n const timestampSec = event.timestamp\n ? Math.floor(event.timestamp / 1000)\n : undefined;\n\n // 1. Resolve identity from event\n const customerId = settings.customerId\n ? resolveString(\n await getMappingValue(event, settings.customerId, { collector }),\n )\n : undefined;\n const anonymousId = settings.anonymousId\n ? resolveString(\n await getMappingValue(event, settings.anonymousId, { collector }),\n )\n : undefined;\n\n if (!customerId && !anonymousId) {\n logger.warn(\n 'Customer.io requires customerId or anonymousId; skipping event',\n { event: event.name },\n );\n return;\n }\n\n // 2. Identify -- rule-level overrides destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n if (identifyMapping !== undefined && customerId) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n await applyIdentify(\n trackClient,\n customerId,\n resolved as Record<string, unknown>,\n state,\n );\n }\n }\n\n // 3. Page (trackPageView)\n if (mappingSettings.page !== undefined && customerId) {\n const resolved = await getMappingValue(event, mappingSettings.page, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as { url?: unknown; [key: string]: unknown };\n const url = isString(r.url) ? r.url : undefined;\n if (url) {\n const { url: _u, ...extraData } = r;\n void _u;\n const pageData =\n Object.keys(extraData).length > 0 ? extraData : undefined;\n await trackClient.trackPageView(customerId, url, pageData);\n }\n }\n }\n\n // 4. Destroy / Suppress / Unsuppress\n if (mappingSettings.destroy === true && customerId) {\n await trackClient.destroy(customerId);\n }\n if (mappingSettings.suppress === true && customerId) {\n await trackClient.suppress(customerId);\n }\n if (mappingSettings.unsuppress === true && customerId) {\n await trackClient.unsuppress(customerId);\n }\n\n // 5. Device management\n if (mappingSettings.addDevice !== undefined && customerId) {\n const resolved = await getMappingValue(event, mappingSettings.addDevice, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as {\n deviceId?: unknown;\n platform?: unknown;\n data?: unknown;\n };\n if (isString(r.deviceId) && isString(r.platform)) {\n await trackClient.addDevice(\n customerId,\n r.deviceId,\n r.platform,\n isObject(r.data) ? (r.data as Record<string, unknown>) : undefined,\n );\n }\n }\n }\n if (mappingSettings.deleteDevice !== undefined && customerId) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.deleteDevice,\n { collector },\n );\n if (isObject(resolved)) {\n const r = resolved as { deviceId?: unknown; platform?: unknown };\n if (isString(r.deviceId) && isString(r.platform)) {\n await trackClient.deleteDevice(customerId, r.deviceId, r.platform);\n }\n }\n }\n\n // 6. Merge\n if (mappingSettings.merge !== undefined && customerId) {\n const resolved = await getMappingValue(event, mappingSettings.merge, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as {\n primaryType?: unknown;\n primaryId?: unknown;\n secondaryType?: unknown;\n secondaryId?: unknown;\n };\n if (\n isString(r.primaryType) &&\n isString(r.primaryId) &&\n isString(r.secondaryType) &&\n isString(r.secondaryId)\n ) {\n await trackClient.mergeCustomers(\n r.primaryType,\n r.primaryId,\n r.secondaryType,\n r.secondaryId,\n );\n }\n }\n }\n\n // 7. Transactional (sendEmail / sendPush)\n if (mappingSettings.sendEmail !== undefined && apiClient) {\n const resolved = await getMappingValue(event, mappingSettings.sendEmail, {\n collector,\n });\n if (isObject(resolved)) {\n await apiClient.sendEmail(resolved);\n }\n }\n if (mappingSettings.sendPush !== undefined && apiClient) {\n const resolved = await getMappingValue(event, mappingSettings.sendPush, {\n collector,\n });\n if (isObject(resolved)) {\n await apiClient.sendPush(resolved);\n }\n }\n\n // 8. Track (unless skip: true)\n if (rule?.skip !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties = isObject(data) ? (data as Record<string, unknown>) : {};\n\n const eventData: {\n name: string;\n data?: Record<string, unknown>;\n timestamp?: number;\n } = { name: eventName };\n eventData.data = properties;\n if (timestampSec !== undefined) eventData.timestamp = timestampSec;\n\n if (customerId) {\n await trackClient.track(customerId, eventData);\n } else if (anonymousId) {\n await trackClient.trackAnonymous(anonymousId, eventData);\n }\n }\n\n settings._state = state;\n};\n\nfunction resolveString(value: unknown): string | undefined {\n if (isString(value) && value.length > 0) return value;\n return undefined;\n}\n\nfunction hashAttributes(attrs: Record<string, unknown> | undefined): string {\n if (!attrs) return '';\n try {\n return JSON.stringify(attrs);\n } catch {\n return '';\n }\n}\n\nasync function applyIdentify(\n trackClient: CustomerIoTrackClientMock,\n customerId: string,\n resolved: Record<string, unknown>,\n state: RuntimeState,\n): Promise<void> {\n const last = state.lastIdentity || {};\n\n const attributesHash = hashAttributes(resolved);\n const customerIdChanged = customerId !== last.customerId;\n const attributesChanged = attributesHash !== (last.attributesHash ?? '');\n\n if (!customerIdChanged && !attributesChanged) return;\n\n await trackClient.identify(customerId, resolved);\n\n state.lastIdentity = {\n customerId,\n attributesHash,\n };\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/**\n * Mock-friendly interface for the TrackClient methods the\n * destination actually calls. Tests provide this via env.trackClient\n * instead of the real SDK.\n */\nexport interface CustomerIoTrackClientMock {\n identify: (\n customerId: string | number,\n attributes: Record<string, unknown>,\n ) => Promise<void>;\n track: (\n customerId: string | number,\n eventData: {\n name: string;\n data?: Record<string, unknown>;\n timestamp?: number;\n },\n ) => Promise<void>;\n trackAnonymous: (\n anonymousId: string,\n eventData: {\n name: string;\n data?: Record<string, unknown>;\n timestamp?: number;\n },\n ) => Promise<void>;\n trackPageView: (\n customerId: string | number,\n url: string,\n data?: Record<string, unknown>,\n ) => Promise<void>;\n destroy: (customerId: string | number) => Promise<void>;\n suppress: (customerId: string | number) => Promise<void>;\n unsuppress: (customerId: string | number) => Promise<void>;\n addDevice: (\n customerId: string | number,\n deviceId: string,\n platform: string,\n data?: Record<string, unknown>,\n ) => Promise<void>;\n deleteDevice: (\n customerId: string | number,\n deviceId: string,\n platform: string,\n ) => Promise<void>;\n mergeCustomers: (\n primaryType: string,\n primaryId: string,\n secondaryType: string,\n secondaryId: string,\n ) => Promise<void>;\n}\n\n/**\n * Mock-friendly interface for the APIClient methods the\n * destination actually calls. Tests provide this via env.apiClient\n * instead of the real SDK.\n */\nexport interface CustomerIoApiClientMock {\n sendEmail: (request: unknown) => Promise<void>;\n sendPush: (request: unknown) => Promise<void>;\n}\n\nexport interface Settings {\n /** Customer.io Site ID (required for Track API). */\n siteId: string;\n /** Customer.io API Key (required for Track API). */\n apiKey: string;\n /** App API Key for transactional messaging (optional). */\n appApiKey?: string;\n /** Region: 'us' or 'eu'. Default: 'us'. */\n region?: 'us' | 'eu';\n /** HTTP request timeout in ms. Default: 10000. */\n timeout?: number;\n /** walkerOS mapping value path to resolve customerId from each event. */\n customerId?: string;\n /** walkerOS mapping value path to resolve anonymousId from each event. */\n anonymousId?: string;\n /** Destination-level identify mapping (fires identify() on first push / change). */\n identify?: WalkerOSMapping.Value;\n /** Runtime state -- not user-facing. */\n _trackClient?: CustomerIoTrackClientMock;\n _apiClient?: CustomerIoApiClientMock;\n _state?: RuntimeState;\n}\n\nexport interface RuntimeState {\n lastIdentity?: {\n customerId?: string;\n attributesHash?: string;\n };\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings. Controls which Customer.io methods are called\n * beyond the default track(). Resolved via getMappingValue() in push().\n */\nexport interface Mapping {\n /** Per-event identify attributes. Resolves to { email?, first_name?, ... }. */\n identify?: WalkerOSMapping.Value;\n /** Fire trackPageView(). Resolves to { url, ... }. */\n page?: WalkerOSMapping.Value;\n /** Fire destroy(). Boolean true triggers deletion. */\n destroy?: boolean;\n /** Fire suppress(). Boolean true triggers suppression. */\n suppress?: boolean;\n /** Fire unsuppress(). Boolean true triggers unsuppression. */\n unsuppress?: boolean;\n /** Fire addDevice(). Resolves to { deviceId, platform, data? }. */\n addDevice?: WalkerOSMapping.Value;\n /** Fire deleteDevice(). Resolves to { deviceId, platform }. */\n deleteDevice?: WalkerOSMapping.Value;\n /** Fire mergeCustomers(). Resolves to { primaryType, primaryId, secondaryType, secondaryId }. */\n merge?: WalkerOSMapping.Value;\n /** Fire sendEmail(). Resolves to { to, transactional_message_id, message_data?, identifiers? }. */\n sendEmail?: WalkerOSMapping.Value;\n /** Fire sendPush(). Resolves to { transactional_message_id, message_data?, identifiers? }. */\n sendPush?: WalkerOSMapping.Value;\n}\n\n/**\n * Env -- optional SDK override. Production leaves this undefined and the\n * destination creates real TrackClient/APIClient instances. Tests provide\n * mocks via env.trackClient and env.apiClient.\n */\nexport interface Env extends DestinationServer.Env {\n trackClient?: CustomerIoTrackClientMock;\n apiClient?: CustomerIoApiClientMock;\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>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","import type {\n Destination,\n Settings,\n CustomerIoTrackClientMock,\n CustomerIoApiClientMock,\n} from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationCustomerIo from './types';\n\nexport const destinationCustomerIo: Destination = {\n type: 'customerio',\n\n config: {},\n\n init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n\n // Use env mocks if provided (testing), otherwise create real SDK clients\n const envTyped = env as\n | {\n trackClient?: CustomerIoTrackClientMock;\n apiClient?: CustomerIoApiClientMock;\n }\n | undefined;\n\n if (!envTyped?.trackClient) {\n // Production path: create real TrackClient\n try {\n // Use dynamic require to allow tests to mock via jest.mock('customerio-node').\n const customerioSdk = require('customerio-node');\n const { TrackClient, RegionUS, RegionEU } = customerioSdk;\n const region = settings.region === 'eu' ? RegionEU : RegionUS;\n const trackClient = new TrackClient(settings.siteId, settings.apiKey, {\n region,\n ...(settings.timeout ? { timeout: settings.timeout } : {}),\n });\n settings._trackClient = trackClient as CustomerIoTrackClientMock;\n } catch (err) {\n logger.throw(`Failed to initialize Customer.io TrackClient: ${err}`);\n }\n }\n\n if (!envTyped?.apiClient && settings.appApiKey) {\n // Production path: create real APIClient for transactional messaging\n try {\n const customerioSdk = require('customerio-node');\n const { APIClient, RegionUS, RegionEU } = customerioSdk;\n const region = settings.region === 'eu' ? RegionEU : RegionUS;\n const apiClient = new APIClient(settings.appApiKey, {\n region,\n ...(settings.timeout ? { timeout: settings.timeout } : {}),\n });\n settings._apiClient = apiClient as CustomerIoApiClientMock;\n } catch (err) {\n logger.throw(`Failed to initialize Customer.io APIClient: ${err}`);\n }\n }\n\n settings._state = {};\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = (config?.settings || {}) as Settings;\n // TrackClient has no flush -- just clear references\n settings._trackClient = undefined;\n settings._apiClient = undefined;\n },\n};\n\nexport default destinationCustomerIo;\n"],"mappings":"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","names":[]}