@sygnl/mapper 1.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/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # @sygnl/mapper
2
+
3
+ Declarative event mapper for transforming events between different ad platform formats.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @sygnl/mapper
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { EventMapper, transforms } from '@sygnl/mapper';
15
+
16
+ const mapper = new EventMapper({
17
+ eventNames: [
18
+ { from: 'purchase', to: 'Purchase' }
19
+ ],
20
+ fields: [
21
+ { from: 'user.email', to: 'userData.em' },
22
+ { from: 'timestamp', to: 'event_time', transform: transforms.msToSeconds }
23
+ ],
24
+ static: [
25
+ { to: 'action_source', value: 'website' }
26
+ ]
27
+ });
28
+
29
+ const result = mapper.map(sourceEvent);
30
+ ```
31
+
32
+ ## Use Cases
33
+
34
+ - Map events to Meta CAPI format
35
+ - Transform for Google Enhanced Conversions
36
+ - Adapt to Snapchat/TikTok/Bing APIs
37
+ - Build platform-agnostic event pipelines
38
+ - Define mappings once, reuse everywhere
39
+
40
+ ## API
41
+
42
+ ### `EventMapper`
43
+
44
+ ```typescript
45
+ const mapper = new EventMapper({
46
+ eventNames?: EventNameMapping[],
47
+ fields?: FieldMapping[],
48
+ static?: StaticField[],
49
+ sourceRoot?: string,
50
+ targetRoot?: string
51
+ });
52
+
53
+ const result = mapper.map(source);
54
+ const results = mapper.mapBatch(sources);
55
+ ```
56
+
57
+ ### Field Mapping
58
+
59
+ ```typescript
60
+ {
61
+ from: 'source.path' | ['path1', 'path2'], // Fallback sources
62
+ to: 'target.path',
63
+ transform?: (value, source) => any,
64
+ condition?: (source) => boolean,
65
+ default?: any,
66
+ skipFalsy?: boolean
67
+ }
68
+ ```
69
+
70
+ ## Transforms
71
+
72
+ Built-in transforms for common conversions:
73
+
74
+ ```typescript
75
+ import { transforms } from '@sygnl/mapper';
76
+
77
+ transforms.msToSeconds(timestamp); // 1704067200000 → 1704067200
78
+ transforms.lowercase(str); // "EMAIL" → "email"
79
+ transforms.toArray(value); // "foo" → ["foo"]
80
+ transforms.pluck('id')(array); // [{id:1},{id:2}] → [1,2]
81
+ transforms.pipe(fn1, fn2, fn3); // Compose transforms
82
+ ```
83
+
84
+ ## Examples
85
+
86
+ ### Meta CAPI Mapping
87
+
88
+ ```typescript
89
+ const metaMapper = new EventMapper({
90
+ eventNames: [
91
+ { from: ['purchase', 'order_completed'], to: 'Purchase' }
92
+ ],
93
+ fields: [
94
+ { from: 'timestamp', to: 'event_time', transform: transforms.msToSeconds },
95
+ { from: 'user.email', to: 'user_data.em' },
96
+ { from: 'products', to: 'custom_data.content_ids', transform: transforms.pluck('id') },
97
+ { from: 'value', to: 'custom_data.value' }
98
+ ],
99
+ static: [
100
+ { to: 'action_source', value: 'website' }
101
+ ],
102
+ targetRoot: 'data.0'
103
+ });
104
+ ```
105
+
106
+ ### Conditional Mapping
107
+
108
+ ```typescript
109
+ {
110
+ from: 'revenue',
111
+ to: 'purchase_value',
112
+ condition: (source) => source.event_type === 'purchase',
113
+ transform: (value) => Math.round(value * 100) / 100
114
+ }
115
+ ```
116
+
117
+ ### Multiple Source Fallbacks
118
+
119
+ ```typescript
120
+ {
121
+ from: ['user.email', 'email', 'user_email'],
122
+ to: 'email'
123
+ }
124
+ ```
125
+
126
+ ## License
127
+
128
+ Apache-2.0
129
+
130
+ Copyright 2026 Edge Foundry, Inc.
package/dist/index.cjs ADDED
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ EventMapper: () => EventMapper,
24
+ transforms: () => transforms_exports
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/EventMapper.ts
29
+ var EventMapper = class {
30
+ constructor(config) {
31
+ this.config = config;
32
+ }
33
+ /**
34
+ * Map an event from source format to target format
35
+ */
36
+ map(source) {
37
+ const result = {
38
+ data: {},
39
+ mappedFields: [],
40
+ skippedFields: [],
41
+ errors: []
42
+ };
43
+ try {
44
+ const sourceData = this.config.sourceRoot ? this.getValueAtPath(source, this.config.sourceRoot) : source;
45
+ if (this.config.eventNames) {
46
+ const eventName = this.mapEventName(sourceData);
47
+ if (eventName) {
48
+ this.setValueAtPath(result.data, "event_name", eventName);
49
+ result.mappedFields.push("event_name");
50
+ }
51
+ }
52
+ if (this.config.fields) {
53
+ for (const fieldMapping of this.config.fields) {
54
+ this.mapField(sourceData, result.data, fieldMapping, result);
55
+ }
56
+ }
57
+ if (this.config.static) {
58
+ for (const staticField of this.config.static) {
59
+ this.mapStaticField(sourceData, result.data, staticField, result);
60
+ }
61
+ }
62
+ if (this.config.targetRoot) {
63
+ const wrapped = {};
64
+ this.setValueAtPath(wrapped, this.config.targetRoot, result.data);
65
+ result.data = wrapped;
66
+ }
67
+ } catch (error) {
68
+ result.errors.push({
69
+ field: "_root",
70
+ error: error instanceof Error ? error.message : String(error)
71
+ });
72
+ }
73
+ return result;
74
+ }
75
+ /**
76
+ * Map event name using event name mappings
77
+ */
78
+ mapEventName(source) {
79
+ if (!this.config.eventNames) return void 0;
80
+ const sourceEventName = source.event_type || source.eventType || source.event_name;
81
+ if (!sourceEventName) return void 0;
82
+ for (const mapping of this.config.eventNames) {
83
+ const fromNames = Array.isArray(mapping.from) ? mapping.from : [mapping.from];
84
+ if (fromNames.includes(sourceEventName)) {
85
+ return mapping.to;
86
+ }
87
+ }
88
+ return void 0;
89
+ }
90
+ /**
91
+ * Map a single field
92
+ */
93
+ mapField(source, target, mapping, result) {
94
+ try {
95
+ if (mapping.condition && !mapping.condition(source)) {
96
+ result.skippedFields.push(mapping.to);
97
+ return;
98
+ }
99
+ const fromPaths = Array.isArray(mapping.from) ? mapping.from : [mapping.from];
100
+ let value = void 0;
101
+ for (const fromPath of fromPaths) {
102
+ value = this.getValueAtPath(source, fromPath);
103
+ if (value !== void 0 && value !== null) break;
104
+ }
105
+ if (value === void 0 || value === null) {
106
+ if (mapping.default !== void 0) {
107
+ value = mapping.default;
108
+ } else {
109
+ result.skippedFields.push(mapping.to);
110
+ return;
111
+ }
112
+ }
113
+ if (mapping.skipFalsy && !value) {
114
+ result.skippedFields.push(mapping.to);
115
+ return;
116
+ }
117
+ if (mapping.transform) {
118
+ value = mapping.transform(value, source);
119
+ }
120
+ this.setValueAtPath(target, mapping.to, value);
121
+ result.mappedFields.push(mapping.to);
122
+ } catch (error) {
123
+ result.errors.push({
124
+ field: mapping.to,
125
+ error: error instanceof Error ? error.message : String(error)
126
+ });
127
+ }
128
+ }
129
+ /**
130
+ * Map a static field
131
+ */
132
+ mapStaticField(source, target, staticField, result) {
133
+ try {
134
+ const value = typeof staticField.value === "function" ? staticField.value(source) : staticField.value;
135
+ this.setValueAtPath(target, staticField.to, value);
136
+ result.mappedFields.push(staticField.to);
137
+ } catch (error) {
138
+ result.errors.push({
139
+ field: staticField.to,
140
+ error: error instanceof Error ? error.message : String(error)
141
+ });
142
+ }
143
+ }
144
+ /**
145
+ * Get value at path using dot notation
146
+ * Supports array indexing (e.g., 'products.0.id')
147
+ */
148
+ getValueAtPath(obj, path) {
149
+ const parts = path.split(".");
150
+ let value = obj;
151
+ for (const part of parts) {
152
+ if (value === void 0 || value === null) return void 0;
153
+ if (/^\d+$/.test(part)) {
154
+ value = value[parseInt(part, 10)];
155
+ } else {
156
+ value = value[part];
157
+ }
158
+ }
159
+ return value;
160
+ }
161
+ /**
162
+ * Set value at path using dot notation
163
+ * Creates nested objects/arrays as needed
164
+ */
165
+ setValueAtPath(obj, path, value) {
166
+ const parts = path.split(".");
167
+ let current = obj;
168
+ for (let i = 0; i < parts.length - 1; i++) {
169
+ const part = parts[i];
170
+ const nextPart = parts[i + 1];
171
+ if (current[part] === void 0 || current[part] === null) {
172
+ if (/^\d+$/.test(nextPart)) {
173
+ current[part] = [];
174
+ } else {
175
+ current[part] = {};
176
+ }
177
+ }
178
+ current = current[part];
179
+ }
180
+ const lastPart = parts[parts.length - 1];
181
+ if (/^\d+$/.test(lastPart)) {
182
+ const index = parseInt(lastPart, 10);
183
+ if (!Array.isArray(current)) {
184
+ throw new Error(`Cannot set array index ${index} on non-array`);
185
+ }
186
+ current[index] = value;
187
+ } else {
188
+ current[lastPart] = value;
189
+ }
190
+ }
191
+ /**
192
+ * Batch map multiple events
193
+ */
194
+ mapBatch(sources) {
195
+ return sources.map((source) => this.map(source));
196
+ }
197
+ };
198
+
199
+ // src/transforms.ts
200
+ var transforms_exports = {};
201
+ __export(transforms_exports, {
202
+ compose: () => compose,
203
+ first: () => first,
204
+ fromISO: () => fromISO,
205
+ identity: () => identity,
206
+ join: () => join,
207
+ lowercase: () => lowercase,
208
+ msToSeconds: () => msToSeconds,
209
+ omit: () => omit,
210
+ pick: () => pick,
211
+ pipe: () => pipe,
212
+ pluck: () => pluck,
213
+ renameKeys: () => renameKeys,
214
+ round: () => round,
215
+ secondsToMs: () => secondsToMs,
216
+ split: () => split,
217
+ toArray: () => toArray,
218
+ toBoolean: () => toBoolean,
219
+ toISO: () => toISO,
220
+ toNumber: () => toNumber,
221
+ toString: () => toString,
222
+ trim: () => trim,
223
+ uppercase: () => uppercase
224
+ });
225
+ var msToSeconds = (ms) => Math.floor(ms / 1e3);
226
+ var secondsToMs = (seconds) => seconds * 1e3;
227
+ var lowercase = (str) => str.toLowerCase();
228
+ var uppercase = (str) => str.toUpperCase();
229
+ var trim = (str) => str.trim();
230
+ var toString = (value) => String(value);
231
+ var toNumber = (value) => Number(value);
232
+ var toBoolean = (value) => Boolean(value);
233
+ var toArray = (value) => {
234
+ if (Array.isArray(value)) return value;
235
+ return [value];
236
+ };
237
+ var first = (value) => {
238
+ if (Array.isArray(value)) return value[0];
239
+ return value;
240
+ };
241
+ var pluck = (property) => (arr) => {
242
+ if (!Array.isArray(arr)) return [];
243
+ return arr.map((item) => item[property]);
244
+ };
245
+ var join = (separator = ",") => (arr) => {
246
+ if (!Array.isArray(arr)) return String(arr);
247
+ return arr.join(separator);
248
+ };
249
+ var split = (separator = ",") => (str) => {
250
+ return str.split(separator);
251
+ };
252
+ var toISO = (timestamp) => {
253
+ return new Date(timestamp).toISOString();
254
+ };
255
+ var fromISO = (iso) => {
256
+ return new Date(iso).getTime();
257
+ };
258
+ var round = (decimals = 0) => (num) => {
259
+ const factor = Math.pow(10, decimals);
260
+ return Math.round(num * factor) / factor;
261
+ };
262
+ var compose = (...fns) => {
263
+ return (value) => fns.reduceRight((acc, fn) => fn(acc), value);
264
+ };
265
+ var pipe = (...fns) => {
266
+ return (value) => fns.reduce((acc, fn) => fn(acc), value);
267
+ };
268
+ var identity = (value) => value;
269
+ var renameKeys = (keyMap) => (obj) => {
270
+ const result = {};
271
+ for (const [oldKey, newKey] of Object.entries(keyMap)) {
272
+ if (obj[oldKey] !== void 0) {
273
+ result[newKey] = obj[oldKey];
274
+ }
275
+ }
276
+ return result;
277
+ };
278
+ var pick = (...keys) => (obj) => {
279
+ const result = {};
280
+ for (const key of keys) {
281
+ if (obj[key] !== void 0) {
282
+ result[key] = obj[key];
283
+ }
284
+ }
285
+ return result;
286
+ };
287
+ var omit = (...keys) => (obj) => {
288
+ const result = { ...obj };
289
+ for (const key of keys) {
290
+ delete result[key];
291
+ }
292
+ return result;
293
+ };
294
+ // Annotate the CommonJS export names for ESM import in node:
295
+ 0 && (module.exports = {
296
+ EventMapper,
297
+ transforms
298
+ });
299
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/EventMapper.ts","../src/transforms.ts"],"sourcesContent":["/**\n * @sygnl/mapper\n * \n * Declarative event mapper for transforming events between different ad platform formats.\n * \n * @example\n * ```typescript\n * import { EventMapper, msToSeconds } from '@sygnl/mapper';\n * \n * const mapper = new EventMapper({\n * eventNames: [\n * { from: 'purchase', to: 'Purchase' }\n * ],\n * fields: [\n * { from: 'user.email', to: 'userData.em' },\n * { from: 'timestamp', to: 'event_time', transform: msToSeconds }\n * ]\n * });\n * \n * const result = mapper.map(sourceEvent);\n * ```\n */\n\nexport { EventMapper } from './EventMapper';\nexport type {\n MapperConfig,\n FieldMapping,\n EventNameMapping,\n StaticField,\n MappingResult,\n TransformFn,\n ConditionFn,\n} from './types';\nexport * as transforms from './transforms';\n","/**\n * EventMapper - Declarative event transformation\n * \n * Map events from one format to another using simple configuration.\n * Perfect for ad platform integrations (Meta, Google, Snapchat, etc.)\n */\n\nimport type {\n MapperConfig,\n FieldMapping,\n EventNameMapping,\n StaticField,\n MappingResult,\n} from './types';\n\nexport class EventMapper {\n private config: MapperConfig;\n\n constructor(config: MapperConfig) {\n this.config = config;\n }\n\n /**\n * Map an event from source format to target format\n */\n map<T = any>(source: any): MappingResult<T> {\n const result: MappingResult<T> = {\n data: {} as T,\n mappedFields: [],\n skippedFields: [],\n errors: [],\n };\n\n try {\n // Start with source root if specified\n const sourceData = this.config.sourceRoot\n ? this.getValueAtPath(source, this.config.sourceRoot)\n : source;\n\n // Map event names\n if (this.config.eventNames) {\n const eventName = this.mapEventName(sourceData);\n if (eventName) {\n this.setValueAtPath(result.data, 'event_name', eventName);\n result.mappedFields.push('event_name');\n }\n }\n\n // Map fields\n if (this.config.fields) {\n for (const fieldMapping of this.config.fields) {\n this.mapField(sourceData, result.data, fieldMapping, result);\n }\n }\n\n // Add static fields\n if (this.config.static) {\n for (const staticField of this.config.static) {\n this.mapStaticField(sourceData, result.data, staticField, result);\n }\n }\n\n // Apply target root if specified\n if (this.config.targetRoot) {\n const wrapped: any = {};\n this.setValueAtPath(wrapped, this.config.targetRoot, result.data);\n result.data = wrapped as T;\n }\n } catch (error) {\n result.errors.push({\n field: '_root',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n\n return result;\n }\n\n /**\n * Map event name using event name mappings\n */\n private mapEventName(source: any): string | undefined {\n if (!this.config.eventNames) return undefined;\n\n // Try to find event_type in source\n const sourceEventName = source.event_type || source.eventType || source.event_name;\n if (!sourceEventName) return undefined;\n\n // Find matching mapping\n for (const mapping of this.config.eventNames) {\n const fromNames = Array.isArray(mapping.from) ? mapping.from : [mapping.from];\n if (fromNames.includes(sourceEventName)) {\n return mapping.to;\n }\n }\n\n return undefined;\n }\n\n /**\n * Map a single field\n */\n private mapField(\n source: any,\n target: any,\n mapping: FieldMapping,\n result: MappingResult\n ): void {\n try {\n // Check condition\n if (mapping.condition && !mapping.condition(source)) {\n result.skippedFields.push(mapping.to);\n return;\n }\n\n // Get source value(s)\n const fromPaths = Array.isArray(mapping.from) ? mapping.from : [mapping.from];\n let value: any = undefined;\n\n // Try each source path until we find a value\n for (const fromPath of fromPaths) {\n value = this.getValueAtPath(source, fromPath);\n if (value !== undefined && value !== null) break;\n }\n\n // Use default if no value found\n if (value === undefined || value === null) {\n if (mapping.default !== undefined) {\n value = mapping.default;\n } else {\n result.skippedFields.push(mapping.to);\n return;\n }\n }\n\n // Skip falsy values if configured\n if (mapping.skipFalsy && !value) {\n result.skippedFields.push(mapping.to);\n return;\n }\n\n // Apply transform\n if (mapping.transform) {\n value = mapping.transform(value, source);\n }\n\n // Set target value\n this.setValueAtPath(target, mapping.to, value);\n result.mappedFields.push(mapping.to);\n } catch (error) {\n result.errors.push({\n field: mapping.to,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Map a static field\n */\n private mapStaticField(\n source: any,\n target: any,\n staticField: StaticField,\n result: MappingResult\n ): void {\n try {\n const value =\n typeof staticField.value === 'function'\n ? staticField.value(source)\n : staticField.value;\n\n this.setValueAtPath(target, staticField.to, value);\n result.mappedFields.push(staticField.to);\n } catch (error) {\n result.errors.push({\n field: staticField.to,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get value at path using dot notation\n * Supports array indexing (e.g., 'products.0.id')\n */\n private getValueAtPath(obj: any, path: string): any {\n const parts = path.split('.');\n let value = obj;\n\n for (const part of parts) {\n if (value === undefined || value === null) return undefined;\n\n // Handle array index\n if (/^\\d+$/.test(part)) {\n value = value[parseInt(part, 10)];\n } else {\n value = value[part];\n }\n }\n\n return value;\n }\n\n /**\n * Set value at path using dot notation\n * Creates nested objects/arrays as needed\n */\n private setValueAtPath(obj: any, path: string, value: any): void {\n const parts = path.split('.');\n let current = obj;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n\n // Create nested structure if needed\n if (current[part] === undefined || current[part] === null) {\n // Next part is array index\n if (/^\\d+$/.test(nextPart)) {\n current[part] = [];\n } else {\n current[part] = {};\n }\n }\n\n current = current[part];\n }\n\n const lastPart = parts[parts.length - 1];\n\n // Handle array index\n if (/^\\d+$/.test(lastPart)) {\n const index = parseInt(lastPart, 10);\n if (!Array.isArray(current)) {\n throw new Error(`Cannot set array index ${index} on non-array`);\n }\n current[index] = value;\n } else {\n current[lastPart] = value;\n }\n }\n\n /**\n * Batch map multiple events\n */\n mapBatch<T = any>(sources: any[]): MappingResult<T>[] {\n return sources.map((source) => this.map<T>(source));\n }\n}\n","/**\n * Common transform functions for event mapping\n */\n\n/**\n * Convert milliseconds to seconds\n */\nexport const msToSeconds = (ms: number): number => Math.floor(ms / 1000);\n\n/**\n * Convert seconds to milliseconds\n */\nexport const secondsToMs = (seconds: number): number => seconds * 1000;\n\n/**\n * Lowercase string\n */\nexport const lowercase = (str: string): string => str.toLowerCase();\n\n/**\n * Uppercase string\n */\nexport const uppercase = (str: string): string => str.toUpperCase();\n\n/**\n * Trim whitespace\n */\nexport const trim = (str: string): string => str.trim();\n\n/**\n * Convert to string\n */\nexport const toString = (value: any): string => String(value);\n\n/**\n * Convert to number\n */\nexport const toNumber = (value: any): number => Number(value);\n\n/**\n * Convert to boolean\n */\nexport const toBoolean = (value: any): boolean => Boolean(value);\n\n/**\n * Wrap value in array\n */\nexport const toArray = (value: any): any[] => {\n if (Array.isArray(value)) return value;\n return [value];\n};\n\n/**\n * Get first element of array, or value if not array\n */\nexport const first = (value: any): any => {\n if (Array.isArray(value)) return value[0];\n return value;\n};\n\n/**\n * Map array of objects to array of property values\n */\nexport const pluck = (property: string) => (arr: any[]): any[] => {\n if (!Array.isArray(arr)) return [];\n return arr.map((item) => item[property]);\n};\n\n/**\n * Join array into string\n */\nexport const join = (separator: string = ',') => (arr: any[]): string => {\n if (!Array.isArray(arr)) return String(arr);\n return arr.join(separator);\n};\n\n/**\n * Split string into array\n */\nexport const split = (separator: string = ',') => (str: string): string[] => {\n return str.split(separator);\n};\n\n/**\n * Format date as ISO 8601\n */\nexport const toISO = (timestamp: number): string => {\n return new Date(timestamp).toISOString();\n};\n\n/**\n * Parse ISO date to timestamp\n */\nexport const fromISO = (iso: string): number => {\n return new Date(iso).getTime();\n};\n\n/**\n * Round number to decimals\n */\nexport const round = (decimals: number = 0) => (num: number): number => {\n const factor = Math.pow(10, decimals);\n return Math.round(num * factor) / factor;\n};\n\n/**\n * Compose multiple transforms (right to left)\n */\nexport const compose = (...fns: ((value: any) => any)[]): ((value: any) => any) => {\n return (value: any) => fns.reduceRight((acc, fn) => fn(acc), value);\n};\n\n/**\n * Pipe multiple transforms (left to right)\n */\nexport const pipe = (...fns: ((value: any) => any)[]): ((value: any) => any) => {\n return (value: any) => fns.reduce((acc, fn) => fn(acc), value);\n};\n\n/**\n * Return value as-is (identity function)\n */\nexport const identity = (value: any): any => value;\n\n/**\n * Rename object keys\n */\nexport const renameKeys = (keyMap: Record<string, string>) => (obj: any): any => {\n const result: any = {};\n for (const [oldKey, newKey] of Object.entries(keyMap)) {\n if (obj[oldKey] !== undefined) {\n result[newKey] = obj[oldKey];\n }\n }\n return result;\n};\n\n/**\n * Pick specific keys from object\n */\nexport const pick = (...keys: string[]) => (obj: any): any => {\n const result: any = {};\n for (const key of keys) {\n if (obj[key] !== undefined) {\n result[key] = obj[key];\n }\n }\n return result;\n};\n\n/**\n * Omit specific keys from object\n */\nexport const omit = (...keys: string[]) => (obj: any): any => {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACeO,IAAM,cAAN,MAAkB;AAAA,EAGvB,YAAY,QAAsB;AAChC,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAa,QAA+B;AAC1C,UAAM,SAA2B;AAAA,MAC/B,MAAM,CAAC;AAAA,MACP,cAAc,CAAC;AAAA,MACf,eAAe,CAAC;AAAA,MAChB,QAAQ,CAAC;AAAA,IACX;AAEA,QAAI;AAEF,YAAM,aAAa,KAAK,OAAO,aAC3B,KAAK,eAAe,QAAQ,KAAK,OAAO,UAAU,IAClD;AAGJ,UAAI,KAAK,OAAO,YAAY;AAC1B,cAAM,YAAY,KAAK,aAAa,UAAU;AAC9C,YAAI,WAAW;AACb,eAAK,eAAe,OAAO,MAAM,cAAc,SAAS;AACxD,iBAAO,aAAa,KAAK,YAAY;AAAA,QACvC;AAAA,MACF;AAGA,UAAI,KAAK,OAAO,QAAQ;AACtB,mBAAW,gBAAgB,KAAK,OAAO,QAAQ;AAC7C,eAAK,SAAS,YAAY,OAAO,MAAM,cAAc,MAAM;AAAA,QAC7D;AAAA,MACF;AAGA,UAAI,KAAK,OAAO,QAAQ;AACtB,mBAAW,eAAe,KAAK,OAAO,QAAQ;AAC5C,eAAK,eAAe,YAAY,OAAO,MAAM,aAAa,MAAM;AAAA,QAClE;AAAA,MACF;AAGA,UAAI,KAAK,OAAO,YAAY;AAC1B,cAAM,UAAe,CAAC;AACtB,aAAK,eAAe,SAAS,KAAK,OAAO,YAAY,OAAO,IAAI;AAChE,eAAO,OAAO;AAAA,MAChB;AAAA,IACF,SAAS,OAAO;AACd,aAAO,OAAO,KAAK;AAAA,QACjB,OAAO;AAAA,QACP,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,QAAiC;AACpD,QAAI,CAAC,KAAK,OAAO,WAAY,QAAO;AAGpC,UAAM,kBAAkB,OAAO,cAAc,OAAO,aAAa,OAAO;AACxE,QAAI,CAAC,gBAAiB,QAAO;AAG7B,eAAW,WAAW,KAAK,OAAO,YAAY;AAC5C,YAAM,YAAY,MAAM,QAAQ,QAAQ,IAAI,IAAI,QAAQ,OAAO,CAAC,QAAQ,IAAI;AAC5E,UAAI,UAAU,SAAS,eAAe,GAAG;AACvC,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,SACN,QACA,QACA,SACA,QACM;AACN,QAAI;AAEF,UAAI,QAAQ,aAAa,CAAC,QAAQ,UAAU,MAAM,GAAG;AACnD,eAAO,cAAc,KAAK,QAAQ,EAAE;AACpC;AAAA,MACF;AAGA,YAAM,YAAY,MAAM,QAAQ,QAAQ,IAAI,IAAI,QAAQ,OAAO,CAAC,QAAQ,IAAI;AAC5E,UAAI,QAAa;AAGjB,iBAAW,YAAY,WAAW;AAChC,gBAAQ,KAAK,eAAe,QAAQ,QAAQ;AAC5C,YAAI,UAAU,UAAa,UAAU,KAAM;AAAA,MAC7C;AAGA,UAAI,UAAU,UAAa,UAAU,MAAM;AACzC,YAAI,QAAQ,YAAY,QAAW;AACjC,kBAAQ,QAAQ;AAAA,QAClB,OAAO;AACL,iBAAO,cAAc,KAAK,QAAQ,EAAE;AACpC;AAAA,QACF;AAAA,MACF;AAGA,UAAI,QAAQ,aAAa,CAAC,OAAO;AAC/B,eAAO,cAAc,KAAK,QAAQ,EAAE;AACpC;AAAA,MACF;AAGA,UAAI,QAAQ,WAAW;AACrB,gBAAQ,QAAQ,UAAU,OAAO,MAAM;AAAA,MACzC;AAGA,WAAK,eAAe,QAAQ,QAAQ,IAAI,KAAK;AAC7C,aAAO,aAAa,KAAK,QAAQ,EAAE;AAAA,IACrC,SAAS,OAAO;AACd,aAAO,OAAO,KAAK;AAAA,QACjB,OAAO,QAAQ;AAAA,QACf,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eACN,QACA,QACA,aACA,QACM;AACN,QAAI;AACF,YAAM,QACJ,OAAO,YAAY,UAAU,aACzB,YAAY,MAAM,MAAM,IACxB,YAAY;AAElB,WAAK,eAAe,QAAQ,YAAY,IAAI,KAAK;AACjD,aAAO,aAAa,KAAK,YAAY,EAAE;AAAA,IACzC,SAAS,OAAO;AACd,aAAO,OAAO,KAAK;AAAA,QACjB,OAAO,YAAY;AAAA,QACnB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe,KAAU,MAAmB;AAClD,UAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,QAAI,QAAQ;AAEZ,eAAW,QAAQ,OAAO;AACxB,UAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAGlD,UAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,gBAAQ,MAAM,SAAS,MAAM,EAAE,CAAC;AAAA,MAClC,OAAO;AACL,gBAAQ,MAAM,IAAI;AAAA,MACpB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe,KAAU,MAAc,OAAkB;AAC/D,UAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,QAAI,UAAU;AAEd,aAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;AACzC,YAAM,OAAO,MAAM,CAAC;AACpB,YAAM,WAAW,MAAM,IAAI,CAAC;AAG5B,UAAI,QAAQ,IAAI,MAAM,UAAa,QAAQ,IAAI,MAAM,MAAM;AAEzD,YAAI,QAAQ,KAAK,QAAQ,GAAG;AAC1B,kBAAQ,IAAI,IAAI,CAAC;AAAA,QACnB,OAAO;AACL,kBAAQ,IAAI,IAAI,CAAC;AAAA,QACnB;AAAA,MACF;AAEA,gBAAU,QAAQ,IAAI;AAAA,IACxB;AAEA,UAAM,WAAW,MAAM,MAAM,SAAS,CAAC;AAGvC,QAAI,QAAQ,KAAK,QAAQ,GAAG;AAC1B,YAAM,QAAQ,SAAS,UAAU,EAAE;AACnC,UAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,cAAM,IAAI,MAAM,0BAA0B,KAAK,eAAe;AAAA,MAChE;AACA,cAAQ,KAAK,IAAI;AAAA,IACnB,OAAO;AACL,cAAQ,QAAQ,IAAI;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,SAAkB,SAAoC;AACpD,WAAO,QAAQ,IAAI,CAAC,WAAW,KAAK,IAAO,MAAM,CAAC;AAAA,EACpD;AACF;;;ACzPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,IAAM,cAAc,CAAC,OAAuB,KAAK,MAAM,KAAK,GAAI;AAKhE,IAAM,cAAc,CAAC,YAA4B,UAAU;AAK3D,IAAM,YAAY,CAAC,QAAwB,IAAI,YAAY;AAK3D,IAAM,YAAY,CAAC,QAAwB,IAAI,YAAY;AAK3D,IAAM,OAAO,CAAC,QAAwB,IAAI,KAAK;AAK/C,IAAM,WAAW,CAAC,UAAuB,OAAO,KAAK;AAKrD,IAAM,WAAW,CAAC,UAAuB,OAAO,KAAK;AAKrD,IAAM,YAAY,CAAC,UAAwB,QAAQ,KAAK;AAKxD,IAAM,UAAU,CAAC,UAAsB;AAC5C,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,SAAO,CAAC,KAAK;AACf;AAKO,IAAM,QAAQ,CAAC,UAAoB;AACxC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,CAAC;AACxC,SAAO;AACT;AAKO,IAAM,QAAQ,CAAC,aAAqB,CAAC,QAAsB;AAChE,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AACjC,SAAO,IAAI,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC;AACzC;AAKO,IAAM,OAAO,CAAC,YAAoB,QAAQ,CAAC,QAAuB;AACvE,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,OAAO,GAAG;AAC1C,SAAO,IAAI,KAAK,SAAS;AAC3B;AAKO,IAAM,QAAQ,CAAC,YAAoB,QAAQ,CAAC,QAA0B;AAC3E,SAAO,IAAI,MAAM,SAAS;AAC5B;AAKO,IAAM,QAAQ,CAAC,cAA8B;AAClD,SAAO,IAAI,KAAK,SAAS,EAAE,YAAY;AACzC;AAKO,IAAM,UAAU,CAAC,QAAwB;AAC9C,SAAO,IAAI,KAAK,GAAG,EAAE,QAAQ;AAC/B;AAKO,IAAM,QAAQ,CAAC,WAAmB,MAAM,CAAC,QAAwB;AACtE,QAAM,SAAS,KAAK,IAAI,IAAI,QAAQ;AACpC,SAAO,KAAK,MAAM,MAAM,MAAM,IAAI;AACpC;AAKO,IAAM,UAAU,IAAI,QAAwD;AACjF,SAAO,CAAC,UAAe,IAAI,YAAY,CAAC,KAAK,OAAO,GAAG,GAAG,GAAG,KAAK;AACpE;AAKO,IAAM,OAAO,IAAI,QAAwD;AAC9E,SAAO,CAAC,UAAe,IAAI,OAAO,CAAC,KAAK,OAAO,GAAG,GAAG,GAAG,KAAK;AAC/D;AAKO,IAAM,WAAW,CAAC,UAAoB;AAKtC,IAAM,aAAa,CAAC,WAAmC,CAAC,QAAkB;AAC/E,QAAM,SAAc,CAAC;AACrB,aAAW,CAAC,QAAQ,MAAM,KAAK,OAAO,QAAQ,MAAM,GAAG;AACrD,QAAI,IAAI,MAAM,MAAM,QAAW;AAC7B,aAAO,MAAM,IAAI,IAAI,MAAM;AAAA,IAC7B;AAAA,EACF;AACA,SAAO;AACT;AAKO,IAAM,OAAO,IAAI,SAAmB,CAAC,QAAkB;AAC5D,QAAM,SAAc,CAAC;AACrB,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,GAAG,MAAM,QAAW;AAC1B,aAAO,GAAG,IAAI,IAAI,GAAG;AAAA,IACvB;AAAA,EACF;AACA,SAAO;AACT;AAKO,IAAM,OAAO,IAAI,SAAmB,CAAC,QAAkB;AAC5D,QAAM,SAAS,EAAE,GAAG,IAAI;AACxB,aAAW,OAAO,MAAM;AACtB,WAAO,OAAO,GAAG;AAAA,EACnB;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Type definitions for event mapper
3
+ */
4
+ /**
5
+ * Transform function to modify a value during mapping
6
+ */
7
+ type TransformFn = (value: any, source: any) => any;
8
+ /**
9
+ * Condition function to determine if mapping should apply
10
+ */
11
+ type ConditionFn = (source: any) => boolean;
12
+ /**
13
+ * Field mapping configuration
14
+ */
15
+ interface FieldMapping {
16
+ /**
17
+ * Source path in dot notation (e.g., 'user.email', 'products.0.id')
18
+ */
19
+ from: string | string[];
20
+ /**
21
+ * Target path in dot notation (e.g., 'userData.em', 'items.0.id')
22
+ */
23
+ to: string;
24
+ /**
25
+ * Optional transform function to modify value
26
+ */
27
+ transform?: TransformFn;
28
+ /**
29
+ * Optional condition - only map if this returns true
30
+ */
31
+ condition?: ConditionFn;
32
+ /**
33
+ * Default value if source is undefined/null
34
+ */
35
+ default?: any;
36
+ /**
37
+ * Whether to skip if value is falsy
38
+ * @default false
39
+ */
40
+ skipFalsy?: boolean;
41
+ }
42
+ /**
43
+ * Event name mapping configuration
44
+ */
45
+ interface EventNameMapping {
46
+ /**
47
+ * Source event name or names
48
+ */
49
+ from: string | string[];
50
+ /**
51
+ * Target event name
52
+ */
53
+ to: string;
54
+ }
55
+ /**
56
+ * Static field to always add to output
57
+ */
58
+ interface StaticField {
59
+ /**
60
+ * Target path
61
+ */
62
+ to: string;
63
+ /**
64
+ * Static value or function to generate value
65
+ */
66
+ value: any | ((source: any) => any);
67
+ }
68
+ /**
69
+ * Mapper configuration
70
+ */
71
+ interface MapperConfig {
72
+ /**
73
+ * Event name mappings
74
+ */
75
+ eventNames?: EventNameMapping[];
76
+ /**
77
+ * Field mappings
78
+ */
79
+ fields?: FieldMapping[];
80
+ /**
81
+ * Static fields to always include
82
+ */
83
+ static?: StaticField[];
84
+ /**
85
+ * Root path for source data
86
+ * @example 'data' to read from source.data.*
87
+ */
88
+ sourceRoot?: string;
89
+ /**
90
+ * Root path for target data
91
+ * @example 'data.0' to write to target.data[0].*
92
+ */
93
+ targetRoot?: string;
94
+ }
95
+ /**
96
+ * Mapping result
97
+ */
98
+ interface MappingResult<T = any> {
99
+ /**
100
+ * Mapped data
101
+ */
102
+ data: T;
103
+ /**
104
+ * Fields that were mapped
105
+ */
106
+ mappedFields: string[];
107
+ /**
108
+ * Fields that were skipped (condition/falsy)
109
+ */
110
+ skippedFields: string[];
111
+ /**
112
+ * Errors encountered during mapping
113
+ */
114
+ errors: Array<{
115
+ field: string;
116
+ error: string;
117
+ }>;
118
+ }
119
+
120
+ /**
121
+ * EventMapper - Declarative event transformation
122
+ *
123
+ * Map events from one format to another using simple configuration.
124
+ * Perfect for ad platform integrations (Meta, Google, Snapchat, etc.)
125
+ */
126
+
127
+ declare class EventMapper {
128
+ private config;
129
+ constructor(config: MapperConfig);
130
+ /**
131
+ * Map an event from source format to target format
132
+ */
133
+ map<T = any>(source: any): MappingResult<T>;
134
+ /**
135
+ * Map event name using event name mappings
136
+ */
137
+ private mapEventName;
138
+ /**
139
+ * Map a single field
140
+ */
141
+ private mapField;
142
+ /**
143
+ * Map a static field
144
+ */
145
+ private mapStaticField;
146
+ /**
147
+ * Get value at path using dot notation
148
+ * Supports array indexing (e.g., 'products.0.id')
149
+ */
150
+ private getValueAtPath;
151
+ /**
152
+ * Set value at path using dot notation
153
+ * Creates nested objects/arrays as needed
154
+ */
155
+ private setValueAtPath;
156
+ /**
157
+ * Batch map multiple events
158
+ */
159
+ mapBatch<T = any>(sources: any[]): MappingResult<T>[];
160
+ }
161
+
162
+ /**
163
+ * Common transform functions for event mapping
164
+ */
165
+ /**
166
+ * Convert milliseconds to seconds
167
+ */
168
+ declare const msToSeconds: (ms: number) => number;
169
+ /**
170
+ * Convert seconds to milliseconds
171
+ */
172
+ declare const secondsToMs: (seconds: number) => number;
173
+ /**
174
+ * Lowercase string
175
+ */
176
+ declare const lowercase: (str: string) => string;
177
+ /**
178
+ * Uppercase string
179
+ */
180
+ declare const uppercase: (str: string) => string;
181
+ /**
182
+ * Trim whitespace
183
+ */
184
+ declare const trim: (str: string) => string;
185
+ /**
186
+ * Convert to string
187
+ */
188
+ declare const toString: (value: any) => string;
189
+ /**
190
+ * Convert to number
191
+ */
192
+ declare const toNumber: (value: any) => number;
193
+ /**
194
+ * Convert to boolean
195
+ */
196
+ declare const toBoolean: (value: any) => boolean;
197
+ /**
198
+ * Wrap value in array
199
+ */
200
+ declare const toArray: (value: any) => any[];
201
+ /**
202
+ * Get first element of array, or value if not array
203
+ */
204
+ declare const first: (value: any) => any;
205
+ /**
206
+ * Map array of objects to array of property values
207
+ */
208
+ declare const pluck: (property: string) => (arr: any[]) => any[];
209
+ /**
210
+ * Join array into string
211
+ */
212
+ declare const join: (separator?: string) => (arr: any[]) => string;
213
+ /**
214
+ * Split string into array
215
+ */
216
+ declare const split: (separator?: string) => (str: string) => string[];
217
+ /**
218
+ * Format date as ISO 8601
219
+ */
220
+ declare const toISO: (timestamp: number) => string;
221
+ /**
222
+ * Parse ISO date to timestamp
223
+ */
224
+ declare const fromISO: (iso: string) => number;
225
+ /**
226
+ * Round number to decimals
227
+ */
228
+ declare const round: (decimals?: number) => (num: number) => number;
229
+ /**
230
+ * Compose multiple transforms (right to left)
231
+ */
232
+ declare const compose: (...fns: ((value: any) => any)[]) => ((value: any) => any);
233
+ /**
234
+ * Pipe multiple transforms (left to right)
235
+ */
236
+ declare const pipe: (...fns: ((value: any) => any)[]) => ((value: any) => any);
237
+ /**
238
+ * Return value as-is (identity function)
239
+ */
240
+ declare const identity: (value: any) => any;
241
+ /**
242
+ * Rename object keys
243
+ */
244
+ declare const renameKeys: (keyMap: Record<string, string>) => (obj: any) => any;
245
+ /**
246
+ * Pick specific keys from object
247
+ */
248
+ declare const pick: (...keys: string[]) => (obj: any) => any;
249
+ /**
250
+ * Omit specific keys from object
251
+ */
252
+ declare const omit: (...keys: string[]) => (obj: any) => any;
253
+
254
+ declare const transforms_compose: typeof compose;
255
+ declare const transforms_first: typeof first;
256
+ declare const transforms_fromISO: typeof fromISO;
257
+ declare const transforms_identity: typeof identity;
258
+ declare const transforms_join: typeof join;
259
+ declare const transforms_lowercase: typeof lowercase;
260
+ declare const transforms_msToSeconds: typeof msToSeconds;
261
+ declare const transforms_omit: typeof omit;
262
+ declare const transforms_pick: typeof pick;
263
+ declare const transforms_pipe: typeof pipe;
264
+ declare const transforms_pluck: typeof pluck;
265
+ declare const transforms_renameKeys: typeof renameKeys;
266
+ declare const transforms_round: typeof round;
267
+ declare const transforms_secondsToMs: typeof secondsToMs;
268
+ declare const transforms_split: typeof split;
269
+ declare const transforms_toArray: typeof toArray;
270
+ declare const transforms_toBoolean: typeof toBoolean;
271
+ declare const transforms_toISO: typeof toISO;
272
+ declare const transforms_toNumber: typeof toNumber;
273
+ declare const transforms_toString: typeof toString;
274
+ declare const transforms_trim: typeof trim;
275
+ declare const transforms_uppercase: typeof uppercase;
276
+ declare namespace transforms {
277
+ export { transforms_compose as compose, transforms_first as first, transforms_fromISO as fromISO, transforms_identity as identity, transforms_join as join, transforms_lowercase as lowercase, transforms_msToSeconds as msToSeconds, transforms_omit as omit, transforms_pick as pick, transforms_pipe as pipe, transforms_pluck as pluck, transforms_renameKeys as renameKeys, transforms_round as round, transforms_secondsToMs as secondsToMs, transforms_split as split, transforms_toArray as toArray, transforms_toBoolean as toBoolean, transforms_toISO as toISO, transforms_toNumber as toNumber, transforms_toString as toString, transforms_trim as trim, transforms_uppercase as uppercase };
278
+ }
279
+
280
+ export { type ConditionFn, EventMapper, type EventNameMapping, type FieldMapping, type MapperConfig, type MappingResult, type StaticField, type TransformFn, transforms };
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Type definitions for event mapper
3
+ */
4
+ /**
5
+ * Transform function to modify a value during mapping
6
+ */
7
+ type TransformFn = (value: any, source: any) => any;
8
+ /**
9
+ * Condition function to determine if mapping should apply
10
+ */
11
+ type ConditionFn = (source: any) => boolean;
12
+ /**
13
+ * Field mapping configuration
14
+ */
15
+ interface FieldMapping {
16
+ /**
17
+ * Source path in dot notation (e.g., 'user.email', 'products.0.id')
18
+ */
19
+ from: string | string[];
20
+ /**
21
+ * Target path in dot notation (e.g., 'userData.em', 'items.0.id')
22
+ */
23
+ to: string;
24
+ /**
25
+ * Optional transform function to modify value
26
+ */
27
+ transform?: TransformFn;
28
+ /**
29
+ * Optional condition - only map if this returns true
30
+ */
31
+ condition?: ConditionFn;
32
+ /**
33
+ * Default value if source is undefined/null
34
+ */
35
+ default?: any;
36
+ /**
37
+ * Whether to skip if value is falsy
38
+ * @default false
39
+ */
40
+ skipFalsy?: boolean;
41
+ }
42
+ /**
43
+ * Event name mapping configuration
44
+ */
45
+ interface EventNameMapping {
46
+ /**
47
+ * Source event name or names
48
+ */
49
+ from: string | string[];
50
+ /**
51
+ * Target event name
52
+ */
53
+ to: string;
54
+ }
55
+ /**
56
+ * Static field to always add to output
57
+ */
58
+ interface StaticField {
59
+ /**
60
+ * Target path
61
+ */
62
+ to: string;
63
+ /**
64
+ * Static value or function to generate value
65
+ */
66
+ value: any | ((source: any) => any);
67
+ }
68
+ /**
69
+ * Mapper configuration
70
+ */
71
+ interface MapperConfig {
72
+ /**
73
+ * Event name mappings
74
+ */
75
+ eventNames?: EventNameMapping[];
76
+ /**
77
+ * Field mappings
78
+ */
79
+ fields?: FieldMapping[];
80
+ /**
81
+ * Static fields to always include
82
+ */
83
+ static?: StaticField[];
84
+ /**
85
+ * Root path for source data
86
+ * @example 'data' to read from source.data.*
87
+ */
88
+ sourceRoot?: string;
89
+ /**
90
+ * Root path for target data
91
+ * @example 'data.0' to write to target.data[0].*
92
+ */
93
+ targetRoot?: string;
94
+ }
95
+ /**
96
+ * Mapping result
97
+ */
98
+ interface MappingResult<T = any> {
99
+ /**
100
+ * Mapped data
101
+ */
102
+ data: T;
103
+ /**
104
+ * Fields that were mapped
105
+ */
106
+ mappedFields: string[];
107
+ /**
108
+ * Fields that were skipped (condition/falsy)
109
+ */
110
+ skippedFields: string[];
111
+ /**
112
+ * Errors encountered during mapping
113
+ */
114
+ errors: Array<{
115
+ field: string;
116
+ error: string;
117
+ }>;
118
+ }
119
+
120
+ /**
121
+ * EventMapper - Declarative event transformation
122
+ *
123
+ * Map events from one format to another using simple configuration.
124
+ * Perfect for ad platform integrations (Meta, Google, Snapchat, etc.)
125
+ */
126
+
127
+ declare class EventMapper {
128
+ private config;
129
+ constructor(config: MapperConfig);
130
+ /**
131
+ * Map an event from source format to target format
132
+ */
133
+ map<T = any>(source: any): MappingResult<T>;
134
+ /**
135
+ * Map event name using event name mappings
136
+ */
137
+ private mapEventName;
138
+ /**
139
+ * Map a single field
140
+ */
141
+ private mapField;
142
+ /**
143
+ * Map a static field
144
+ */
145
+ private mapStaticField;
146
+ /**
147
+ * Get value at path using dot notation
148
+ * Supports array indexing (e.g., 'products.0.id')
149
+ */
150
+ private getValueAtPath;
151
+ /**
152
+ * Set value at path using dot notation
153
+ * Creates nested objects/arrays as needed
154
+ */
155
+ private setValueAtPath;
156
+ /**
157
+ * Batch map multiple events
158
+ */
159
+ mapBatch<T = any>(sources: any[]): MappingResult<T>[];
160
+ }
161
+
162
+ /**
163
+ * Common transform functions for event mapping
164
+ */
165
+ /**
166
+ * Convert milliseconds to seconds
167
+ */
168
+ declare const msToSeconds: (ms: number) => number;
169
+ /**
170
+ * Convert seconds to milliseconds
171
+ */
172
+ declare const secondsToMs: (seconds: number) => number;
173
+ /**
174
+ * Lowercase string
175
+ */
176
+ declare const lowercase: (str: string) => string;
177
+ /**
178
+ * Uppercase string
179
+ */
180
+ declare const uppercase: (str: string) => string;
181
+ /**
182
+ * Trim whitespace
183
+ */
184
+ declare const trim: (str: string) => string;
185
+ /**
186
+ * Convert to string
187
+ */
188
+ declare const toString: (value: any) => string;
189
+ /**
190
+ * Convert to number
191
+ */
192
+ declare const toNumber: (value: any) => number;
193
+ /**
194
+ * Convert to boolean
195
+ */
196
+ declare const toBoolean: (value: any) => boolean;
197
+ /**
198
+ * Wrap value in array
199
+ */
200
+ declare const toArray: (value: any) => any[];
201
+ /**
202
+ * Get first element of array, or value if not array
203
+ */
204
+ declare const first: (value: any) => any;
205
+ /**
206
+ * Map array of objects to array of property values
207
+ */
208
+ declare const pluck: (property: string) => (arr: any[]) => any[];
209
+ /**
210
+ * Join array into string
211
+ */
212
+ declare const join: (separator?: string) => (arr: any[]) => string;
213
+ /**
214
+ * Split string into array
215
+ */
216
+ declare const split: (separator?: string) => (str: string) => string[];
217
+ /**
218
+ * Format date as ISO 8601
219
+ */
220
+ declare const toISO: (timestamp: number) => string;
221
+ /**
222
+ * Parse ISO date to timestamp
223
+ */
224
+ declare const fromISO: (iso: string) => number;
225
+ /**
226
+ * Round number to decimals
227
+ */
228
+ declare const round: (decimals?: number) => (num: number) => number;
229
+ /**
230
+ * Compose multiple transforms (right to left)
231
+ */
232
+ declare const compose: (...fns: ((value: any) => any)[]) => ((value: any) => any);
233
+ /**
234
+ * Pipe multiple transforms (left to right)
235
+ */
236
+ declare const pipe: (...fns: ((value: any) => any)[]) => ((value: any) => any);
237
+ /**
238
+ * Return value as-is (identity function)
239
+ */
240
+ declare const identity: (value: any) => any;
241
+ /**
242
+ * Rename object keys
243
+ */
244
+ declare const renameKeys: (keyMap: Record<string, string>) => (obj: any) => any;
245
+ /**
246
+ * Pick specific keys from object
247
+ */
248
+ declare const pick: (...keys: string[]) => (obj: any) => any;
249
+ /**
250
+ * Omit specific keys from object
251
+ */
252
+ declare const omit: (...keys: string[]) => (obj: any) => any;
253
+
254
+ declare const transforms_compose: typeof compose;
255
+ declare const transforms_first: typeof first;
256
+ declare const transforms_fromISO: typeof fromISO;
257
+ declare const transforms_identity: typeof identity;
258
+ declare const transforms_join: typeof join;
259
+ declare const transforms_lowercase: typeof lowercase;
260
+ declare const transforms_msToSeconds: typeof msToSeconds;
261
+ declare const transforms_omit: typeof omit;
262
+ declare const transforms_pick: typeof pick;
263
+ declare const transforms_pipe: typeof pipe;
264
+ declare const transforms_pluck: typeof pluck;
265
+ declare const transforms_renameKeys: typeof renameKeys;
266
+ declare const transforms_round: typeof round;
267
+ declare const transforms_secondsToMs: typeof secondsToMs;
268
+ declare const transforms_split: typeof split;
269
+ declare const transforms_toArray: typeof toArray;
270
+ declare const transforms_toBoolean: typeof toBoolean;
271
+ declare const transforms_toISO: typeof toISO;
272
+ declare const transforms_toNumber: typeof toNumber;
273
+ declare const transforms_toString: typeof toString;
274
+ declare const transforms_trim: typeof trim;
275
+ declare const transforms_uppercase: typeof uppercase;
276
+ declare namespace transforms {
277
+ export { transforms_compose as compose, transforms_first as first, transforms_fromISO as fromISO, transforms_identity as identity, transforms_join as join, transforms_lowercase as lowercase, transforms_msToSeconds as msToSeconds, transforms_omit as omit, transforms_pick as pick, transforms_pipe as pipe, transforms_pluck as pluck, transforms_renameKeys as renameKeys, transforms_round as round, transforms_secondsToMs as secondsToMs, transforms_split as split, transforms_toArray as toArray, transforms_toBoolean as toBoolean, transforms_toISO as toISO, transforms_toNumber as toNumber, transforms_toString as toString, transforms_trim as trim, transforms_uppercase as uppercase };
278
+ }
279
+
280
+ export { type ConditionFn, EventMapper, type EventNameMapping, type FieldMapping, type MapperConfig, type MappingResult, type StaticField, type TransformFn, transforms };
package/dist/index.js ADDED
@@ -0,0 +1,277 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/EventMapper.ts
8
+ var EventMapper = class {
9
+ constructor(config) {
10
+ this.config = config;
11
+ }
12
+ /**
13
+ * Map an event from source format to target format
14
+ */
15
+ map(source) {
16
+ const result = {
17
+ data: {},
18
+ mappedFields: [],
19
+ skippedFields: [],
20
+ errors: []
21
+ };
22
+ try {
23
+ const sourceData = this.config.sourceRoot ? this.getValueAtPath(source, this.config.sourceRoot) : source;
24
+ if (this.config.eventNames) {
25
+ const eventName = this.mapEventName(sourceData);
26
+ if (eventName) {
27
+ this.setValueAtPath(result.data, "event_name", eventName);
28
+ result.mappedFields.push("event_name");
29
+ }
30
+ }
31
+ if (this.config.fields) {
32
+ for (const fieldMapping of this.config.fields) {
33
+ this.mapField(sourceData, result.data, fieldMapping, result);
34
+ }
35
+ }
36
+ if (this.config.static) {
37
+ for (const staticField of this.config.static) {
38
+ this.mapStaticField(sourceData, result.data, staticField, result);
39
+ }
40
+ }
41
+ if (this.config.targetRoot) {
42
+ const wrapped = {};
43
+ this.setValueAtPath(wrapped, this.config.targetRoot, result.data);
44
+ result.data = wrapped;
45
+ }
46
+ } catch (error) {
47
+ result.errors.push({
48
+ field: "_root",
49
+ error: error instanceof Error ? error.message : String(error)
50
+ });
51
+ }
52
+ return result;
53
+ }
54
+ /**
55
+ * Map event name using event name mappings
56
+ */
57
+ mapEventName(source) {
58
+ if (!this.config.eventNames) return void 0;
59
+ const sourceEventName = source.event_type || source.eventType || source.event_name;
60
+ if (!sourceEventName) return void 0;
61
+ for (const mapping of this.config.eventNames) {
62
+ const fromNames = Array.isArray(mapping.from) ? mapping.from : [mapping.from];
63
+ if (fromNames.includes(sourceEventName)) {
64
+ return mapping.to;
65
+ }
66
+ }
67
+ return void 0;
68
+ }
69
+ /**
70
+ * Map a single field
71
+ */
72
+ mapField(source, target, mapping, result) {
73
+ try {
74
+ if (mapping.condition && !mapping.condition(source)) {
75
+ result.skippedFields.push(mapping.to);
76
+ return;
77
+ }
78
+ const fromPaths = Array.isArray(mapping.from) ? mapping.from : [mapping.from];
79
+ let value = void 0;
80
+ for (const fromPath of fromPaths) {
81
+ value = this.getValueAtPath(source, fromPath);
82
+ if (value !== void 0 && value !== null) break;
83
+ }
84
+ if (value === void 0 || value === null) {
85
+ if (mapping.default !== void 0) {
86
+ value = mapping.default;
87
+ } else {
88
+ result.skippedFields.push(mapping.to);
89
+ return;
90
+ }
91
+ }
92
+ if (mapping.skipFalsy && !value) {
93
+ result.skippedFields.push(mapping.to);
94
+ return;
95
+ }
96
+ if (mapping.transform) {
97
+ value = mapping.transform(value, source);
98
+ }
99
+ this.setValueAtPath(target, mapping.to, value);
100
+ result.mappedFields.push(mapping.to);
101
+ } catch (error) {
102
+ result.errors.push({
103
+ field: mapping.to,
104
+ error: error instanceof Error ? error.message : String(error)
105
+ });
106
+ }
107
+ }
108
+ /**
109
+ * Map a static field
110
+ */
111
+ mapStaticField(source, target, staticField, result) {
112
+ try {
113
+ const value = typeof staticField.value === "function" ? staticField.value(source) : staticField.value;
114
+ this.setValueAtPath(target, staticField.to, value);
115
+ result.mappedFields.push(staticField.to);
116
+ } catch (error) {
117
+ result.errors.push({
118
+ field: staticField.to,
119
+ error: error instanceof Error ? error.message : String(error)
120
+ });
121
+ }
122
+ }
123
+ /**
124
+ * Get value at path using dot notation
125
+ * Supports array indexing (e.g., 'products.0.id')
126
+ */
127
+ getValueAtPath(obj, path) {
128
+ const parts = path.split(".");
129
+ let value = obj;
130
+ for (const part of parts) {
131
+ if (value === void 0 || value === null) return void 0;
132
+ if (/^\d+$/.test(part)) {
133
+ value = value[parseInt(part, 10)];
134
+ } else {
135
+ value = value[part];
136
+ }
137
+ }
138
+ return value;
139
+ }
140
+ /**
141
+ * Set value at path using dot notation
142
+ * Creates nested objects/arrays as needed
143
+ */
144
+ setValueAtPath(obj, path, value) {
145
+ const parts = path.split(".");
146
+ let current = obj;
147
+ for (let i = 0; i < parts.length - 1; i++) {
148
+ const part = parts[i];
149
+ const nextPart = parts[i + 1];
150
+ if (current[part] === void 0 || current[part] === null) {
151
+ if (/^\d+$/.test(nextPart)) {
152
+ current[part] = [];
153
+ } else {
154
+ current[part] = {};
155
+ }
156
+ }
157
+ current = current[part];
158
+ }
159
+ const lastPart = parts[parts.length - 1];
160
+ if (/^\d+$/.test(lastPart)) {
161
+ const index = parseInt(lastPart, 10);
162
+ if (!Array.isArray(current)) {
163
+ throw new Error(`Cannot set array index ${index} on non-array`);
164
+ }
165
+ current[index] = value;
166
+ } else {
167
+ current[lastPart] = value;
168
+ }
169
+ }
170
+ /**
171
+ * Batch map multiple events
172
+ */
173
+ mapBatch(sources) {
174
+ return sources.map((source) => this.map(source));
175
+ }
176
+ };
177
+
178
+ // src/transforms.ts
179
+ var transforms_exports = {};
180
+ __export(transforms_exports, {
181
+ compose: () => compose,
182
+ first: () => first,
183
+ fromISO: () => fromISO,
184
+ identity: () => identity,
185
+ join: () => join,
186
+ lowercase: () => lowercase,
187
+ msToSeconds: () => msToSeconds,
188
+ omit: () => omit,
189
+ pick: () => pick,
190
+ pipe: () => pipe,
191
+ pluck: () => pluck,
192
+ renameKeys: () => renameKeys,
193
+ round: () => round,
194
+ secondsToMs: () => secondsToMs,
195
+ split: () => split,
196
+ toArray: () => toArray,
197
+ toBoolean: () => toBoolean,
198
+ toISO: () => toISO,
199
+ toNumber: () => toNumber,
200
+ toString: () => toString,
201
+ trim: () => trim,
202
+ uppercase: () => uppercase
203
+ });
204
+ var msToSeconds = (ms) => Math.floor(ms / 1e3);
205
+ var secondsToMs = (seconds) => seconds * 1e3;
206
+ var lowercase = (str) => str.toLowerCase();
207
+ var uppercase = (str) => str.toUpperCase();
208
+ var trim = (str) => str.trim();
209
+ var toString = (value) => String(value);
210
+ var toNumber = (value) => Number(value);
211
+ var toBoolean = (value) => Boolean(value);
212
+ var toArray = (value) => {
213
+ if (Array.isArray(value)) return value;
214
+ return [value];
215
+ };
216
+ var first = (value) => {
217
+ if (Array.isArray(value)) return value[0];
218
+ return value;
219
+ };
220
+ var pluck = (property) => (arr) => {
221
+ if (!Array.isArray(arr)) return [];
222
+ return arr.map((item) => item[property]);
223
+ };
224
+ var join = (separator = ",") => (arr) => {
225
+ if (!Array.isArray(arr)) return String(arr);
226
+ return arr.join(separator);
227
+ };
228
+ var split = (separator = ",") => (str) => {
229
+ return str.split(separator);
230
+ };
231
+ var toISO = (timestamp) => {
232
+ return new Date(timestamp).toISOString();
233
+ };
234
+ var fromISO = (iso) => {
235
+ return new Date(iso).getTime();
236
+ };
237
+ var round = (decimals = 0) => (num) => {
238
+ const factor = Math.pow(10, decimals);
239
+ return Math.round(num * factor) / factor;
240
+ };
241
+ var compose = (...fns) => {
242
+ return (value) => fns.reduceRight((acc, fn) => fn(acc), value);
243
+ };
244
+ var pipe = (...fns) => {
245
+ return (value) => fns.reduce((acc, fn) => fn(acc), value);
246
+ };
247
+ var identity = (value) => value;
248
+ var renameKeys = (keyMap) => (obj) => {
249
+ const result = {};
250
+ for (const [oldKey, newKey] of Object.entries(keyMap)) {
251
+ if (obj[oldKey] !== void 0) {
252
+ result[newKey] = obj[oldKey];
253
+ }
254
+ }
255
+ return result;
256
+ };
257
+ var pick = (...keys) => (obj) => {
258
+ const result = {};
259
+ for (const key of keys) {
260
+ if (obj[key] !== void 0) {
261
+ result[key] = obj[key];
262
+ }
263
+ }
264
+ return result;
265
+ };
266
+ var omit = (...keys) => (obj) => {
267
+ const result = { ...obj };
268
+ for (const key of keys) {
269
+ delete result[key];
270
+ }
271
+ return result;
272
+ };
273
+ export {
274
+ EventMapper,
275
+ transforms_exports as transforms
276
+ };
277
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/EventMapper.ts","../src/transforms.ts"],"sourcesContent":["/**\n * EventMapper - Declarative event transformation\n * \n * Map events from one format to another using simple configuration.\n * Perfect for ad platform integrations (Meta, Google, Snapchat, etc.)\n */\n\nimport type {\n MapperConfig,\n FieldMapping,\n EventNameMapping,\n StaticField,\n MappingResult,\n} from './types';\n\nexport class EventMapper {\n private config: MapperConfig;\n\n constructor(config: MapperConfig) {\n this.config = config;\n }\n\n /**\n * Map an event from source format to target format\n */\n map<T = any>(source: any): MappingResult<T> {\n const result: MappingResult<T> = {\n data: {} as T,\n mappedFields: [],\n skippedFields: [],\n errors: [],\n };\n\n try {\n // Start with source root if specified\n const sourceData = this.config.sourceRoot\n ? this.getValueAtPath(source, this.config.sourceRoot)\n : source;\n\n // Map event names\n if (this.config.eventNames) {\n const eventName = this.mapEventName(sourceData);\n if (eventName) {\n this.setValueAtPath(result.data, 'event_name', eventName);\n result.mappedFields.push('event_name');\n }\n }\n\n // Map fields\n if (this.config.fields) {\n for (const fieldMapping of this.config.fields) {\n this.mapField(sourceData, result.data, fieldMapping, result);\n }\n }\n\n // Add static fields\n if (this.config.static) {\n for (const staticField of this.config.static) {\n this.mapStaticField(sourceData, result.data, staticField, result);\n }\n }\n\n // Apply target root if specified\n if (this.config.targetRoot) {\n const wrapped: any = {};\n this.setValueAtPath(wrapped, this.config.targetRoot, result.data);\n result.data = wrapped as T;\n }\n } catch (error) {\n result.errors.push({\n field: '_root',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n\n return result;\n }\n\n /**\n * Map event name using event name mappings\n */\n private mapEventName(source: any): string | undefined {\n if (!this.config.eventNames) return undefined;\n\n // Try to find event_type in source\n const sourceEventName = source.event_type || source.eventType || source.event_name;\n if (!sourceEventName) return undefined;\n\n // Find matching mapping\n for (const mapping of this.config.eventNames) {\n const fromNames = Array.isArray(mapping.from) ? mapping.from : [mapping.from];\n if (fromNames.includes(sourceEventName)) {\n return mapping.to;\n }\n }\n\n return undefined;\n }\n\n /**\n * Map a single field\n */\n private mapField(\n source: any,\n target: any,\n mapping: FieldMapping,\n result: MappingResult\n ): void {\n try {\n // Check condition\n if (mapping.condition && !mapping.condition(source)) {\n result.skippedFields.push(mapping.to);\n return;\n }\n\n // Get source value(s)\n const fromPaths = Array.isArray(mapping.from) ? mapping.from : [mapping.from];\n let value: any = undefined;\n\n // Try each source path until we find a value\n for (const fromPath of fromPaths) {\n value = this.getValueAtPath(source, fromPath);\n if (value !== undefined && value !== null) break;\n }\n\n // Use default if no value found\n if (value === undefined || value === null) {\n if (mapping.default !== undefined) {\n value = mapping.default;\n } else {\n result.skippedFields.push(mapping.to);\n return;\n }\n }\n\n // Skip falsy values if configured\n if (mapping.skipFalsy && !value) {\n result.skippedFields.push(mapping.to);\n return;\n }\n\n // Apply transform\n if (mapping.transform) {\n value = mapping.transform(value, source);\n }\n\n // Set target value\n this.setValueAtPath(target, mapping.to, value);\n result.mappedFields.push(mapping.to);\n } catch (error) {\n result.errors.push({\n field: mapping.to,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Map a static field\n */\n private mapStaticField(\n source: any,\n target: any,\n staticField: StaticField,\n result: MappingResult\n ): void {\n try {\n const value =\n typeof staticField.value === 'function'\n ? staticField.value(source)\n : staticField.value;\n\n this.setValueAtPath(target, staticField.to, value);\n result.mappedFields.push(staticField.to);\n } catch (error) {\n result.errors.push({\n field: staticField.to,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get value at path using dot notation\n * Supports array indexing (e.g., 'products.0.id')\n */\n private getValueAtPath(obj: any, path: string): any {\n const parts = path.split('.');\n let value = obj;\n\n for (const part of parts) {\n if (value === undefined || value === null) return undefined;\n\n // Handle array index\n if (/^\\d+$/.test(part)) {\n value = value[parseInt(part, 10)];\n } else {\n value = value[part];\n }\n }\n\n return value;\n }\n\n /**\n * Set value at path using dot notation\n * Creates nested objects/arrays as needed\n */\n private setValueAtPath(obj: any, path: string, value: any): void {\n const parts = path.split('.');\n let current = obj;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n\n // Create nested structure if needed\n if (current[part] === undefined || current[part] === null) {\n // Next part is array index\n if (/^\\d+$/.test(nextPart)) {\n current[part] = [];\n } else {\n current[part] = {};\n }\n }\n\n current = current[part];\n }\n\n const lastPart = parts[parts.length - 1];\n\n // Handle array index\n if (/^\\d+$/.test(lastPart)) {\n const index = parseInt(lastPart, 10);\n if (!Array.isArray(current)) {\n throw new Error(`Cannot set array index ${index} on non-array`);\n }\n current[index] = value;\n } else {\n current[lastPart] = value;\n }\n }\n\n /**\n * Batch map multiple events\n */\n mapBatch<T = any>(sources: any[]): MappingResult<T>[] {\n return sources.map((source) => this.map<T>(source));\n }\n}\n","/**\n * Common transform functions for event mapping\n */\n\n/**\n * Convert milliseconds to seconds\n */\nexport const msToSeconds = (ms: number): number => Math.floor(ms / 1000);\n\n/**\n * Convert seconds to milliseconds\n */\nexport const secondsToMs = (seconds: number): number => seconds * 1000;\n\n/**\n * Lowercase string\n */\nexport const lowercase = (str: string): string => str.toLowerCase();\n\n/**\n * Uppercase string\n */\nexport const uppercase = (str: string): string => str.toUpperCase();\n\n/**\n * Trim whitespace\n */\nexport const trim = (str: string): string => str.trim();\n\n/**\n * Convert to string\n */\nexport const toString = (value: any): string => String(value);\n\n/**\n * Convert to number\n */\nexport const toNumber = (value: any): number => Number(value);\n\n/**\n * Convert to boolean\n */\nexport const toBoolean = (value: any): boolean => Boolean(value);\n\n/**\n * Wrap value in array\n */\nexport const toArray = (value: any): any[] => {\n if (Array.isArray(value)) return value;\n return [value];\n};\n\n/**\n * Get first element of array, or value if not array\n */\nexport const first = (value: any): any => {\n if (Array.isArray(value)) return value[0];\n return value;\n};\n\n/**\n * Map array of objects to array of property values\n */\nexport const pluck = (property: string) => (arr: any[]): any[] => {\n if (!Array.isArray(arr)) return [];\n return arr.map((item) => item[property]);\n};\n\n/**\n * Join array into string\n */\nexport const join = (separator: string = ',') => (arr: any[]): string => {\n if (!Array.isArray(arr)) return String(arr);\n return arr.join(separator);\n};\n\n/**\n * Split string into array\n */\nexport const split = (separator: string = ',') => (str: string): string[] => {\n return str.split(separator);\n};\n\n/**\n * Format date as ISO 8601\n */\nexport const toISO = (timestamp: number): string => {\n return new Date(timestamp).toISOString();\n};\n\n/**\n * Parse ISO date to timestamp\n */\nexport const fromISO = (iso: string): number => {\n return new Date(iso).getTime();\n};\n\n/**\n * Round number to decimals\n */\nexport const round = (decimals: number = 0) => (num: number): number => {\n const factor = Math.pow(10, decimals);\n return Math.round(num * factor) / factor;\n};\n\n/**\n * Compose multiple transforms (right to left)\n */\nexport const compose = (...fns: ((value: any) => any)[]): ((value: any) => any) => {\n return (value: any) => fns.reduceRight((acc, fn) => fn(acc), value);\n};\n\n/**\n * Pipe multiple transforms (left to right)\n */\nexport const pipe = (...fns: ((value: any) => any)[]): ((value: any) => any) => {\n return (value: any) => fns.reduce((acc, fn) => fn(acc), value);\n};\n\n/**\n * Return value as-is (identity function)\n */\nexport const identity = (value: any): any => value;\n\n/**\n * Rename object keys\n */\nexport const renameKeys = (keyMap: Record<string, string>) => (obj: any): any => {\n const result: any = {};\n for (const [oldKey, newKey] of Object.entries(keyMap)) {\n if (obj[oldKey] !== undefined) {\n result[newKey] = obj[oldKey];\n }\n }\n return result;\n};\n\n/**\n * Pick specific keys from object\n */\nexport const pick = (...keys: string[]) => (obj: any): any => {\n const result: any = {};\n for (const key of keys) {\n if (obj[key] !== undefined) {\n result[key] = obj[key];\n }\n }\n return result;\n};\n\n/**\n * Omit specific keys from object\n */\nexport const omit = (...keys: string[]) => (obj: any): any => {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result;\n};\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@sygnl/mapper",
3
+ "version": "1.0.0",
4
+ "description": "Declarative event mapper for transforming events between different ad platform formats",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "keywords": [
20
+ "mapper",
21
+ "event-mapping",
22
+ "transform",
23
+ "ad-platforms",
24
+ "meta",
25
+ "google",
26
+ "snapchat",
27
+ "tiktok",
28
+ "conversion-api"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsup",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest",
34
+ "test:coverage": "vitest run --coverage",
35
+ "typecheck": "tsc --noEmit",
36
+ "prepublishOnly": "npm run build"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^20.10.0",
40
+ "tsup": "^8.0.1",
41
+ "typescript": "^5.3.3",
42
+ "vitest": "^1.0.4",
43
+ "@vitest/coverage-v8": "^1.0.4"
44
+ },
45
+ "engines": {
46
+ "node": ">=18"
47
+ },
48
+ "author": "Edge Foundry, Inc.",
49
+ "license": "Apache-2.0"
50
+ }