@walkeros/server-destination-mixpanel 4.8.1 → 4.8.2
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/CHANGELOG.md +27 -0
- package/README.md +1 -1
- package/dist/dev.d.mts +11 -2
- package/dist/dev.d.ts +11 -2
- package/dist/dev.js +1 -1
- package/dist/dev.js.map +1 -1
- package/dist/dev.mjs +1 -1
- package/dist/dev.mjs.map +1 -1
- package/dist/examples/index.d.mts +10 -1
- package/dist/examples/index.d.ts +10 -1
- package/dist/examples/index.js +48 -7
- package/dist/examples/index.mjs +49 -8
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/walkerOS.json +219 -13
- package/package.json +4 -4
package/dist/examples/index.js
CHANGED
|
@@ -90,13 +90,17 @@ var step_exports = {};
|
|
|
90
90
|
__export(step_exports, {
|
|
91
91
|
aliasBeforeTrack: () => aliasBeforeTrack,
|
|
92
92
|
allPeopleOperations: () => allPeopleOperations,
|
|
93
|
+
allPeopleOperationsSkip: () => allPeopleOperationsSkip,
|
|
93
94
|
companyGroupProfile: () => companyGroupProfile,
|
|
95
|
+
companyGroupProfileSkip: () => companyGroupProfileSkip,
|
|
94
96
|
defaultEventForwarding: () => defaultEventForwarding,
|
|
95
97
|
historicalImport: () => historicalImport,
|
|
96
98
|
perEventIdentify: () => perEventIdentify,
|
|
99
|
+
silentRule: () => silentRule,
|
|
97
100
|
trackWithGroup: () => trackWithGroup,
|
|
98
101
|
trackWithInclude: () => trackWithInclude,
|
|
99
102
|
userLoginPeopleSet: () => userLoginPeopleSet,
|
|
103
|
+
userLoginPeopleSetSkip: () => userLoginPeopleSetSkip,
|
|
100
104
|
wildcardIgnored: () => wildcardIgnored
|
|
101
105
|
});
|
|
102
106
|
var import_core = require("@walkeros/core");
|
|
@@ -143,7 +147,8 @@ var trackWithInclude = {
|
|
|
143
147
|
var perEventIdentify = {
|
|
144
148
|
title: "Per-event identify",
|
|
145
149
|
description: "A mapping-level identify overrides the destination default to resolve the distinct_id from event data.",
|
|
146
|
-
in: (0, import_core.
|
|
150
|
+
in: (0, import_core.createEvent)({
|
|
151
|
+
name: "user login",
|
|
147
152
|
timestamp: 1700000102,
|
|
148
153
|
data: {
|
|
149
154
|
user_id: "resolved-id",
|
|
@@ -209,7 +214,8 @@ var trackWithGroup = {
|
|
|
209
214
|
var userLoginPeopleSet = {
|
|
210
215
|
title: "User login people",
|
|
211
216
|
description: "A user login fires Mixpanel people.set, set_once, and increment operations without sending a track event.",
|
|
212
|
-
in: (0, import_core.
|
|
217
|
+
in: (0, import_core.createEvent)({
|
|
218
|
+
name: "user login",
|
|
213
219
|
timestamp: 1700000104,
|
|
214
220
|
data: {
|
|
215
221
|
user_id: "new-user-123",
|
|
@@ -262,7 +268,8 @@ var userLoginPeopleSet = {
|
|
|
262
268
|
var allPeopleOperations = {
|
|
263
269
|
title: "Common people operations",
|
|
264
270
|
description: "A profile update exercises the common Mixpanel people vocabulary: set, set_once, increment, append, union, remove, and unset. delete_user is not covered by this example.",
|
|
265
|
-
in: (0, import_core.
|
|
271
|
+
in: (0, import_core.createEvent)({
|
|
272
|
+
name: "profile update",
|
|
266
273
|
timestamp: 1700000105,
|
|
267
274
|
data: {
|
|
268
275
|
name: "Jane Doe",
|
|
@@ -331,7 +338,8 @@ var allPeopleOperations = {
|
|
|
331
338
|
var companyGroupProfile = {
|
|
332
339
|
title: "Group profile",
|
|
333
340
|
description: "A company update sets Mixpanel group profile properties via groups.set and groups.set_once.",
|
|
334
|
-
in: (0, import_core.
|
|
341
|
+
in: (0, import_core.createEvent)({
|
|
342
|
+
name: "company update",
|
|
335
343
|
timestamp: 1700000106,
|
|
336
344
|
data: {
|
|
337
345
|
company_id: "acme-inc",
|
|
@@ -380,7 +388,7 @@ var historicalImport = {
|
|
|
380
388
|
in: (0, import_core.getEvent)("order complete", {
|
|
381
389
|
timestamp: 1700000107,
|
|
382
390
|
data: {
|
|
383
|
-
|
|
391
|
+
value: 99.99
|
|
384
392
|
}
|
|
385
393
|
}),
|
|
386
394
|
settings: {
|
|
@@ -396,7 +404,8 @@ var historicalImport = {
|
|
|
396
404
|
var aliasBeforeTrack = {
|
|
397
405
|
title: "Alias before track",
|
|
398
406
|
description: "A user login merges a prior anonymous id into the new user id via mp.alias before sending the track event.",
|
|
399
|
-
in: (0, import_core.
|
|
407
|
+
in: (0, import_core.createEvent)({
|
|
408
|
+
name: "user login",
|
|
400
409
|
timestamp: 1700000108,
|
|
401
410
|
data: {
|
|
402
411
|
user_id: "new-user-456",
|
|
@@ -420,10 +429,42 @@ var aliasBeforeTrack = {
|
|
|
420
429
|
};
|
|
421
430
|
var wildcardIgnored = {
|
|
422
431
|
public: false,
|
|
423
|
-
in: (0, import_core.
|
|
432
|
+
in: (0, import_core.createEvent)({ name: "debug noise", timestamp: 1700000109 }),
|
|
424
433
|
mapping: { ignore: true },
|
|
425
434
|
out: []
|
|
426
435
|
};
|
|
436
|
+
var silentRule = {
|
|
437
|
+
public: false,
|
|
438
|
+
description: "A rule with silent: true sends nothing to Mixpanel.",
|
|
439
|
+
in: (0, import_core.getEvent)("page view", { timestamp: 170000099e4 }),
|
|
440
|
+
mapping: { silent: true },
|
|
441
|
+
out: []
|
|
442
|
+
};
|
|
443
|
+
function skipWithoutInput(target, name, timestamp) {
|
|
444
|
+
const [entity, action] = name.split(" ");
|
|
445
|
+
return {
|
|
446
|
+
public: false,
|
|
447
|
+
description: `A ${name} event without the data its rule reads has no profile or group to address: nothing is sent, and that is not a failure.`,
|
|
448
|
+
in: { name, entity, action, timestamp },
|
|
449
|
+
mapping: target.mapping,
|
|
450
|
+
out: []
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
var userLoginPeopleSetSkip = skipWithoutInput(
|
|
454
|
+
userLoginPeopleSet,
|
|
455
|
+
"user login",
|
|
456
|
+
1700000991e3
|
|
457
|
+
);
|
|
458
|
+
var allPeopleOperationsSkip = skipWithoutInput(
|
|
459
|
+
allPeopleOperations,
|
|
460
|
+
"profile update",
|
|
461
|
+
1700000992e3
|
|
462
|
+
);
|
|
463
|
+
var companyGroupProfileSkip = skipWithoutInput(
|
|
464
|
+
companyGroupProfile,
|
|
465
|
+
"company update",
|
|
466
|
+
1700000993e3
|
|
467
|
+
);
|
|
427
468
|
// Annotate the CommonJS export names for ESM import in node:
|
|
428
469
|
0 && (module.exports = {
|
|
429
470
|
env,
|
package/dist/examples/index.mjs
CHANGED
|
@@ -69,16 +69,20 @@ var step_exports = {};
|
|
|
69
69
|
__export(step_exports, {
|
|
70
70
|
aliasBeforeTrack: () => aliasBeforeTrack,
|
|
71
71
|
allPeopleOperations: () => allPeopleOperations,
|
|
72
|
+
allPeopleOperationsSkip: () => allPeopleOperationsSkip,
|
|
72
73
|
companyGroupProfile: () => companyGroupProfile,
|
|
74
|
+
companyGroupProfileSkip: () => companyGroupProfileSkip,
|
|
73
75
|
defaultEventForwarding: () => defaultEventForwarding,
|
|
74
76
|
historicalImport: () => historicalImport,
|
|
75
77
|
perEventIdentify: () => perEventIdentify,
|
|
78
|
+
silentRule: () => silentRule,
|
|
76
79
|
trackWithGroup: () => trackWithGroup,
|
|
77
80
|
trackWithInclude: () => trackWithInclude,
|
|
78
81
|
userLoginPeopleSet: () => userLoginPeopleSet,
|
|
82
|
+
userLoginPeopleSetSkip: () => userLoginPeopleSetSkip,
|
|
79
83
|
wildcardIgnored: () => wildcardIgnored
|
|
80
84
|
});
|
|
81
|
-
import { getEvent } from "@walkeros/core";
|
|
85
|
+
import { createEvent, getEvent } from "@walkeros/core";
|
|
82
86
|
var defaultEventForwarding = {
|
|
83
87
|
title: "Default track",
|
|
84
88
|
description: "A walkerOS event is forwarded to Mixpanel as a track call with the user id as the distinct_id.",
|
|
@@ -122,7 +126,8 @@ var trackWithInclude = {
|
|
|
122
126
|
var perEventIdentify = {
|
|
123
127
|
title: "Per-event identify",
|
|
124
128
|
description: "A mapping-level identify overrides the destination default to resolve the distinct_id from event data.",
|
|
125
|
-
in:
|
|
129
|
+
in: createEvent({
|
|
130
|
+
name: "user login",
|
|
126
131
|
timestamp: 1700000102,
|
|
127
132
|
data: {
|
|
128
133
|
user_id: "resolved-id",
|
|
@@ -188,7 +193,8 @@ var trackWithGroup = {
|
|
|
188
193
|
var userLoginPeopleSet = {
|
|
189
194
|
title: "User login people",
|
|
190
195
|
description: "A user login fires Mixpanel people.set, set_once, and increment operations without sending a track event.",
|
|
191
|
-
in:
|
|
196
|
+
in: createEvent({
|
|
197
|
+
name: "user login",
|
|
192
198
|
timestamp: 1700000104,
|
|
193
199
|
data: {
|
|
194
200
|
user_id: "new-user-123",
|
|
@@ -241,7 +247,8 @@ var userLoginPeopleSet = {
|
|
|
241
247
|
var allPeopleOperations = {
|
|
242
248
|
title: "Common people operations",
|
|
243
249
|
description: "A profile update exercises the common Mixpanel people vocabulary: set, set_once, increment, append, union, remove, and unset. delete_user is not covered by this example.",
|
|
244
|
-
in:
|
|
250
|
+
in: createEvent({
|
|
251
|
+
name: "profile update",
|
|
245
252
|
timestamp: 1700000105,
|
|
246
253
|
data: {
|
|
247
254
|
name: "Jane Doe",
|
|
@@ -310,7 +317,8 @@ var allPeopleOperations = {
|
|
|
310
317
|
var companyGroupProfile = {
|
|
311
318
|
title: "Group profile",
|
|
312
319
|
description: "A company update sets Mixpanel group profile properties via groups.set and groups.set_once.",
|
|
313
|
-
in:
|
|
320
|
+
in: createEvent({
|
|
321
|
+
name: "company update",
|
|
314
322
|
timestamp: 1700000106,
|
|
315
323
|
data: {
|
|
316
324
|
company_id: "acme-inc",
|
|
@@ -359,7 +367,7 @@ var historicalImport = {
|
|
|
359
367
|
in: getEvent("order complete", {
|
|
360
368
|
timestamp: 1700000107,
|
|
361
369
|
data: {
|
|
362
|
-
|
|
370
|
+
value: 99.99
|
|
363
371
|
}
|
|
364
372
|
}),
|
|
365
373
|
settings: {
|
|
@@ -375,7 +383,8 @@ var historicalImport = {
|
|
|
375
383
|
var aliasBeforeTrack = {
|
|
376
384
|
title: "Alias before track",
|
|
377
385
|
description: "A user login merges a prior anonymous id into the new user id via mp.alias before sending the track event.",
|
|
378
|
-
in:
|
|
386
|
+
in: createEvent({
|
|
387
|
+
name: "user login",
|
|
379
388
|
timestamp: 1700000108,
|
|
380
389
|
data: {
|
|
381
390
|
user_id: "new-user-456",
|
|
@@ -399,10 +408,42 @@ var aliasBeforeTrack = {
|
|
|
399
408
|
};
|
|
400
409
|
var wildcardIgnored = {
|
|
401
410
|
public: false,
|
|
402
|
-
in:
|
|
411
|
+
in: createEvent({ name: "debug noise", timestamp: 1700000109 }),
|
|
403
412
|
mapping: { ignore: true },
|
|
404
413
|
out: []
|
|
405
414
|
};
|
|
415
|
+
var silentRule = {
|
|
416
|
+
public: false,
|
|
417
|
+
description: "A rule with silent: true sends nothing to Mixpanel.",
|
|
418
|
+
in: getEvent("page view", { timestamp: 170000099e4 }),
|
|
419
|
+
mapping: { silent: true },
|
|
420
|
+
out: []
|
|
421
|
+
};
|
|
422
|
+
function skipWithoutInput(target, name, timestamp) {
|
|
423
|
+
const [entity, action] = name.split(" ");
|
|
424
|
+
return {
|
|
425
|
+
public: false,
|
|
426
|
+
description: `A ${name} event without the data its rule reads has no profile or group to address: nothing is sent, and that is not a failure.`,
|
|
427
|
+
in: { name, entity, action, timestamp },
|
|
428
|
+
mapping: target.mapping,
|
|
429
|
+
out: []
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
var userLoginPeopleSetSkip = skipWithoutInput(
|
|
433
|
+
userLoginPeopleSet,
|
|
434
|
+
"user login",
|
|
435
|
+
1700000991e3
|
|
436
|
+
);
|
|
437
|
+
var allPeopleOperationsSkip = skipWithoutInput(
|
|
438
|
+
allPeopleOperations,
|
|
439
|
+
"profile update",
|
|
440
|
+
1700000992e3
|
|
441
|
+
);
|
|
442
|
+
var companyGroupProfileSkip = skipWithoutInput(
|
|
443
|
+
companyGroupProfile,
|
|
444
|
+
"company update",
|
|
445
|
+
1700000993e3
|
|
446
|
+
);
|
|
406
447
|
export {
|
|
407
448
|
env_exports as env,
|
|
408
449
|
step_exports as step
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var mod,__create=Object.create,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty,__copyProps=(to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to},index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationMixpanel:()=>types_exports,default:()=>index_default,destinationMixpanel:()=>destinationMixpanel}),module.exports=(mod=index_exports,__copyProps(__defProp({},"__esModule",{value:!0}),mod));var import_mixpanel=((mod,isNodeMode,target)=>(target=null!=mod?__create(__getProtoOf(mod)):{},__copyProps(!isNodeMode&&mod&&mod.__esModule?target:__defProp(target,"default",{value:mod,enumerable:!0}),mod)))(require("mixpanel"));var
|
|
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,{DestinationMixpanel:()=>types_exports,default:()=>index_default,destinationMixpanel:()=>destinationMixpanel}),module.exports=(mod=index_exports,__copyProps(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core"),import_mixpanel=((mod,isNodeMode,target)=>(target=null!=mod?__create(__getProtoOf(mod)):{},__copyProps(!isNodeMode&&mod&&mod.__esModule?target:__defProp(target,"default",{value:mod,enumerable:!0}),mod)))(require("mixpanel"));var import_core2=require("@walkeros/core"),PEOPLE_OBJECT_OPS=["set","set_once","increment","append","union","remove"],GROUP_OBJECT_OPS=["set","set_once","union","remove"];function wrapCallback(fn){return new Promise((resolve,reject)=>{const fail=error=>reject(new import_core2.StepError("Mixpanel request failed",{code:"transport",cause:error}));try{const answer=fn(err=>err?fail(err):resolve());(0,import_core2.isThenable)(answer)&&answer.then(()=>resolve(),fail)}catch(error){fail(error)}})}var push=async function(event,{config:config,rule:rule,data:data,collector:collector,logger:logger}){const settings=config.settings,client=settings.client;if(!client)throw new import_core2.StepError("Mixpanel client not initialized",{code:"not-ready"});const mappingSettings=rule?.settings||{},identifyMapping=mappingSettings.identify??settings.identify;let distinctId,alias;if(void 0!==identifyMapping){const resolved=await(0,import_core2.getMappingValue)(event,identifyMapping,{collector:collector});if((0,import_core2.isObject)(resolved)){const r=resolved;(0,import_core2.isString)(r.distinctId)&&""!==r.distinctId&&(distinctId=r.distinctId),(0,import_core2.isString)(r.alias)&&""!==r.alias&&(alias=r.alias)}}if(distinctId&&alias&&await wrapCallback(cb=>client.alias(distinctId,alias,cb)),void 0!==mappingSettings.people){const resolved=distinctId?await(0,import_core2.getMappingValue)(event,mappingSettings.people,{collector:collector}):void 0;distinctId&&(0,import_core2.isObject)(resolved)?await async function(client,distinctId,resolved){const promises=[];for(const op of PEOPLE_OBJECT_OPS){const bag=resolved[op];(0,import_core2.isObject)(bag)&&0!==Object.keys(bag).length&&promises.push(wrapCallback(cb=>client.people[op](distinctId,bag,cb)))}const unsetVal=resolved.unset;if(void 0!==unsetVal)if((0,import_core2.isString)(unsetVal))promises.push(wrapCallback(cb=>client.people.unset(distinctId,unsetVal,cb)));else if((0,import_core2.isArray)(unsetVal)){const names=unsetVal.filter(v=>(0,import_core2.isString)(v));names.length>0&&promises.push(wrapCallback(cb=>client.people.unset(distinctId,names,cb)))}!0===resolved.delete_user&&promises.push(wrapCallback(cb=>client.people.delete_user(distinctId,cb))),await Promise.all(promises)}(client,distinctId,resolved):logger.debug("Mixpanel skipped people: identify resolved to nothing",{event:event.name,mappingKey:distinctId?"people":"identify"})}let groupProps={};const groupMapping=mappingSettings.group??settings.group;if(void 0!==groupMapping){const resolved=await(0,import_core2.getMappingValue)(event,groupMapping,{collector:collector});if((0,import_core2.isObject)(resolved)){const{key:gKey,id:gId}=resolved;(0,import_core2.isString)(gKey)&&""!==gKey&&(0,import_core2.isString)(gId)&&""!==gId&&(groupProps={[gKey]:gId})}}if(void 0!==mappingSettings.groupProfile){const resolved=await(0,import_core2.getMappingValue)(event,mappingSettings.groupProfile,{collector:collector});(0,import_core2.isObject)(resolved)&&await async function(client,resolved,dropped){const{key:key,id:id}=resolved;if(!(0,import_core2.isString)(key)||""===key||!(0,import_core2.isString)(id)||""===id)return void dropped();const promises=[];for(const op of GROUP_OBJECT_OPS){const bag=resolved[op];(0,import_core2.isObject)(bag)&&0!==Object.keys(bag).length&&promises.push(wrapCallback(cb=>client.groups[op](key,id,bag,cb)))}const unsetVal=resolved.unset;if(void 0!==unsetVal)if((0,import_core2.isString)(unsetVal))promises.push(wrapCallback(cb=>client.groups.unset(key,id,unsetVal,cb)));else if((0,import_core2.isArray)(unsetVal)){const names=unsetVal.filter(v=>(0,import_core2.isString)(v));names.length>0&&promises.push(wrapCallback(cb=>client.groups.unset(key,id,names,cb)))}!0===resolved.delete&&promises.push(wrapCallback(cb=>client.groups.delete_group(key,id,cb))),await Promise.all(promises)}(client,resolved,()=>logger.debug("Mixpanel skipped groupProfile: groupProfile resolved to nothing",{event:event.name,mappingKey:"groupProfile"}))}if(!0!==rule?.silent){const eventName=(0,import_core2.isString)(rule?.name)?rule.name:event.name,properties={};distinctId&&(properties.distinct_id=distinctId),Object.assign(properties,groupProps),(0,import_core2.isObject)(data)&&Object.assign(properties,data);if(settings.useImport||mappingSettings.useImport){const timestamp=event.timestamp||Date.now();await wrapCallback(cb=>client.import(eventName,timestamp,properties,cb))}else await wrapCallback(cb=>client.track(eventName,properties,cb))}},types_exports={},destinationMixpanel={type:"mixpanel",config:{},async init({config:partialConfig,env:env,logger:logger}){const config=function(partialConfig={},env,logger){const settings=partialConfig.settings||{},{apiKey:apiKey}=settings;if(!apiKey)throw new import_core.StepError("Config settings apiKey missing",{code:"config"});const initOptions={};void 0!==settings.secret&&(initOptions.secret=settings.secret),void 0!==settings.host&&(initOptions.host=settings.host),void 0!==settings.protocol&&(initOptions.protocol=settings.protocol),void 0!==settings.keepAlive&&(initOptions.keepAlive=settings.keepAlive),void 0!==settings.geolocate&&(initOptions.geolocate=settings.geolocate),void 0!==settings.debug&&(initOptions.debug=settings.debug),void 0!==settings.verbose&&(initOptions.verbose=settings.verbose),void 0!==settings.test&&(initOptions.test=settings.test),settings.useImport&&!settings.secret&&logger.warn("useImport requires secret for /import authentication");const client=(env?.Mixpanel||import_mixpanel.default).init(apiKey,initOptions),settingsConfig={...settings,apiKey:apiKey,client:client};return{...partialConfig,settings:settingsConfig}}(partialConfig,env,logger);return config},push:async(event,context)=>await push(event,context),destroy({config:config}){config?.settings&&(config.settings.client=void 0)}},index_default=destinationMixpanel;//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationMixpanel from './types';\n\nexport const destinationMixpanel: Destination = {\n type: 'mixpanel',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env, logger);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n destroy({ config }) {\n // SDK fires immediately — no flush/close needed.\n // Just clear the client reference.\n if (config?.settings) {\n config.settings.client = undefined;\n }\n },\n};\n\nexport default destinationMixpanel;\n","import type {\n Config,\n Env,\n MixpanelClient,\n PartialConfig,\n Settings,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport Mixpanel from 'mixpanel';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env: Env | undefined,\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 // Build SDK init options from settings\n const initOptions: Record<string, unknown> = {};\n if (settings.secret !== undefined) initOptions.secret = settings.secret;\n if (settings.host !== undefined) initOptions.host = settings.host;\n if (settings.protocol !== undefined) initOptions.protocol = settings.protocol;\n if (settings.keepAlive !== undefined)\n initOptions.keepAlive = settings.keepAlive;\n if (settings.geolocate !== undefined)\n initOptions.geolocate = settings.geolocate;\n if (settings.debug !== undefined) initOptions.debug = settings.debug;\n if (settings.verbose !== undefined) initOptions.verbose = settings.verbose;\n if (settings.test !== undefined) initOptions.test = settings.test;\n\n // Warn if useImport without secret\n if (settings.useImport && !settings.secret) {\n logger.warn('useImport requires secret for /import authentication');\n }\n\n // Use Mixpanel from env if available, otherwise use real Mixpanel\n const MixpanelFactory = env?.Mixpanel || Mixpanel;\n const client = MixpanelFactory.init(\n apiKey,\n initOptions,\n ) as unknown as MixpanelClient;\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n client,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { MixpanelCallback, MixpanelClient, PushFn } from './types';\nimport { getMappingValue, isArray, isObject, isString } from '@walkeros/core';\n\ntype PeopleObjectOp =\n | 'set'\n | 'set_once'\n | 'increment'\n | 'append'\n | 'union'\n | 'remove';\n\nconst PEOPLE_OBJECT_OPS: PeopleObjectOp[] = [\n 'set',\n 'set_once',\n 'increment',\n 'append',\n 'union',\n 'remove',\n];\n\ntype GroupObjectOp = 'set' | 'set_once' | 'union' | 'remove';\n\nconst GROUP_OBJECT_OPS: GroupObjectOp[] = [\n 'set',\n 'set_once',\n 'union',\n 'remove',\n];\n\n/**\n * Wraps a Mixpanel SDK callback-based call in a Promise.\n */\nfunction wrapCallback(fn: (cb: MixpanelCallback) => void): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n fn((err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n\n/**\n * Apply people operations to the Mixpanel client.\n * All people methods require distinct_id as the first argument.\n */\nasync function applyPeople(\n client: MixpanelClient,\n distinctId: string,\n resolved: Record<string, unknown>,\n): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (const op of PEOPLE_OBJECT_OPS) {\n const bag = resolved[op];\n if (!isObject(bag) || Object.keys(bag).length === 0) continue;\n promises.push(\n wrapCallback((cb) => {\n (\n client.people[op] as (\n id: string,\n props: Record<string, unknown>,\n cb: MixpanelCallback,\n ) => void\n )(distinctId, bag as Record<string, unknown>, cb);\n }),\n );\n }\n\n // Handle unset - string or string[]\n const unsetVal = resolved.unset;\n if (unsetVal !== undefined) {\n if (isString(unsetVal)) {\n promises.push(\n wrapCallback((cb) => {\n client.people.unset(distinctId, unsetVal, cb);\n }),\n );\n } else if (isArray(unsetVal)) {\n const names = (unsetVal as unknown[]).filter((v): v is string =>\n isString(v),\n );\n if (names.length > 0) {\n promises.push(\n wrapCallback((cb) => {\n client.people.unset(distinctId, names, cb);\n }),\n );\n }\n }\n }\n\n // Handle delete_user\n if (resolved.delete_user === true) {\n promises.push(\n wrapCallback((cb) => {\n client.people.delete_user(distinctId, cb);\n }),\n );\n }\n\n await Promise.all(promises);\n}\n\n/**\n * Apply group profile operations to the Mixpanel client.\n */\nasync function applyGroupProfile(\n client: MixpanelClient,\n resolved: Record<string, unknown>,\n): Promise<void> {\n const { key, id } = resolved as { key?: unknown; id?: unknown };\n if (!isString(key) || key === '' || !isString(id) || id === '') return;\n\n const promises: Promise<void>[] = [];\n\n for (const op of GROUP_OBJECT_OPS) {\n const bag = resolved[op];\n if (!isObject(bag) || Object.keys(bag).length === 0) continue;\n promises.push(\n wrapCallback((cb) => {\n (\n client.groups[op] as (\n gk: string,\n gi: string,\n props: Record<string, unknown>,\n cb: MixpanelCallback,\n ) => void\n )(key, id, bag as Record<string, unknown>, cb);\n }),\n );\n }\n\n // Handle unset\n const unsetVal = resolved.unset;\n if (unsetVal !== undefined) {\n if (isString(unsetVal)) {\n promises.push(\n wrapCallback((cb) => {\n client.groups.unset(key, id, unsetVal, cb);\n }),\n );\n } else if (isArray(unsetVal)) {\n const names = (unsetVal as unknown[]).filter((v): v is string =>\n isString(v),\n );\n if (names.length > 0) {\n promises.push(\n wrapCallback((cb) => {\n client.groups.unset(key, id, names, cb);\n }),\n );\n }\n }\n }\n\n // Handle delete\n if (resolved.delete === true) {\n promises.push(\n wrapCallback((cb) => {\n client.groups.delete_group(key, id, cb);\n }),\n );\n }\n\n await Promise.all(promises);\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, logger },\n) {\n const settings = config.settings!;\n const client = settings.client;\n if (!client) {\n logger.throw('Mixpanel client not initialized');\n return;\n }\n\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 distinctId: string | undefined;\n let alias: string | undefined;\n\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as Record<string, unknown>;\n if (isString(r.distinctId) && r.distinctId !== '') {\n distinctId = r.distinctId;\n }\n if (isString(r.alias) && r.alias !== '') {\n alias = r.alias;\n }\n }\n }\n\n // 2. Alias - fire before people/track (legacy identity merge)\n if (distinctId && alias) {\n await wrapCallback((cb) => {\n client.alias(distinctId!, alias!, cb);\n });\n }\n\n // 3. People operations - require distinct_id\n if (distinctId && mappingSettings.people !== undefined) {\n const resolved = await getMappingValue(event, mappingSettings.people, {\n collector,\n });\n if (isObject(resolved)) {\n await applyPeople(\n client,\n distinctId,\n resolved as Record<string, unknown>,\n );\n }\n }\n\n // 4. Group - attach group keys to event properties\n let groupProps: Record<string, unknown> = {};\n const groupMapping = mappingSettings.group ?? settings.group;\n if (groupMapping !== undefined) {\n const resolved = await getMappingValue(event, groupMapping, { collector });\n if (isObject(resolved)) {\n const { key: gKey, id: gId } = resolved as {\n key?: unknown;\n id?: unknown;\n };\n if (isString(gKey) && gKey !== '' && isString(gId) && gId !== '') {\n groupProps = { [gKey]: gId };\n }\n }\n }\n\n // 5. Group profile operations\n if (mappingSettings.groupProfile !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.groupProfile,\n {\n collector,\n },\n );\n if (isObject(resolved)) {\n await applyGroupProfile(client, resolved as Record<string, unknown>);\n }\n }\n\n // 6. Track/Import - unless the rule opts out via silent\n if (rule?.silent !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties: Record<string, unknown> = {};\n\n // Add distinct_id to properties\n if (distinctId) {\n properties.distinct_id = distinctId;\n }\n\n // Add group properties\n Object.assign(properties, groupProps);\n\n // Add mapped data (from collector/rule resolution)\n if (isObject(data)) {\n Object.assign(properties, data as Record<string, unknown>);\n }\n\n // Determine if we should use import or track\n const useImport = settings.useImport || mappingSettings.useImport;\n\n if (useImport) {\n const timestamp = event.timestamp || Date.now();\n await wrapCallback((cb) => {\n client.import(eventName, timestamp, properties, cb);\n });\n } else {\n await wrapCallback((cb) => {\n client.track(eventName, properties, cb);\n });\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';\nimport type Mixpanel from 'mixpanel';\n\n// Re-export the SDK's callback type for convenience\nexport type MixpanelCallback = (err: Error | undefined) => void;\n\n/**\n * Subset of the Mixpanel People API used by the destination.\n * Every method requires `distinct_id` as the first argument (stateless server SDK).\n */\nexport interface MixpanelPeople {\n set(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n set_once(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n increment(\n distinctId: string,\n properties: Record<string, number>,\n callback?: MixpanelCallback,\n ): void;\n append(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n union(\n distinctId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n remove(\n distinctId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n unset(\n distinctId: string,\n propertyName: string | string[],\n callback?: MixpanelCallback,\n ): void;\n delete_user(distinctId: string, callback?: MixpanelCallback): void;\n}\n\n/**\n * Subset of the Mixpanel Groups API used by the destination.\n * Every method requires `(groupKey, groupId)` as the first two args.\n */\nexport interface MixpanelGroups {\n set(\n groupKey: string,\n groupId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n set_once(\n groupKey: string,\n groupId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n union(\n groupKey: string,\n groupId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n remove(\n groupKey: string,\n groupId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n unset(\n groupKey: string,\n groupId: string,\n propertyName: string | string[],\n callback?: MixpanelCallback,\n ): void;\n delete_group(\n groupKey: string,\n groupId: string,\n callback?: MixpanelCallback,\n ): void;\n}\n\n/**\n * Subset of the Mixpanel SDK instance the destination uses.\n */\nexport interface MixpanelClient {\n track(\n eventName: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n import(\n eventName: string,\n time: Date | number,\n properties?: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n alias(distinctId: string, alias: string, callback?: MixpanelCallback): void;\n people: MixpanelPeople;\n groups: MixpanelGroups;\n}\n\nexport interface Settings {\n apiKey: string;\n secret?: string;\n host?: string;\n protocol?: string;\n keepAlive?: boolean;\n geolocate?: boolean;\n debug?: boolean;\n verbose?: boolean;\n test?: boolean;\n identify?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n include?: string[];\n useImport?: boolean;\n /** Initialized Mixpanel client instance — set during init(). */\n client?: MixpanelClient;\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings. Keys follow Mixpanel's native method names.\n * No `reset` (not applicable server-side).\n */\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n people?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n groupProfile?: WalkerOSMapping.Value;\n useImport?: WalkerOSMapping.Value;\n}\n\n/**\n * Environment with optional Mixpanel constructor override for testing.\n * Follows the same pattern as GCP BigQuery's `env.BigQuery`.\n */\nexport interface Env extends DestinationServer.Env {\n Mixpanel?: { init: (...args: unknown[]) => MixpanelClient };\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":["Mixpanel"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationMixpanel from './types';\n\nexport const destinationMixpanel: Destination = {\n type: 'mixpanel',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env, logger);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n destroy({ config }) {\n // SDK fires immediately — no flush/close needed.\n // Just clear the client reference.\n if (config?.settings) {\n config.settings.client = undefined;\n }\n },\n};\n\nexport default destinationMixpanel;\n","import type {\n Config,\n Env,\n MixpanelClient,\n PartialConfig,\n Settings,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { StepError } from '@walkeros/core';\nimport Mixpanel from 'mixpanel';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env: Env | undefined,\n logger: Logger.Instance,\n): Config {\n const settings: Partial<Settings> = partialConfig.settings || {};\n const { apiKey } = settings;\n\n if (!apiKey)\n throw new StepError('Config settings apiKey missing', { code: 'config' });\n\n // Build SDK init options from settings\n const initOptions: Record<string, unknown> = {};\n if (settings.secret !== undefined) initOptions.secret = settings.secret;\n if (settings.host !== undefined) initOptions.host = settings.host;\n if (settings.protocol !== undefined) initOptions.protocol = settings.protocol;\n if (settings.keepAlive !== undefined)\n initOptions.keepAlive = settings.keepAlive;\n if (settings.geolocate !== undefined)\n initOptions.geolocate = settings.geolocate;\n if (settings.debug !== undefined) initOptions.debug = settings.debug;\n if (settings.verbose !== undefined) initOptions.verbose = settings.verbose;\n if (settings.test !== undefined) initOptions.test = settings.test;\n\n // Warn if useImport without secret\n if (settings.useImport && !settings.secret) {\n logger.warn('useImport requires secret for /import authentication');\n }\n\n // Use Mixpanel from env if available, otherwise use real Mixpanel\n const MixpanelFactory = env?.Mixpanel || Mixpanel;\n const client = MixpanelFactory.init(\n apiKey,\n initOptions,\n ) as unknown as MixpanelClient;\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n client,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { MixpanelCallback, MixpanelClient, PushFn } from './types';\nimport {\n getMappingValue,\n isArray,\n isObject,\n isString,\n isThenable,\n StepError,\n} from '@walkeros/core';\n\ntype PeopleObjectOp =\n | 'set'\n | 'set_once'\n | 'increment'\n | 'append'\n | 'union'\n | 'remove';\n\nconst PEOPLE_OBJECT_OPS: PeopleObjectOp[] = [\n 'set',\n 'set_once',\n 'increment',\n 'append',\n 'union',\n 'remove',\n];\n\ntype GroupObjectOp = 'set' | 'set_once' | 'union' | 'remove';\n\nconst GROUP_OBJECT_OPS: GroupObjectOp[] = [\n 'set',\n 'set_once',\n 'union',\n 'remove',\n];\n\n/**\n * Wraps a Mixpanel SDK callback-based call in a Promise.\n */\nfunction wrapCallback(fn: (cb: MixpanelCallback) => unknown): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n // The SDK's own error stays on `cause`, never in the message.\n const fail = (error: unknown) =>\n reject(\n new StepError('Mixpanel request failed', {\n code: 'transport',\n cause: error,\n }),\n );\n try {\n const answer = fn((err) => (err ? fail(err) : resolve()));\n // An injected client may answer with a promise instead of the callback.\n if (isThenable(answer)) answer.then(() => resolve(), fail);\n } catch (error) {\n fail(error);\n }\n });\n}\n\n/**\n * Apply people operations to the Mixpanel client.\n * All people methods require distinct_id as the first argument.\n */\nasync function applyPeople(\n client: MixpanelClient,\n distinctId: string,\n resolved: Record<string, unknown>,\n): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (const op of PEOPLE_OBJECT_OPS) {\n const bag = resolved[op];\n if (!isObject(bag) || Object.keys(bag).length === 0) continue;\n promises.push(\n wrapCallback((cb) =>\n (\n client.people[op] as (\n id: string,\n props: Record<string, unknown>,\n cb: MixpanelCallback,\n ) => void\n )(distinctId, bag, cb),\n ),\n );\n }\n\n // Handle unset - string or string[]\n const unsetVal = resolved.unset;\n if (unsetVal !== undefined) {\n if (isString(unsetVal)) {\n promises.push(\n wrapCallback((cb) => client.people.unset(distinctId, unsetVal, cb)),\n );\n } else if (isArray(unsetVal)) {\n const names = (unsetVal as unknown[]).filter((v): v is string =>\n isString(v),\n );\n if (names.length > 0) {\n promises.push(\n wrapCallback((cb) => client.people.unset(distinctId, names, cb)),\n );\n }\n }\n }\n\n // Handle delete_user\n if (resolved.delete_user === true) {\n promises.push(\n wrapCallback((cb) => client.people.delete_user(distinctId, cb)),\n );\n }\n\n await Promise.all(promises);\n}\n\n/**\n * Apply group profile operations to the Mixpanel client.\n */\nasync function applyGroupProfile(\n client: MixpanelClient,\n resolved: Record<string, unknown>,\n dropped: () => void,\n): Promise<void> {\n const { key, id } = resolved as { key?: unknown; id?: unknown };\n if (!isString(key) || key === '' || !isString(id) || id === '') {\n dropped();\n return;\n }\n\n const promises: Promise<void>[] = [];\n\n for (const op of GROUP_OBJECT_OPS) {\n const bag = resolved[op];\n if (!isObject(bag) || Object.keys(bag).length === 0) continue;\n promises.push(\n wrapCallback((cb) =>\n (\n client.groups[op] as (\n gk: string,\n gi: string,\n props: Record<string, unknown>,\n cb: MixpanelCallback,\n ) => void\n )(key, id, bag, cb),\n ),\n );\n }\n\n // Handle unset\n const unsetVal = resolved.unset;\n if (unsetVal !== undefined) {\n if (isString(unsetVal)) {\n promises.push(\n wrapCallback((cb) => client.groups.unset(key, id, unsetVal, cb)),\n );\n } else if (isArray(unsetVal)) {\n const names = (unsetVal as unknown[]).filter((v): v is string =>\n isString(v),\n );\n if (names.length > 0) {\n promises.push(\n wrapCallback((cb) => client.groups.unset(key, id, names, cb)),\n );\n }\n }\n }\n\n // Handle delete\n if (resolved.delete === true) {\n promises.push(\n wrapCallback((cb) => client.groups.delete_group(key, id, cb)),\n );\n }\n\n await Promise.all(promises);\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, logger },\n) {\n const settings = config.settings!;\n const client = settings.client;\n if (!client)\n throw new StepError('Mixpanel client not initialized', {\n code: 'not-ready',\n });\n\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 distinctId: string | undefined;\n let alias: string | undefined;\n\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as Record<string, unknown>;\n if (isString(r.distinctId) && r.distinctId !== '') {\n distinctId = r.distinctId;\n }\n if (isString(r.alias) && r.alias !== '') {\n alias = r.alias;\n }\n }\n }\n\n // 2. Alias - fire before people/track (legacy identity merge)\n if (distinctId && alias) {\n await wrapCallback((cb) => client.alias(distinctId!, alias!, cb));\n }\n\n // 3. People operations - require distinct_id\n if (mappingSettings.people !== undefined) {\n const resolved = distinctId\n ? await getMappingValue(event, mappingSettings.people, { collector })\n : undefined;\n if (distinctId && isObject(resolved)) {\n await applyPeople(\n client,\n distinctId,\n resolved as Record<string, unknown>,\n );\n } else {\n // Nothing to address: a deliberate skip, named by its mapping key.\n logger.debug('Mixpanel skipped people: identify resolved to nothing', {\n event: event.name,\n mappingKey: distinctId ? 'people' : 'identify',\n });\n }\n }\n\n // 4. Group - attach group keys to event properties\n let groupProps: Record<string, unknown> = {};\n const groupMapping = mappingSettings.group ?? settings.group;\n if (groupMapping !== undefined) {\n const resolved = await getMappingValue(event, groupMapping, { collector });\n if (isObject(resolved)) {\n const { key: gKey, id: gId } = resolved as {\n key?: unknown;\n id?: unknown;\n };\n if (isString(gKey) && gKey !== '' && isString(gId) && gId !== '') {\n groupProps = { [gKey]: gId };\n }\n }\n }\n\n // 5. Group profile operations\n if (mappingSettings.groupProfile !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.groupProfile,\n {\n collector,\n },\n );\n if (isObject(resolved)) {\n // A group profile without key and id has nothing to address: the event\n // still goes out, and the skip is a deliberate decision (DEBUG).\n await applyGroupProfile(client, resolved, () =>\n logger.debug(\n 'Mixpanel skipped groupProfile: groupProfile resolved to nothing',\n { event: event.name, mappingKey: 'groupProfile' },\n ),\n );\n }\n }\n\n // 6. Track/Import - unless the rule opts out via silent\n if (rule?.silent !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties: Record<string, unknown> = {};\n\n // Add distinct_id to properties\n if (distinctId) {\n properties.distinct_id = distinctId;\n }\n\n // Add group properties\n Object.assign(properties, groupProps);\n\n // Add mapped data (from collector/rule resolution)\n if (isObject(data)) {\n Object.assign(properties, data as Record<string, unknown>);\n }\n\n // Determine if we should use import or track\n const useImport = settings.useImport || mappingSettings.useImport;\n\n if (useImport) {\n const timestamp = event.timestamp || Date.now();\n await wrapCallback((cb) =>\n client.import(eventName, timestamp, properties, cb),\n );\n } else {\n await wrapCallback((cb) => client.track(eventName, properties, cb));\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';\nimport type Mixpanel from 'mixpanel';\n\n// Re-export the SDK's callback type for convenience\nexport type MixpanelCallback = (err: Error | undefined) => void;\n\n/**\n * Subset of the Mixpanel People API used by the destination.\n * Every method requires `distinct_id` as the first argument (stateless server SDK).\n */\nexport interface MixpanelPeople {\n set(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n set_once(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n increment(\n distinctId: string,\n properties: Record<string, number>,\n callback?: MixpanelCallback,\n ): void;\n append(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n union(\n distinctId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n remove(\n distinctId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n unset(\n distinctId: string,\n propertyName: string | string[],\n callback?: MixpanelCallback,\n ): void;\n delete_user(distinctId: string, callback?: MixpanelCallback): void;\n}\n\n/**\n * Subset of the Mixpanel Groups API used by the destination.\n * Every method requires `(groupKey, groupId)` as the first two args.\n */\nexport interface MixpanelGroups {\n set(\n groupKey: string,\n groupId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n set_once(\n groupKey: string,\n groupId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n union(\n groupKey: string,\n groupId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n remove(\n groupKey: string,\n groupId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n unset(\n groupKey: string,\n groupId: string,\n propertyName: string | string[],\n callback?: MixpanelCallback,\n ): void;\n delete_group(\n groupKey: string,\n groupId: string,\n callback?: MixpanelCallback,\n ): void;\n}\n\n/**\n * Subset of the Mixpanel SDK instance the destination uses.\n */\nexport interface MixpanelClient {\n track(\n eventName: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n import(\n eventName: string,\n time: Date | number,\n properties?: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n alias(distinctId: string, alias: string, callback?: MixpanelCallback): void;\n people: MixpanelPeople;\n groups: MixpanelGroups;\n}\n\nexport interface Settings {\n apiKey: string;\n secret?: string;\n host?: string;\n protocol?: string;\n keepAlive?: boolean;\n geolocate?: boolean;\n debug?: boolean;\n verbose?: boolean;\n test?: boolean;\n identify?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n include?: string[];\n useImport?: boolean;\n /** Initialized Mixpanel client instance — set during init(). */\n client?: MixpanelClient;\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings. Keys follow Mixpanel's native method names.\n * No `reset` (not applicable server-side).\n */\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n people?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n groupProfile?: WalkerOSMapping.Value;\n useImport?: WalkerOSMapping.Value;\n}\n\n/**\n * Environment with optional Mixpanel constructor override for testing.\n * Follows the same pattern as GCP BigQuery's `env.BigQuery`.\n */\nexport interface Env extends DestinationServer.Env {\n Mixpanel?: { init: (...args: unknown[]) => MixpanelClient };\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":["Mixpanel","import_core"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import Mixpanel from"mixpanel";import{getMappingValue,isArray,isObject,isString}from"@walkeros/core";var PEOPLE_OBJECT_OPS=["set","set_once","increment","append","union","remove"],GROUP_OBJECT_OPS=["set","set_once","union","remove"];function wrapCallback(fn){return new Promise((resolve,reject)=>{fn(err=>
|
|
1
|
+
import{createRequire}from"module";createRequire(import.meta.url);import{StepError}from"@walkeros/core";import Mixpanel from"mixpanel";import{getMappingValue,isArray,isObject,isString,isThenable,StepError as StepError2}from"@walkeros/core";var PEOPLE_OBJECT_OPS=["set","set_once","increment","append","union","remove"],GROUP_OBJECT_OPS=["set","set_once","union","remove"];function wrapCallback(fn){return new Promise((resolve,reject)=>{const fail=error=>reject(new StepError2("Mixpanel request failed",{code:"transport",cause:error}));try{const answer=fn(err=>err?fail(err):resolve());isThenable(answer)&&answer.then(()=>resolve(),fail)}catch(error){fail(error)}})}var push=async function(event,{config:config,rule:rule,data:data,collector:collector,logger:logger}){const settings=config.settings,client=settings.client;if(!client)throw new StepError2("Mixpanel client not initialized",{code:"not-ready"});const mappingSettings=rule?.settings||{},identifyMapping=mappingSettings.identify??settings.identify;let distinctId,alias;if(void 0!==identifyMapping){const resolved=await getMappingValue(event,identifyMapping,{collector:collector});if(isObject(resolved)){const r=resolved;isString(r.distinctId)&&""!==r.distinctId&&(distinctId=r.distinctId),isString(r.alias)&&""!==r.alias&&(alias=r.alias)}}if(distinctId&&alias&&await wrapCallback(cb=>client.alias(distinctId,alias,cb)),void 0!==mappingSettings.people){const resolved=distinctId?await getMappingValue(event,mappingSettings.people,{collector:collector}):void 0;distinctId&&isObject(resolved)?await async function(client,distinctId,resolved){const promises=[];for(const op of PEOPLE_OBJECT_OPS){const bag=resolved[op];isObject(bag)&&0!==Object.keys(bag).length&&promises.push(wrapCallback(cb=>client.people[op](distinctId,bag,cb)))}const unsetVal=resolved.unset;if(void 0!==unsetVal)if(isString(unsetVal))promises.push(wrapCallback(cb=>client.people.unset(distinctId,unsetVal,cb)));else if(isArray(unsetVal)){const names=unsetVal.filter(v=>isString(v));names.length>0&&promises.push(wrapCallback(cb=>client.people.unset(distinctId,names,cb)))}!0===resolved.delete_user&&promises.push(wrapCallback(cb=>client.people.delete_user(distinctId,cb))),await Promise.all(promises)}(client,distinctId,resolved):logger.debug("Mixpanel skipped people: identify resolved to nothing",{event:event.name,mappingKey:distinctId?"people":"identify"})}let groupProps={};const groupMapping=mappingSettings.group??settings.group;if(void 0!==groupMapping){const resolved=await getMappingValue(event,groupMapping,{collector:collector});if(isObject(resolved)){const{key:gKey,id:gId}=resolved;isString(gKey)&&""!==gKey&&isString(gId)&&""!==gId&&(groupProps={[gKey]:gId})}}if(void 0!==mappingSettings.groupProfile){const resolved=await getMappingValue(event,mappingSettings.groupProfile,{collector:collector});isObject(resolved)&&await async function(client,resolved,dropped){const{key:key,id:id}=resolved;if(!isString(key)||""===key||!isString(id)||""===id)return void dropped();const promises=[];for(const op of GROUP_OBJECT_OPS){const bag=resolved[op];isObject(bag)&&0!==Object.keys(bag).length&&promises.push(wrapCallback(cb=>client.groups[op](key,id,bag,cb)))}const unsetVal=resolved.unset;if(void 0!==unsetVal)if(isString(unsetVal))promises.push(wrapCallback(cb=>client.groups.unset(key,id,unsetVal,cb)));else if(isArray(unsetVal)){const names=unsetVal.filter(v=>isString(v));names.length>0&&promises.push(wrapCallback(cb=>client.groups.unset(key,id,names,cb)))}!0===resolved.delete&&promises.push(wrapCallback(cb=>client.groups.delete_group(key,id,cb))),await Promise.all(promises)}(client,resolved,()=>logger.debug("Mixpanel skipped groupProfile: groupProfile resolved to nothing",{event:event.name,mappingKey:"groupProfile"}))}if(!0!==rule?.silent){const eventName=isString(rule?.name)?rule.name:event.name,properties={};distinctId&&(properties.distinct_id=distinctId),Object.assign(properties,groupProps),isObject(data)&&Object.assign(properties,data);if(settings.useImport||mappingSettings.useImport){const timestamp=event.timestamp||Date.now();await wrapCallback(cb=>client.import(eventName,timestamp,properties,cb))}else await wrapCallback(cb=>client.track(eventName,properties,cb))}},types_exports={},destinationMixpanel={type:"mixpanel",config:{},async init({config:partialConfig,env:env,logger:logger}){const config=function(partialConfig={},env,logger){const settings=partialConfig.settings||{},{apiKey:apiKey}=settings;if(!apiKey)throw new StepError("Config settings apiKey missing",{code:"config"});const initOptions={};void 0!==settings.secret&&(initOptions.secret=settings.secret),void 0!==settings.host&&(initOptions.host=settings.host),void 0!==settings.protocol&&(initOptions.protocol=settings.protocol),void 0!==settings.keepAlive&&(initOptions.keepAlive=settings.keepAlive),void 0!==settings.geolocate&&(initOptions.geolocate=settings.geolocate),void 0!==settings.debug&&(initOptions.debug=settings.debug),void 0!==settings.verbose&&(initOptions.verbose=settings.verbose),void 0!==settings.test&&(initOptions.test=settings.test),settings.useImport&&!settings.secret&&logger.warn("useImport requires secret for /import authentication");const client=(env?.Mixpanel||Mixpanel).init(apiKey,initOptions),settingsConfig={...settings,apiKey:apiKey,client:client};return{...partialConfig,settings:settingsConfig}}(partialConfig,env,logger);return config},push:async(event,context)=>await push(event,context),destroy({config:config}){config?.settings&&(config.settings.client=void 0)}},index_default=destinationMixpanel;export{types_exports as DestinationMixpanel,index_default as default,destinationMixpanel};//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type {\n Config,\n Env,\n MixpanelClient,\n PartialConfig,\n Settings,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport Mixpanel from 'mixpanel';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env: Env | undefined,\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 // Build SDK init options from settings\n const initOptions: Record<string, unknown> = {};\n if (settings.secret !== undefined) initOptions.secret = settings.secret;\n if (settings.host !== undefined) initOptions.host = settings.host;\n if (settings.protocol !== undefined) initOptions.protocol = settings.protocol;\n if (settings.keepAlive !== undefined)\n initOptions.keepAlive = settings.keepAlive;\n if (settings.geolocate !== undefined)\n initOptions.geolocate = settings.geolocate;\n if (settings.debug !== undefined) initOptions.debug = settings.debug;\n if (settings.verbose !== undefined) initOptions.verbose = settings.verbose;\n if (settings.test !== undefined) initOptions.test = settings.test;\n\n // Warn if useImport without secret\n if (settings.useImport && !settings.secret) {\n logger.warn('useImport requires secret for /import authentication');\n }\n\n // Use Mixpanel from env if available, otherwise use real Mixpanel\n const MixpanelFactory = env?.Mixpanel || Mixpanel;\n const client = MixpanelFactory.init(\n apiKey,\n initOptions,\n ) as unknown as MixpanelClient;\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n client,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { MixpanelCallback, MixpanelClient, PushFn } from './types';\nimport { getMappingValue, isArray, isObject, isString } from '@walkeros/core';\n\ntype PeopleObjectOp =\n | 'set'\n | 'set_once'\n | 'increment'\n | 'append'\n | 'union'\n | 'remove';\n\nconst PEOPLE_OBJECT_OPS: PeopleObjectOp[] = [\n 'set',\n 'set_once',\n 'increment',\n 'append',\n 'union',\n 'remove',\n];\n\ntype GroupObjectOp = 'set' | 'set_once' | 'union' | 'remove';\n\nconst GROUP_OBJECT_OPS: GroupObjectOp[] = [\n 'set',\n 'set_once',\n 'union',\n 'remove',\n];\n\n/**\n * Wraps a Mixpanel SDK callback-based call in a Promise.\n */\nfunction wrapCallback(fn: (cb: MixpanelCallback) => void): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n fn((err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n\n/**\n * Apply people operations to the Mixpanel client.\n * All people methods require distinct_id as the first argument.\n */\nasync function applyPeople(\n client: MixpanelClient,\n distinctId: string,\n resolved: Record<string, unknown>,\n): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (const op of PEOPLE_OBJECT_OPS) {\n const bag = resolved[op];\n if (!isObject(bag) || Object.keys(bag).length === 0) continue;\n promises.push(\n wrapCallback((cb) => {\n (\n client.people[op] as (\n id: string,\n props: Record<string, unknown>,\n cb: MixpanelCallback,\n ) => void\n )(distinctId, bag as Record<string, unknown>, cb);\n }),\n );\n }\n\n // Handle unset - string or string[]\n const unsetVal = resolved.unset;\n if (unsetVal !== undefined) {\n if (isString(unsetVal)) {\n promises.push(\n wrapCallback((cb) => {\n client.people.unset(distinctId, unsetVal, cb);\n }),\n );\n } else if (isArray(unsetVal)) {\n const names = (unsetVal as unknown[]).filter((v): v is string =>\n isString(v),\n );\n if (names.length > 0) {\n promises.push(\n wrapCallback((cb) => {\n client.people.unset(distinctId, names, cb);\n }),\n );\n }\n }\n }\n\n // Handle delete_user\n if (resolved.delete_user === true) {\n promises.push(\n wrapCallback((cb) => {\n client.people.delete_user(distinctId, cb);\n }),\n );\n }\n\n await Promise.all(promises);\n}\n\n/**\n * Apply group profile operations to the Mixpanel client.\n */\nasync function applyGroupProfile(\n client: MixpanelClient,\n resolved: Record<string, unknown>,\n): Promise<void> {\n const { key, id } = resolved as { key?: unknown; id?: unknown };\n if (!isString(key) || key === '' || !isString(id) || id === '') return;\n\n const promises: Promise<void>[] = [];\n\n for (const op of GROUP_OBJECT_OPS) {\n const bag = resolved[op];\n if (!isObject(bag) || Object.keys(bag).length === 0) continue;\n promises.push(\n wrapCallback((cb) => {\n (\n client.groups[op] as (\n gk: string,\n gi: string,\n props: Record<string, unknown>,\n cb: MixpanelCallback,\n ) => void\n )(key, id, bag as Record<string, unknown>, cb);\n }),\n );\n }\n\n // Handle unset\n const unsetVal = resolved.unset;\n if (unsetVal !== undefined) {\n if (isString(unsetVal)) {\n promises.push(\n wrapCallback((cb) => {\n client.groups.unset(key, id, unsetVal, cb);\n }),\n );\n } else if (isArray(unsetVal)) {\n const names = (unsetVal as unknown[]).filter((v): v is string =>\n isString(v),\n );\n if (names.length > 0) {\n promises.push(\n wrapCallback((cb) => {\n client.groups.unset(key, id, names, cb);\n }),\n );\n }\n }\n }\n\n // Handle delete\n if (resolved.delete === true) {\n promises.push(\n wrapCallback((cb) => {\n client.groups.delete_group(key, id, cb);\n }),\n );\n }\n\n await Promise.all(promises);\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, logger },\n) {\n const settings = config.settings!;\n const client = settings.client;\n if (!client) {\n logger.throw('Mixpanel client not initialized');\n return;\n }\n\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 distinctId: string | undefined;\n let alias: string | undefined;\n\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as Record<string, unknown>;\n if (isString(r.distinctId) && r.distinctId !== '') {\n distinctId = r.distinctId;\n }\n if (isString(r.alias) && r.alias !== '') {\n alias = r.alias;\n }\n }\n }\n\n // 2. Alias - fire before people/track (legacy identity merge)\n if (distinctId && alias) {\n await wrapCallback((cb) => {\n client.alias(distinctId!, alias!, cb);\n });\n }\n\n // 3. People operations - require distinct_id\n if (distinctId && mappingSettings.people !== undefined) {\n const resolved = await getMappingValue(event, mappingSettings.people, {\n collector,\n });\n if (isObject(resolved)) {\n await applyPeople(\n client,\n distinctId,\n resolved as Record<string, unknown>,\n );\n }\n }\n\n // 4. Group - attach group keys to event properties\n let groupProps: Record<string, unknown> = {};\n const groupMapping = mappingSettings.group ?? settings.group;\n if (groupMapping !== undefined) {\n const resolved = await getMappingValue(event, groupMapping, { collector });\n if (isObject(resolved)) {\n const { key: gKey, id: gId } = resolved as {\n key?: unknown;\n id?: unknown;\n };\n if (isString(gKey) && gKey !== '' && isString(gId) && gId !== '') {\n groupProps = { [gKey]: gId };\n }\n }\n }\n\n // 5. Group profile operations\n if (mappingSettings.groupProfile !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.groupProfile,\n {\n collector,\n },\n );\n if (isObject(resolved)) {\n await applyGroupProfile(client, resolved as Record<string, unknown>);\n }\n }\n\n // 6. Track/Import - unless the rule opts out via silent\n if (rule?.silent !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties: Record<string, unknown> = {};\n\n // Add distinct_id to properties\n if (distinctId) {\n properties.distinct_id = distinctId;\n }\n\n // Add group properties\n Object.assign(properties, groupProps);\n\n // Add mapped data (from collector/rule resolution)\n if (isObject(data)) {\n Object.assign(properties, data as Record<string, unknown>);\n }\n\n // Determine if we should use import or track\n const useImport = settings.useImport || mappingSettings.useImport;\n\n if (useImport) {\n const timestamp = event.timestamp || Date.now();\n await wrapCallback((cb) => {\n client.import(eventName, timestamp, properties, cb);\n });\n } else {\n await wrapCallback((cb) => {\n client.track(eventName, properties, cb);\n });\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';\nimport type Mixpanel from 'mixpanel';\n\n// Re-export the SDK's callback type for convenience\nexport type MixpanelCallback = (err: Error | undefined) => void;\n\n/**\n * Subset of the Mixpanel People API used by the destination.\n * Every method requires `distinct_id` as the first argument (stateless server SDK).\n */\nexport interface MixpanelPeople {\n set(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n set_once(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n increment(\n distinctId: string,\n properties: Record<string, number>,\n callback?: MixpanelCallback,\n ): void;\n append(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n union(\n distinctId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n remove(\n distinctId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n unset(\n distinctId: string,\n propertyName: string | string[],\n callback?: MixpanelCallback,\n ): void;\n delete_user(distinctId: string, callback?: MixpanelCallback): void;\n}\n\n/**\n * Subset of the Mixpanel Groups API used by the destination.\n * Every method requires `(groupKey, groupId)` as the first two args.\n */\nexport interface MixpanelGroups {\n set(\n groupKey: string,\n groupId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n set_once(\n groupKey: string,\n groupId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n union(\n groupKey: string,\n groupId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n remove(\n groupKey: string,\n groupId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n unset(\n groupKey: string,\n groupId: string,\n propertyName: string | string[],\n callback?: MixpanelCallback,\n ): void;\n delete_group(\n groupKey: string,\n groupId: string,\n callback?: MixpanelCallback,\n ): void;\n}\n\n/**\n * Subset of the Mixpanel SDK instance the destination uses.\n */\nexport interface MixpanelClient {\n track(\n eventName: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n import(\n eventName: string,\n time: Date | number,\n properties?: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n alias(distinctId: string, alias: string, callback?: MixpanelCallback): void;\n people: MixpanelPeople;\n groups: MixpanelGroups;\n}\n\nexport interface Settings {\n apiKey: string;\n secret?: string;\n host?: string;\n protocol?: string;\n keepAlive?: boolean;\n geolocate?: boolean;\n debug?: boolean;\n verbose?: boolean;\n test?: boolean;\n identify?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n include?: string[];\n useImport?: boolean;\n /** Initialized Mixpanel client instance — set during init(). */\n client?: MixpanelClient;\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings. Keys follow Mixpanel's native method names.\n * No `reset` (not applicable server-side).\n */\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n people?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n groupProfile?: WalkerOSMapping.Value;\n useImport?: WalkerOSMapping.Value;\n}\n\n/**\n * Environment with optional Mixpanel constructor override for testing.\n * Follows the same pattern as GCP BigQuery's `env.BigQuery`.\n */\nexport interface Env extends DestinationServer.Env {\n Mixpanel?: { init: (...args: unknown[]) => MixpanelClient };\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 { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationMixpanel from './types';\n\nexport const destinationMixpanel: Destination = {\n type: 'mixpanel',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env, logger);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n destroy({ config }) {\n // SDK fires immediately — no flush/close needed.\n // Just clear the client reference.\n if (config?.settings) {\n config.settings.client = undefined;\n }\n },\n};\n\nexport default destinationMixpanel;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type {\n Config,\n Env,\n MixpanelClient,\n PartialConfig,\n Settings,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { StepError } from '@walkeros/core';\nimport Mixpanel from 'mixpanel';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env: Env | undefined,\n logger: Logger.Instance,\n): Config {\n const settings: Partial<Settings> = partialConfig.settings || {};\n const { apiKey } = settings;\n\n if (!apiKey)\n throw new StepError('Config settings apiKey missing', { code: 'config' });\n\n // Build SDK init options from settings\n const initOptions: Record<string, unknown> = {};\n if (settings.secret !== undefined) initOptions.secret = settings.secret;\n if (settings.host !== undefined) initOptions.host = settings.host;\n if (settings.protocol !== undefined) initOptions.protocol = settings.protocol;\n if (settings.keepAlive !== undefined)\n initOptions.keepAlive = settings.keepAlive;\n if (settings.geolocate !== undefined)\n initOptions.geolocate = settings.geolocate;\n if (settings.debug !== undefined) initOptions.debug = settings.debug;\n if (settings.verbose !== undefined) initOptions.verbose = settings.verbose;\n if (settings.test !== undefined) initOptions.test = settings.test;\n\n // Warn if useImport without secret\n if (settings.useImport && !settings.secret) {\n logger.warn('useImport requires secret for /import authentication');\n }\n\n // Use Mixpanel from env if available, otherwise use real Mixpanel\n const MixpanelFactory = env?.Mixpanel || Mixpanel;\n const client = MixpanelFactory.init(\n apiKey,\n initOptions,\n ) as unknown as MixpanelClient;\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n client,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { MixpanelCallback, MixpanelClient, PushFn } from './types';\nimport {\n getMappingValue,\n isArray,\n isObject,\n isString,\n isThenable,\n StepError,\n} from '@walkeros/core';\n\ntype PeopleObjectOp =\n | 'set'\n | 'set_once'\n | 'increment'\n | 'append'\n | 'union'\n | 'remove';\n\nconst PEOPLE_OBJECT_OPS: PeopleObjectOp[] = [\n 'set',\n 'set_once',\n 'increment',\n 'append',\n 'union',\n 'remove',\n];\n\ntype GroupObjectOp = 'set' | 'set_once' | 'union' | 'remove';\n\nconst GROUP_OBJECT_OPS: GroupObjectOp[] = [\n 'set',\n 'set_once',\n 'union',\n 'remove',\n];\n\n/**\n * Wraps a Mixpanel SDK callback-based call in a Promise.\n */\nfunction wrapCallback(fn: (cb: MixpanelCallback) => unknown): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n // The SDK's own error stays on `cause`, never in the message.\n const fail = (error: unknown) =>\n reject(\n new StepError('Mixpanel request failed', {\n code: 'transport',\n cause: error,\n }),\n );\n try {\n const answer = fn((err) => (err ? fail(err) : resolve()));\n // An injected client may answer with a promise instead of the callback.\n if (isThenable(answer)) answer.then(() => resolve(), fail);\n } catch (error) {\n fail(error);\n }\n });\n}\n\n/**\n * Apply people operations to the Mixpanel client.\n * All people methods require distinct_id as the first argument.\n */\nasync function applyPeople(\n client: MixpanelClient,\n distinctId: string,\n resolved: Record<string, unknown>,\n): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (const op of PEOPLE_OBJECT_OPS) {\n const bag = resolved[op];\n if (!isObject(bag) || Object.keys(bag).length === 0) continue;\n promises.push(\n wrapCallback((cb) =>\n (\n client.people[op] as (\n id: string,\n props: Record<string, unknown>,\n cb: MixpanelCallback,\n ) => void\n )(distinctId, bag, cb),\n ),\n );\n }\n\n // Handle unset - string or string[]\n const unsetVal = resolved.unset;\n if (unsetVal !== undefined) {\n if (isString(unsetVal)) {\n promises.push(\n wrapCallback((cb) => client.people.unset(distinctId, unsetVal, cb)),\n );\n } else if (isArray(unsetVal)) {\n const names = (unsetVal as unknown[]).filter((v): v is string =>\n isString(v),\n );\n if (names.length > 0) {\n promises.push(\n wrapCallback((cb) => client.people.unset(distinctId, names, cb)),\n );\n }\n }\n }\n\n // Handle delete_user\n if (resolved.delete_user === true) {\n promises.push(\n wrapCallback((cb) => client.people.delete_user(distinctId, cb)),\n );\n }\n\n await Promise.all(promises);\n}\n\n/**\n * Apply group profile operations to the Mixpanel client.\n */\nasync function applyGroupProfile(\n client: MixpanelClient,\n resolved: Record<string, unknown>,\n dropped: () => void,\n): Promise<void> {\n const { key, id } = resolved as { key?: unknown; id?: unknown };\n if (!isString(key) || key === '' || !isString(id) || id === '') {\n dropped();\n return;\n }\n\n const promises: Promise<void>[] = [];\n\n for (const op of GROUP_OBJECT_OPS) {\n const bag = resolved[op];\n if (!isObject(bag) || Object.keys(bag).length === 0) continue;\n promises.push(\n wrapCallback((cb) =>\n (\n client.groups[op] as (\n gk: string,\n gi: string,\n props: Record<string, unknown>,\n cb: MixpanelCallback,\n ) => void\n )(key, id, bag, cb),\n ),\n );\n }\n\n // Handle unset\n const unsetVal = resolved.unset;\n if (unsetVal !== undefined) {\n if (isString(unsetVal)) {\n promises.push(\n wrapCallback((cb) => client.groups.unset(key, id, unsetVal, cb)),\n );\n } else if (isArray(unsetVal)) {\n const names = (unsetVal as unknown[]).filter((v): v is string =>\n isString(v),\n );\n if (names.length > 0) {\n promises.push(\n wrapCallback((cb) => client.groups.unset(key, id, names, cb)),\n );\n }\n }\n }\n\n // Handle delete\n if (resolved.delete === true) {\n promises.push(\n wrapCallback((cb) => client.groups.delete_group(key, id, cb)),\n );\n }\n\n await Promise.all(promises);\n}\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, logger },\n) {\n const settings = config.settings!;\n const client = settings.client;\n if (!client)\n throw new StepError('Mixpanel client not initialized', {\n code: 'not-ready',\n });\n\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 distinctId: string | undefined;\n let alias: string | undefined;\n\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as Record<string, unknown>;\n if (isString(r.distinctId) && r.distinctId !== '') {\n distinctId = r.distinctId;\n }\n if (isString(r.alias) && r.alias !== '') {\n alias = r.alias;\n }\n }\n }\n\n // 2. Alias - fire before people/track (legacy identity merge)\n if (distinctId && alias) {\n await wrapCallback((cb) => client.alias(distinctId!, alias!, cb));\n }\n\n // 3. People operations - require distinct_id\n if (mappingSettings.people !== undefined) {\n const resolved = distinctId\n ? await getMappingValue(event, mappingSettings.people, { collector })\n : undefined;\n if (distinctId && isObject(resolved)) {\n await applyPeople(\n client,\n distinctId,\n resolved as Record<string, unknown>,\n );\n } else {\n // Nothing to address: a deliberate skip, named by its mapping key.\n logger.debug('Mixpanel skipped people: identify resolved to nothing', {\n event: event.name,\n mappingKey: distinctId ? 'people' : 'identify',\n });\n }\n }\n\n // 4. Group - attach group keys to event properties\n let groupProps: Record<string, unknown> = {};\n const groupMapping = mappingSettings.group ?? settings.group;\n if (groupMapping !== undefined) {\n const resolved = await getMappingValue(event, groupMapping, { collector });\n if (isObject(resolved)) {\n const { key: gKey, id: gId } = resolved as {\n key?: unknown;\n id?: unknown;\n };\n if (isString(gKey) && gKey !== '' && isString(gId) && gId !== '') {\n groupProps = { [gKey]: gId };\n }\n }\n }\n\n // 5. Group profile operations\n if (mappingSettings.groupProfile !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.groupProfile,\n {\n collector,\n },\n );\n if (isObject(resolved)) {\n // A group profile without key and id has nothing to address: the event\n // still goes out, and the skip is a deliberate decision (DEBUG).\n await applyGroupProfile(client, resolved, () =>\n logger.debug(\n 'Mixpanel skipped groupProfile: groupProfile resolved to nothing',\n { event: event.name, mappingKey: 'groupProfile' },\n ),\n );\n }\n }\n\n // 6. Track/Import - unless the rule opts out via silent\n if (rule?.silent !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties: Record<string, unknown> = {};\n\n // Add distinct_id to properties\n if (distinctId) {\n properties.distinct_id = distinctId;\n }\n\n // Add group properties\n Object.assign(properties, groupProps);\n\n // Add mapped data (from collector/rule resolution)\n if (isObject(data)) {\n Object.assign(properties, data as Record<string, unknown>);\n }\n\n // Determine if we should use import or track\n const useImport = settings.useImport || mappingSettings.useImport;\n\n if (useImport) {\n const timestamp = event.timestamp || Date.now();\n await wrapCallback((cb) =>\n client.import(eventName, timestamp, properties, cb),\n );\n } else {\n await wrapCallback((cb) => client.track(eventName, properties, cb));\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';\nimport type Mixpanel from 'mixpanel';\n\n// Re-export the SDK's callback type for convenience\nexport type MixpanelCallback = (err: Error | undefined) => void;\n\n/**\n * Subset of the Mixpanel People API used by the destination.\n * Every method requires `distinct_id` as the first argument (stateless server SDK).\n */\nexport interface MixpanelPeople {\n set(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n set_once(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n increment(\n distinctId: string,\n properties: Record<string, number>,\n callback?: MixpanelCallback,\n ): void;\n append(\n distinctId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n union(\n distinctId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n remove(\n distinctId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n unset(\n distinctId: string,\n propertyName: string | string[],\n callback?: MixpanelCallback,\n ): void;\n delete_user(distinctId: string, callback?: MixpanelCallback): void;\n}\n\n/**\n * Subset of the Mixpanel Groups API used by the destination.\n * Every method requires `(groupKey, groupId)` as the first two args.\n */\nexport interface MixpanelGroups {\n set(\n groupKey: string,\n groupId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n set_once(\n groupKey: string,\n groupId: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n union(\n groupKey: string,\n groupId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n remove(\n groupKey: string,\n groupId: string,\n data: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n unset(\n groupKey: string,\n groupId: string,\n propertyName: string | string[],\n callback?: MixpanelCallback,\n ): void;\n delete_group(\n groupKey: string,\n groupId: string,\n callback?: MixpanelCallback,\n ): void;\n}\n\n/**\n * Subset of the Mixpanel SDK instance the destination uses.\n */\nexport interface MixpanelClient {\n track(\n eventName: string,\n properties: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n import(\n eventName: string,\n time: Date | number,\n properties?: Record<string, unknown>,\n callback?: MixpanelCallback,\n ): void;\n alias(distinctId: string, alias: string, callback?: MixpanelCallback): void;\n people: MixpanelPeople;\n groups: MixpanelGroups;\n}\n\nexport interface Settings {\n apiKey: string;\n secret?: string;\n host?: string;\n protocol?: string;\n keepAlive?: boolean;\n geolocate?: boolean;\n debug?: boolean;\n verbose?: boolean;\n test?: boolean;\n identify?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n include?: string[];\n useImport?: boolean;\n /** Initialized Mixpanel client instance — set during init(). */\n client?: MixpanelClient;\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings. Keys follow Mixpanel's native method names.\n * No `reset` (not applicable server-side).\n */\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n people?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n groupProfile?: WalkerOSMapping.Value;\n useImport?: WalkerOSMapping.Value;\n}\n\n/**\n * Environment with optional Mixpanel constructor override for testing.\n * Follows the same pattern as GCP BigQuery's `env.BigQuery`.\n */\nexport interface Env extends DestinationServer.Env {\n Mixpanel?: { init: (...args: unknown[]) => MixpanelClient };\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 { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationMixpanel from './types';\n\nexport const destinationMixpanel: Destination = {\n type: 'mixpanel',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env, logger);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n destroy({ config }) {\n // SDK fires immediately — no flush/close needed.\n // Just clear the client reference.\n if (config?.settings) {\n config.settings.client = undefined;\n }\n },\n};\n\nexport default destinationMixpanel;\n"],"mappings":"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","names":["StepError"]}
|