@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.
@@ -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.getEvent)("user login", {
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.getEvent)("user login", {
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.getEvent)("profile update", {
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.getEvent)("company update", {
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
- total: 99.99
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.getEvent)("user login", {
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.getEvent)("debug noise", { timestamp: 1700000109 }),
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,
@@ -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: getEvent("user login", {
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: getEvent("user login", {
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: getEvent("profile update", {
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: getEvent("company update", {
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
- total: 99.99
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: getEvent("user login", {
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: getEvent("debug noise", { timestamp: 1700000109 }),
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 import_core=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)=>{fn(err=>{err?reject(err):resolve()})})}var push=async function(event,{config:config,rule:rule,data:data,collector:collector,logger:logger}){const settings=config.settings,client=settings.client;if(!client)return void logger.throw("Mixpanel client not initialized");const mappingSettings=rule?.settings||{},identifyMapping=mappingSettings.identify??settings.identify;let distinctId,alias;if(void 0!==identifyMapping){const resolved=await(0,import_core.getMappingValue)(event,identifyMapping,{collector:collector});if((0,import_core.isObject)(resolved)){const r=resolved;(0,import_core.isString)(r.distinctId)&&""!==r.distinctId&&(distinctId=r.distinctId),(0,import_core.isString)(r.alias)&&""!==r.alias&&(alias=r.alias)}}if(distinctId&&alias&&await wrapCallback(cb=>{client.alias(distinctId,alias,cb)}),distinctId&&void 0!==mappingSettings.people){const resolved=await(0,import_core.getMappingValue)(event,mappingSettings.people,{collector:collector});(0,import_core.isObject)(resolved)&&await async function(client,distinctId,resolved){const promises=[];for(const op of PEOPLE_OBJECT_OPS){const bag=resolved[op];(0,import_core.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_core.isString)(unsetVal))promises.push(wrapCallback(cb=>{client.people.unset(distinctId,unsetVal,cb)}));else if((0,import_core.isArray)(unsetVal)){const names=unsetVal.filter(v=>(0,import_core.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)}let groupProps={};const groupMapping=mappingSettings.group??settings.group;if(void 0!==groupMapping){const resolved=await(0,import_core.getMappingValue)(event,groupMapping,{collector:collector});if((0,import_core.isObject)(resolved)){const{key:gKey,id:gId}=resolved;(0,import_core.isString)(gKey)&&""!==gKey&&(0,import_core.isString)(gId)&&""!==gId&&(groupProps={[gKey]:gId})}}if(void 0!==mappingSettings.groupProfile){const resolved=await(0,import_core.getMappingValue)(event,mappingSettings.groupProfile,{collector:collector});(0,import_core.isObject)(resolved)&&await async function(client,resolved){const{key:key,id:id}=resolved;if(!(0,import_core.isString)(key)||""===key||!(0,import_core.isString)(id)||""===id)return;const promises=[];for(const op of GROUP_OBJECT_OPS){const bag=resolved[op];(0,import_core.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_core.isString)(unsetVal))promises.push(wrapCallback(cb=>{client.groups.unset(key,id,unsetVal,cb)}));else if((0,import_core.isArray)(unsetVal)){const names=unsetVal.filter(v=>(0,import_core.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)}if(!0!==rule?.silent){const eventName=(0,import_core.isString)(rule?.name)?rule.name:event.name,properties={};distinctId&&(properties.distinct_id=distinctId),Object.assign(properties,groupProps),(0,import_core.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;apiKey||logger.throw("Config settings apiKey missing");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
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQA,sBAAqB;AAEd,SAAS,UACd,gBAA+B,CAAC,GAChC,KACA,QACQ;AACR,QAAM,WAAY,cAAc,YAAY,CAAC;AAC7C,QAAM,EAAE,OAAO,IAAI;AAEnB,MAAI,CAAC,OAAQ,QAAO,MAAM,gCAAgC;AAG1D,QAAM,cAAuC,CAAC;AAC9C,MAAI,SAAS,WAAW,OAAW,aAAY,SAAS,SAAS;AACjE,MAAI,SAAS,SAAS,OAAW,aAAY,OAAO,SAAS;AAC7D,MAAI,SAAS,aAAa,OAAW,aAAY,WAAW,SAAS;AACrE,MAAI,SAAS,cAAc;AACzB,gBAAY,YAAY,SAAS;AACnC,MAAI,SAAS,cAAc;AACzB,gBAAY,YAAY,SAAS;AACnC,MAAI,SAAS,UAAU,OAAW,aAAY,QAAQ,SAAS;AAC/D,MAAI,SAAS,YAAY,OAAW,aAAY,UAAU,SAAS;AACnE,MAAI,SAAS,SAAS,OAAW,aAAY,OAAO,SAAS;AAG7D,MAAI,SAAS,aAAa,CAAC,SAAS,QAAQ;AAC1C,WAAO,KAAK,sDAAsD;AAAA,EACpE;AAGA,QAAM,kBAAkB,KAAK,YAAY,gBAAAA;AACzC,QAAM,SAAS,gBAAgB;AAAA,IAC7B;AAAA,IACA;AAAA,EACF;AAEA,QAAM,iBAA2B;AAAA,IAC/B,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,eAAe,UAAU,eAAe;AACtD;;;ACnDA,kBAA6D;AAU7D,IAAM,oBAAsC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIA,IAAM,mBAAoC;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKA,SAAS,aAAa,IAAmD;AACvE,SAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,OAAG,CAAC,QAAQ;AACV,UAAI,IAAK,QAAO,GAAG;AAAA,UACd,SAAQ;AAAA,IACf,CAAC;AAAA,EACH,CAAC;AACH;AAMA,eAAe,YACb,QACA,YACA,UACe;AACf,QAAM,WAA4B,CAAC;AAEnC,aAAW,MAAM,mBAAmB;AAClC,UAAM,MAAM,SAAS,EAAE;AACvB,QAAI,KAAC,sBAAS,GAAG,KAAK,OAAO,KAAK,GAAG,EAAE,WAAW,EAAG;AACrD,aAAS;AAAA,MACP,aAAa,CAAC,OAAO;AACnB,QACE,OAAO,OAAO,EAAE,EAKhB,YAAY,KAAgC,EAAE;AAAA,MAClD,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,WAAW,SAAS;AAC1B,MAAI,aAAa,QAAW;AAC1B,YAAI,sBAAS,QAAQ,GAAG;AACtB,eAAS;AAAA,QACP,aAAa,CAAC,OAAO;AACnB,iBAAO,OAAO,MAAM,YAAY,UAAU,EAAE;AAAA,QAC9C,CAAC;AAAA,MACH;AAAA,IACF,eAAW,qBAAQ,QAAQ,GAAG;AAC5B,YAAM,QAAS,SAAuB;AAAA,QAAO,CAAC,UAC5C,sBAAS,CAAC;AAAA,MACZ;AACA,UAAI,MAAM,SAAS,GAAG;AACpB,iBAAS;AAAA,UACP,aAAa,CAAC,OAAO;AACnB,mBAAO,OAAO,MAAM,YAAY,OAAO,EAAE;AAAA,UAC3C,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,gBAAgB,MAAM;AACjC,aAAS;AAAA,MACP,aAAa,CAAC,OAAO;AACnB,eAAO,OAAO,YAAY,YAAY,EAAE;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,QAAQ,IAAI,QAAQ;AAC5B;AAKA,eAAe,kBACb,QACA,UACe;AACf,QAAM,EAAE,KAAK,GAAG,IAAI;AACpB,MAAI,KAAC,sBAAS,GAAG,KAAK,QAAQ,MAAM,KAAC,sBAAS,EAAE,KAAK,OAAO,GAAI;AAEhE,QAAM,WAA4B,CAAC;AAEnC,aAAW,MAAM,kBAAkB;AACjC,UAAM,MAAM,SAAS,EAAE;AACvB,QAAI,KAAC,sBAAS,GAAG,KAAK,OAAO,KAAK,GAAG,EAAE,WAAW,EAAG;AACrD,aAAS;AAAA,MACP,aAAa,CAAC,OAAO;AACnB,QACE,OAAO,OAAO,EAAE,EAMhB,KAAK,IAAI,KAAgC,EAAE;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,WAAW,SAAS;AAC1B,MAAI,aAAa,QAAW;AAC1B,YAAI,sBAAS,QAAQ,GAAG;AACtB,eAAS;AAAA,QACP,aAAa,CAAC,OAAO;AACnB,iBAAO,OAAO,MAAM,KAAK,IAAI,UAAU,EAAE;AAAA,QAC3C,CAAC;AAAA,MACH;AAAA,IACF,eAAW,qBAAQ,QAAQ,GAAG;AAC5B,YAAM,QAAS,SAAuB;AAAA,QAAO,CAAC,UAC5C,sBAAS,CAAC;AAAA,MACZ;AACA,UAAI,MAAM,SAAS,GAAG;AACpB,iBAAS;AAAA,UACP,aAAa,CAAC,OAAO;AACnB,mBAAO,OAAO,MAAM,KAAK,IAAI,OAAO,EAAE;AAAA,UACxC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,WAAW,MAAM;AAC5B,aAAS;AAAA,MACP,aAAa,CAAC,OAAO;AACnB,eAAO,OAAO,aAAa,KAAK,IAAI,EAAE;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,QAAQ,IAAI,QAAQ;AAC5B;AAEO,IAAM,OAAe,eAC1B,OACA,EAAE,QAAQ,MAAM,MAAM,WAAW,OAAO,GACxC;AACA,QAAM,WAAW,OAAO;AACxB,QAAM,SAAS,SAAS;AACxB,MAAI,CAAC,QAAQ;AACX,WAAO,MAAM,iCAAiC;AAC9C;AAAA,EACF;AAEA,QAAM,kBAAkB,MAAM,YAAY,CAAC;AAG3C,QAAM,kBAAkB,gBAAgB,YAAY,SAAS;AAC7D,MAAI;AACJ,MAAI;AAEJ,MAAI,oBAAoB,QAAW;AACjC,UAAM,WAAW,UAAM,6BAAgB,OAAO,iBAAiB;AAAA,MAC7D;AAAA,IACF,CAAC;AACD,YAAI,sBAAS,QAAQ,GAAG;AACtB,YAAM,IAAI;AACV,cAAI,sBAAS,EAAE,UAAU,KAAK,EAAE,eAAe,IAAI;AACjD,qBAAa,EAAE;AAAA,MACjB;AACA,cAAI,sBAAS,EAAE,KAAK,KAAK,EAAE,UAAU,IAAI;AACvC,gBAAQ,EAAE;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,MAAI,cAAc,OAAO;AACvB,UAAM,aAAa,CAAC,OAAO;AACzB,aAAO,MAAM,YAAa,OAAQ,EAAE;AAAA,IACtC,CAAC;AAAA,EACH;AAGA,MAAI,cAAc,gBAAgB,WAAW,QAAW;AACtD,UAAM,WAAW,UAAM,6BAAgB,OAAO,gBAAgB,QAAQ;AAAA,MACpE;AAAA,IACF,CAAC;AACD,YAAI,sBAAS,QAAQ,GAAG;AACtB,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,aAAsC,CAAC;AAC3C,QAAM,eAAe,gBAAgB,SAAS,SAAS;AACvD,MAAI,iBAAiB,QAAW;AAC9B,UAAM,WAAW,UAAM,6BAAgB,OAAO,cAAc,EAAE,UAAU,CAAC;AACzE,YAAI,sBAAS,QAAQ,GAAG;AACtB,YAAM,EAAE,KAAK,MAAM,IAAI,IAAI,IAAI;AAI/B,cAAI,sBAAS,IAAI,KAAK,SAAS,UAAM,sBAAS,GAAG,KAAK,QAAQ,IAAI;AAChE,qBAAa,EAAE,CAAC,IAAI,GAAG,IAAI;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAGA,MAAI,gBAAgB,iBAAiB,QAAW;AAC9C,UAAM,WAAW,UAAM;AAAA,MACrB;AAAA,MACA,gBAAgB;AAAA,MAChB;AAAA,QACE;AAAA,MACF;AAAA,IACF;AACA,YAAI,sBAAS,QAAQ,GAAG;AACtB,YAAM,kBAAkB,QAAQ,QAAmC;AAAA,IACrE;AAAA,EACF;AAGA,MAAI,MAAM,WAAW,MAAM;AACzB,UAAM,gBAAY,sBAAS,MAAM,IAAI,IAAI,KAAK,OAAO,MAAM;AAC3D,UAAM,aAAsC,CAAC;AAG7C,QAAI,YAAY;AACd,iBAAW,cAAc;AAAA,IAC3B;AAGA,WAAO,OAAO,YAAY,UAAU;AAGpC,YAAI,sBAAS,IAAI,GAAG;AAClB,aAAO,OAAO,YAAY,IAA+B;AAAA,IAC3D;AAGA,UAAM,YAAY,SAAS,aAAa,gBAAgB;AAExD,QAAI,WAAW;AACb,YAAM,YAAY,MAAM,aAAa,KAAK,IAAI;AAC9C,YAAM,aAAa,CAAC,OAAO;AACzB,eAAO,OAAO,WAAW,WAAW,YAAY,EAAE;AAAA,MACpD,CAAC;AAAA,IACH,OAAO;AACL,YAAM,aAAa,CAAC,OAAO;AACzB,eAAO,MAAM,WAAW,YAAY,EAAE;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC3RA;;;AHOO,IAAM,sBAAmC;AAAA,EAC9C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,KAAK,OAAO,GAAG;AACjD,UAAM,SAAS,UAAU,eAAe,KAAK,MAAM;AACnD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AAAA,EAEA,QAAQ,EAAE,OAAO,GAAG;AAGlB,QAAI,QAAQ,UAAU;AACpB,aAAO,SAAS,SAAS;AAAA,IAC3B;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","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=>{err?reject(err):resolve()})})}var push=async function(event,{config:config,rule:rule,data:data,collector:collector,logger:logger}){const settings=config.settings,client=settings.client;if(!client)return void logger.throw("Mixpanel client not initialized");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)}),distinctId&&void 0!==mappingSettings.people){const resolved=await getMappingValue(event,mappingSettings.people,{collector:collector});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)}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){const{key:key,id:id}=resolved;if(!isString(key)||""===key||!isString(id)||""===id)return;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)}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;apiKey||logger.throw("Config settings apiKey missing");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
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
@@ -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":";AAQA,OAAO,cAAc;AAEd,SAAS,UACd,gBAA+B,CAAC,GAChC,KACA,QACQ;AACR,QAAM,WAAY,cAAc,YAAY,CAAC;AAC7C,QAAM,EAAE,OAAO,IAAI;AAEnB,MAAI,CAAC,OAAQ,QAAO,MAAM,gCAAgC;AAG1D,QAAM,cAAuC,CAAC;AAC9C,MAAI,SAAS,WAAW,OAAW,aAAY,SAAS,SAAS;AACjE,MAAI,SAAS,SAAS,OAAW,aAAY,OAAO,SAAS;AAC7D,MAAI,SAAS,aAAa,OAAW,aAAY,WAAW,SAAS;AACrE,MAAI,SAAS,cAAc;AACzB,gBAAY,YAAY,SAAS;AACnC,MAAI,SAAS,cAAc;AACzB,gBAAY,YAAY,SAAS;AACnC,MAAI,SAAS,UAAU,OAAW,aAAY,QAAQ,SAAS;AAC/D,MAAI,SAAS,YAAY,OAAW,aAAY,UAAU,SAAS;AACnE,MAAI,SAAS,SAAS,OAAW,aAAY,OAAO,SAAS;AAG7D,MAAI,SAAS,aAAa,CAAC,SAAS,QAAQ;AAC1C,WAAO,KAAK,sDAAsD;AAAA,EACpE;AAGA,QAAM,kBAAkB,KAAK,YAAY;AACzC,QAAM,SAAS,gBAAgB;AAAA,IAC7B;AAAA,IACA;AAAA,EACF;AAEA,QAAM,iBAA2B;AAAA,IAC/B,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,eAAe,UAAU,eAAe;AACtD;;;ACnDA,SAAS,iBAAiB,SAAS,UAAU,gBAAgB;AAU7D,IAAM,oBAAsC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIA,IAAM,mBAAoC;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKA,SAAS,aAAa,IAAmD;AACvE,SAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,OAAG,CAAC,QAAQ;AACV,UAAI,IAAK,QAAO,GAAG;AAAA,UACd,SAAQ;AAAA,IACf,CAAC;AAAA,EACH,CAAC;AACH;AAMA,eAAe,YACb,QACA,YACA,UACe;AACf,QAAM,WAA4B,CAAC;AAEnC,aAAW,MAAM,mBAAmB;AAClC,UAAM,MAAM,SAAS,EAAE;AACvB,QAAI,CAAC,SAAS,GAAG,KAAK,OAAO,KAAK,GAAG,EAAE,WAAW,EAAG;AACrD,aAAS;AAAA,MACP,aAAa,CAAC,OAAO;AACnB,QACE,OAAO,OAAO,EAAE,EAKhB,YAAY,KAAgC,EAAE;AAAA,MAClD,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,WAAW,SAAS;AAC1B,MAAI,aAAa,QAAW;AAC1B,QAAI,SAAS,QAAQ,GAAG;AACtB,eAAS;AAAA,QACP,aAAa,CAAC,OAAO;AACnB,iBAAO,OAAO,MAAM,YAAY,UAAU,EAAE;AAAA,QAC9C,CAAC;AAAA,MACH;AAAA,IACF,WAAW,QAAQ,QAAQ,GAAG;AAC5B,YAAM,QAAS,SAAuB;AAAA,QAAO,CAAC,MAC5C,SAAS,CAAC;AAAA,MACZ;AACA,UAAI,MAAM,SAAS,GAAG;AACpB,iBAAS;AAAA,UACP,aAAa,CAAC,OAAO;AACnB,mBAAO,OAAO,MAAM,YAAY,OAAO,EAAE;AAAA,UAC3C,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,gBAAgB,MAAM;AACjC,aAAS;AAAA,MACP,aAAa,CAAC,OAAO;AACnB,eAAO,OAAO,YAAY,YAAY,EAAE;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,QAAQ,IAAI,QAAQ;AAC5B;AAKA,eAAe,kBACb,QACA,UACe;AACf,QAAM,EAAE,KAAK,GAAG,IAAI;AACpB,MAAI,CAAC,SAAS,GAAG,KAAK,QAAQ,MAAM,CAAC,SAAS,EAAE,KAAK,OAAO,GAAI;AAEhE,QAAM,WAA4B,CAAC;AAEnC,aAAW,MAAM,kBAAkB;AACjC,UAAM,MAAM,SAAS,EAAE;AACvB,QAAI,CAAC,SAAS,GAAG,KAAK,OAAO,KAAK,GAAG,EAAE,WAAW,EAAG;AACrD,aAAS;AAAA,MACP,aAAa,CAAC,OAAO;AACnB,QACE,OAAO,OAAO,EAAE,EAMhB,KAAK,IAAI,KAAgC,EAAE;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,WAAW,SAAS;AAC1B,MAAI,aAAa,QAAW;AAC1B,QAAI,SAAS,QAAQ,GAAG;AACtB,eAAS;AAAA,QACP,aAAa,CAAC,OAAO;AACnB,iBAAO,OAAO,MAAM,KAAK,IAAI,UAAU,EAAE;AAAA,QAC3C,CAAC;AAAA,MACH;AAAA,IACF,WAAW,QAAQ,QAAQ,GAAG;AAC5B,YAAM,QAAS,SAAuB;AAAA,QAAO,CAAC,MAC5C,SAAS,CAAC;AAAA,MACZ;AACA,UAAI,MAAM,SAAS,GAAG;AACpB,iBAAS;AAAA,UACP,aAAa,CAAC,OAAO;AACnB,mBAAO,OAAO,MAAM,KAAK,IAAI,OAAO,EAAE;AAAA,UACxC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,WAAW,MAAM;AAC5B,aAAS;AAAA,MACP,aAAa,CAAC,OAAO;AACnB,eAAO,OAAO,aAAa,KAAK,IAAI,EAAE;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,QAAQ,IAAI,QAAQ;AAC5B;AAEO,IAAM,OAAe,eAC1B,OACA,EAAE,QAAQ,MAAM,MAAM,WAAW,OAAO,GACxC;AACA,QAAM,WAAW,OAAO;AACxB,QAAM,SAAS,SAAS;AACxB,MAAI,CAAC,QAAQ;AACX,WAAO,MAAM,iCAAiC;AAC9C;AAAA,EACF;AAEA,QAAM,kBAAkB,MAAM,YAAY,CAAC;AAG3C,QAAM,kBAAkB,gBAAgB,YAAY,SAAS;AAC7D,MAAI;AACJ,MAAI;AAEJ,MAAI,oBAAoB,QAAW;AACjC,UAAM,WAAW,MAAM,gBAAgB,OAAO,iBAAiB;AAAA,MAC7D;AAAA,IACF,CAAC;AACD,QAAI,SAAS,QAAQ,GAAG;AACtB,YAAM,IAAI;AACV,UAAI,SAAS,EAAE,UAAU,KAAK,EAAE,eAAe,IAAI;AACjD,qBAAa,EAAE;AAAA,MACjB;AACA,UAAI,SAAS,EAAE,KAAK,KAAK,EAAE,UAAU,IAAI;AACvC,gBAAQ,EAAE;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,MAAI,cAAc,OAAO;AACvB,UAAM,aAAa,CAAC,OAAO;AACzB,aAAO,MAAM,YAAa,OAAQ,EAAE;AAAA,IACtC,CAAC;AAAA,EACH;AAGA,MAAI,cAAc,gBAAgB,WAAW,QAAW;AACtD,UAAM,WAAW,MAAM,gBAAgB,OAAO,gBAAgB,QAAQ;AAAA,MACpE;AAAA,IACF,CAAC;AACD,QAAI,SAAS,QAAQ,GAAG;AACtB,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,aAAsC,CAAC;AAC3C,QAAM,eAAe,gBAAgB,SAAS,SAAS;AACvD,MAAI,iBAAiB,QAAW;AAC9B,UAAM,WAAW,MAAM,gBAAgB,OAAO,cAAc,EAAE,UAAU,CAAC;AACzE,QAAI,SAAS,QAAQ,GAAG;AACtB,YAAM,EAAE,KAAK,MAAM,IAAI,IAAI,IAAI;AAI/B,UAAI,SAAS,IAAI,KAAK,SAAS,MAAM,SAAS,GAAG,KAAK,QAAQ,IAAI;AAChE,qBAAa,EAAE,CAAC,IAAI,GAAG,IAAI;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAGA,MAAI,gBAAgB,iBAAiB,QAAW;AAC9C,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA,gBAAgB;AAAA,MAChB;AAAA,QACE;AAAA,MACF;AAAA,IACF;AACA,QAAI,SAAS,QAAQ,GAAG;AACtB,YAAM,kBAAkB,QAAQ,QAAmC;AAAA,IACrE;AAAA,EACF;AAGA,MAAI,MAAM,WAAW,MAAM;AACzB,UAAM,YAAY,SAAS,MAAM,IAAI,IAAI,KAAK,OAAO,MAAM;AAC3D,UAAM,aAAsC,CAAC;AAG7C,QAAI,YAAY;AACd,iBAAW,cAAc;AAAA,IAC3B;AAGA,WAAO,OAAO,YAAY,UAAU;AAGpC,QAAI,SAAS,IAAI,GAAG;AAClB,aAAO,OAAO,YAAY,IAA+B;AAAA,IAC3D;AAGA,UAAM,YAAY,SAAS,aAAa,gBAAgB;AAExD,QAAI,WAAW;AACb,YAAM,YAAY,MAAM,aAAa,KAAK,IAAI;AAC9C,YAAM,aAAa,CAAC,OAAO;AACzB,eAAO,OAAO,WAAW,WAAW,YAAY,EAAE;AAAA,MACpD,CAAC;AAAA,IACH,OAAO;AACL,YAAM,aAAa,CAAC,OAAO;AACzB,eAAO,MAAM,WAAW,YAAY,EAAE;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC3RA;;;ACOO,IAAM,sBAAmC;AAAA,EAC9C,MAAM;AAAA,EAEN,QAAQ,CAAC;AAAA,EAET,MAAM,KAAK,EAAE,QAAQ,eAAe,KAAK,OAAO,GAAG;AACjD,UAAM,SAAS,UAAU,eAAe,KAAK,MAAM;AACnD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,OAAO,SAAS;AACzB,WAAO,MAAM,KAAK,OAAO,OAAO;AAAA,EAClC;AAAA,EAEA,QAAQ,EAAE,OAAO,GAAG;AAGlB,QAAI,QAAQ,UAAU;AACpB,aAAO,SAAS,SAAS;AAAA,IAC3B;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","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"]}