autotel-posthog 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +191 -0
- package/README.md +158 -0
- package/dist/index.cjs +267 -0
- package/dist/index.d.cts +122 -0
- package/dist/index.d.ts +122 -0
- package/dist/index.js +263 -0
- package/dist/subscriber.cjs +543 -0
- package/dist/subscriber.d.cts +369 -0
- package/dist/subscriber.d.ts +369 -0
- package/dist/subscriber.js +519 -0
- package/package.json +90 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { EventPayload, EventSubscriber } from "autotel-subscribers";
|
|
2
|
+
import { EventAttributes } from "autotel/event-subscriber";
|
|
3
|
+
import { PostHog } from "posthog-node";
|
|
4
|
+
//#region src/values.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Reading values that arrive from outside: a page's PostHog instance, an
|
|
7
|
+
* event's properties, an error someone threw. Nothing about them is known
|
|
8
|
+
* until one of these asks, and each answers with the type it looked for or
|
|
9
|
+
* `undefined`.
|
|
10
|
+
*
|
|
11
|
+
* This is the boundary. The `typeof` checks and the `unknown` parameters below
|
|
12
|
+
* are what a boundary is made of; past it, the package works with types.
|
|
13
|
+
*
|
|
14
|
+
* Internal - not exported from the package entry points.
|
|
15
|
+
*/
|
|
16
|
+
/** An object whose fields have not been read yet. */
|
|
17
|
+
interface UnknownRecord {
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/subscriber/index.d.ts
|
|
22
|
+
/**
|
|
23
|
+
* Error context for enhanced error handling
|
|
24
|
+
*
|
|
25
|
+
* Provides detailed context about the event that caused an error.
|
|
26
|
+
*/
|
|
27
|
+
interface ErrorContext {
|
|
28
|
+
/** The error that occurred */
|
|
29
|
+
error: Error;
|
|
30
|
+
/** Event name (if applicable) */
|
|
31
|
+
eventName?: string;
|
|
32
|
+
/** Event type (event, funnel, outcome, value) */
|
|
33
|
+
eventType?: 'event' | 'funnel' | 'outcome' | 'value';
|
|
34
|
+
/** Event attributes (filtered) */
|
|
35
|
+
attributes?: EventAttributes;
|
|
36
|
+
/** Subscriber name */
|
|
37
|
+
subscriberName: string;
|
|
38
|
+
}
|
|
39
|
+
type StringRedactor = (value: string) => string;
|
|
40
|
+
interface PostHogConfig {
|
|
41
|
+
/** PostHog API key (starts with phc_) - required if not providing custom client */
|
|
42
|
+
apiKey?: string;
|
|
43
|
+
/** PostHog host (defaults to US cloud) */
|
|
44
|
+
host?: string;
|
|
45
|
+
/** Enable/disable the subscriber */
|
|
46
|
+
enabled?: boolean;
|
|
47
|
+
/** Custom PostHog client instance (bypasses apiKey/host) */
|
|
48
|
+
client?: PostHog;
|
|
49
|
+
/**
|
|
50
|
+
* Use global browser client (window.posthog)
|
|
51
|
+
*
|
|
52
|
+
* When true, uses the PostHog client already loaded on the page via script tag.
|
|
53
|
+
* This is useful for Next.js apps that initialize PostHog in _app.tsx.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* // Browser - uses window.posthog
|
|
58
|
+
* const subscriber = new PostHogSubscriber({
|
|
59
|
+
* useGlobalClient: true,
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
useGlobalClient?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Serverless mode preset (AWS Lambda, Vercel Functions, Next.js API routes)
|
|
66
|
+
*
|
|
67
|
+
* When true, auto-configures for serverless environments:
|
|
68
|
+
* - flushAt: 1 (send immediately, don't batch)
|
|
69
|
+
* - flushInterval: 0 (disable interval-based flushing)
|
|
70
|
+
* - requestTimeout: 3000 (shorter timeout for fast responses)
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* // Vercel / Next.js API route
|
|
75
|
+
* const subscriber = new PostHogSubscriber({
|
|
76
|
+
* apiKey: 'phc_...',
|
|
77
|
+
* serverless: true,
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
serverless?: boolean;
|
|
82
|
+
/** Flush batch when it reaches this size (default: 20, set to 1 for immediate send) */
|
|
83
|
+
flushAt?: number;
|
|
84
|
+
/** Flush interval in milliseconds (default: 10000, set to 0 to disable) */
|
|
85
|
+
flushInterval?: number;
|
|
86
|
+
/** Disable geoip lookup to reduce request size (default: false) */
|
|
87
|
+
disableGeoip?: boolean;
|
|
88
|
+
/** Request timeout in milliseconds (default: 10000) */
|
|
89
|
+
requestTimeout?: number;
|
|
90
|
+
/** Send feature flag evaluation events (default: true) */
|
|
91
|
+
sendFeatureFlags?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Automatically filter out undefined and null values from attributes
|
|
94
|
+
*
|
|
95
|
+
* When true (default), undefined and null values are removed before sending.
|
|
96
|
+
* This improves DX when passing objects with optional properties.
|
|
97
|
+
*
|
|
98
|
+
* @default true
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* // With filterUndefinedValues: true (default)
|
|
103
|
+
* subscriber.trackEvent('user.action', {
|
|
104
|
+
* userId: user.id,
|
|
105
|
+
* email: user.email, // might be undefined - will be filtered
|
|
106
|
+
* plan: user.subscription, // might be null - will be filtered
|
|
107
|
+
* });
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
filterUndefinedValues?: boolean;
|
|
111
|
+
/** Error callback for debugging and monitoring */
|
|
112
|
+
onError?: (error: Error) => void;
|
|
113
|
+
/**
|
|
114
|
+
* Enhanced error callback with event context
|
|
115
|
+
*
|
|
116
|
+
* Provides detailed context about the event that caused the error.
|
|
117
|
+
* If both onError and onErrorWithContext are provided, both are called.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* const subscriber = new PostHogSubscriber({
|
|
122
|
+
* apiKey: 'phc_...',
|
|
123
|
+
* onErrorWithContext: (ctx) => {
|
|
124
|
+
* console.error(`Failed to track ${ctx.eventType}: ${ctx.eventName}`, ctx.error);
|
|
125
|
+
* Sentry.captureException(ctx.error, { extra: ctx });
|
|
126
|
+
* }
|
|
127
|
+
* });
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
onErrorWithContext?: (context: ErrorContext) => void;
|
|
131
|
+
/** Known attribute paths to redact using slow-redact (path-based, immutable). */
|
|
132
|
+
redactPaths?: string[];
|
|
133
|
+
/** String redactor for value-based PII scanning. Applied after path-based redaction. */
|
|
134
|
+
stringRedactor?: StringRedactor;
|
|
135
|
+
/** Enable debug logging (default: false) */
|
|
136
|
+
debug?: boolean;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* PostHog feature flag options
|
|
140
|
+
*/
|
|
141
|
+
interface FeatureFlagOptions {
|
|
142
|
+
/** Group context for group-based feature flags */
|
|
143
|
+
groups?: Record<string, string | number>;
|
|
144
|
+
/** Group properties for feature flag evaluation */
|
|
145
|
+
groupProperties?: Record<string, Record<string, any>>;
|
|
146
|
+
/** Person properties for feature flag evaluation */
|
|
147
|
+
personProperties?: Record<string, any>;
|
|
148
|
+
/** Only evaluate locally, don't send $feature_flag_called event */
|
|
149
|
+
onlyEvaluateLocally?: boolean;
|
|
150
|
+
/** Send feature flag events even if disabled globally */
|
|
151
|
+
sendFeatureFlagEvents?: boolean;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Person properties for identify calls
|
|
155
|
+
*/
|
|
156
|
+
interface PersonProperties {
|
|
157
|
+
/** Set properties (will update existing values) */
|
|
158
|
+
$set?: Record<string, any>;
|
|
159
|
+
/** Set properties only if they don't exist */
|
|
160
|
+
$set_once?: Record<string, any>;
|
|
161
|
+
/** Any custom properties */
|
|
162
|
+
[key: string]: any;
|
|
163
|
+
}
|
|
164
|
+
declare class PostHogSubscriber extends EventSubscriber {
|
|
165
|
+
readonly name = "PostHogSubscriber";
|
|
166
|
+
readonly version = "2.0.0";
|
|
167
|
+
private posthog;
|
|
168
|
+
private config;
|
|
169
|
+
private initPromise;
|
|
170
|
+
/** True when using browser's window.posthog (different API signature) */
|
|
171
|
+
private isBrowserClient;
|
|
172
|
+
/**
|
|
173
|
+
* The same client seen through the browser SDK's shape.
|
|
174
|
+
*
|
|
175
|
+
* The two SDKs disagree about `capture`: Node takes one object, the browser
|
|
176
|
+
* takes a name and properties. Rather than cast at each call site, the cast
|
|
177
|
+
* happens once here and the calls are typed against `posthog-js` itself — so
|
|
178
|
+
* a change to the browser signature is a compile error rather than a runtime
|
|
179
|
+
* one in a page.
|
|
180
|
+
*/
|
|
181
|
+
private get browserClient();
|
|
182
|
+
private pathRedactor;
|
|
183
|
+
private stringRedactor;
|
|
184
|
+
constructor(config: PostHogConfig);
|
|
185
|
+
private initialize;
|
|
186
|
+
private setupErrorHandling;
|
|
187
|
+
private ensureInitialized;
|
|
188
|
+
/**
|
|
189
|
+
* Feature-flag options as posthog-node's own parameter type.
|
|
190
|
+
*
|
|
191
|
+
* SAFETY: FeatureFlagOptions above mirrors the fields posthog-node accepts -
|
|
192
|
+
* groups, person and group properties, and the two evaluation switches. The
|
|
193
|
+
* SDK declares them inline on each method rather than as a named type, so
|
|
194
|
+
* the correspondence is stated here once instead of at each call.
|
|
195
|
+
*/
|
|
196
|
+
private flagOptions;
|
|
197
|
+
private extractDistinctId;
|
|
198
|
+
private redactProperties;
|
|
199
|
+
private redactStringValues;
|
|
200
|
+
private redactArray;
|
|
201
|
+
/** One value, redacted: a string masked, a container walked. */
|
|
202
|
+
private redactValue;
|
|
203
|
+
/**
|
|
204
|
+
* Set the string redactor. Called by autotel init() when attributeRedactor is configured.
|
|
205
|
+
* Can also be called manually.
|
|
206
|
+
*/
|
|
207
|
+
setStringRedactor(redactor: StringRedactor): void;
|
|
208
|
+
/**
|
|
209
|
+
* Send payload to PostHog
|
|
210
|
+
*
|
|
211
|
+
* Maps autotel context to PostHog-specific field names:
|
|
212
|
+
* - autotel.trace_id → $trace_id
|
|
213
|
+
* - autotel.span_id → $span_id
|
|
214
|
+
* - autotel.correlation_id → $correlation_id
|
|
215
|
+
* - autotel.trace_url → $trace_url
|
|
216
|
+
*/
|
|
217
|
+
protected sendToDestination(payload: EventPayload): Promise<void>;
|
|
218
|
+
/**
|
|
219
|
+
* Check if a feature flag is enabled for a user
|
|
220
|
+
*
|
|
221
|
+
* @param flagKey - Feature flag key
|
|
222
|
+
* @param distinctId - User ID or anonymous ID
|
|
223
|
+
* @param options - Feature flag evaluation options
|
|
224
|
+
* @returns true if enabled, false otherwise
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* const isEnabled = await subscriber.isFeatureEnabled('new-checkout', 'user-123');
|
|
229
|
+
*
|
|
230
|
+
* // With groups
|
|
231
|
+
* const isEnabled = await subscriber.isFeatureEnabled('beta-features', 'user-123', {
|
|
232
|
+
* groups: { company: 'acme-corp' }
|
|
233
|
+
* });
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
isFeatureEnabled(flagKey: string, distinctId: string, options?: FeatureFlagOptions): Promise<boolean>;
|
|
237
|
+
/**
|
|
238
|
+
* Get feature flag value for a user
|
|
239
|
+
*
|
|
240
|
+
* @param flagKey - Feature flag key
|
|
241
|
+
* @param distinctId - User ID or anonymous ID
|
|
242
|
+
* @param options - Feature flag evaluation options
|
|
243
|
+
* @returns Flag value (string, boolean, or undefined)
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* const variant = await subscriber.getFeatureFlag('experiment-variant', 'user-123');
|
|
248
|
+
* // Returns: 'control' | 'test' | 'test-2' | undefined
|
|
249
|
+
*
|
|
250
|
+
* // With person properties
|
|
251
|
+
* const variant = await subscriber.getFeatureFlag('premium-feature', 'user-123', {
|
|
252
|
+
* personProperties: { plan: 'premium' }
|
|
253
|
+
* });
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
getFeatureFlag(flagKey: string, distinctId: string, options?: FeatureFlagOptions): Promise<string | boolean | undefined>;
|
|
257
|
+
/**
|
|
258
|
+
* Get all feature flags for a user
|
|
259
|
+
*
|
|
260
|
+
* @param distinctId - User ID or anonymous ID
|
|
261
|
+
* @param options - Feature flag evaluation options
|
|
262
|
+
* @returns Object mapping flag keys to their values
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```typescript
|
|
266
|
+
* const flags = await subscriber.getAllFlags('user-123');
|
|
267
|
+
* // Returns: { 'new-checkout': true, 'experiment-variant': 'test', ... }
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
getAllFlags(distinctId: string, options?: FeatureFlagOptions): Promise<Record<string, string | number | boolean>>;
|
|
271
|
+
/**
|
|
272
|
+
* Reload feature flags from PostHog server
|
|
273
|
+
*
|
|
274
|
+
* Call this to refresh feature flag definitions without restarting.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* await subscriber.reloadFeatureFlags();
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
reloadFeatureFlags(): Promise<void>;
|
|
282
|
+
/**
|
|
283
|
+
* Identify a user and set their properties
|
|
284
|
+
*
|
|
285
|
+
* @param distinctId - User ID
|
|
286
|
+
* @param properties - Person properties ($set, $set_once, or custom properties)
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```typescript
|
|
290
|
+
* // Set properties (will update existing values)
|
|
291
|
+
* await subscriber.identify('user-123', {
|
|
292
|
+
* $set: {
|
|
293
|
+
* email: 'user@example.com',
|
|
294
|
+
* plan: 'premium'
|
|
295
|
+
* }
|
|
296
|
+
* });
|
|
297
|
+
*
|
|
298
|
+
* // Set properties only once (won't update if already exists)
|
|
299
|
+
* await subscriber.identify('user-123', {
|
|
300
|
+
* $set_once: {
|
|
301
|
+
* signup_date: '2025-01-17'
|
|
302
|
+
* }
|
|
303
|
+
* });
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
identify(distinctId: string, properties?: PersonProperties): Promise<void>;
|
|
307
|
+
/**
|
|
308
|
+
* Identify a group and set its properties
|
|
309
|
+
*
|
|
310
|
+
* Groups are useful for B2B SaaS to track organizations, teams, or accounts.
|
|
311
|
+
*
|
|
312
|
+
* @param groupType - Type of group (e.g., 'company', 'organization', 'team')
|
|
313
|
+
* @param groupKey - Unique identifier for the group
|
|
314
|
+
* @param properties - Group properties
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* ```typescript
|
|
318
|
+
* await subscriber.groupIdentify('company', 'acme-corp', {
|
|
319
|
+
* $set: {
|
|
320
|
+
* name: 'Acme Corporation',
|
|
321
|
+
* industry: 'saas',
|
|
322
|
+
* employees: 500,
|
|
323
|
+
* plan: 'enterprise'
|
|
324
|
+
* }
|
|
325
|
+
* });
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
groupIdentify(groupType: string, groupKey: string | number, properties?: Record<string, any>): Promise<void>;
|
|
329
|
+
/**
|
|
330
|
+
* Track an event with group context
|
|
331
|
+
*
|
|
332
|
+
* Use this to associate events with groups (e.g., organizations).
|
|
333
|
+
*
|
|
334
|
+
* @param name - Event name
|
|
335
|
+
* @param attributes - Event attributes
|
|
336
|
+
* @param groups - Group context (e.g., { company: 'acme-corp' })
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```typescript
|
|
340
|
+
* await subscriber.trackEventWithGroups('feature.used', {
|
|
341
|
+
* userId: 'user-123',
|
|
342
|
+
* feature: 'advanced-events'
|
|
343
|
+
* }, {
|
|
344
|
+
* company: 'acme-corp'
|
|
345
|
+
* });
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
trackEventWithGroups(name: string, attributes?: EventAttributes, groups?: Record<string, string | number>): Promise<void>;
|
|
349
|
+
/**
|
|
350
|
+
* Capture an exception and send to PostHog error tracking.
|
|
351
|
+
*
|
|
352
|
+
* If using browser client (window.posthog), delegates to its captureException.
|
|
353
|
+
* Otherwise, formats and sends via posthog-node capture API.
|
|
354
|
+
*/
|
|
355
|
+
captureException(error: unknown, options?: {
|
|
356
|
+
distinctId?: string;
|
|
357
|
+
additionalProperties?: UnknownRecord;
|
|
358
|
+
}): Promise<void>;
|
|
359
|
+
/**
|
|
360
|
+
* Flush pending events and clean up resources
|
|
361
|
+
*/
|
|
362
|
+
shutdown(): Promise<void>;
|
|
363
|
+
/**
|
|
364
|
+
* Handle errors with custom error handler
|
|
365
|
+
*/
|
|
366
|
+
protected handleError(error: Error, payload: EventPayload): void;
|
|
367
|
+
}
|
|
368
|
+
//#endregion
|
|
369
|
+
export { ErrorContext, FeatureFlagOptions, PersonProperties, PostHogConfig, PostHogSubscriber };
|