@walkeros/server-destination-posthog 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.
@@ -86,17 +86,20 @@ __export(step_exports, {
86
86
  consentRevoke: () => consentRevoke,
87
87
  defaultCapture: () => defaultCapture,
88
88
  groupIdentifyWithProperties: () => groupIdentifyWithProperties,
89
- identifyWithSetAndSetOnce: () => identifyWithSetAndSetOnce
89
+ groupIdentifyWithoutData: () => groupIdentifyWithoutData,
90
+ identifyWithSetAndSetOnce: () => identifyWithSetAndSetOnce,
91
+ silentRule: () => silentRule
90
92
  });
91
93
  var import_core = require("@walkeros/core");
92
94
  var defaultCapture = {
93
95
  title: "Default capture",
94
96
  description: "A walker event becomes a PostHog capture call with the user id as distinctId and no extra properties.",
95
- in: (0, import_core.getEvent)("product view", { timestamp: 1700000100 }),
97
+ in: (0, import_core.getEvent)("product view", { id: "ev1700000100", timestamp: 1700000100 }),
96
98
  out: [
97
99
  [
98
100
  "client.capture",
99
101
  {
102
+ uuid: "b8a7f21f-1a9f-8aa7-8480-8d16fb64c44c",
100
103
  distinctId: "us3r",
101
104
  event: "product view",
102
105
  properties: {}
@@ -107,12 +110,13 @@ var defaultCapture = {
107
110
  var captureWithInclude = {
108
111
  title: "Capture with include",
109
112
  description: "Destination-level include flattens data and globals sections into prefixed PostHog event properties.",
110
- in: (0, import_core.getEvent)("order complete", { timestamp: 1700000101 }),
113
+ in: (0, import_core.getEvent)("order complete", { id: "ev1700000101", timestamp: 1700000101 }),
111
114
  configInclude: ["data", "globals"],
112
115
  out: [
113
116
  [
114
117
  "client.capture",
115
118
  {
119
+ uuid: "a5a5ede9-4f3b-85f4-b30f-3da8773fabfa",
116
120
  distinctId: "us3r",
117
121
  event: "order complete",
118
122
  properties: {
@@ -120,7 +124,7 @@ var captureWithInclude = {
120
124
  data_currency: "EUR",
121
125
  data_shipping: 5.22,
122
126
  data_taxes: 73.76,
123
- data_total: 555,
127
+ data_value: 555,
124
128
  globals_pagegroup: "shop"
125
129
  }
126
130
  }
@@ -130,7 +134,8 @@ var captureWithInclude = {
130
134
  var identifyWithSetAndSetOnce = {
131
135
  title: "Identify with $set",
132
136
  description: "A user login fires PostHog identify with $set and $set_once person properties and skips the capture.",
133
- in: (0, import_core.getEvent)("user login", {
137
+ in: (0, import_core.createEvent)({
138
+ name: "user login",
134
139
  timestamp: 1700000102,
135
140
  data: {
136
141
  user_id: "new-user-123",
@@ -180,7 +185,8 @@ var identifyWithSetAndSetOnce = {
180
185
  var groupIdentifyWithProperties = {
181
186
  title: "Group identify",
182
187
  description: "A company update fires PostHog groupIdentify with group type, key, and associated group properties.",
183
- in: (0, import_core.getEvent)("company update", {
188
+ in: (0, import_core.createEvent)({
189
+ name: "company update",
184
190
  timestamp: 1700000103,
185
191
  data: {
186
192
  company_id: "company_123",
@@ -223,6 +229,7 @@ var captureWithGroupContext = {
223
229
  title: "Capture with group",
224
230
  description: "A destination-level group mapping attaches the resolved group context to every PostHog capture call.",
225
231
  in: (0, import_core.getEvent)("page view", {
232
+ id: "ev1700000104",
226
233
  timestamp: 1700000104,
227
234
  globals: { pagegroup: "docs", company_id: "company_123" }
228
235
  }),
@@ -238,6 +245,7 @@ var captureWithGroupContext = {
238
245
  [
239
246
  "client.capture",
240
247
  {
248
+ uuid: "c6a47305-44fc-8835-b15f-3f494c1f9e20",
241
249
  distinctId: "us3r",
242
250
  event: "page view",
243
251
  properties: {},
@@ -246,12 +254,14 @@ var captureWithGroupContext = {
246
254
  ]
247
255
  ]
248
256
  };
257
+ var analyticsDenied = { analytics: false };
258
+ var analyticsGranted = { analytics: true };
249
259
  var consentRevoke = {
250
260
  title: "Consent revoked",
251
261
  description: "A walker consent command with analytics denied calls client.disable on the PostHog client.",
252
262
  command: "consent",
253
263
  before: { analytics: true },
254
- in: { analytics: false },
264
+ in: analyticsDenied,
255
265
  settings: {},
256
266
  out: [["client.enable"], ["client.disable"]]
257
267
  };
@@ -259,10 +269,29 @@ var consentGrant = {
259
269
  title: "Consent granted",
260
270
  description: "A walker consent command with analytics granted calls client.enable on the PostHog client.",
261
271
  command: "consent",
262
- in: { analytics: true },
272
+ in: analyticsGranted,
263
273
  settings: {},
264
274
  out: [["client.enable"]]
265
275
  };
276
+ var silentRule = {
277
+ public: false,
278
+ description: "A rule with silent: true and no identify or group mapping sends nothing to PostHog.",
279
+ in: (0, import_core.getEvent)("page view", { timestamp: 1700000105 }),
280
+ mapping: { silent: true },
281
+ out: []
282
+ };
283
+ var groupIdentifyWithoutData = {
284
+ public: false,
285
+ description: "A silent group rule whose key finds no data sends nothing: an unmet mapping, not a failure, so the push returns normally.",
286
+ in: {
287
+ name: "company update",
288
+ entity: "company",
289
+ action: "update",
290
+ timestamp: 1700000106
291
+ },
292
+ mapping: groupIdentifyWithProperties.mapping,
293
+ out: []
294
+ };
266
295
  // Annotate the CommonJS export names for ESM import in node:
267
296
  0 && (module.exports = {
268
297
  env,
@@ -65,17 +65,20 @@ __export(step_exports, {
65
65
  consentRevoke: () => consentRevoke,
66
66
  defaultCapture: () => defaultCapture,
67
67
  groupIdentifyWithProperties: () => groupIdentifyWithProperties,
68
- identifyWithSetAndSetOnce: () => identifyWithSetAndSetOnce
68
+ groupIdentifyWithoutData: () => groupIdentifyWithoutData,
69
+ identifyWithSetAndSetOnce: () => identifyWithSetAndSetOnce,
70
+ silentRule: () => silentRule
69
71
  });
70
- import { getEvent } from "@walkeros/core";
72
+ import { createEvent, getEvent } from "@walkeros/core";
71
73
  var defaultCapture = {
72
74
  title: "Default capture",
73
75
  description: "A walker event becomes a PostHog capture call with the user id as distinctId and no extra properties.",
74
- in: getEvent("product view", { timestamp: 1700000100 }),
76
+ in: getEvent("product view", { id: "ev1700000100", timestamp: 1700000100 }),
75
77
  out: [
76
78
  [
77
79
  "client.capture",
78
80
  {
81
+ uuid: "b8a7f21f-1a9f-8aa7-8480-8d16fb64c44c",
79
82
  distinctId: "us3r",
80
83
  event: "product view",
81
84
  properties: {}
@@ -86,12 +89,13 @@ var defaultCapture = {
86
89
  var captureWithInclude = {
87
90
  title: "Capture with include",
88
91
  description: "Destination-level include flattens data and globals sections into prefixed PostHog event properties.",
89
- in: getEvent("order complete", { timestamp: 1700000101 }),
92
+ in: getEvent("order complete", { id: "ev1700000101", timestamp: 1700000101 }),
90
93
  configInclude: ["data", "globals"],
91
94
  out: [
92
95
  [
93
96
  "client.capture",
94
97
  {
98
+ uuid: "a5a5ede9-4f3b-85f4-b30f-3da8773fabfa",
95
99
  distinctId: "us3r",
96
100
  event: "order complete",
97
101
  properties: {
@@ -99,7 +103,7 @@ var captureWithInclude = {
99
103
  data_currency: "EUR",
100
104
  data_shipping: 5.22,
101
105
  data_taxes: 73.76,
102
- data_total: 555,
106
+ data_value: 555,
103
107
  globals_pagegroup: "shop"
104
108
  }
105
109
  }
@@ -109,7 +113,8 @@ var captureWithInclude = {
109
113
  var identifyWithSetAndSetOnce = {
110
114
  title: "Identify with $set",
111
115
  description: "A user login fires PostHog identify with $set and $set_once person properties and skips the capture.",
112
- in: getEvent("user login", {
116
+ in: createEvent({
117
+ name: "user login",
113
118
  timestamp: 1700000102,
114
119
  data: {
115
120
  user_id: "new-user-123",
@@ -159,7 +164,8 @@ var identifyWithSetAndSetOnce = {
159
164
  var groupIdentifyWithProperties = {
160
165
  title: "Group identify",
161
166
  description: "A company update fires PostHog groupIdentify with group type, key, and associated group properties.",
162
- in: getEvent("company update", {
167
+ in: createEvent({
168
+ name: "company update",
163
169
  timestamp: 1700000103,
164
170
  data: {
165
171
  company_id: "company_123",
@@ -202,6 +208,7 @@ var captureWithGroupContext = {
202
208
  title: "Capture with group",
203
209
  description: "A destination-level group mapping attaches the resolved group context to every PostHog capture call.",
204
210
  in: getEvent("page view", {
211
+ id: "ev1700000104",
205
212
  timestamp: 1700000104,
206
213
  globals: { pagegroup: "docs", company_id: "company_123" }
207
214
  }),
@@ -217,6 +224,7 @@ var captureWithGroupContext = {
217
224
  [
218
225
  "client.capture",
219
226
  {
227
+ uuid: "c6a47305-44fc-8835-b15f-3f494c1f9e20",
220
228
  distinctId: "us3r",
221
229
  event: "page view",
222
230
  properties: {},
@@ -225,12 +233,14 @@ var captureWithGroupContext = {
225
233
  ]
226
234
  ]
227
235
  };
236
+ var analyticsDenied = { analytics: false };
237
+ var analyticsGranted = { analytics: true };
228
238
  var consentRevoke = {
229
239
  title: "Consent revoked",
230
240
  description: "A walker consent command with analytics denied calls client.disable on the PostHog client.",
231
241
  command: "consent",
232
242
  before: { analytics: true },
233
- in: { analytics: false },
243
+ in: analyticsDenied,
234
244
  settings: {},
235
245
  out: [["client.enable"], ["client.disable"]]
236
246
  };
@@ -238,10 +248,29 @@ var consentGrant = {
238
248
  title: "Consent granted",
239
249
  description: "A walker consent command with analytics granted calls client.enable on the PostHog client.",
240
250
  command: "consent",
241
- in: { analytics: true },
251
+ in: analyticsGranted,
242
252
  settings: {},
243
253
  out: [["client.enable"]]
244
254
  };
255
+ var silentRule = {
256
+ public: false,
257
+ description: "A rule with silent: true and no identify or group mapping sends nothing to PostHog.",
258
+ in: getEvent("page view", { timestamp: 1700000105 }),
259
+ mapping: { silent: true },
260
+ out: []
261
+ };
262
+ var groupIdentifyWithoutData = {
263
+ public: false,
264
+ description: "A silent group rule whose key finds no data sends nothing: an unmet mapping, not a failure, so the push returns normally.",
265
+ in: {
266
+ name: "company update",
267
+ entity: "company",
268
+ action: "update",
269
+ timestamp: 1700000106
270
+ },
271
+ mapping: groupIdentifyWithProperties.mapping,
272
+ out: []
273
+ };
245
274
  export {
246
275
  env_exports as env,
247
276
  step_exports as step
package/dist/index.d.mts CHANGED
@@ -11,8 +11,6 @@ interface Settings {
11
11
  identify?: Mapping$1.Value;
12
12
  /** Destination-level group mapping */
13
13
  group?: Mapping$1.Value;
14
- /** Event sections to flatten into capture properties */
15
- include?: string[];
16
14
  host?: string;
17
15
  flushAt?: number;
18
16
  flushInterval?: number;
@@ -25,6 +23,8 @@ interface Settings {
25
23
  fetchRetryDelay?: number;
26
24
  debug?: boolean;
27
25
  disabled?: boolean;
26
+ /** The running send; the next one waits for it. Runtime only. */
27
+ _sending?: Promise<void>;
28
28
  }
29
29
  type InitSettings = Partial<Settings>;
30
30
  interface Mapping {
@@ -40,6 +40,10 @@ interface PostHogClient {
40
40
  capture(props: Parameters<PostHog['capture']>[0]): void;
41
41
  identify(props: Parameters<PostHog['identify']>[0]): void;
42
42
  groupIdentify(props: Parameters<PostHog['groupIdentify']>[0]): void;
43
+ /** Sends the queued calls; rejects when the request failed. */
44
+ flush(): Promise<void>;
45
+ /** The SDK reports a failed send as an `error` event; returns its remover. */
46
+ on?(event: 'error', listener: (error: unknown) => void): () => void;
43
47
  shutdown(): Promise<void> | void;
44
48
  enable(): Promise<void> | void;
45
49
  disable(): Promise<void> | void;
@@ -56,6 +60,7 @@ type Config = {
56
60
  } & DestinationServer.Config<Types>;
57
61
  type InitFn = DestinationServer.InitFn<Types>;
58
62
  type PushFn = DestinationServer.PushFn<Types>;
63
+ type PushBatchFn = Destination$1.PushBatchFn<Types>;
59
64
  type PartialConfig = DestinationServer.PartialConfig<Types>;
60
65
  type PushEvents = DestinationServer.PushEvents<Mapping>;
61
66
  type Rule = Mapping$1.Rule<Mapping>;
@@ -69,6 +74,7 @@ type index_InitSettings = InitSettings;
69
74
  type index_Mapping = Mapping;
70
75
  type index_PartialConfig = PartialConfig;
71
76
  type index_PostHogClient = PostHogClient;
77
+ type index_PushBatchFn = PushBatchFn;
72
78
  type index_PushEvents = PushEvents;
73
79
  type index_PushFn = PushFn;
74
80
  type index_Rule = Rule;
@@ -76,7 +82,7 @@ type index_Rules = Rules;
76
82
  type index_Settings = Settings;
77
83
  type index_Types = Types;
78
84
  declare namespace index {
79
- export type { index_Config as Config, index_Destination as Destination, index_Env as Env, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PostHogClient as PostHogClient, index_PushEvents as PushEvents, index_PushFn as PushFn, index_Rule as Rule, index_Rules as Rules, index_Settings as Settings, index_Types as Types };
85
+ export type { index_Config as Config, index_Destination as Destination, index_Env as Env, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PostHogClient as PostHogClient, index_PushBatchFn as PushBatchFn, index_PushEvents as PushEvents, index_PushFn as PushFn, index_Rule as Rule, index_Rules as Rules, index_Settings as Settings, index_Types as Types };
80
86
  }
81
87
 
82
88
  declare const destinationPostHog: Destination;
package/dist/index.d.ts CHANGED
@@ -11,8 +11,6 @@ interface Settings {
11
11
  identify?: Mapping$1.Value;
12
12
  /** Destination-level group mapping */
13
13
  group?: Mapping$1.Value;
14
- /** Event sections to flatten into capture properties */
15
- include?: string[];
16
14
  host?: string;
17
15
  flushAt?: number;
18
16
  flushInterval?: number;
@@ -25,6 +23,8 @@ interface Settings {
25
23
  fetchRetryDelay?: number;
26
24
  debug?: boolean;
27
25
  disabled?: boolean;
26
+ /** The running send; the next one waits for it. Runtime only. */
27
+ _sending?: Promise<void>;
28
28
  }
29
29
  type InitSettings = Partial<Settings>;
30
30
  interface Mapping {
@@ -40,6 +40,10 @@ interface PostHogClient {
40
40
  capture(props: Parameters<PostHog['capture']>[0]): void;
41
41
  identify(props: Parameters<PostHog['identify']>[0]): void;
42
42
  groupIdentify(props: Parameters<PostHog['groupIdentify']>[0]): void;
43
+ /** Sends the queued calls; rejects when the request failed. */
44
+ flush(): Promise<void>;
45
+ /** The SDK reports a failed send as an `error` event; returns its remover. */
46
+ on?(event: 'error', listener: (error: unknown) => void): () => void;
43
47
  shutdown(): Promise<void> | void;
44
48
  enable(): Promise<void> | void;
45
49
  disable(): Promise<void> | void;
@@ -56,6 +60,7 @@ type Config = {
56
60
  } & DestinationServer.Config<Types>;
57
61
  type InitFn = DestinationServer.InitFn<Types>;
58
62
  type PushFn = DestinationServer.PushFn<Types>;
63
+ type PushBatchFn = Destination$1.PushBatchFn<Types>;
59
64
  type PartialConfig = DestinationServer.PartialConfig<Types>;
60
65
  type PushEvents = DestinationServer.PushEvents<Mapping>;
61
66
  type Rule = Mapping$1.Rule<Mapping>;
@@ -69,6 +74,7 @@ type index_InitSettings = InitSettings;
69
74
  type index_Mapping = Mapping;
70
75
  type index_PartialConfig = PartialConfig;
71
76
  type index_PostHogClient = PostHogClient;
77
+ type index_PushBatchFn = PushBatchFn;
72
78
  type index_PushEvents = PushEvents;
73
79
  type index_PushFn = PushFn;
74
80
  type index_Rule = Rule;
@@ -76,7 +82,7 @@ type index_Rules = Rules;
76
82
  type index_Settings = Settings;
77
83
  type index_Types = Types;
78
84
  declare namespace index {
79
- export type { index_Config as Config, index_Destination as Destination, index_Env as Env, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PostHogClient as PostHogClient, index_PushEvents as PushEvents, index_PushFn as PushFn, index_Rule as Rule, index_Rules as Rules, index_Settings as Settings, index_Types as Types };
85
+ export type { index_Config as Config, index_Destination as Destination, index_Env as Env, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PostHogClient as PostHogClient, index_PushBatchFn as PushBatchFn, index_PushEvents as PushEvents, index_PushFn as PushFn, index_Rule as Rule, index_Rules as Rules, index_Settings as Settings, index_Types as Types };
80
86
  }
81
87
 
82
88
  declare const destinationPostHog: Destination;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationPostHog:()=>types_exports,default:()=>index_default,destinationPostHog:()=>destinationPostHog}),module.exports=(mod=index_exports,((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})(__defProp({},"__esModule",{value:!0}),mod));var import_posthog_node=require("posthog-node");var import_core=require("@walkeros/core"),types_exports={},destinationPostHog={type:"posthog",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 options={};settings.host&&(options.host=settings.host),void 0!==settings.flushAt&&(options.flushAt=settings.flushAt),void 0!==settings.flushInterval&&(options.flushInterval=settings.flushInterval),settings.personalApiKey&&(options.personalApiKey=settings.personalApiKey),void 0!==settings.featureFlagsPollingInterval&&(options.featureFlagsPollingInterval=settings.featureFlagsPollingInterval),void 0!==settings.disableGeoip&&(options.disableGeoip=settings.disableGeoip),void 0!==settings.disableCompression&&(options.disableCompression=settings.disableCompression),void 0!==settings.requestTimeout&&(options.requestTimeout=settings.requestTimeout),void 0!==settings.fetchRetryCount&&(options.fetchRetryCount=settings.fetchRetryCount),void 0!==settings.fetchRetryDelay&&(options.fetchRetryDelay=settings.fetchRetryDelay),void 0!==settings.debug&&(options.debug=settings.debug),void 0!==settings.disabled&&(options.disabled=settings.disabled);const client=new(env?.PostHog||import_posthog_node.PostHog)(apiKey,options),settingsConfig={...settings,apiKey:apiKey,client:client};return{...partialConfig,settings:settingsConfig}}(partialConfig,env,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,collector:collector}){const settings=config.settings,client=settings.client;if(!client)return;const mappingSettings=rule?.settings||{},identifyMapping=mappingSettings.identify??settings.identify;let distinctId,identifyResolved;if(void 0!==identifyMapping){const resolved=await(0,import_core.getMappingValue)(event,identifyMapping,{collector:collector});(0,import_core.isObject)(resolved)&&(identifyResolved=resolved,(0,import_core.isString)(identifyResolved.distinctId)&&(distinctId=identifyResolved.distinctId))}if(distinctId||(distinctId=((0,import_core.isString)(event.user?.id)?event.user.id:void 0)||((0,import_core.isString)(event.user?.hash)?event.user.hash:void 0)||((0,import_core.isString)(event.user?.session)?event.user.session:void 0)||"anonymous"),identifyResolved){const $set=(0,import_core.isObject)(identifyResolved.$set)?identifyResolved.$set:void 0,$setOnce=(0,import_core.isObject)(identifyResolved.$set_once)?identifyResolved.$set_once:void 0;if($set||$setOnce){const properties={};$set&&(properties.$set=$set),$setOnce&&(properties.$set_once=$setOnce),client.identify({distinctId:distinctId,properties:properties})}}const groupMapping=mappingSettings.group??settings.group;let groups;if(void 0!==groupMapping){const resolved=await(0,import_core.getMappingValue)(event,groupMapping,{collector:collector});if((0,import_core.isObject)(resolved)){const groupResolved=resolved,type=groupResolved.type,key=groupResolved.key,properties=(0,import_core.isObject)(groupResolved.properties)?groupResolved.properties:void 0;(0,import_core.isString)(type)&&((0,import_core.isString)(key)||"number"==typeof key)&&(properties&&client.groupIdentify({groupType:type,groupKey:String(key),properties:properties}),groups={[type]:key})}}if(!0!==rule?.silent){const captureArgs={distinctId:distinctId,event:(0,import_core.isString)(rule?.name)?rule.name:event.name,properties:(0,import_core.isObject)(data)?data:{}};groups&&(captureArgs.groups=groups),client.capture(captureArgs)}}(event,context),async destroy({config:config}){const client=config?.settings?.client;client&&await client.shutdown()},on(type,context){if("consent"!==type||!context?.data)return;const client=(context.config?.settings||{}).client;if(!client)return;const consent=context.data,required=context.config?.consent;if(!required||0===Object.keys(required).length)return;Object.keys(required).every(key=>!0===consent[key])?client.enable():client.disable()}},index_default=destinationPostHog;//# sourceMappingURL=index.js.map
1
+ "use strict";var mod,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,index_exports={};((target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})})(index_exports,{DestinationPostHog:()=>types_exports,default:()=>index_default,destinationPostHog:()=>destinationPostHog}),module.exports=(mod=index_exports,((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})(__defProp({},"__esModule",{value:!0}),mod));var import_core=require("@walkeros/core"),import_server_core=require("@walkeros/server-core"),import_posthog_node=require("posthog-node");var import_crypto=require("crypto"),import_core2=require("@walkeros/core"),import_server_core2=require("@walkeros/server-core");async function call(client,message,send2){let failure;const off=client.on?.("error",error=>{failure=failure??error});try{await send2()}catch(error){failure=failure??error}finally{off?.()}if(void 0!==failure)throw new import_core2.StepError(message,{code:timedOut(failure)?"timeout":"transport",cause:failure})}function timedOut(error){if("object"!=typeof error||null===error)return!1;const name=Reflect.get(error,"name");return"AbortError"===name||"TimeoutError"===name||timedOut(Reflect.get(error,"error")??Reflect.get(error,"cause"))}function skipped(logger,event,call2,key){logger.debug(`PostHog skipped ${call2}: ${key} resolved to nothing`,{event:event.name})}async function queue(message,send2){try{await send2()}catch(error){throw new import_core2.StepError(message,{code:"transport",cause:error})}}function exclusive(settings,task){const running=(settings._sending??Promise.resolve()).then(task);return settings._sending=running.catch(()=>{}),running}function clientOf(settings){const client=settings?.client;if(!settings||!client)throw new import_core2.StepError("PostHog client not initialized",{code:"not-ready"});return{settings:settings,client:client}}async function send(event,rule,data,settings,client,collector,logger){const mappingSettings=rule?.settings||{},identifyMapping=mappingSettings.identify??settings.identify;let distinctId,identifyResolved;if(void 0!==identifyMapping){const resolved=await(0,import_core2.getMappingValue)(event,identifyMapping,{collector:collector});(0,import_core2.isObject)(resolved)?(identifyResolved=resolved,(0,import_core2.isString)(identifyResolved.distinctId)&&(distinctId=identifyResolved.distinctId)):skipped(logger,event,"identify","identify")}if(distinctId||(distinctId=((0,import_core2.isString)(event.user?.id)?event.user.id:void 0)||((0,import_core2.isString)(event.user?.hash)?event.user.hash:void 0)||((0,import_core2.isString)(event.user?.session)?event.user.session:void 0)||"anonymous"),identifyResolved){const $set=(0,import_core2.isObject)(identifyResolved.$set)?identifyResolved.$set:void 0,$setOnce=(0,import_core2.isObject)(identifyResolved.$set_once)?identifyResolved.$set_once:void 0;if($set||$setOnce){const properties={};$set&&(properties.$set=$set),$setOnce&&(properties.$set_once=$setOnce),await queue("PostHog identify failed",()=>client.identify({distinctId:distinctId,properties:properties}))}}const groupMapping=mappingSettings.group??settings.group;let groups;if(void 0!==groupMapping){const resolved=await(0,import_core2.getMappingValue)(event,groupMapping,{collector:collector});if((0,import_core2.isObject)(resolved)){const groupResolved=resolved,type=groupResolved.type,key=groupResolved.key,properties=(0,import_core2.isObject)(groupResolved.properties)?groupResolved.properties:void 0;(0,import_core2.isString)(type)&&((0,import_core2.isString)(key)||"number"==typeof key)?(properties&&await queue("PostHog group identify failed",()=>client.groupIdentify({groupType:type,groupKey:String(key),properties:properties})),groups={[type]:key}):skipped(logger,event,"group","group")}else skipped(logger,event,"group","group")}if(!0!==rule?.silent){const eventName=(0,import_core2.isString)(rule?.name)?rule.name:event.name,properties=(0,import_core2.isObject)(data)?data:{},captureArgs={distinctId:distinctId,event:eventName,properties:properties};groups&&(captureArgs.groups=groups),event.id&&(captureArgs.uuid=function(id){const hex=(0,import_crypto.createHash)("sha256").update(id).digest("hex"),variant=(3&parseInt(hex[16],16)|8).toString(16);return[hex.slice(0,8),hex.slice(8,12),`8${hex.slice(13,16)}`,`${variant}${hex.slice(17,20)}`,hex.slice(20,32)].join("-")}(event.id)),await queue("PostHog capture failed",()=>client.capture(captureArgs))}}var types_exports={},destinationPostHog={type:"posthog",config:{batch:{size:20,wait:1e4}},init:async({config:partialConfig,env:env})=>function(partialConfig={},env){const settings=partialConfig.settings||{},{apiKey:apiKey}=settings;if(!apiKey)throw new import_core.StepError("Config settings apiKey missing",{code:"config"});const budget=(0,import_server_core.retryBudget)(partialConfig.timeout),options={requestTimeout:budget.attempt,fetchRetryCount:budget.retries,fetchRetryDelay:budget.wait};settings.host&&(options.host=settings.host),void 0!==settings.flushAt&&(options.flushAt=settings.flushAt),void 0!==settings.flushInterval&&(options.flushInterval=settings.flushInterval),settings.personalApiKey&&(options.personalApiKey=settings.personalApiKey),void 0!==settings.featureFlagsPollingInterval&&(options.featureFlagsPollingInterval=settings.featureFlagsPollingInterval),void 0!==settings.disableGeoip&&(options.disableGeoip=settings.disableGeoip),void 0!==settings.disableCompression&&(options.disableCompression=settings.disableCompression),void 0!==settings.requestTimeout&&(options.requestTimeout=settings.requestTimeout),void 0!==settings.fetchRetryCount&&(options.fetchRetryCount=settings.fetchRetryCount),void 0!==settings.fetchRetryDelay&&(options.fetchRetryDelay=settings.fetchRetryDelay),void 0!==settings.debug&&(options.debug=settings.debug),void 0!==settings.disabled&&(options.disabled=settings.disabled);const client=new(env?.PostHog||import_posthog_node.PostHog)(apiKey,options),settingsConfig={...settings,apiKey:apiKey,client:client};return{...partialConfig,settings:settingsConfig}}(partialConfig,env),push:async function(event,{config:config,rule:rule,data:data,collector:collector,logger:logger}){const{settings:settings,client:client}=clientOf(config.settings);await exclusive(settings,async()=>{await send(event,rule,data,settings,client,collector,logger),await call(client,"PostHog send failed",()=>client.flush())})},pushBatch:async function(batch,{config:config,collector:collector,logger:logger}){const{settings:settings,client:client}=clientOf(config.settings),failed=[];let sendError;return await exclusive(settings,async()=>{const queued=[];for(const[index,entry]of batch.entries.entries())await send(entry.event,entry.rule,entry.data,settings,client,collector,logger).then(()=>queued.push(index),error=>failed.push({index:index,error:error}));queued.length&&await call(client,"PostHog send failed",()=>client.flush()).catch(error=>{sendError=error;for(const index of queued)failed.push({index:index,error:error})})}),(0,import_server_core2.batchOutcome)(batch.entries.length,failed,sendError)},async destroy({config:config}){const client=config?.settings?.client;client&&await client.shutdown()},on(type,context){if("consent"!==type||!context?.data)return;const client=(context.config?.settings||{}).client;if(!client)return;const consent=context.data,required=context.config?.consent;if(!required||0===Object.keys(required).length)return;Object.keys(required).every(key=>!0===consent[key])?client.enable():client.disable()}},index_default=destinationPostHog;//# 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 { WalkerOS } from '@walkeros/core';\nimport type { Destination, Env, Settings } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationPostHog from './types';\n\nexport const destinationPostHog: Destination = {\n type: 'posthog',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env as Env | undefined, logger);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const client = (config?.settings as Settings | undefined)?.client;\n if (client) {\n await client.shutdown();\n }\n },\n\n on(type, context) {\n if (type !== 'consent' || !context?.data) return;\n\n const settings = (context.config?.settings || {}) as Settings;\n const client = settings.client;\n if (!client) return;\n\n const consent = context.data as WalkerOS.Consent;\n const required = (context.config as { consent?: WalkerOS.Consent })\n ?.consent;\n if (!required || Object.keys(required).length === 0) return;\n\n const allGranted = Object.keys(required).every(\n (key) => consent[key] === true,\n );\n if (allGranted) {\n client.enable();\n } else {\n client.disable();\n }\n },\n};\n\nexport default destinationPostHog;\n","import type { Config, Env, PartialConfig, Settings } from './types';\nimport type { Logger } from '@walkeros/core';\nimport { PostHog } from 'posthog-node';\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 // Extract PostHog SDK options from settings\n const options: Record<string, unknown> = {};\n if (settings.host) options.host = settings.host;\n if (settings.flushAt !== undefined) options.flushAt = settings.flushAt;\n if (settings.flushInterval !== undefined)\n options.flushInterval = settings.flushInterval;\n if (settings.personalApiKey) options.personalApiKey = settings.personalApiKey;\n if (settings.featureFlagsPollingInterval !== undefined)\n options.featureFlagsPollingInterval = settings.featureFlagsPollingInterval;\n if (settings.disableGeoip !== undefined)\n options.disableGeoip = settings.disableGeoip;\n if (settings.disableCompression !== undefined)\n options.disableCompression = settings.disableCompression;\n if (settings.requestTimeout !== undefined)\n options.requestTimeout = settings.requestTimeout;\n if (settings.fetchRetryCount !== undefined)\n options.fetchRetryCount = settings.fetchRetryCount;\n if (settings.fetchRetryDelay !== undefined)\n options.fetchRetryDelay = settings.fetchRetryDelay;\n if (settings.debug !== undefined) options.debug = settings.debug;\n if (settings.disabled !== undefined) options.disabled = settings.disabled;\n\n // Use PostHog from env if available, otherwise use real PostHog\n const PostHogClass = env?.PostHog || PostHog;\n const client = new PostHogClass(apiKey, options);\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n client,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { PushFn } from './types';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector },\n) {\n const settings = config.settings!;\n const client = settings.client;\n if (!client) return;\n\n const mappingSettings = (rule?.settings || {}) as Record<string, unknown>;\n\n // Resolve distinctId: rule-level identify wins over destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n let distinctId: string | undefined;\n let identifyResolved: Record<string, unknown> | undefined;\n\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n identifyResolved = resolved as Record<string, unknown>;\n if (isString(identifyResolved.distinctId)) {\n distinctId = identifyResolved.distinctId as string;\n }\n }\n }\n\n // Fallback distinctId from event.user\n if (!distinctId) {\n distinctId =\n (isString(event.user?.id) ? event.user.id : undefined) ||\n (isString(event.user?.hash) ? event.user.hash : undefined) ||\n (isString(event.user?.session) ? event.user.session : undefined) ||\n 'anonymous';\n }\n\n // 1. Identity - if $set or $set_once present, call client.identify()\n if (identifyResolved) {\n const $set = isObject(identifyResolved.$set)\n ? (identifyResolved.$set as Record<string, unknown>)\n : undefined;\n const $setOnce = isObject(identifyResolved.$set_once)\n ? (identifyResolved.$set_once as Record<string, unknown>)\n : undefined;\n\n if ($set || $setOnce) {\n const properties: Record<string, unknown> = {};\n if ($set) properties.$set = $set;\n if ($setOnce) properties.$set_once = $setOnce;\n client.identify({ distinctId, properties });\n }\n }\n\n // 2. Group - resolve group mapping (rule-level wins)\n const groupMapping = mappingSettings.group ?? settings.group;\n let groups: Record<string, string | number> | undefined;\n\n if (groupMapping !== undefined) {\n const resolved = await getMappingValue(event, groupMapping, {\n collector,\n });\n if (isObject(resolved)) {\n const groupResolved = resolved as Record<string, unknown>;\n const type = groupResolved.type;\n const key = groupResolved.key;\n const properties = isObject(groupResolved.properties)\n ? (groupResolved.properties as Record<string, unknown>)\n : undefined;\n\n if (isString(type) && (isString(key) || typeof key === 'number')) {\n // If properties present, call groupIdentify\n if (properties) {\n client.groupIdentify({\n groupType: type,\n groupKey: String(key),\n properties,\n });\n }\n // Build groups object for capture\n groups = { [type]: key as string | number };\n }\n }\n }\n\n // 3. Capture - unless rule opts out via silent\n if (rule?.silent !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties = isObject(data) ? (data as Record<string, unknown>) : {};\n\n const captureArgs: Record<string, unknown> = {\n distinctId,\n event: eventName,\n properties,\n };\n if (groups) captureArgs.groups = groups;\n\n client.capture(captureArgs as Parameters<typeof client.capture>[0]);\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 { PostHog } from 'posthog-node';\n\nexport interface Settings {\n /** PostHog project API key (phc_...) */\n apiKey: string;\n /** PostHog client instance, populated by init */\n client?: PostHogClient;\n /** Destination-level identity mapping */\n identify?: WalkerOSMapping.Value;\n /** Destination-level group mapping */\n group?: WalkerOSMapping.Value;\n /** Event sections to flatten into capture properties */\n include?: string[];\n // PostHog SDK passthrough options\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n personalApiKey?: string;\n featureFlagsPollingInterval?: number;\n disableGeoip?: boolean;\n disableCompression?: boolean;\n requestTimeout?: number;\n fetchRetryCount?: number;\n fetchRetryDelay?: number;\n debug?: boolean;\n disabled?: boolean;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n}\n\n/**\n * The part of a PostHog client this destination calls. `PostHog` from\n * `posthog-node` satisfies it, and so does an injected mock (tests, simulate)\n * without a cast.\n */\nexport interface PostHogClient {\n capture(props: Parameters<PostHog['capture']>[0]): void;\n identify(props: Parameters<PostHog['identify']>[0]): void;\n groupIdentify(props: Parameters<PostHog['groupIdentify']>[0]): void;\n shutdown(): Promise<void> | void;\n enable(): Promise<void> | void;\n disable(): Promise<void> | void;\n}\n\nexport interface Env extends DestinationServer.Env {\n PostHog?: new (\n apiKey: string,\n options?: ConstructorParameters<typeof PostHog>[1],\n ) => PostHogClient;\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":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type { WalkerOS } from '@walkeros/core';\nimport type { Destination, Env, Settings } from './types';\nimport { getConfig } from './config';\nimport { push, pushBatch } from './push';\n\n// Types\nexport * as DestinationPostHog from './types';\n\nexport const destinationPostHog: Destination = {\n type: 'posthog',\n\n // Batched by default, at the SDK's own former defaults (20 events, 10 s).\n config: { batch: { size: 20, wait: 10_000 } },\n\n async init({ config: partialConfig, env }) {\n return getConfig(partialConfig, env);\n },\n\n push,\n\n pushBatch,\n\n async destroy({ config }) {\n const client = config?.settings?.client;\n if (client) {\n await client.shutdown();\n }\n },\n\n on(type, context) {\n if (type !== 'consent' || !context?.data) return;\n\n const settings = (context.config?.settings || {}) as Settings;\n const client = settings.client;\n if (!client) return;\n\n const consent = context.data as WalkerOS.Consent;\n const required = (context.config as { consent?: WalkerOS.Consent })\n ?.consent;\n if (!required || Object.keys(required).length === 0) return;\n\n const allGranted = Object.keys(required).every(\n (key) => consent[key] === true,\n );\n if (allGranted) {\n client.enable();\n } else {\n client.disable();\n }\n },\n};\n\nexport default destinationPostHog;\n","import type { Config, Env, PartialConfig, Settings } from './types';\nimport { StepError } from '@walkeros/core';\nimport { retryBudget } from '@walkeros/server-core';\nimport { PostHog } from 'posthog-node';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env: Env | undefined,\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 // The SDK's own retry ends within config.timeout: a quarter of it per\n // request, two retries a tenth of it apart. A value set in the settings\n // wins.\n const budget = retryBudget(partialConfig.timeout);\n const options: Record<string, unknown> = {\n requestTimeout: budget.attempt,\n fetchRetryCount: budget.retries,\n fetchRetryDelay: budget.wait,\n };\n\n // Extract PostHog SDK options from settings\n if (settings.host) options.host = settings.host;\n if (settings.flushAt !== undefined) options.flushAt = settings.flushAt;\n if (settings.flushInterval !== undefined)\n options.flushInterval = settings.flushInterval;\n if (settings.personalApiKey) options.personalApiKey = settings.personalApiKey;\n if (settings.featureFlagsPollingInterval !== undefined)\n options.featureFlagsPollingInterval = settings.featureFlagsPollingInterval;\n if (settings.disableGeoip !== undefined)\n options.disableGeoip = settings.disableGeoip;\n if (settings.disableCompression !== undefined)\n options.disableCompression = settings.disableCompression;\n if (settings.requestTimeout !== undefined)\n options.requestTimeout = settings.requestTimeout;\n if (settings.fetchRetryCount !== undefined)\n options.fetchRetryCount = settings.fetchRetryCount;\n if (settings.fetchRetryDelay !== undefined)\n options.fetchRetryDelay = settings.fetchRetryDelay;\n if (settings.debug !== undefined) options.debug = settings.debug;\n if (settings.disabled !== undefined) options.disabled = settings.disabled;\n\n // Use PostHog from env if available, otherwise use real PostHog\n const PostHogClass = env?.PostHog || PostHog;\n const client = new PostHogClass(apiKey, options);\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n client,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { Collector, Destination, Logger, WalkerOS } from '@walkeros/core';\nimport type {\n PostHogClient,\n PushBatchFn,\n PushFn,\n Rule,\n Settings,\n} from './types';\nimport { createHash } from 'crypto';\nimport { getMappingValue, isObject, isString, StepError } from '@walkeros/core';\nimport { batchOutcome } from '@walkeros/server-core';\n\n/**\n * Run one flush to its end. The SDK reports a failed send as an `error`\n * event and a rejected flush; the call listens for the event while it runs.\n * Sends never overlap (`exclusive`), so the event belongs to this flush.\n */\nasync function call(\n client: PostHogClient,\n message: string,\n send: () => unknown,\n): Promise<void> {\n let failure: unknown;\n const off = client.on?.('error', (error) => {\n failure = failure ?? error;\n });\n try {\n await send();\n } catch (error) {\n failure = failure ?? error;\n } finally {\n off?.();\n }\n if (failure !== undefined)\n throw new StepError(message, {\n code: timedOut(failure) ? 'timeout' : 'transport',\n cause: failure,\n });\n}\n\n/**\n * Whether the SDK's last request timed out: it aborts a request after\n * `requestTimeout` and reports a network error carrying the abort.\n */\nfunction timedOut(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false;\n const name: unknown = Reflect.get(error, 'name');\n if (name === 'AbortError' || name === 'TimeoutError') return true;\n return timedOut(Reflect.get(error, 'error') ?? Reflect.get(error, 'cause'));\n}\n\n/**\n * The uuid PostHog deduplicates a captured event by, derived from the event\n * id: the same event resent gets the same uuid. PostHog takes only a UUID,\n * so the id is hashed into one (RFC 9562 version 8, name based).\n */\nfunction uuidOf(id: string): string {\n const hex = createHash('sha256').update(id).digest('hex');\n const variant = ((parseInt(hex[16], 16) & 0x3) | 0x8).toString(16);\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n `8${hex.slice(13, 16)}`,\n `${variant}${hex.slice(17, 20)}`,\n hex.slice(20, 32),\n ].join('-');\n}\n\n/**\n * A configured mapping that resolved to nothing skips its call: a declared\n * skip, said once at DEBUG with the event and the mapping key, never the\n * value, so a wrong mapping path does not look like an event without data.\n */\nfunction skipped(\n logger: Logger.Instance,\n event: WalkerOS.Event,\n call: string,\n key: string,\n): void {\n logger.debug(`PostHog skipped ${call}: ${key} resolved to nothing`, {\n event: event.name,\n });\n}\n\n/** Run one queueing call; an injected client may answer with a promise. */\nasync function queue(message: string, send: () => unknown): Promise<void> {\n try {\n await send();\n } catch (error) {\n throw new StepError(message, { code: 'transport', cause: error });\n }\n}\n\n/**\n * One send at a time per client: its calls queued, then one flush. A flush\n * sends the whole queue, so a send that overlapped another could be carried,\n * and failed, by the other's request without hearing of it.\n */\nfunction exclusive(\n settings: Partial<Settings>,\n task: () => Promise<void>,\n): Promise<void> {\n const running = (settings._sending ?? Promise.resolve()).then(task);\n settings._sending = running.catch(() => undefined);\n return running;\n}\n\n/** The settings and client init resolved, or a StepError. */\nfunction clientOf(settings: Partial<Settings> | undefined): {\n settings: Partial<Settings>;\n client: PostHogClient;\n} {\n const client = settings?.client;\n if (!settings || !client)\n throw new StepError('PostHog client not initialized', {\n code: 'not-ready',\n });\n return { settings, client };\n}\n\n/** One event: its calls queued and sent by one flush. */\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, logger },\n) {\n const { settings, client } = clientOf(config.settings);\n await exclusive(settings, async () => {\n await send(event, rule, data, settings, client, collector, logger);\n await call(client, 'PostHog send failed', () => client.flush());\n });\n};\n\n/**\n * A flushed `config.batch` batch: every entry's calls queued, then one flush\n * sends them. An entry whose calls could not be queued fails alone; a failed\n * flush fails the batch, since PostHog answers a request as a whole.\n */\nexport const pushBatch: PushBatchFn = async function (\n batch,\n { config, collector, logger },\n) {\n const { settings, client } = clientOf(config.settings);\n const failed: Destination.BatchFailure[] = [];\n let sendError: unknown;\n\n await exclusive(settings, async () => {\n const queued: number[] = [];\n for (const [index, entry] of batch.entries.entries())\n await send(\n entry.event,\n entry.rule,\n entry.data,\n settings,\n client,\n collector,\n logger,\n ).then(\n () => queued.push(index),\n (error: unknown) => failed.push({ index, error }),\n );\n\n // One request carries every queued entry: a failed flush fails them all.\n if (queued.length)\n await call(client, 'PostHog send failed', () => client.flush()).catch(\n (error: unknown) => {\n sendError = error;\n for (const index of queued) failed.push({ index, error });\n },\n );\n });\n\n return batchOutcome(batch.entries.length, failed, sendError);\n};\n\n/** The calls of one event (identify, group identify, capture). */\nasync function send(\n event: WalkerOS.Event,\n rule: Rule | undefined,\n data: Destination.Data,\n settings: Partial<Settings>,\n client: PostHogClient,\n collector: Collector.Instance,\n logger: Logger.Instance,\n): Promise<void> {\n const mappingSettings = (rule?.settings || {}) as Record<string, unknown>;\n\n // Resolve distinctId: rule-level identify wins over destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n let distinctId: string | undefined;\n let identifyResolved: Record<string, unknown> | undefined;\n\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n identifyResolved = resolved as Record<string, unknown>;\n if (isString(identifyResolved.distinctId)) {\n distinctId = identifyResolved.distinctId as string;\n }\n } else skipped(logger, event, 'identify', 'identify');\n }\n\n // Fallback distinctId from event.user\n if (!distinctId) {\n distinctId =\n (isString(event.user?.id) ? event.user.id : undefined) ||\n (isString(event.user?.hash) ? event.user.hash : undefined) ||\n (isString(event.user?.session) ? event.user.session : undefined) ||\n 'anonymous';\n }\n\n // 1. Identity - if $set or $set_once present, call client.identify()\n if (identifyResolved) {\n const $set = isObject(identifyResolved.$set)\n ? (identifyResolved.$set as Record<string, unknown>)\n : undefined;\n const $setOnce = isObject(identifyResolved.$set_once)\n ? (identifyResolved.$set_once as Record<string, unknown>)\n : undefined;\n\n if ($set || $setOnce) {\n const properties: Record<string, unknown> = {};\n if ($set) properties.$set = $set;\n if ($setOnce) properties.$set_once = $setOnce;\n await queue('PostHog identify failed', () =>\n client.identify({ distinctId, properties }),\n );\n }\n }\n\n // 2. Group - resolve group mapping (rule-level wins)\n const groupMapping = mappingSettings.group ?? settings.group;\n let groups: Record<string, string | number> | undefined;\n\n if (groupMapping !== undefined) {\n const resolved = await getMappingValue(event, groupMapping, {\n collector,\n });\n if (isObject(resolved)) {\n const groupResolved = resolved as Record<string, unknown>;\n const type = groupResolved.type;\n const key = groupResolved.key;\n const properties = isObject(groupResolved.properties)\n ? (groupResolved.properties as Record<string, unknown>)\n : undefined;\n\n if (isString(type) && (isString(key) || typeof key === 'number')) {\n // If properties present, call groupIdentify\n // No immediate variant: queued, then flushed in this push.\n if (properties)\n await queue('PostHog group identify failed', () =>\n client.groupIdentify({\n groupType: type,\n groupKey: String(key),\n properties,\n }),\n );\n // Build groups object for capture\n groups = { [type]: key as string | number };\n } else skipped(logger, event, 'group', 'group');\n } else skipped(logger, event, 'group', 'group');\n }\n\n // 3. Capture - unless rule opts out via silent\n if (rule?.silent !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties = isObject(data) ? (data as Record<string, unknown>) : {};\n\n const captureArgs: Parameters<PostHogClient['capture']>[0] = {\n distinctId,\n event: eventName,\n properties,\n };\n if (groups) captureArgs.groups = groups;\n if (event.id) captureArgs.uuid = uuidOf(event.id);\n\n await queue('PostHog capture failed', () => client.capture(captureArgs));\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 { PostHog } from 'posthog-node';\n\nexport interface Settings {\n /** PostHog project API key (phc_...) */\n apiKey: string;\n /** PostHog client instance, populated by init */\n client?: PostHogClient;\n /** Destination-level identity mapping */\n identify?: WalkerOSMapping.Value;\n /** Destination-level group mapping */\n group?: WalkerOSMapping.Value;\n // PostHog SDK passthrough options\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n personalApiKey?: string;\n featureFlagsPollingInterval?: number;\n disableGeoip?: boolean;\n disableCompression?: boolean;\n requestTimeout?: number;\n fetchRetryCount?: number;\n fetchRetryDelay?: number;\n debug?: boolean;\n disabled?: boolean;\n /** The running send; the next one waits for it. Runtime only. */\n _sending?: Promise<void>;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n}\n\n/**\n * The part of a PostHog client this destination calls. `PostHog` from\n * `posthog-node` satisfies it, and so does an injected mock (tests, simulate)\n * without a cast.\n */\nexport interface PostHogClient {\n capture(props: Parameters<PostHog['capture']>[0]): void;\n identify(props: Parameters<PostHog['identify']>[0]): void;\n groupIdentify(props: Parameters<PostHog['groupIdentify']>[0]): void;\n /** Sends the queued calls; rejects when the request failed. */\n flush(): Promise<void>;\n /** The SDK reports a failed send as an `error` event; returns its remover. */\n on?(event: 'error', listener: (error: unknown) => void): () => void;\n shutdown(): Promise<void> | void;\n enable(): Promise<void> | void;\n disable(): Promise<void> | void;\n}\n\nexport interface Env extends DestinationServer.Env {\n PostHog?: new (\n apiKey: string,\n options?: ConstructorParameters<typeof PostHog>[1],\n ) => PostHogClient;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PushBatchFn = CoreDestination.PushBatchFn<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":["import_core","import_server_core","send","call"]}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{PostHog}from"posthog-node";import{getMappingValue,isObject,isString}from"@walkeros/core";var types_exports={},destinationPostHog={type:"posthog",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 options={};settings.host&&(options.host=settings.host),void 0!==settings.flushAt&&(options.flushAt=settings.flushAt),void 0!==settings.flushInterval&&(options.flushInterval=settings.flushInterval),settings.personalApiKey&&(options.personalApiKey=settings.personalApiKey),void 0!==settings.featureFlagsPollingInterval&&(options.featureFlagsPollingInterval=settings.featureFlagsPollingInterval),void 0!==settings.disableGeoip&&(options.disableGeoip=settings.disableGeoip),void 0!==settings.disableCompression&&(options.disableCompression=settings.disableCompression),void 0!==settings.requestTimeout&&(options.requestTimeout=settings.requestTimeout),void 0!==settings.fetchRetryCount&&(options.fetchRetryCount=settings.fetchRetryCount),void 0!==settings.fetchRetryDelay&&(options.fetchRetryDelay=settings.fetchRetryDelay),void 0!==settings.debug&&(options.debug=settings.debug),void 0!==settings.disabled&&(options.disabled=settings.disabled);const client=new(env?.PostHog||PostHog)(apiKey,options),settingsConfig={...settings,apiKey:apiKey,client:client};return{...partialConfig,settings:settingsConfig}}(partialConfig,env,logger);return config},push:async(event,context)=>await async function(event,{config:config,rule:rule,data:data,collector:collector}){const settings=config.settings,client=settings.client;if(!client)return;const mappingSettings=rule?.settings||{},identifyMapping=mappingSettings.identify??settings.identify;let distinctId,identifyResolved;if(void 0!==identifyMapping){const resolved=await getMappingValue(event,identifyMapping,{collector:collector});isObject(resolved)&&(identifyResolved=resolved,isString(identifyResolved.distinctId)&&(distinctId=identifyResolved.distinctId))}if(distinctId||(distinctId=(isString(event.user?.id)?event.user.id:void 0)||(isString(event.user?.hash)?event.user.hash:void 0)||(isString(event.user?.session)?event.user.session:void 0)||"anonymous"),identifyResolved){const $set=isObject(identifyResolved.$set)?identifyResolved.$set:void 0,$setOnce=isObject(identifyResolved.$set_once)?identifyResolved.$set_once:void 0;if($set||$setOnce){const properties={};$set&&(properties.$set=$set),$setOnce&&(properties.$set_once=$setOnce),client.identify({distinctId:distinctId,properties:properties})}}const groupMapping=mappingSettings.group??settings.group;let groups;if(void 0!==groupMapping){const resolved=await getMappingValue(event,groupMapping,{collector:collector});if(isObject(resolved)){const groupResolved=resolved,type=groupResolved.type,key=groupResolved.key,properties=isObject(groupResolved.properties)?groupResolved.properties:void 0;isString(type)&&(isString(key)||"number"==typeof key)&&(properties&&client.groupIdentify({groupType:type,groupKey:String(key),properties:properties}),groups={[type]:key})}}if(!0!==rule?.silent){const captureArgs={distinctId:distinctId,event:isString(rule?.name)?rule.name:event.name,properties:isObject(data)?data:{}};groups&&(captureArgs.groups=groups),client.capture(captureArgs)}}(event,context),async destroy({config:config}){const client=config?.settings?.client;client&&await client.shutdown()},on(type,context){if("consent"!==type||!context?.data)return;const client=(context.config?.settings||{}).client;if(!client)return;const consent=context.data,required=context.config?.consent;if(!required||0===Object.keys(required).length)return;Object.keys(required).every(key=>!0===consent[key])?client.enable():client.disable()}},index_default=destinationPostHog;export{types_exports as DestinationPostHog,index_default as default,destinationPostHog};//# sourceMappingURL=index.mjs.map
1
+ import{createRequire}from"module";createRequire(import.meta.url);import{StepError}from"@walkeros/core";import{retryBudget}from"@walkeros/server-core";import{PostHog}from"posthog-node";import{createHash}from"crypto";import{getMappingValue,isObject,isString,StepError as StepError2}from"@walkeros/core";import{batchOutcome}from"@walkeros/server-core";async function call(client,message,send2){let failure;const off=client.on?.("error",error=>{failure=failure??error});try{await send2()}catch(error){failure=failure??error}finally{off?.()}if(void 0!==failure)throw new StepError2(message,{code:timedOut(failure)?"timeout":"transport",cause:failure})}function timedOut(error){if("object"!=typeof error||null===error)return!1;const name=Reflect.get(error,"name");return"AbortError"===name||"TimeoutError"===name||timedOut(Reflect.get(error,"error")??Reflect.get(error,"cause"))}function skipped(logger,event,call2,key){logger.debug(`PostHog skipped ${call2}: ${key} resolved to nothing`,{event:event.name})}async function queue(message,send2){try{await send2()}catch(error){throw new StepError2(message,{code:"transport",cause:error})}}function exclusive(settings,task){const running=(settings._sending??Promise.resolve()).then(task);return settings._sending=running.catch(()=>{}),running}function clientOf(settings){const client=settings?.client;if(!settings||!client)throw new StepError2("PostHog client not initialized",{code:"not-ready"});return{settings:settings,client:client}}async function send(event,rule,data,settings,client,collector,logger){const mappingSettings=rule?.settings||{},identifyMapping=mappingSettings.identify??settings.identify;let distinctId,identifyResolved;if(void 0!==identifyMapping){const resolved=await getMappingValue(event,identifyMapping,{collector:collector});isObject(resolved)?(identifyResolved=resolved,isString(identifyResolved.distinctId)&&(distinctId=identifyResolved.distinctId)):skipped(logger,event,"identify","identify")}if(distinctId||(distinctId=(isString(event.user?.id)?event.user.id:void 0)||(isString(event.user?.hash)?event.user.hash:void 0)||(isString(event.user?.session)?event.user.session:void 0)||"anonymous"),identifyResolved){const $set=isObject(identifyResolved.$set)?identifyResolved.$set:void 0,$setOnce=isObject(identifyResolved.$set_once)?identifyResolved.$set_once:void 0;if($set||$setOnce){const properties={};$set&&(properties.$set=$set),$setOnce&&(properties.$set_once=$setOnce),await queue("PostHog identify failed",()=>client.identify({distinctId:distinctId,properties:properties}))}}const groupMapping=mappingSettings.group??settings.group;let groups;if(void 0!==groupMapping){const resolved=await getMappingValue(event,groupMapping,{collector:collector});if(isObject(resolved)){const groupResolved=resolved,type=groupResolved.type,key=groupResolved.key,properties=isObject(groupResolved.properties)?groupResolved.properties:void 0;isString(type)&&(isString(key)||"number"==typeof key)?(properties&&await queue("PostHog group identify failed",()=>client.groupIdentify({groupType:type,groupKey:String(key),properties:properties})),groups={[type]:key}):skipped(logger,event,"group","group")}else skipped(logger,event,"group","group")}if(!0!==rule?.silent){const eventName=isString(rule?.name)?rule.name:event.name,properties=isObject(data)?data:{},captureArgs={distinctId:distinctId,event:eventName,properties:properties};groups&&(captureArgs.groups=groups),event.id&&(captureArgs.uuid=function(id){const hex=createHash("sha256").update(id).digest("hex"),variant=(3&parseInt(hex[16],16)|8).toString(16);return[hex.slice(0,8),hex.slice(8,12),`8${hex.slice(13,16)}`,`${variant}${hex.slice(17,20)}`,hex.slice(20,32)].join("-")}(event.id)),await queue("PostHog capture failed",()=>client.capture(captureArgs))}}var types_exports={},destinationPostHog={type:"posthog",config:{batch:{size:20,wait:1e4}},init:async({config:partialConfig,env:env})=>function(partialConfig={},env){const settings=partialConfig.settings||{},{apiKey:apiKey}=settings;if(!apiKey)throw new StepError("Config settings apiKey missing",{code:"config"});const budget=retryBudget(partialConfig.timeout),options={requestTimeout:budget.attempt,fetchRetryCount:budget.retries,fetchRetryDelay:budget.wait};settings.host&&(options.host=settings.host),void 0!==settings.flushAt&&(options.flushAt=settings.flushAt),void 0!==settings.flushInterval&&(options.flushInterval=settings.flushInterval),settings.personalApiKey&&(options.personalApiKey=settings.personalApiKey),void 0!==settings.featureFlagsPollingInterval&&(options.featureFlagsPollingInterval=settings.featureFlagsPollingInterval),void 0!==settings.disableGeoip&&(options.disableGeoip=settings.disableGeoip),void 0!==settings.disableCompression&&(options.disableCompression=settings.disableCompression),void 0!==settings.requestTimeout&&(options.requestTimeout=settings.requestTimeout),void 0!==settings.fetchRetryCount&&(options.fetchRetryCount=settings.fetchRetryCount),void 0!==settings.fetchRetryDelay&&(options.fetchRetryDelay=settings.fetchRetryDelay),void 0!==settings.debug&&(options.debug=settings.debug),void 0!==settings.disabled&&(options.disabled=settings.disabled);const client=new(env?.PostHog||PostHog)(apiKey,options),settingsConfig={...settings,apiKey:apiKey,client:client};return{...partialConfig,settings:settingsConfig}}(partialConfig,env),push:async function(event,{config:config,rule:rule,data:data,collector:collector,logger:logger}){const{settings:settings,client:client}=clientOf(config.settings);await exclusive(settings,async()=>{await send(event,rule,data,settings,client,collector,logger),await call(client,"PostHog send failed",()=>client.flush())})},pushBatch:async function(batch,{config:config,collector:collector,logger:logger}){const{settings:settings,client:client}=clientOf(config.settings),failed=[];let sendError;return await exclusive(settings,async()=>{const queued=[];for(const[index,entry]of batch.entries.entries())await send(entry.event,entry.rule,entry.data,settings,client,collector,logger).then(()=>queued.push(index),error=>failed.push({index:index,error:error}));queued.length&&await call(client,"PostHog send failed",()=>client.flush()).catch(error=>{sendError=error;for(const index of queued)failed.push({index:index,error:error})})}),batchOutcome(batch.entries.length,failed,sendError)},async destroy({config:config}){const client=config?.settings?.client;client&&await client.shutdown()},on(type,context){if("consent"!==type||!context?.data)return;const client=(context.config?.settings||{}).client;if(!client)return;const consent=context.data,required=context.config?.consent;if(!required||0===Object.keys(required).length)return;Object.keys(required).every(key=>!0===consent[key])?client.enable():client.disable()}},index_default=destinationPostHog;export{types_exports as DestinationPostHog,index_default as default,destinationPostHog};//# 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 { Config, Env, PartialConfig, Settings } from './types';\nimport type { Logger } from '@walkeros/core';\nimport { PostHog } from 'posthog-node';\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 // Extract PostHog SDK options from settings\n const options: Record<string, unknown> = {};\n if (settings.host) options.host = settings.host;\n if (settings.flushAt !== undefined) options.flushAt = settings.flushAt;\n if (settings.flushInterval !== undefined)\n options.flushInterval = settings.flushInterval;\n if (settings.personalApiKey) options.personalApiKey = settings.personalApiKey;\n if (settings.featureFlagsPollingInterval !== undefined)\n options.featureFlagsPollingInterval = settings.featureFlagsPollingInterval;\n if (settings.disableGeoip !== undefined)\n options.disableGeoip = settings.disableGeoip;\n if (settings.disableCompression !== undefined)\n options.disableCompression = settings.disableCompression;\n if (settings.requestTimeout !== undefined)\n options.requestTimeout = settings.requestTimeout;\n if (settings.fetchRetryCount !== undefined)\n options.fetchRetryCount = settings.fetchRetryCount;\n if (settings.fetchRetryDelay !== undefined)\n options.fetchRetryDelay = settings.fetchRetryDelay;\n if (settings.debug !== undefined) options.debug = settings.debug;\n if (settings.disabled !== undefined) options.disabled = settings.disabled;\n\n // Use PostHog from env if available, otherwise use real PostHog\n const PostHogClass = env?.PostHog || PostHog;\n const client = new PostHogClass(apiKey, options);\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n client,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { PushFn } from './types';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector },\n) {\n const settings = config.settings!;\n const client = settings.client;\n if (!client) return;\n\n const mappingSettings = (rule?.settings || {}) as Record<string, unknown>;\n\n // Resolve distinctId: rule-level identify wins over destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n let distinctId: string | undefined;\n let identifyResolved: Record<string, unknown> | undefined;\n\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n identifyResolved = resolved as Record<string, unknown>;\n if (isString(identifyResolved.distinctId)) {\n distinctId = identifyResolved.distinctId as string;\n }\n }\n }\n\n // Fallback distinctId from event.user\n if (!distinctId) {\n distinctId =\n (isString(event.user?.id) ? event.user.id : undefined) ||\n (isString(event.user?.hash) ? event.user.hash : undefined) ||\n (isString(event.user?.session) ? event.user.session : undefined) ||\n 'anonymous';\n }\n\n // 1. Identity - if $set or $set_once present, call client.identify()\n if (identifyResolved) {\n const $set = isObject(identifyResolved.$set)\n ? (identifyResolved.$set as Record<string, unknown>)\n : undefined;\n const $setOnce = isObject(identifyResolved.$set_once)\n ? (identifyResolved.$set_once as Record<string, unknown>)\n : undefined;\n\n if ($set || $setOnce) {\n const properties: Record<string, unknown> = {};\n if ($set) properties.$set = $set;\n if ($setOnce) properties.$set_once = $setOnce;\n client.identify({ distinctId, properties });\n }\n }\n\n // 2. Group - resolve group mapping (rule-level wins)\n const groupMapping = mappingSettings.group ?? settings.group;\n let groups: Record<string, string | number> | undefined;\n\n if (groupMapping !== undefined) {\n const resolved = await getMappingValue(event, groupMapping, {\n collector,\n });\n if (isObject(resolved)) {\n const groupResolved = resolved as Record<string, unknown>;\n const type = groupResolved.type;\n const key = groupResolved.key;\n const properties = isObject(groupResolved.properties)\n ? (groupResolved.properties as Record<string, unknown>)\n : undefined;\n\n if (isString(type) && (isString(key) || typeof key === 'number')) {\n // If properties present, call groupIdentify\n if (properties) {\n client.groupIdentify({\n groupType: type,\n groupKey: String(key),\n properties,\n });\n }\n // Build groups object for capture\n groups = { [type]: key as string | number };\n }\n }\n }\n\n // 3. Capture - unless rule opts out via silent\n if (rule?.silent !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties = isObject(data) ? (data as Record<string, unknown>) : {};\n\n const captureArgs: Record<string, unknown> = {\n distinctId,\n event: eventName,\n properties,\n };\n if (groups) captureArgs.groups = groups;\n\n client.capture(captureArgs as Parameters<typeof client.capture>[0]);\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 { PostHog } from 'posthog-node';\n\nexport interface Settings {\n /** PostHog project API key (phc_...) */\n apiKey: string;\n /** PostHog client instance, populated by init */\n client?: PostHogClient;\n /** Destination-level identity mapping */\n identify?: WalkerOSMapping.Value;\n /** Destination-level group mapping */\n group?: WalkerOSMapping.Value;\n /** Event sections to flatten into capture properties */\n include?: string[];\n // PostHog SDK passthrough options\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n personalApiKey?: string;\n featureFlagsPollingInterval?: number;\n disableGeoip?: boolean;\n disableCompression?: boolean;\n requestTimeout?: number;\n fetchRetryCount?: number;\n fetchRetryDelay?: number;\n debug?: boolean;\n disabled?: boolean;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n}\n\n/**\n * The part of a PostHog client this destination calls. `PostHog` from\n * `posthog-node` satisfies it, and so does an injected mock (tests, simulate)\n * without a cast.\n */\nexport interface PostHogClient {\n capture(props: Parameters<PostHog['capture']>[0]): void;\n identify(props: Parameters<PostHog['identify']>[0]): void;\n groupIdentify(props: Parameters<PostHog['groupIdentify']>[0]): void;\n shutdown(): Promise<void> | void;\n enable(): Promise<void> | void;\n disable(): Promise<void> | void;\n}\n\nexport interface Env extends DestinationServer.Env {\n PostHog?: new (\n apiKey: string,\n options?: ConstructorParameters<typeof PostHog>[1],\n ) => PostHogClient;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","import type { WalkerOS } from '@walkeros/core';\nimport type { Destination, Env, Settings } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationPostHog from './types';\n\nexport const destinationPostHog: Destination = {\n type: 'posthog',\n\n config: {},\n\n async init({ config: partialConfig, env, logger }) {\n const config = getConfig(partialConfig, env as Env | undefined, logger);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const client = (config?.settings as Settings | undefined)?.client;\n if (client) {\n await client.shutdown();\n }\n },\n\n on(type, context) {\n if (type !== 'consent' || !context?.data) return;\n\n const settings = (context.config?.settings || {}) as Settings;\n const client = settings.client;\n if (!client) return;\n\n const consent = context.data as WalkerOS.Consent;\n const required = (context.config as { consent?: WalkerOS.Consent })\n ?.consent;\n if (!required || Object.keys(required).length === 0) return;\n\n const allGranted = Object.keys(required).every(\n (key) => consent[key] === true,\n );\n if (allGranted) {\n client.enable();\n } else {\n client.disable();\n }\n },\n};\n\nexport default destinationPostHog;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type { Config, Env, PartialConfig, Settings } from './types';\nimport { StepError } from '@walkeros/core';\nimport { retryBudget } from '@walkeros/server-core';\nimport { PostHog } from 'posthog-node';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n env: Env | undefined,\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 // The SDK's own retry ends within config.timeout: a quarter of it per\n // request, two retries a tenth of it apart. A value set in the settings\n // wins.\n const budget = retryBudget(partialConfig.timeout);\n const options: Record<string, unknown> = {\n requestTimeout: budget.attempt,\n fetchRetryCount: budget.retries,\n fetchRetryDelay: budget.wait,\n };\n\n // Extract PostHog SDK options from settings\n if (settings.host) options.host = settings.host;\n if (settings.flushAt !== undefined) options.flushAt = settings.flushAt;\n if (settings.flushInterval !== undefined)\n options.flushInterval = settings.flushInterval;\n if (settings.personalApiKey) options.personalApiKey = settings.personalApiKey;\n if (settings.featureFlagsPollingInterval !== undefined)\n options.featureFlagsPollingInterval = settings.featureFlagsPollingInterval;\n if (settings.disableGeoip !== undefined)\n options.disableGeoip = settings.disableGeoip;\n if (settings.disableCompression !== undefined)\n options.disableCompression = settings.disableCompression;\n if (settings.requestTimeout !== undefined)\n options.requestTimeout = settings.requestTimeout;\n if (settings.fetchRetryCount !== undefined)\n options.fetchRetryCount = settings.fetchRetryCount;\n if (settings.fetchRetryDelay !== undefined)\n options.fetchRetryDelay = settings.fetchRetryDelay;\n if (settings.debug !== undefined) options.debug = settings.debug;\n if (settings.disabled !== undefined) options.disabled = settings.disabled;\n\n // Use PostHog from env if available, otherwise use real PostHog\n const PostHogClass = env?.PostHog || PostHog;\n const client = new PostHogClass(apiKey, options);\n\n const settingsConfig: Settings = {\n ...settings,\n apiKey,\n client,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type { Collector, Destination, Logger, WalkerOS } from '@walkeros/core';\nimport type {\n PostHogClient,\n PushBatchFn,\n PushFn,\n Rule,\n Settings,\n} from './types';\nimport { createHash } from 'crypto';\nimport { getMappingValue, isObject, isString, StepError } from '@walkeros/core';\nimport { batchOutcome } from '@walkeros/server-core';\n\n/**\n * Run one flush to its end. The SDK reports a failed send as an `error`\n * event and a rejected flush; the call listens for the event while it runs.\n * Sends never overlap (`exclusive`), so the event belongs to this flush.\n */\nasync function call(\n client: PostHogClient,\n message: string,\n send: () => unknown,\n): Promise<void> {\n let failure: unknown;\n const off = client.on?.('error', (error) => {\n failure = failure ?? error;\n });\n try {\n await send();\n } catch (error) {\n failure = failure ?? error;\n } finally {\n off?.();\n }\n if (failure !== undefined)\n throw new StepError(message, {\n code: timedOut(failure) ? 'timeout' : 'transport',\n cause: failure,\n });\n}\n\n/**\n * Whether the SDK's last request timed out: it aborts a request after\n * `requestTimeout` and reports a network error carrying the abort.\n */\nfunction timedOut(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false;\n const name: unknown = Reflect.get(error, 'name');\n if (name === 'AbortError' || name === 'TimeoutError') return true;\n return timedOut(Reflect.get(error, 'error') ?? Reflect.get(error, 'cause'));\n}\n\n/**\n * The uuid PostHog deduplicates a captured event by, derived from the event\n * id: the same event resent gets the same uuid. PostHog takes only a UUID,\n * so the id is hashed into one (RFC 9562 version 8, name based).\n */\nfunction uuidOf(id: string): string {\n const hex = createHash('sha256').update(id).digest('hex');\n const variant = ((parseInt(hex[16], 16) & 0x3) | 0x8).toString(16);\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n `8${hex.slice(13, 16)}`,\n `${variant}${hex.slice(17, 20)}`,\n hex.slice(20, 32),\n ].join('-');\n}\n\n/**\n * A configured mapping that resolved to nothing skips its call: a declared\n * skip, said once at DEBUG with the event and the mapping key, never the\n * value, so a wrong mapping path does not look like an event without data.\n */\nfunction skipped(\n logger: Logger.Instance,\n event: WalkerOS.Event,\n call: string,\n key: string,\n): void {\n logger.debug(`PostHog skipped ${call}: ${key} resolved to nothing`, {\n event: event.name,\n });\n}\n\n/** Run one queueing call; an injected client may answer with a promise. */\nasync function queue(message: string, send: () => unknown): Promise<void> {\n try {\n await send();\n } catch (error) {\n throw new StepError(message, { code: 'transport', cause: error });\n }\n}\n\n/**\n * One send at a time per client: its calls queued, then one flush. A flush\n * sends the whole queue, so a send that overlapped another could be carried,\n * and failed, by the other's request without hearing of it.\n */\nfunction exclusive(\n settings: Partial<Settings>,\n task: () => Promise<void>,\n): Promise<void> {\n const running = (settings._sending ?? Promise.resolve()).then(task);\n settings._sending = running.catch(() => undefined);\n return running;\n}\n\n/** The settings and client init resolved, or a StepError. */\nfunction clientOf(settings: Partial<Settings> | undefined): {\n settings: Partial<Settings>;\n client: PostHogClient;\n} {\n const client = settings?.client;\n if (!settings || !client)\n throw new StepError('PostHog client not initialized', {\n code: 'not-ready',\n });\n return { settings, client };\n}\n\n/** One event: its calls queued and sent by one flush. */\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, logger },\n) {\n const { settings, client } = clientOf(config.settings);\n await exclusive(settings, async () => {\n await send(event, rule, data, settings, client, collector, logger);\n await call(client, 'PostHog send failed', () => client.flush());\n });\n};\n\n/**\n * A flushed `config.batch` batch: every entry's calls queued, then one flush\n * sends them. An entry whose calls could not be queued fails alone; a failed\n * flush fails the batch, since PostHog answers a request as a whole.\n */\nexport const pushBatch: PushBatchFn = async function (\n batch,\n { config, collector, logger },\n) {\n const { settings, client } = clientOf(config.settings);\n const failed: Destination.BatchFailure[] = [];\n let sendError: unknown;\n\n await exclusive(settings, async () => {\n const queued: number[] = [];\n for (const [index, entry] of batch.entries.entries())\n await send(\n entry.event,\n entry.rule,\n entry.data,\n settings,\n client,\n collector,\n logger,\n ).then(\n () => queued.push(index),\n (error: unknown) => failed.push({ index, error }),\n );\n\n // One request carries every queued entry: a failed flush fails them all.\n if (queued.length)\n await call(client, 'PostHog send failed', () => client.flush()).catch(\n (error: unknown) => {\n sendError = error;\n for (const index of queued) failed.push({ index, error });\n },\n );\n });\n\n return batchOutcome(batch.entries.length, failed, sendError);\n};\n\n/** The calls of one event (identify, group identify, capture). */\nasync function send(\n event: WalkerOS.Event,\n rule: Rule | undefined,\n data: Destination.Data,\n settings: Partial<Settings>,\n client: PostHogClient,\n collector: Collector.Instance,\n logger: Logger.Instance,\n): Promise<void> {\n const mappingSettings = (rule?.settings || {}) as Record<string, unknown>;\n\n // Resolve distinctId: rule-level identify wins over destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n let distinctId: string | undefined;\n let identifyResolved: Record<string, unknown> | undefined;\n\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n identifyResolved = resolved as Record<string, unknown>;\n if (isString(identifyResolved.distinctId)) {\n distinctId = identifyResolved.distinctId as string;\n }\n } else skipped(logger, event, 'identify', 'identify');\n }\n\n // Fallback distinctId from event.user\n if (!distinctId) {\n distinctId =\n (isString(event.user?.id) ? event.user.id : undefined) ||\n (isString(event.user?.hash) ? event.user.hash : undefined) ||\n (isString(event.user?.session) ? event.user.session : undefined) ||\n 'anonymous';\n }\n\n // 1. Identity - if $set or $set_once present, call client.identify()\n if (identifyResolved) {\n const $set = isObject(identifyResolved.$set)\n ? (identifyResolved.$set as Record<string, unknown>)\n : undefined;\n const $setOnce = isObject(identifyResolved.$set_once)\n ? (identifyResolved.$set_once as Record<string, unknown>)\n : undefined;\n\n if ($set || $setOnce) {\n const properties: Record<string, unknown> = {};\n if ($set) properties.$set = $set;\n if ($setOnce) properties.$set_once = $setOnce;\n await queue('PostHog identify failed', () =>\n client.identify({ distinctId, properties }),\n );\n }\n }\n\n // 2. Group - resolve group mapping (rule-level wins)\n const groupMapping = mappingSettings.group ?? settings.group;\n let groups: Record<string, string | number> | undefined;\n\n if (groupMapping !== undefined) {\n const resolved = await getMappingValue(event, groupMapping, {\n collector,\n });\n if (isObject(resolved)) {\n const groupResolved = resolved as Record<string, unknown>;\n const type = groupResolved.type;\n const key = groupResolved.key;\n const properties = isObject(groupResolved.properties)\n ? (groupResolved.properties as Record<string, unknown>)\n : undefined;\n\n if (isString(type) && (isString(key) || typeof key === 'number')) {\n // If properties present, call groupIdentify\n // No immediate variant: queued, then flushed in this push.\n if (properties)\n await queue('PostHog group identify failed', () =>\n client.groupIdentify({\n groupType: type,\n groupKey: String(key),\n properties,\n }),\n );\n // Build groups object for capture\n groups = { [type]: key as string | number };\n } else skipped(logger, event, 'group', 'group');\n } else skipped(logger, event, 'group', 'group');\n }\n\n // 3. Capture - unless rule opts out via silent\n if (rule?.silent !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties = isObject(data) ? (data as Record<string, unknown>) : {};\n\n const captureArgs: Parameters<PostHogClient['capture']>[0] = {\n distinctId,\n event: eventName,\n properties,\n };\n if (groups) captureArgs.groups = groups;\n if (event.id) captureArgs.uuid = uuidOf(event.id);\n\n await queue('PostHog capture failed', () => client.capture(captureArgs));\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 { PostHog } from 'posthog-node';\n\nexport interface Settings {\n /** PostHog project API key (phc_...) */\n apiKey: string;\n /** PostHog client instance, populated by init */\n client?: PostHogClient;\n /** Destination-level identity mapping */\n identify?: WalkerOSMapping.Value;\n /** Destination-level group mapping */\n group?: WalkerOSMapping.Value;\n // PostHog SDK passthrough options\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n personalApiKey?: string;\n featureFlagsPollingInterval?: number;\n disableGeoip?: boolean;\n disableCompression?: boolean;\n requestTimeout?: number;\n fetchRetryCount?: number;\n fetchRetryDelay?: number;\n debug?: boolean;\n disabled?: boolean;\n /** The running send; the next one waits for it. Runtime only. */\n _sending?: Promise<void>;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n identify?: WalkerOSMapping.Value;\n group?: WalkerOSMapping.Value;\n}\n\n/**\n * The part of a PostHog client this destination calls. `PostHog` from\n * `posthog-node` satisfies it, and so does an injected mock (tests, simulate)\n * without a cast.\n */\nexport interface PostHogClient {\n capture(props: Parameters<PostHog['capture']>[0]): void;\n identify(props: Parameters<PostHog['identify']>[0]): void;\n groupIdentify(props: Parameters<PostHog['groupIdentify']>[0]): void;\n /** Sends the queued calls; rejects when the request failed. */\n flush(): Promise<void>;\n /** The SDK reports a failed send as an `error` event; returns its remover. */\n on?(event: 'error', listener: (error: unknown) => void): () => void;\n shutdown(): Promise<void> | void;\n enable(): Promise<void> | void;\n disable(): Promise<void> | void;\n}\n\nexport interface Env extends DestinationServer.Env {\n PostHog?: new (\n apiKey: string,\n options?: ConstructorParameters<typeof PostHog>[1],\n ) => PostHogClient;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PushBatchFn = CoreDestination.PushBatchFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","import type { WalkerOS } from '@walkeros/core';\nimport type { Destination, Env, Settings } from './types';\nimport { getConfig } from './config';\nimport { push, pushBatch } from './push';\n\n// Types\nexport * as DestinationPostHog from './types';\n\nexport const destinationPostHog: Destination = {\n type: 'posthog',\n\n // Batched by default, at the SDK's own former defaults (20 events, 10 s).\n config: { batch: { size: 20, wait: 10_000 } },\n\n async init({ config: partialConfig, env }) {\n return getConfig(partialConfig, env);\n },\n\n push,\n\n pushBatch,\n\n async destroy({ config }) {\n const client = config?.settings?.client;\n if (client) {\n await client.shutdown();\n }\n },\n\n on(type, context) {\n if (type !== 'consent' || !context?.data) return;\n\n const settings = (context.config?.settings || {}) as Settings;\n const client = settings.client;\n if (!client) return;\n\n const consent = context.data as WalkerOS.Consent;\n const required = (context.config as { consent?: WalkerOS.Consent })\n ?.consent;\n if (!required || Object.keys(required).length === 0) return;\n\n const allGranted = Object.keys(required).every(\n (key) => consent[key] === true,\n );\n if (allGranted) {\n client.enable();\n } else {\n client.disable();\n }\n },\n};\n\nexport default destinationPostHog;\n"],"mappings":"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","names":["StepError","send","call"]}