@walkeros/server-destination-amplitude 3.3.0-next-1776098542393

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,167 @@
1
+ import { Mapping as Mapping$1, Destination as Destination$1 } from '@walkeros/core';
2
+ import { DestinationServer } from '@walkeros/server-core';
3
+
4
+ /**
5
+ * Amplitude SDK surface -- the subset of @amplitude/analytics-node the
6
+ * destination actually uses. Tests provide a mock via env.amplitude;
7
+ * production uses the real SDK import.
8
+ *
9
+ * Key difference from web: no setUserId/setDeviceId/setSessionId.
10
+ * Identity is per-event via EventOptions on every SDK call.
11
+ */
12
+ interface AmplitudeSDK {
13
+ init: (apiKey: string, options?: Record<string, unknown>) => {
14
+ promise: Promise<void>;
15
+ };
16
+ track: (eventType: string, eventProperties?: Record<string, unknown>, eventOptions?: EventOptions) => void;
17
+ identify: (identify: IdentifyInstance, eventOptions?: EventOptions) => void;
18
+ revenue: (revenue: RevenueInstance, eventOptions?: EventOptions) => void;
19
+ setGroup: (groupType: string, groupName: string | string[], eventOptions?: EventOptions) => void;
20
+ groupIdentify: (groupType: string, groupName: string, identify: IdentifyInstance, eventOptions?: EventOptions) => void;
21
+ setOptOut: (optOut: boolean) => void;
22
+ flush: () => {
23
+ promise: Promise<void>;
24
+ };
25
+ Identify: new () => IdentifyInstance;
26
+ Revenue: new () => RevenueInstance;
27
+ }
28
+ /**
29
+ * Per-event identity and metadata fields. Passed to every SDK call.
30
+ * Maps directly to Amplitude's EventOptions type from the Node SDK.
31
+ */
32
+ interface EventOptions {
33
+ user_id?: string;
34
+ device_id?: string;
35
+ session_id?: number;
36
+ time?: number;
37
+ insert_id?: string;
38
+ ip?: string;
39
+ city?: string;
40
+ country?: string;
41
+ region?: string;
42
+ language?: string;
43
+ platform?: string;
44
+ os_name?: string;
45
+ os_version?: string;
46
+ device_brand?: string;
47
+ device_manufacturer?: string;
48
+ device_model?: string;
49
+ app_version?: string;
50
+ carrier?: string;
51
+ user_agent?: string;
52
+ groups?: Record<string, unknown>;
53
+ plan?: Record<string, unknown>;
54
+ ingestion_metadata?: Record<string, unknown>;
55
+ partner_id?: string;
56
+ extra?: Record<string, unknown>;
57
+ }
58
+ /** Chainable Identify -- mirrors @amplitude/analytics-node Identify class. */
59
+ interface IdentifyInstance {
60
+ set: (property: string, value: unknown) => IdentifyInstance;
61
+ setOnce: (property: string, value: unknown) => IdentifyInstance;
62
+ add: (property: string, value: number) => IdentifyInstance;
63
+ append: (property: string, value: unknown) => IdentifyInstance;
64
+ prepend: (property: string, value: unknown) => IdentifyInstance;
65
+ preInsert: (property: string, value: unknown) => IdentifyInstance;
66
+ postInsert: (property: string, value: unknown) => IdentifyInstance;
67
+ remove: (property: string, value: unknown) => IdentifyInstance;
68
+ unset: (property: string) => IdentifyInstance;
69
+ clearAll: () => IdentifyInstance;
70
+ }
71
+ /** Chainable Revenue -- mirrors @amplitude/analytics-node Revenue class. */
72
+ interface RevenueInstance {
73
+ setProductId: (id: string) => RevenueInstance;
74
+ setPrice: (price: number) => RevenueInstance;
75
+ setQuantity: (quantity: number) => RevenueInstance;
76
+ setRevenueType: (type: string) => RevenueInstance;
77
+ setCurrency: (currency: string) => RevenueInstance;
78
+ setRevenue: (revenue: number) => RevenueInstance;
79
+ setReceipt: (receipt: string) => RevenueInstance;
80
+ setReceiptSig: (signature: string) => RevenueInstance;
81
+ setEventProperties: (properties: Record<string, unknown>) => RevenueInstance;
82
+ }
83
+ /**
84
+ * Destination-level settings. apiKey is required; all other fields
85
+ * are optional and passed through to the Amplitude Node SDK init().
86
+ */
87
+ interface Settings {
88
+ apiKey: string;
89
+ serverZone?: 'US' | 'EU';
90
+ flushIntervalMillis?: number;
91
+ flushQueueSize?: number;
92
+ flushMaxRetries?: number;
93
+ useBatch?: boolean;
94
+ minIdLength?: number;
95
+ serverUrl?: string;
96
+ logLevel?: number;
97
+ optOut?: boolean;
98
+ offline?: boolean;
99
+ enableRequestBodyCompression?: boolean;
100
+ plan?: Record<string, unknown>;
101
+ ingestionMetadata?: Record<string, unknown>;
102
+ /** walkerOS mapping value for per-event identity resolution. */
103
+ identify?: Mapping$1.Value;
104
+ /** walkerOS mapping value for per-event EventOptions (time, insert_id, ip, etc). */
105
+ eventOptions?: Mapping$1.Value;
106
+ /** Sections to include as event_properties (e.g., ['data', 'globals']). */
107
+ include?: string[];
108
+ }
109
+ type InitSettings = Partial<Settings>;
110
+ /**
111
+ * Per-rule mapping settings. Each is a walkerOS mapping value resolved
112
+ * via getMappingValue(). Revenue supports loop for multi-item orders.
113
+ */
114
+ interface Mapping {
115
+ identify?: Mapping$1.Value;
116
+ revenue?: Mapping$1.Value;
117
+ group?: Mapping$1.Value;
118
+ groupIdentify?: Mapping$1.Value;
119
+ eventOptions?: Mapping$1.Value;
120
+ include?: string[];
121
+ }
122
+ /**
123
+ * Env -- optional SDK override. Production leaves this undefined and the
124
+ * destination falls back to the real @amplitude/analytics-node import.
125
+ * Tests provide a mock via env.amplitude.
126
+ */
127
+ interface Env extends DestinationServer.Env {
128
+ amplitude?: AmplitudeSDK;
129
+ }
130
+ type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings>;
131
+ interface Destination extends DestinationServer.Destination<Types> {
132
+ init: DestinationServer.InitFn<Types>;
133
+ }
134
+ type Config = {
135
+ settings: Settings;
136
+ } & DestinationServer.Config<Types>;
137
+ type InitFn = DestinationServer.InitFn<Types>;
138
+ type PushFn = DestinationServer.PushFn<Types>;
139
+ type PartialConfig = DestinationServer.PartialConfig<Types>;
140
+ type PushEvents = DestinationServer.PushEvents<Mapping>;
141
+ type Rule = Mapping$1.Rule<Mapping>;
142
+ type Rules = Mapping$1.Rules<Rule>;
143
+
144
+ type index_AmplitudeSDK = AmplitudeSDK;
145
+ type index_Config = Config;
146
+ type index_Destination = Destination;
147
+ type index_Env = Env;
148
+ type index_EventOptions = EventOptions;
149
+ type index_IdentifyInstance = IdentifyInstance;
150
+ type index_InitFn = InitFn;
151
+ type index_InitSettings = InitSettings;
152
+ type index_Mapping = Mapping;
153
+ type index_PartialConfig = PartialConfig;
154
+ type index_PushEvents = PushEvents;
155
+ type index_PushFn = PushFn;
156
+ type index_RevenueInstance = RevenueInstance;
157
+ type index_Rule = Rule;
158
+ type index_Rules = Rules;
159
+ type index_Settings = Settings;
160
+ type index_Types = Types;
161
+ declare namespace index {
162
+ export type { index_AmplitudeSDK as AmplitudeSDK, index_Config as Config, index_Destination as Destination, index_Env as Env, index_EventOptions as EventOptions, index_IdentifyInstance as IdentifyInstance, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PushEvents as PushEvents, index_PushFn as PushFn, index_RevenueInstance as RevenueInstance, index_Rule as Rule, index_Rules as Rules, index_Settings as Settings, index_Types as Types };
163
+ }
164
+
165
+ declare const destinationAmplitude: Destination;
166
+
167
+ export { index as DestinationAmplitude, destinationAmplitude as default, destinationAmplitude };
package/dist/index.js ADDED
@@ -0,0 +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},index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationAmplitude:()=>types_exports,default:()=>index_default,destinationAmplitude:()=>destinationAmplitude}),module.exports=(mod=index_exports,__copyProps(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core"),amplitudeSDK=((mod,isNodeMode,target)=>(target=null!=mod?__create(__getProtoOf(mod)):{},__copyProps(!isNodeMode&&mod&&mod.__esModule?target:__defProp(target,"default",{value:mod,enumerable:!0}),mod)))(require("@amplitude/analytics-node")),IDENTIFY_OP_KEYS=["set","setOnce","add","append","prepend","preInsert","postInsert","remove"],IDENTITY_KEYS=["user_id","device_id","session_id"],REVENUE_FIELD_MAP={productId:"setProductId",price:"setPrice",quantity:"setQuantity",revenueType:"setRevenueType",currency:"setCurrency",revenue:"setRevenue",receipt:"setReceipt",receiptSig:"setReceiptSig"};function getAmplitude(env){const amplitude=null==env?void 0:env.amplitude;return null!=amplitude?amplitude:amplitudeSDK}function buildIdentify(amp,resolved){let identify;const ensure=()=>(identify||(identify=new amp.Identify),identify);for(const op of IDENTIFY_OP_KEYS){const bag=resolved[op];if((0,import_core.isObject)(bag))for(const[prop,value]of Object.entries(bag))(0,import_core.isDefined)(value)&&("add"===op?(0,import_core.isNumber)(value)&&ensure().add(prop,value):ensure()[op](prop,value))}if((0,import_core.isArray)(resolved.unset))for(const prop of resolved.unset)(0,import_core.isString)(prop)&&ensure().unset(prop);return!0===resolved.clearAll&&ensure().clearAll(),identify}function buildRevenue(amp,item){const rev=new amp.Revenue;for(const[key,setter]of Object.entries(REVENUE_FIELD_MAP)){const value=item[key];(0,import_core.isDefined)(value)&&rev[setter](value)}return(0,import_core.isObject)(item.eventProperties)&&rev.setEventProperties(item.eventProperties),rev}function buildEventOptions(identityResolved,eventOptionsResolved){const opts={};if(identityResolved&&((0,import_core.isString)(identityResolved.user_id)&&(opts.user_id=identityResolved.user_id),(0,import_core.isString)(identityResolved.device_id)&&(opts.device_id=identityResolved.device_id),void 0!==identityResolved.session_id)){const session=identityResolved.session_id;opts.session_id=(0,import_core.isNumber)(session)?session:(0,import_core.isString)(session)&&/^\d+$/.test(session)?Number(session):(0,import_core.isString)(session)?function(value){let hash=5381;for(let i=0;i<value.length;i++)hash=(hash<<5)+hash+value.charCodeAt(i)|0;return Math.abs(hash)}(session):void 0}if(eventOptionsResolved)for(const[key,value]of Object.entries(eventOptionsResolved))(0,import_core.isDefined)(value)&&!IDENTITY_KEYS.includes(key)&&(opts[key]=value);return opts}var types_exports={},destinationAmplitude={type:"amplitude",config:{},async init({config:partialConfig,env:env,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{apiKey:apiKey}=settings;apiKey||logger.throw("Config settings apiKey missing");const settingsConfig={...settings,apiKey:apiKey};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger),amp=getAmplitude(env),{apiKey:apiKey,identify:_identify,eventOptions:_eventOptions,include:_include,...nodeOptions}=config.settings;return await amp.init(apiKey,nodeOptions).promise,config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,collector:collector,env:env}){var _a,_b,_c;const amp=getAmplitude(env),settings=config.settings,mappingSettings=(null==rule?void 0:rule.settings)||{},identifyMapping=null!=(_a=mappingSettings.identify)?_a:settings.identify;let identifyResolved;if(void 0!==identifyMapping){const resolved=await(0,import_core.getMappingValue)(event,identifyMapping,{collector:collector});(0,import_core.isObject)(resolved)&&(identifyResolved=resolved)}const eventOptionsMapping=null!=(_b=mappingSettings.eventOptions)?_b:settings.eventOptions;let eventOptionsResolved;if(void 0!==eventOptionsMapping){const resolved=await(0,import_core.getMappingValue)(event,eventOptionsMapping,{collector:collector});(0,import_core.isObject)(resolved)&&(eventOptionsResolved=resolved)}const eventOptions=buildEventOptions(identifyResolved,eventOptionsResolved),hasEventOptions=Object.keys(eventOptions).length>0;if(identifyResolved){const id=buildIdentify(amp,identifyResolved);id&&amp.identify(id,hasEventOptions?eventOptions:void 0)}if(void 0!==mappingSettings.group){const resolved=await(0,import_core.getMappingValue)(event,mappingSettings.group,{collector:collector});if((0,import_core.isObject)(resolved)){const{type:type,name:name}=resolved;(0,import_core.isString)(type)&&((0,import_core.isString)(name)||(0,import_core.isArray)(name))&&amp.setGroup(type,name,hasEventOptions?eventOptions:void 0)}}if(void 0!==mappingSettings.groupIdentify){const resolved=await(0,import_core.getMappingValue)(event,mappingSettings.groupIdentify,{collector:collector});if((0,import_core.isObject)(resolved)){const{type:type,name:name}=resolved;if((0,import_core.isString)(type)&&(0,import_core.isString)(name)){const id=buildIdentify(amp,resolved);id&&amp.groupIdentify(type,name,id,hasEventOptions?eventOptions:void 0)}}}if(void 0!==mappingSettings.revenue){const resolved=await(0,import_core.getMappingValue)(event,mappingSettings.revenue,{collector:collector}),items=(0,import_core.isArray)(resolved)?resolved:(0,import_core.isObject)(resolved)?[resolved]:[];for(const item of items)(0,import_core.isObject)(item)&&amp.revenue(buildRevenue(amp,item),hasEventOptions?eventOptions:void 0)}if(!0!==(null==rule?void 0:rule.skip)){const eventType=(0,import_core.isString)(null==rule?void 0:rule.name)?rule.name:event.name,include=null!=(_c=mappingSettings.include)?_c:settings.include,eventProperties=include?(0,import_core.flattenIncludeSections)(event,include):(0,import_core.isObject)(data)?data:{};amp.track(eventType,eventProperties,hasEventOptions?eventOptions:void 0)}}(event,context),on(type,context){var _a;if("consent"!==type||!context.data)return;const amp=getAmplitude(context.env),consent=context.data,required=null==(_a=context.config)?void 0:_a.consent;if(!required||0===Object.keys(required).length)return;const allGranted=Object.keys(required).every(key=>!0===consent[key]);amp.setOptOut(!allGranted)},async destroy({env:env}){const amp=getAmplitude(env);await amp.flush().promise}},index_default=destinationAmplitude;//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type { WalkerOS } from '@walkeros/core';\nimport type { Destination, Env } from './types';\nimport { getConfig } from './config';\nimport { push, getAmplitude } from './push';\n\nexport * as DestinationAmplitude from './types';\n\nexport const destinationAmplitude: Destination = {\n type: 'amplitude',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, logger);\n const amp = getAmplitude(env as Record<string, unknown> | undefined);\n\n // Destructure walkerOS-specific keys; the rest flow through to the SDK.\n const {\n apiKey,\n identify: _identify,\n eventOptions: _eventOptions,\n include: _include,\n ...nodeOptions\n } = config.settings;\n\n await amp.init(apiKey, nodeOptions).promise;\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n on(type, context) {\n if (type !== 'consent' || !context.data) return;\n const amp = getAmplitude(\n context.env as Record<string, unknown> | undefined,\n );\n\n const consent = context.data as WalkerOS.Consent;\n const required = context.config?.consent;\n if (!required || Object.keys(required).length === 0) return;\n\n const allGranted = Object.keys(required).every(\n (key) => consent[key] === true,\n );\n amp.setOptOut(!allGranted);\n },\n\n async destroy({ env }) {\n const amp = getAmplitude(env as Record<string, unknown> | undefined);\n await amp.flush().promise;\n },\n};\n\nexport default destinationAmplitude;\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 { apiKey } = settings;\n\n if (!apiKey) logger.throw('Config settings apiKey missing');\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n PushFn,\n AmplitudeSDK,\n EventOptions,\n IdentifyInstance,\n} from './types';\nimport {\n getMappingValue,\n isArray,\n isDefined,\n isNumber,\n isObject,\n isString,\n flattenIncludeSections,\n} from '@walkeros/core';\nimport * as amplitudeSDK from '@amplitude/analytics-node';\n\ntype IdentifyOpKey =\n | 'set'\n | 'setOnce'\n | 'add'\n | 'append'\n | 'prepend'\n | 'preInsert'\n | 'postInsert'\n | 'remove';\n\nconst IDENTIFY_OP_KEYS: IdentifyOpKey[] = [\n 'set',\n 'setOnce',\n 'add',\n 'append',\n 'prepend',\n 'preInsert',\n 'postInsert',\n 'remove',\n];\n\n/** Identity keys that map to EventOptions fields (not Identify operations). */\nconst IDENTITY_KEYS = ['user_id', 'device_id', 'session_id'] as const;\n\ntype RevenueFieldSetter =\n | 'setProductId'\n | 'setPrice'\n | 'setQuantity'\n | 'setRevenueType'\n | 'setCurrency'\n | 'setRevenue'\n | 'setReceipt'\n | 'setReceiptSig';\n\nconst REVENUE_FIELD_MAP: Record<string, RevenueFieldSetter> = {\n productId: 'setProductId',\n price: 'setPrice',\n quantity: 'setQuantity',\n revenueType: 'setRevenueType',\n currency: 'setCurrency',\n revenue: 'setRevenue',\n receipt: 'setReceipt',\n receiptSig: 'setReceiptSig',\n};\n\nexport function getAmplitude(\n env: Record<string, unknown> | undefined,\n): AmplitudeSDK {\n const amplitude = env?.amplitude as AmplitudeSDK | undefined;\n return amplitude ?? (amplitudeSDK as unknown as AmplitudeSDK);\n}\n\n/**\n * Deterministic string -> positive integer hash (djb2).\n * Used for session_id when walkerOS provides a string session.\n */\nfunction hashStringToInt(value: string): number {\n let hash = 5381;\n for (let i = 0; i < value.length; i++) {\n hash = ((hash << 5) + hash + value.charCodeAt(i)) | 0;\n }\n return Math.abs(hash);\n}\n\nfunction buildIdentify(\n amp: AmplitudeSDK,\n resolved: Record<string, unknown>,\n): IdentifyInstance | undefined {\n let identify: IdentifyInstance | undefined;\n const ensure = () => {\n if (!identify) identify = new amp.Identify();\n return identify;\n };\n\n for (const op of IDENTIFY_OP_KEYS) {\n const bag = resolved[op];\n if (!isObject(bag)) continue;\n for (const [prop, value] of Object.entries(bag)) {\n if (!isDefined(value)) continue;\n if (op === 'add') {\n if (isNumber(value)) ensure().add(prop, value);\n } else {\n ensure()[op](prop, value);\n }\n }\n }\n\n if (isArray(resolved.unset)) {\n for (const prop of resolved.unset) {\n if (isString(prop)) ensure().unset(prop);\n }\n }\n\n if (resolved.clearAll === true) {\n ensure().clearAll();\n }\n\n return identify;\n}\n\nfunction buildRevenue(\n amp: AmplitudeSDK,\n item: Record<string, unknown>,\n): InstanceType<AmplitudeSDK['Revenue']> {\n const rev = new amp.Revenue();\n for (const [key, setter] of Object.entries(REVENUE_FIELD_MAP)) {\n const value = item[key];\n if (!isDefined(value)) continue;\n (rev[setter] as (v: unknown) => unknown)(value);\n }\n if (isObject(item.eventProperties)) {\n rev.setEventProperties(item.eventProperties as Record<string, unknown>);\n }\n return rev;\n}\n\n/**\n * Build EventOptions from resolved identity and eventOptions mappings.\n */\nfunction buildEventOptions(\n identityResolved?: Record<string, unknown>,\n eventOptionsResolved?: Record<string, unknown>,\n): EventOptions {\n const opts: EventOptions = {};\n\n if (identityResolved) {\n if (isString(identityResolved.user_id))\n opts.user_id = identityResolved.user_id;\n if (isString(identityResolved.device_id))\n opts.device_id = identityResolved.device_id;\n if (identityResolved.session_id !== undefined) {\n const session = identityResolved.session_id;\n opts.session_id = isNumber(session)\n ? session\n : isString(session) && /^\\d+$/.test(session)\n ? Number(session)\n : isString(session)\n ? hashStringToInt(session)\n : undefined;\n }\n }\n\n if (eventOptionsResolved) {\n // Copy all recognized EventOptions fields\n for (const [key, value] of Object.entries(eventOptionsResolved)) {\n if (\n isDefined(value) &&\n !IDENTITY_KEYS.includes(key as (typeof IDENTITY_KEYS)[number])\n ) {\n (opts as Record<string, unknown>)[key] = value;\n }\n }\n }\n\n return opts;\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env },\n) {\n const amp = getAmplitude(env as Record<string, unknown> | undefined);\n const settings = config.settings!;\n const mappingSettings = rule?.settings || {};\n\n // 1. Resolve identity -- rule-level override wins over destination-level.\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n let identifyResolved: Record<string, unknown> | undefined;\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n identifyResolved = resolved as Record<string, unknown>;\n }\n }\n\n // 2. Resolve eventOptions -- rule-level override wins over destination-level.\n const eventOptionsMapping =\n mappingSettings.eventOptions ?? settings.eventOptions;\n let eventOptionsResolved: Record<string, unknown> | undefined;\n if (eventOptionsMapping !== undefined) {\n const resolved = await getMappingValue(event, eventOptionsMapping, {\n collector,\n });\n if (isObject(resolved)) {\n eventOptionsResolved = resolved as Record<string, unknown>;\n }\n }\n\n // 3. Build EventOptions from identity + eventOptions.\n const eventOptions = buildEventOptions(\n identifyResolved,\n eventOptionsResolved,\n );\n const hasEventOptions = Object.keys(eventOptions).length > 0;\n\n // 4. Identify operations -- fires amplitude.identify() if op keys are present.\n if (identifyResolved) {\n const id = buildIdentify(amp, identifyResolved);\n if (id) amp.identify(id, hasEventOptions ? eventOptions : undefined);\n }\n\n // 5. Group assignment\n if (mappingSettings.group !== undefined) {\n const resolved = await getMappingValue(event, mappingSettings.group, {\n collector,\n });\n if (isObject(resolved)) {\n const { type, name } = resolved as {\n type?: unknown;\n name?: unknown;\n };\n if (isString(type) && (isString(name) || isArray(name))) {\n amp.setGroup(\n type,\n name as string | string[],\n hasEventOptions ? eventOptions : undefined,\n );\n }\n }\n }\n\n // 6. Group identify (properties on the group)\n if (mappingSettings.groupIdentify !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.groupIdentify,\n { collector },\n );\n if (isObject(resolved)) {\n const { type, name } = resolved as {\n type?: unknown;\n name?: unknown;\n };\n if (isString(type) && isString(name)) {\n const id = buildIdentify(amp, resolved as Record<string, unknown>);\n if (id)\n amp.groupIdentify(\n type,\n name,\n id,\n hasEventOptions ? eventOptions : undefined,\n );\n }\n }\n }\n\n // 7. Revenue -- single object or array from loop -> N revenue() calls.\n if (mappingSettings.revenue !== undefined) {\n const resolved = await getMappingValue(event, mappingSettings.revenue, {\n collector,\n });\n const items = isArray(resolved)\n ? (resolved as Record<string, unknown>[])\n : isObject(resolved)\n ? [resolved as Record<string, unknown>]\n : [];\n for (const item of items) {\n if (!isObject(item)) continue;\n amp.revenue(\n buildRevenue(amp, item),\n hasEventOptions ? eventOptions : undefined,\n );\n }\n }\n\n // 8. Default track (unless skip: true)\n if (rule?.skip !== true) {\n const eventType = isString(rule?.name) ? rule.name : event.name;\n\n // Resolve include: rule-level replaces destination-level.\n const include = mappingSettings.include ?? settings.include;\n const eventProperties: Record<string, unknown> = include\n ? flattenIncludeSections(event, include)\n : isObject(data)\n ? (data as Record<string, unknown>)\n : {};\n\n amp.track(\n eventType,\n eventProperties,\n hasEventOptions ? eventOptions : undefined,\n );\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 * Amplitude SDK surface -- the subset of @amplitude/analytics-node the\n * destination actually uses. Tests provide a mock via env.amplitude;\n * production uses the real SDK import.\n *\n * Key difference from web: no setUserId/setDeviceId/setSessionId.\n * Identity is per-event via EventOptions on every SDK call.\n */\nexport interface AmplitudeSDK {\n init: (\n apiKey: string,\n options?: Record<string, unknown>,\n ) => { promise: Promise<void> };\n track: (\n eventType: string,\n eventProperties?: Record<string, unknown>,\n eventOptions?: EventOptions,\n ) => void;\n identify: (identify: IdentifyInstance, eventOptions?: EventOptions) => void;\n revenue: (revenue: RevenueInstance, eventOptions?: EventOptions) => void;\n setGroup: (\n groupType: string,\n groupName: string | string[],\n eventOptions?: EventOptions,\n ) => void;\n groupIdentify: (\n groupType: string,\n groupName: string,\n identify: IdentifyInstance,\n eventOptions?: EventOptions,\n ) => void;\n setOptOut: (optOut: boolean) => void;\n flush: () => { promise: Promise<void> };\n Identify: new () => IdentifyInstance;\n Revenue: new () => RevenueInstance;\n}\n\n/**\n * Per-event identity and metadata fields. Passed to every SDK call.\n * Maps directly to Amplitude's EventOptions type from the Node SDK.\n */\nexport interface EventOptions {\n user_id?: string;\n device_id?: string;\n session_id?: number;\n time?: number;\n insert_id?: string;\n ip?: string;\n city?: string;\n country?: string;\n region?: string;\n language?: string;\n platform?: string;\n os_name?: string;\n os_version?: string;\n device_brand?: string;\n device_manufacturer?: string;\n device_model?: string;\n app_version?: string;\n carrier?: string;\n user_agent?: string;\n groups?: Record<string, unknown>;\n plan?: Record<string, unknown>;\n ingestion_metadata?: Record<string, unknown>;\n partner_id?: string;\n extra?: Record<string, unknown>;\n}\n\n/** Chainable Identify -- mirrors @amplitude/analytics-node Identify class. */\nexport interface IdentifyInstance {\n set: (property: string, value: unknown) => IdentifyInstance;\n setOnce: (property: string, value: unknown) => IdentifyInstance;\n add: (property: string, value: number) => IdentifyInstance;\n append: (property: string, value: unknown) => IdentifyInstance;\n prepend: (property: string, value: unknown) => IdentifyInstance;\n preInsert: (property: string, value: unknown) => IdentifyInstance;\n postInsert: (property: string, value: unknown) => IdentifyInstance;\n remove: (property: string, value: unknown) => IdentifyInstance;\n unset: (property: string) => IdentifyInstance;\n clearAll: () => IdentifyInstance;\n}\n\n/** Chainable Revenue -- mirrors @amplitude/analytics-node Revenue class. */\nexport interface RevenueInstance {\n setProductId: (id: string) => RevenueInstance;\n setPrice: (price: number) => RevenueInstance;\n setQuantity: (quantity: number) => RevenueInstance;\n setRevenueType: (type: string) => RevenueInstance;\n setCurrency: (currency: string) => RevenueInstance;\n setRevenue: (revenue: number) => RevenueInstance;\n setReceipt: (receipt: string) => RevenueInstance;\n setReceiptSig: (signature: string) => RevenueInstance;\n setEventProperties: (properties: Record<string, unknown>) => RevenueInstance;\n}\n\n/**\n * Destination-level settings. apiKey is required; all other fields\n * are optional and passed through to the Amplitude Node SDK init().\n */\nexport interface Settings {\n apiKey: string;\n serverZone?: 'US' | 'EU';\n flushIntervalMillis?: number;\n flushQueueSize?: number;\n flushMaxRetries?: number;\n useBatch?: boolean;\n minIdLength?: number;\n serverUrl?: string;\n logLevel?: number;\n optOut?: boolean;\n offline?: boolean;\n enableRequestBodyCompression?: boolean;\n plan?: Record<string, unknown>;\n ingestionMetadata?: Record<string, unknown>;\n\n /** walkerOS mapping value for per-event identity resolution. */\n identify?: WalkerOSMapping.Value;\n /** walkerOS mapping value for per-event EventOptions (time, insert_id, ip, etc). */\n eventOptions?: WalkerOSMapping.Value;\n /** Sections to include as event_properties (e.g., ['data', 'globals']). */\n include?: string[];\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings. Each is a walkerOS mapping value resolved\n * via getMappingValue(). Revenue supports loop for multi-item orders.\n */\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n revenue?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n groupIdentify?: WalkerOSMapping.Value;\n eventOptions?: WalkerOSMapping.Value;\n include?: string[];\n}\n\n/**\n * Env -- optional SDK override. Production leaves this undefined and the\n * destination falls back to the real @amplitude/analytics-node import.\n * Tests provide a mock via env.amplitude.\n */\nexport interface Env extends DestinationServer.Env {\n amplitude?: AmplitudeSDK;\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"],"mappings":"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","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ import{getMappingValue,isArray,isDefined,isNumber,isObject,isString,flattenIncludeSections}from"@walkeros/core";import*as amplitudeSDK from"@amplitude/analytics-node";var IDENTIFY_OP_KEYS=["set","setOnce","add","append","prepend","preInsert","postInsert","remove"],IDENTITY_KEYS=["user_id","device_id","session_id"],REVENUE_FIELD_MAP={productId:"setProductId",price:"setPrice",quantity:"setQuantity",revenueType:"setRevenueType",currency:"setCurrency",revenue:"setRevenue",receipt:"setReceipt",receiptSig:"setReceiptSig"};function getAmplitude(env){const amplitude=null==env?void 0:env.amplitude;return null!=amplitude?amplitude:amplitudeSDK}function buildIdentify(amp,resolved){let identify;const ensure=()=>(identify||(identify=new amp.Identify),identify);for(const op of IDENTIFY_OP_KEYS){const bag=resolved[op];if(isObject(bag))for(const[prop,value]of Object.entries(bag))isDefined(value)&&("add"===op?isNumber(value)&&ensure().add(prop,value):ensure()[op](prop,value))}if(isArray(resolved.unset))for(const prop of resolved.unset)isString(prop)&&ensure().unset(prop);return!0===resolved.clearAll&&ensure().clearAll(),identify}function buildRevenue(amp,item){const rev=new amp.Revenue;for(const[key,setter]of Object.entries(REVENUE_FIELD_MAP)){const value=item[key];isDefined(value)&&rev[setter](value)}return isObject(item.eventProperties)&&rev.setEventProperties(item.eventProperties),rev}function buildEventOptions(identityResolved,eventOptionsResolved){const opts={};if(identityResolved&&(isString(identityResolved.user_id)&&(opts.user_id=identityResolved.user_id),isString(identityResolved.device_id)&&(opts.device_id=identityResolved.device_id),void 0!==identityResolved.session_id)){const session=identityResolved.session_id;opts.session_id=isNumber(session)?session:isString(session)&&/^\d+$/.test(session)?Number(session):isString(session)?function(value){let hash=5381;for(let i=0;i<value.length;i++)hash=(hash<<5)+hash+value.charCodeAt(i)|0;return Math.abs(hash)}(session):void 0}if(eventOptionsResolved)for(const[key,value]of Object.entries(eventOptionsResolved))isDefined(value)&&!IDENTITY_KEYS.includes(key)&&(opts[key]=value);return opts}var types_exports={},destinationAmplitude={type:"amplitude",config:{},async init({config:partialConfig,env:env,logger:logger}){const config=function(partialConfig={},logger){const settings=partialConfig.settings||{},{apiKey:apiKey}=settings;apiKey||logger.throw("Config settings apiKey missing");const settingsConfig={...settings,apiKey:apiKey};return{...partialConfig,settings:settingsConfig}}(partialConfig,logger),amp=getAmplitude(env),{apiKey:apiKey,identify:_identify,eventOptions:_eventOptions,include:_include,...nodeOptions}=config.settings;return await amp.init(apiKey,nodeOptions).promise,config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,collector:collector,env:env}){var _a,_b,_c;const amp=getAmplitude(env),settings=config.settings,mappingSettings=(null==rule?void 0:rule.settings)||{},identifyMapping=null!=(_a=mappingSettings.identify)?_a:settings.identify;let identifyResolved;if(void 0!==identifyMapping){const resolved=await getMappingValue(event,identifyMapping,{collector:collector});isObject(resolved)&&(identifyResolved=resolved)}const eventOptionsMapping=null!=(_b=mappingSettings.eventOptions)?_b:settings.eventOptions;let eventOptionsResolved;if(void 0!==eventOptionsMapping){const resolved=await getMappingValue(event,eventOptionsMapping,{collector:collector});isObject(resolved)&&(eventOptionsResolved=resolved)}const eventOptions=buildEventOptions(identifyResolved,eventOptionsResolved),hasEventOptions=Object.keys(eventOptions).length>0;if(identifyResolved){const id=buildIdentify(amp,identifyResolved);id&&amp.identify(id,hasEventOptions?eventOptions:void 0)}if(void 0!==mappingSettings.group){const resolved=await getMappingValue(event,mappingSettings.group,{collector:collector});if(isObject(resolved)){const{type:type,name:name}=resolved;isString(type)&&(isString(name)||isArray(name))&&amp.setGroup(type,name,hasEventOptions?eventOptions:void 0)}}if(void 0!==mappingSettings.groupIdentify){const resolved=await getMappingValue(event,mappingSettings.groupIdentify,{collector:collector});if(isObject(resolved)){const{type:type,name:name}=resolved;if(isString(type)&&isString(name)){const id=buildIdentify(amp,resolved);id&&amp.groupIdentify(type,name,id,hasEventOptions?eventOptions:void 0)}}}if(void 0!==mappingSettings.revenue){const resolved=await getMappingValue(event,mappingSettings.revenue,{collector:collector}),items=isArray(resolved)?resolved:isObject(resolved)?[resolved]:[];for(const item of items)isObject(item)&&amp.revenue(buildRevenue(amp,item),hasEventOptions?eventOptions:void 0)}if(!0!==(null==rule?void 0:rule.skip)){const eventType=isString(null==rule?void 0:rule.name)?rule.name:event.name,include=null!=(_c=mappingSettings.include)?_c:settings.include,eventProperties=include?flattenIncludeSections(event,include):isObject(data)?data:{};amp.track(eventType,eventProperties,hasEventOptions?eventOptions:void 0)}}(event,context),on(type,context){var _a;if("consent"!==type||!context.data)return;const amp=getAmplitude(context.env),consent=context.data,required=null==(_a=context.config)?void 0:_a.consent;if(!required||0===Object.keys(required).length)return;const allGranted=Object.keys(required).every(key=>!0===consent[key]);amp.setOptOut(!allGranted)},async destroy({env:env}){const amp=getAmplitude(env);await amp.flush().promise}},index_default=destinationAmplitude;export{types_exports as DestinationAmplitude,index_default as default,destinationAmplitude};//# sourceMappingURL=index.mjs.map
@@ -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 { apiKey } = settings;\n\n if (!apiKey) logger.throw('Config settings apiKey missing');\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n PushFn,\n AmplitudeSDK,\n EventOptions,\n IdentifyInstance,\n} from './types';\nimport {\n getMappingValue,\n isArray,\n isDefined,\n isNumber,\n isObject,\n isString,\n flattenIncludeSections,\n} from '@walkeros/core';\nimport * as amplitudeSDK from '@amplitude/analytics-node';\n\ntype IdentifyOpKey =\n | 'set'\n | 'setOnce'\n | 'add'\n | 'append'\n | 'prepend'\n | 'preInsert'\n | 'postInsert'\n | 'remove';\n\nconst IDENTIFY_OP_KEYS: IdentifyOpKey[] = [\n 'set',\n 'setOnce',\n 'add',\n 'append',\n 'prepend',\n 'preInsert',\n 'postInsert',\n 'remove',\n];\n\n/** Identity keys that map to EventOptions fields (not Identify operations). */\nconst IDENTITY_KEYS = ['user_id', 'device_id', 'session_id'] as const;\n\ntype RevenueFieldSetter =\n | 'setProductId'\n | 'setPrice'\n | 'setQuantity'\n | 'setRevenueType'\n | 'setCurrency'\n | 'setRevenue'\n | 'setReceipt'\n | 'setReceiptSig';\n\nconst REVENUE_FIELD_MAP: Record<string, RevenueFieldSetter> = {\n productId: 'setProductId',\n price: 'setPrice',\n quantity: 'setQuantity',\n revenueType: 'setRevenueType',\n currency: 'setCurrency',\n revenue: 'setRevenue',\n receipt: 'setReceipt',\n receiptSig: 'setReceiptSig',\n};\n\nexport function getAmplitude(\n env: Record<string, unknown> | undefined,\n): AmplitudeSDK {\n const amplitude = env?.amplitude as AmplitudeSDK | undefined;\n return amplitude ?? (amplitudeSDK as unknown as AmplitudeSDK);\n}\n\n/**\n * Deterministic string -> positive integer hash (djb2).\n * Used for session_id when walkerOS provides a string session.\n */\nfunction hashStringToInt(value: string): number {\n let hash = 5381;\n for (let i = 0; i < value.length; i++) {\n hash = ((hash << 5) + hash + value.charCodeAt(i)) | 0;\n }\n return Math.abs(hash);\n}\n\nfunction buildIdentify(\n amp: AmplitudeSDK,\n resolved: Record<string, unknown>,\n): IdentifyInstance | undefined {\n let identify: IdentifyInstance | undefined;\n const ensure = () => {\n if (!identify) identify = new amp.Identify();\n return identify;\n };\n\n for (const op of IDENTIFY_OP_KEYS) {\n const bag = resolved[op];\n if (!isObject(bag)) continue;\n for (const [prop, value] of Object.entries(bag)) {\n if (!isDefined(value)) continue;\n if (op === 'add') {\n if (isNumber(value)) ensure().add(prop, value);\n } else {\n ensure()[op](prop, value);\n }\n }\n }\n\n if (isArray(resolved.unset)) {\n for (const prop of resolved.unset) {\n if (isString(prop)) ensure().unset(prop);\n }\n }\n\n if (resolved.clearAll === true) {\n ensure().clearAll();\n }\n\n return identify;\n}\n\nfunction buildRevenue(\n amp: AmplitudeSDK,\n item: Record<string, unknown>,\n): InstanceType<AmplitudeSDK['Revenue']> {\n const rev = new amp.Revenue();\n for (const [key, setter] of Object.entries(REVENUE_FIELD_MAP)) {\n const value = item[key];\n if (!isDefined(value)) continue;\n (rev[setter] as (v: unknown) => unknown)(value);\n }\n if (isObject(item.eventProperties)) {\n rev.setEventProperties(item.eventProperties as Record<string, unknown>);\n }\n return rev;\n}\n\n/**\n * Build EventOptions from resolved identity and eventOptions mappings.\n */\nfunction buildEventOptions(\n identityResolved?: Record<string, unknown>,\n eventOptionsResolved?: Record<string, unknown>,\n): EventOptions {\n const opts: EventOptions = {};\n\n if (identityResolved) {\n if (isString(identityResolved.user_id))\n opts.user_id = identityResolved.user_id;\n if (isString(identityResolved.device_id))\n opts.device_id = identityResolved.device_id;\n if (identityResolved.session_id !== undefined) {\n const session = identityResolved.session_id;\n opts.session_id = isNumber(session)\n ? session\n : isString(session) && /^\\d+$/.test(session)\n ? Number(session)\n : isString(session)\n ? hashStringToInt(session)\n : undefined;\n }\n }\n\n if (eventOptionsResolved) {\n // Copy all recognized EventOptions fields\n for (const [key, value] of Object.entries(eventOptionsResolved)) {\n if (\n isDefined(value) &&\n !IDENTITY_KEYS.includes(key as (typeof IDENTITY_KEYS)[number])\n ) {\n (opts as Record<string, unknown>)[key] = value;\n }\n }\n }\n\n return opts;\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env },\n) {\n const amp = getAmplitude(env as Record<string, unknown> | undefined);\n const settings = config.settings!;\n const mappingSettings = rule?.settings || {};\n\n // 1. Resolve identity -- rule-level override wins over destination-level.\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n let identifyResolved: Record<string, unknown> | undefined;\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n identifyResolved = resolved as Record<string, unknown>;\n }\n }\n\n // 2. Resolve eventOptions -- rule-level override wins over destination-level.\n const eventOptionsMapping =\n mappingSettings.eventOptions ?? settings.eventOptions;\n let eventOptionsResolved: Record<string, unknown> | undefined;\n if (eventOptionsMapping !== undefined) {\n const resolved = await getMappingValue(event, eventOptionsMapping, {\n collector,\n });\n if (isObject(resolved)) {\n eventOptionsResolved = resolved as Record<string, unknown>;\n }\n }\n\n // 3. Build EventOptions from identity + eventOptions.\n const eventOptions = buildEventOptions(\n identifyResolved,\n eventOptionsResolved,\n );\n const hasEventOptions = Object.keys(eventOptions).length > 0;\n\n // 4. Identify operations -- fires amplitude.identify() if op keys are present.\n if (identifyResolved) {\n const id = buildIdentify(amp, identifyResolved);\n if (id) amp.identify(id, hasEventOptions ? eventOptions : undefined);\n }\n\n // 5. Group assignment\n if (mappingSettings.group !== undefined) {\n const resolved = await getMappingValue(event, mappingSettings.group, {\n collector,\n });\n if (isObject(resolved)) {\n const { type, name } = resolved as {\n type?: unknown;\n name?: unknown;\n };\n if (isString(type) && (isString(name) || isArray(name))) {\n amp.setGroup(\n type,\n name as string | string[],\n hasEventOptions ? eventOptions : undefined,\n );\n }\n }\n }\n\n // 6. Group identify (properties on the group)\n if (mappingSettings.groupIdentify !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.groupIdentify,\n { collector },\n );\n if (isObject(resolved)) {\n const { type, name } = resolved as {\n type?: unknown;\n name?: unknown;\n };\n if (isString(type) && isString(name)) {\n const id = buildIdentify(amp, resolved as Record<string, unknown>);\n if (id)\n amp.groupIdentify(\n type,\n name,\n id,\n hasEventOptions ? eventOptions : undefined,\n );\n }\n }\n }\n\n // 7. Revenue -- single object or array from loop -> N revenue() calls.\n if (mappingSettings.revenue !== undefined) {\n const resolved = await getMappingValue(event, mappingSettings.revenue, {\n collector,\n });\n const items = isArray(resolved)\n ? (resolved as Record<string, unknown>[])\n : isObject(resolved)\n ? [resolved as Record<string, unknown>]\n : [];\n for (const item of items) {\n if (!isObject(item)) continue;\n amp.revenue(\n buildRevenue(amp, item),\n hasEventOptions ? eventOptions : undefined,\n );\n }\n }\n\n // 8. Default track (unless skip: true)\n if (rule?.skip !== true) {\n const eventType = isString(rule?.name) ? rule.name : event.name;\n\n // Resolve include: rule-level replaces destination-level.\n const include = mappingSettings.include ?? settings.include;\n const eventProperties: Record<string, unknown> = include\n ? flattenIncludeSections(event, include)\n : isObject(data)\n ? (data as Record<string, unknown>)\n : {};\n\n amp.track(\n eventType,\n eventProperties,\n hasEventOptions ? eventOptions : undefined,\n );\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 * Amplitude SDK surface -- the subset of @amplitude/analytics-node the\n * destination actually uses. Tests provide a mock via env.amplitude;\n * production uses the real SDK import.\n *\n * Key difference from web: no setUserId/setDeviceId/setSessionId.\n * Identity is per-event via EventOptions on every SDK call.\n */\nexport interface AmplitudeSDK {\n init: (\n apiKey: string,\n options?: Record<string, unknown>,\n ) => { promise: Promise<void> };\n track: (\n eventType: string,\n eventProperties?: Record<string, unknown>,\n eventOptions?: EventOptions,\n ) => void;\n identify: (identify: IdentifyInstance, eventOptions?: EventOptions) => void;\n revenue: (revenue: RevenueInstance, eventOptions?: EventOptions) => void;\n setGroup: (\n groupType: string,\n groupName: string | string[],\n eventOptions?: EventOptions,\n ) => void;\n groupIdentify: (\n groupType: string,\n groupName: string,\n identify: IdentifyInstance,\n eventOptions?: EventOptions,\n ) => void;\n setOptOut: (optOut: boolean) => void;\n flush: () => { promise: Promise<void> };\n Identify: new () => IdentifyInstance;\n Revenue: new () => RevenueInstance;\n}\n\n/**\n * Per-event identity and metadata fields. Passed to every SDK call.\n * Maps directly to Amplitude's EventOptions type from the Node SDK.\n */\nexport interface EventOptions {\n user_id?: string;\n device_id?: string;\n session_id?: number;\n time?: number;\n insert_id?: string;\n ip?: string;\n city?: string;\n country?: string;\n region?: string;\n language?: string;\n platform?: string;\n os_name?: string;\n os_version?: string;\n device_brand?: string;\n device_manufacturer?: string;\n device_model?: string;\n app_version?: string;\n carrier?: string;\n user_agent?: string;\n groups?: Record<string, unknown>;\n plan?: Record<string, unknown>;\n ingestion_metadata?: Record<string, unknown>;\n partner_id?: string;\n extra?: Record<string, unknown>;\n}\n\n/** Chainable Identify -- mirrors @amplitude/analytics-node Identify class. */\nexport interface IdentifyInstance {\n set: (property: string, value: unknown) => IdentifyInstance;\n setOnce: (property: string, value: unknown) => IdentifyInstance;\n add: (property: string, value: number) => IdentifyInstance;\n append: (property: string, value: unknown) => IdentifyInstance;\n prepend: (property: string, value: unknown) => IdentifyInstance;\n preInsert: (property: string, value: unknown) => IdentifyInstance;\n postInsert: (property: string, value: unknown) => IdentifyInstance;\n remove: (property: string, value: unknown) => IdentifyInstance;\n unset: (property: string) => IdentifyInstance;\n clearAll: () => IdentifyInstance;\n}\n\n/** Chainable Revenue -- mirrors @amplitude/analytics-node Revenue class. */\nexport interface RevenueInstance {\n setProductId: (id: string) => RevenueInstance;\n setPrice: (price: number) => RevenueInstance;\n setQuantity: (quantity: number) => RevenueInstance;\n setRevenueType: (type: string) => RevenueInstance;\n setCurrency: (currency: string) => RevenueInstance;\n setRevenue: (revenue: number) => RevenueInstance;\n setReceipt: (receipt: string) => RevenueInstance;\n setReceiptSig: (signature: string) => RevenueInstance;\n setEventProperties: (properties: Record<string, unknown>) => RevenueInstance;\n}\n\n/**\n * Destination-level settings. apiKey is required; all other fields\n * are optional and passed through to the Amplitude Node SDK init().\n */\nexport interface Settings {\n apiKey: string;\n serverZone?: 'US' | 'EU';\n flushIntervalMillis?: number;\n flushQueueSize?: number;\n flushMaxRetries?: number;\n useBatch?: boolean;\n minIdLength?: number;\n serverUrl?: string;\n logLevel?: number;\n optOut?: boolean;\n offline?: boolean;\n enableRequestBodyCompression?: boolean;\n plan?: Record<string, unknown>;\n ingestionMetadata?: Record<string, unknown>;\n\n /** walkerOS mapping value for per-event identity resolution. */\n identify?: WalkerOSMapping.Value;\n /** walkerOS mapping value for per-event EventOptions (time, insert_id, ip, etc). */\n eventOptions?: WalkerOSMapping.Value;\n /** Sections to include as event_properties (e.g., ['data', 'globals']). */\n include?: string[];\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings. Each is a walkerOS mapping value resolved\n * via getMappingValue(). Revenue supports loop for multi-item orders.\n */\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n revenue?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n groupIdentify?: WalkerOSMapping.Value;\n eventOptions?: WalkerOSMapping.Value;\n include?: string[];\n}\n\n/**\n * Env -- optional SDK override. Production leaves this undefined and the\n * destination falls back to the real @amplitude/analytics-node import.\n * Tests provide a mock via env.amplitude.\n */\nexport interface Env extends DestinationServer.Env {\n amplitude?: AmplitudeSDK;\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","import type { WalkerOS } from '@walkeros/core';\nimport type { Destination, Env } from './types';\nimport { getConfig } from './config';\nimport { push, getAmplitude } from './push';\n\nexport * as DestinationAmplitude from './types';\n\nexport const destinationAmplitude: Destination = {\n type: 'amplitude',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, logger);\n const amp = getAmplitude(env as Record<string, unknown> | undefined);\n\n // Destructure walkerOS-specific keys; the rest flow through to the SDK.\n const {\n apiKey,\n identify: _identify,\n eventOptions: _eventOptions,\n include: _include,\n ...nodeOptions\n } = config.settings;\n\n await amp.init(apiKey, nodeOptions).promise;\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n on(type, context) {\n if (type !== 'consent' || !context.data) return;\n const amp = getAmplitude(\n context.env as Record<string, unknown> | undefined,\n );\n\n const consent = context.data as WalkerOS.Consent;\n const required = context.config?.consent;\n if (!required || Object.keys(required).length === 0) return;\n\n const allGranted = Object.keys(required).every(\n (key) => consent[key] === true,\n );\n amp.setOptOut(!allGranted);\n },\n\n async destroy({ env }) {\n const amp = getAmplitude(env as Record<string, unknown> | undefined);\n await amp.flush().promise;\n },\n};\n\nexport default destinationAmplitude;\n"],"mappings":"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","names":[]}