autotel-subscribers 41.0.2 → 41.0.4
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/dist/amplitude.cjs +2 -2
- package/dist/amplitude.cjs.map +1 -1
- package/dist/amplitude.js +2 -2
- package/dist/architecture-snapshot.cjs +6 -6
- package/dist/architecture-snapshot.cjs.map +1 -1
- package/dist/architecture-snapshot.js +3 -3
- package/dist/architecture-snapshot.js.map +1 -1
- package/dist/{cjs-BS1fE_MP.js → cjs-Bef2t9Tr.js} +348 -109
- package/dist/cjs-Bef2t9Tr.js.map +1 -0
- package/dist/{cjs-CC1S3xV3.cjs → cjs-C2fugEI8.cjs} +169 -164
- package/dist/{cjs-CC1S3xV3.cjs.map → cjs-C2fugEI8.cjs.map} +1 -1
- package/dist/{cjs-BVWTUHeD.cjs → cjs-C5tev9Yr.cjs} +458 -219
- package/dist/cjs-C5tev9Yr.cjs.map +1 -0
- package/dist/{cjs-j3aHAiuq.js → cjs-CY69zXGd.js} +20 -15
- package/dist/{cjs-j3aHAiuq.js.map → cjs-CY69zXGd.js.map} +1 -1
- package/dist/factories.cjs +2 -2
- package/dist/factories.d.cts +1 -1
- package/dist/factories.d.ts +1 -1
- package/dist/factories.js +1 -1
- package/dist/file.cjs +2 -2
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{index.node-T6N3xCyo.js → index.node-BF2WkODf.js} +368 -148
- package/dist/index.node-BF2WkODf.js.map +1 -0
- package/dist/{index.node-CVFSZNnN.cjs → index.node-DOkEUdYV.cjs} +369 -149
- package/dist/index.node-DOkEUdYV.cjs.map +1 -0
- package/dist/middleware.cjs +1 -1
- package/dist/{mixpanel-node-CTaHqgil.cjs → mixpanel-node-BVS2X-h7.cjs} +32 -31
- package/dist/{mixpanel-node-CTaHqgil.cjs.map → mixpanel-node-BVS2X-h7.cjs.map} +1 -1
- package/dist/{mixpanel-node-2RXHuOWK.js → mixpanel-node-BltEtoG6.js} +5 -4
- package/dist/{mixpanel-node-2RXHuOWK.js.map → mixpanel-node-BltEtoG6.js.map} +1 -1
- package/dist/mixpanel.cjs +2 -2
- package/dist/mixpanel.cjs.map +1 -1
- package/dist/mixpanel.js +2 -2
- package/dist/{posthog-DTpCMk3r.js → posthog-C9M1c_oG.js} +2 -2
- package/dist/{posthog-DTpCMk3r.js.map → posthog-C9M1c_oG.js.map} +1 -1
- package/dist/{posthog-DLBf2UJJ.d.ts → posthog-DCV5Arkw.d.ts} +217 -24
- package/dist/posthog-DCV5Arkw.d.ts.map +1 -0
- package/dist/{posthog-Duh9pZs7.d.cts → posthog-DRYlG5fG.d.cts} +217 -24
- package/dist/posthog-DRYlG5fG.d.cts.map +1 -0
- package/dist/{posthog-Bz9XTdX5.cjs → posthog-DZfoAW1q.cjs} +4 -4
- package/dist/{posthog-Bz9XTdX5.cjs.map → posthog-DZfoAW1q.cjs.map} +1 -1
- package/dist/posthog.cjs +2 -2
- package/dist/posthog.d.cts +1 -1
- package/dist/posthog.d.ts +1 -1
- package/dist/posthog.js +1 -1
- package/dist/{chunk-CiiB0FCw.js → rolldown-runtime-BHkdefai.js} +9 -2
- package/dist/{chunk-BIkA7V7q.cjs → rolldown-runtime-CfAboj1T.cjs} +8 -1
- package/dist/security.cjs +1 -1
- package/dist/segment.cjs +2 -2
- package/dist/segment.cjs.map +1 -1
- package/dist/segment.js +2 -2
- package/dist/slack.cjs +1 -1
- package/dist/{tslib.es6-Ck6tgf4J.cjs → tslib.es6-02HJIdSd.cjs} +4 -4
- package/dist/{tslib.es6-Ck6tgf4J.cjs.map → tslib.es6-02HJIdSd.cjs.map} +1 -1
- package/dist/{tslib.es6-13Ha9x3r.js → tslib.es6-Dvm0j0am.js} +2 -2
- package/dist/{tslib.es6-13Ha9x3r.js.map → tslib.es6-Dvm0j0am.js.map} +1 -1
- package/dist/webhook.cjs +1 -1
- package/package.json +15 -15
- package/dist/cjs-BS1fE_MP.js.map +0 -1
- package/dist/cjs-BVWTUHeD.cjs.map +0 -1
- package/dist/index.node-CVFSZNnN.cjs.map +0 -1
- package/dist/index.node-T6N3xCyo.js.map +0 -1
- package/dist/posthog-DLBf2UJJ.d.ts.map +0 -1
- package/dist/posthog-Duh9pZs7.d.cts.map +0 -1
package/dist/mixpanel.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const
|
|
2
|
+
const require_rolldown_runtime = require('./rolldown-runtime-CfAboj1T.cjs');
|
|
3
3
|
|
|
4
4
|
//#region src/mixpanel.ts
|
|
5
5
|
var MixpanelSubscriber = class {
|
|
@@ -16,7 +16,7 @@ var MixpanelSubscriber = class {
|
|
|
16
16
|
}
|
|
17
17
|
async initialize() {
|
|
18
18
|
try {
|
|
19
|
-
const Mixpanel = await Promise.resolve().then(() => /* @__PURE__ */
|
|
19
|
+
const Mixpanel = await Promise.resolve().then(() => /* @__PURE__ */ require_rolldown_runtime.__toESM(require("./mixpanel-node-BVS2X-h7.cjs").default, 1));
|
|
20
20
|
this.mixpanel = Mixpanel.default.init(this.config.token);
|
|
21
21
|
} catch (error) {
|
|
22
22
|
console.error("Mixpanel subscriber failed to initialize. Install mixpanel: pnpm add mixpanel", error);
|
package/dist/mixpanel.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mixpanel.cjs","names":[],"sources":["../src/mixpanel.ts"],"sourcesContent":["/**\n * Mixpanel Subscriber for autotel\n *\n * Send events to Mixpanel for product events.\n *\n * @example\n * ```typescript\n * import { Events } from 'autotel/events';\n * import { MixpanelSubscriber } from 'autotel-subscribers/mixpanel';\n *\n * const events = new Events('checkout', {\n * subscribers: [\n * new MixpanelSubscriber({\n * token: process.env.MIXPANEL_TOKEN!\n * })\n * ]\n * });\n *\n * events.trackEvent('order.completed', { userId: '123', amount: 99.99 });\n * ```\n */\n\nimport type {\n EventSubscriber,\n EventAttributes,\n FunnelStatus,\n OutcomeStatus,\n EventTrackingOptions,\n AutotelEventContext,\n} from 'autotel/event-subscriber';\n\nexport interface MixpanelConfig {\n /** Mixpanel project token */\n token: string;\n /** Enable/disable the subscriber */\n enabled?: boolean;\n}\n\nexport class MixpanelSubscriber implements EventSubscriber {\n readonly name = 'MixpanelSubscriber';\n readonly version = '1.0.0';\n\n private mixpanel: any;\n private enabled: boolean;\n private config: MixpanelConfig;\n private initPromise: Promise<void> | null = null;\n\n constructor(config: MixpanelConfig) {\n this.enabled = config.enabled ?? true;\n this.config = config;\n\n if (this.enabled) {\n // Start initialization immediately but don't block constructor\n this.initPromise = this.initialize();\n }\n }\n\n private async initialize(): Promise<void> {\n try {\n // Dynamic import to avoid adding mixpanel as a hard dependency\n const Mixpanel = await import('mixpanel');\n this.mixpanel = Mixpanel.default.init(this.config.token);\n } catch (error) {\n console.error(\n 'Mixpanel subscriber failed to initialize. Install mixpanel: pnpm add mixpanel',\n error,\n );\n this.enabled = false;\n }\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise) {\n await this.initPromise;\n this.initPromise = null;\n }\n }\n\n /**\n * Map autotel context to Mixpanel properties\n *\n * Mixpanel uses standard snake_case field names:\n * - autotel.trace_id → trace_id\n * - autotel.span_id → span_id\n * - autotel.correlation_id → correlation_id\n */\n private mapAutotelContext(\n autotel?: AutotelEventContext,\n ): Record<string, unknown> {\n if (!autotel) return {};\n\n const mapped: Record<string, unknown> = {};\n\n if (autotel.trace_id) {\n mapped.trace_id = autotel.trace_id;\n }\n if (autotel.span_id) {\n mapped.span_id = autotel.span_id;\n }\n if (autotel.correlation_id) {\n mapped.correlation_id = autotel.correlation_id;\n }\n if (autotel.trace_flags) {\n mapped.trace_flags = autotel.trace_flags;\n }\n if (autotel.trace_state) {\n mapped.trace_state = autotel.trace_state;\n }\n if (autotel.trace_url) {\n mapped.trace_url = autotel.trace_url;\n }\n // Batch/fan-in context\n if (autotel.linked_trace_id_count !== undefined) {\n mapped.linked_trace_id_count = autotel.linked_trace_id_count;\n }\n if (autotel.linked_trace_id_hash) {\n mapped.linked_trace_id_hash = autotel.linked_trace_id_hash;\n }\n if (autotel.linked_trace_ids) {\n mapped.linked_trace_ids = autotel.linked_trace_ids;\n }\n\n return mapped;\n }\n\n async trackEvent(\n name: string,\n attributes?: EventAttributes,\n options?: EventTrackingOptions,\n ): Promise<void> {\n if (!this.enabled) return;\n\n await this.ensureInitialized();\n const distinctId = attributes?.userId || attributes?.user_id || 'anonymous';\n const autotelProps = this.mapAutotelContext(options?.autotel);\n\n this.mixpanel?.track(name, {\n distinct_id: distinctId,\n ...attributes,\n ...autotelProps,\n });\n }\n\n async trackFunnelStep(\n funnelName: string,\n step: FunnelStatus,\n attributes?: EventAttributes,\n options?: EventTrackingOptions,\n ): Promise<void> {\n if (!this.enabled) return;\n\n await this.ensureInitialized();\n const distinctId = attributes?.userId || attributes?.user_id || 'anonymous';\n const autotelProps = this.mapAutotelContext(options?.autotel);\n\n this.mixpanel?.track(`${funnelName}.${step}`, {\n distinct_id: distinctId,\n funnel: funnelName,\n step,\n ...attributes,\n ...autotelProps,\n });\n }\n\n async trackOutcome(\n operationName: string,\n outcome: OutcomeStatus,\n attributes?: EventAttributes,\n options?: EventTrackingOptions,\n ): Promise<void> {\n if (!this.enabled) return;\n\n await this.ensureInitialized();\n const distinctId = attributes?.userId || attributes?.user_id || 'anonymous';\n const autotelProps = this.mapAutotelContext(options?.autotel);\n\n this.mixpanel?.track(`${operationName}.${outcome}`, {\n distinct_id: distinctId,\n operation: operationName,\n outcome,\n ...attributes,\n ...autotelProps,\n });\n }\n\n async trackValue(\n name: string,\n value: number,\n attributes?: EventAttributes,\n options?: EventTrackingOptions,\n ): Promise<void> {\n if (!this.enabled) return;\n\n await this.ensureInitialized();\n const distinctId = attributes?.userId || attributes?.user_id || 'anonymous';\n const autotelProps = this.mapAutotelContext(options?.autotel);\n\n this.mixpanel?.track(name, {\n distinct_id: distinctId,\n value,\n ...attributes,\n ...autotelProps,\n });\n }\n}\n"],"mappings":";;;;AAsCA,IAAa,qBAAb,MAA2D;CACzD,AAAS,OAAO;CAChB,AAAS,UAAU;CAEnB,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ,cAAoC;CAE5C,YAAY,QAAwB;EAClC,KAAK,UAAU,OAAO,WAAW;EACjC,KAAK,SAAS;EAEd,IAAI,KAAK,SAEP,KAAK,cAAc,KAAK,WAAW;CAEvC;CAEA,MAAc,aAA4B;EACxC,IAAI;GAEF,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"mixpanel.cjs","names":[],"sources":["../src/mixpanel.ts"],"sourcesContent":["/**\n * Mixpanel Subscriber for autotel\n *\n * Send events to Mixpanel for product events.\n *\n * @example\n * ```typescript\n * import { Events } from 'autotel/events';\n * import { MixpanelSubscriber } from 'autotel-subscribers/mixpanel';\n *\n * const events = new Events('checkout', {\n * subscribers: [\n * new MixpanelSubscriber({\n * token: process.env.MIXPANEL_TOKEN!\n * })\n * ]\n * });\n *\n * events.trackEvent('order.completed', { userId: '123', amount: 99.99 });\n * ```\n */\n\nimport type {\n EventSubscriber,\n EventAttributes,\n FunnelStatus,\n OutcomeStatus,\n EventTrackingOptions,\n AutotelEventContext,\n} from 'autotel/event-subscriber';\n\nexport interface MixpanelConfig {\n /** Mixpanel project token */\n token: string;\n /** Enable/disable the subscriber */\n enabled?: boolean;\n}\n\nexport class MixpanelSubscriber implements EventSubscriber {\n readonly name = 'MixpanelSubscriber';\n readonly version = '1.0.0';\n\n private mixpanel: any;\n private enabled: boolean;\n private config: MixpanelConfig;\n private initPromise: Promise<void> | null = null;\n\n constructor(config: MixpanelConfig) {\n this.enabled = config.enabled ?? true;\n this.config = config;\n\n if (this.enabled) {\n // Start initialization immediately but don't block constructor\n this.initPromise = this.initialize();\n }\n }\n\n private async initialize(): Promise<void> {\n try {\n // Dynamic import to avoid adding mixpanel as a hard dependency\n const Mixpanel = await import('mixpanel');\n this.mixpanel = Mixpanel.default.init(this.config.token);\n } catch (error) {\n console.error(\n 'Mixpanel subscriber failed to initialize. Install mixpanel: pnpm add mixpanel',\n error,\n );\n this.enabled = false;\n }\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise) {\n await this.initPromise;\n this.initPromise = null;\n }\n }\n\n /**\n * Map autotel context to Mixpanel properties\n *\n * Mixpanel uses standard snake_case field names:\n * - autotel.trace_id → trace_id\n * - autotel.span_id → span_id\n * - autotel.correlation_id → correlation_id\n */\n private mapAutotelContext(\n autotel?: AutotelEventContext,\n ): Record<string, unknown> {\n if (!autotel) return {};\n\n const mapped: Record<string, unknown> = {};\n\n if (autotel.trace_id) {\n mapped.trace_id = autotel.trace_id;\n }\n if (autotel.span_id) {\n mapped.span_id = autotel.span_id;\n }\n if (autotel.correlation_id) {\n mapped.correlation_id = autotel.correlation_id;\n }\n if (autotel.trace_flags) {\n mapped.trace_flags = autotel.trace_flags;\n }\n if (autotel.trace_state) {\n mapped.trace_state = autotel.trace_state;\n }\n if (autotel.trace_url) {\n mapped.trace_url = autotel.trace_url;\n }\n // Batch/fan-in context\n if (autotel.linked_trace_id_count !== undefined) {\n mapped.linked_trace_id_count = autotel.linked_trace_id_count;\n }\n if (autotel.linked_trace_id_hash) {\n mapped.linked_trace_id_hash = autotel.linked_trace_id_hash;\n }\n if (autotel.linked_trace_ids) {\n mapped.linked_trace_ids = autotel.linked_trace_ids;\n }\n\n return mapped;\n }\n\n async trackEvent(\n name: string,\n attributes?: EventAttributes,\n options?: EventTrackingOptions,\n ): Promise<void> {\n if (!this.enabled) return;\n\n await this.ensureInitialized();\n const distinctId = attributes?.userId || attributes?.user_id || 'anonymous';\n const autotelProps = this.mapAutotelContext(options?.autotel);\n\n this.mixpanel?.track(name, {\n distinct_id: distinctId,\n ...attributes,\n ...autotelProps,\n });\n }\n\n async trackFunnelStep(\n funnelName: string,\n step: FunnelStatus,\n attributes?: EventAttributes,\n options?: EventTrackingOptions,\n ): Promise<void> {\n if (!this.enabled) return;\n\n await this.ensureInitialized();\n const distinctId = attributes?.userId || attributes?.user_id || 'anonymous';\n const autotelProps = this.mapAutotelContext(options?.autotel);\n\n this.mixpanel?.track(`${funnelName}.${step}`, {\n distinct_id: distinctId,\n funnel: funnelName,\n step,\n ...attributes,\n ...autotelProps,\n });\n }\n\n async trackOutcome(\n operationName: string,\n outcome: OutcomeStatus,\n attributes?: EventAttributes,\n options?: EventTrackingOptions,\n ): Promise<void> {\n if (!this.enabled) return;\n\n await this.ensureInitialized();\n const distinctId = attributes?.userId || attributes?.user_id || 'anonymous';\n const autotelProps = this.mapAutotelContext(options?.autotel);\n\n this.mixpanel?.track(`${operationName}.${outcome}`, {\n distinct_id: distinctId,\n operation: operationName,\n outcome,\n ...attributes,\n ...autotelProps,\n });\n }\n\n async trackValue(\n name: string,\n value: number,\n attributes?: EventAttributes,\n options?: EventTrackingOptions,\n ): Promise<void> {\n if (!this.enabled) return;\n\n await this.ensureInitialized();\n const distinctId = attributes?.userId || attributes?.user_id || 'anonymous';\n const autotelProps = this.mapAutotelContext(options?.autotel);\n\n this.mixpanel?.track(name, {\n distinct_id: distinctId,\n value,\n ...attributes,\n ...autotelProps,\n });\n }\n}\n"],"mappings":";;;;AAsCA,IAAa,qBAAb,MAA2D;CACzD,AAAS,OAAO;CAChB,AAAS,UAAU;CAEnB,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ,cAAoC;CAE5C,YAAY,QAAwB;EAClC,KAAK,UAAU,OAAO,WAAW;EACjC,KAAK,SAAS;EAEd,IAAI,KAAK,SAEP,KAAK,cAAc,KAAK,WAAW;CAEvC;CAEA,MAAc,aAA4B;EACxC,IAAI;GAEF,MAAM,WAAW,4FAAM;GACvB,KAAK,WAAW,SAAS,QAAQ,KAAK,KAAK,OAAO,KAAK;EACzD,SAAS,OAAO;GACd,QAAQ,MACN,iFACA,KACF;GACA,KAAK,UAAU;EACjB;CACF;CAEA,MAAc,oBAAmC;EAC/C,IAAI,KAAK,aAAa;GACpB,MAAM,KAAK;GACX,KAAK,cAAc;EACrB;CACF;;;;;;;;;CAUA,AAAQ,kBACN,SACyB;EACzB,IAAI,CAAC,SAAS,OAAO,CAAC;EAEtB,MAAM,SAAkC,CAAC;EAEzC,IAAI,QAAQ,UACV,OAAO,WAAW,QAAQ;EAE5B,IAAI,QAAQ,SACV,OAAO,UAAU,QAAQ;EAE3B,IAAI,QAAQ,gBACV,OAAO,iBAAiB,QAAQ;EAElC,IAAI,QAAQ,aACV,OAAO,cAAc,QAAQ;EAE/B,IAAI,QAAQ,aACV,OAAO,cAAc,QAAQ;EAE/B,IAAI,QAAQ,WACV,OAAO,YAAY,QAAQ;EAG7B,IAAI,QAAQ,0BAA0B,QACpC,OAAO,wBAAwB,QAAQ;EAEzC,IAAI,QAAQ,sBACV,OAAO,uBAAuB,QAAQ;EAExC,IAAI,QAAQ,kBACV,OAAO,mBAAmB,QAAQ;EAGpC,OAAO;CACT;CAEA,MAAM,WACJ,MACA,YACA,SACe;EACf,IAAI,CAAC,KAAK,SAAS;EAEnB,MAAM,KAAK,kBAAkB;EAC7B,MAAM,aAAa,YAAY,UAAU,YAAY,WAAW;EAChE,MAAM,eAAe,KAAK,kBAAkB,SAAS,OAAO;EAE5D,KAAK,UAAU,MAAM,MAAM;GACzB,aAAa;GACb,GAAG;GACH,GAAG;EACL,CAAC;CACH;CAEA,MAAM,gBACJ,YACA,MACA,YACA,SACe;EACf,IAAI,CAAC,KAAK,SAAS;EAEnB,MAAM,KAAK,kBAAkB;EAC7B,MAAM,aAAa,YAAY,UAAU,YAAY,WAAW;EAChE,MAAM,eAAe,KAAK,kBAAkB,SAAS,OAAO;EAE5D,KAAK,UAAU,MAAM,GAAG,WAAW,GAAG,QAAQ;GAC5C,aAAa;GACb,QAAQ;GACR;GACA,GAAG;GACH,GAAG;EACL,CAAC;CACH;CAEA,MAAM,aACJ,eACA,SACA,YACA,SACe;EACf,IAAI,CAAC,KAAK,SAAS;EAEnB,MAAM,KAAK,kBAAkB;EAC7B,MAAM,aAAa,YAAY,UAAU,YAAY,WAAW;EAChE,MAAM,eAAe,KAAK,kBAAkB,SAAS,OAAO;EAE5D,KAAK,UAAU,MAAM,GAAG,cAAc,GAAG,WAAW;GAClD,aAAa;GACb,WAAW;GACX;GACA,GAAG;GACH,GAAG;EACL,CAAC;CACH;CAEA,MAAM,WACJ,MACA,OACA,YACA,SACe;EACf,IAAI,CAAC,KAAK,SAAS;EAEnB,MAAM,KAAK,kBAAkB;EAC7B,MAAM,aAAa,YAAY,UAAU,YAAY,WAAW;EAChE,MAAM,eAAe,KAAK,kBAAkB,SAAS,OAAO;EAE5D,KAAK,UAAU,MAAM,MAAM;GACzB,aAAa;GACb;GACA,GAAG;GACH,GAAG;EACL,CAAC;CACH;AACF"}
|
package/dist/mixpanel.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as __toESM } from "./
|
|
1
|
+
import { o as __toESM } from "./rolldown-runtime-BHkdefai.js";
|
|
2
2
|
|
|
3
3
|
//#region src/mixpanel.ts
|
|
4
4
|
var MixpanelSubscriber = class {
|
|
@@ -15,7 +15,7 @@ var MixpanelSubscriber = class {
|
|
|
15
15
|
}
|
|
16
16
|
async initialize() {
|
|
17
17
|
try {
|
|
18
|
-
const Mixpanel = await import("./mixpanel-node-
|
|
18
|
+
const Mixpanel = await import("./mixpanel-node-BltEtoG6.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
|
|
19
19
|
this.mixpanel = Mixpanel.default.init(this.config.token);
|
|
20
20
|
} catch (error) {
|
|
21
21
|
console.error("Mixpanel subscriber failed to initialize. Install mixpanel: pnpm add mixpanel", error);
|
|
@@ -111,7 +111,7 @@ var PostHogSubscriber = class extends EventSubscriber {
|
|
|
111
111
|
this.setupErrorHandling();
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
|
-
const { PostHog } = await import("./index.node-
|
|
114
|
+
const { PostHog } = await import("./index.node-BF2WkODf.js");
|
|
115
115
|
this.posthog = new PostHog(this.config.apiKey, {
|
|
116
116
|
host: this.config.host || "https://us.i.posthog.com",
|
|
117
117
|
flushAt: this.config.flushAt,
|
|
@@ -475,4 +475,4 @@ var PostHogSubscriber = class extends EventSubscriber {
|
|
|
475
475
|
|
|
476
476
|
//#endregion
|
|
477
477
|
export { PostHogSubscriber as t };
|
|
478
|
-
//# sourceMappingURL=posthog-
|
|
478
|
+
//# sourceMappingURL=posthog-C9M1c_oG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-DTpCMk3r.js","names":[],"sources":["../src/posthog-error-formatter.ts","../src/posthog.ts"],"sourcesContent":["/**\n * Format errors for PostHog's $exception event format.\n * Compatible with autotel-web's ExceptionList type.\n */\n\ntype StringRedactor = (value: string) => string;\n\ninterface StackFrame {\n filename?: string;\n function?: string;\n lineno?: number;\n colno?: number;\n abs_path?: string;\n in_app?: boolean;\n platform?: string;\n}\n\ninterface ExceptionRecord {\n type: string;\n value: string;\n mechanism: { type: string; handled: boolean };\n stacktrace?: { frames: StackFrame[] };\n}\n\ninterface PostHogExceptionProperties {\n $exception_list: Array<{\n type: string;\n value: string;\n mechanism: { type: string; handled: boolean };\n stacktrace: { frames: Array<StackFrame & { platform: string }> };\n }>;\n}\n\nconst MAX_CAUSE_DEPTH = 5;\n\nexport function formatExceptionForPostHog(\n exceptionList: ExceptionRecord[],\n platform: string = 'web:javascript',\n redactor?: StringRedactor,\n): PostHogExceptionProperties {\n return {\n $exception_list: exceptionList.map((ex) => ({\n type: ex.type,\n value: redactor ? redactor(ex.value) : ex.value,\n mechanism: ex.mechanism,\n stacktrace: {\n frames: (ex.stacktrace?.frames || []).map((frame) => ({\n ...frame,\n abs_path: frame.abs_path && redactor ? redactor(frame.abs_path) : frame.abs_path,\n platform,\n })),\n },\n })),\n };\n}\n\nexport function errorToExceptionList(\n input: unknown,\n redactor?: StringRedactor,\n): ExceptionRecord[] {\n const error = input instanceof Error ? input : new Error(\n input === null || input === undefined ? 'Unknown error' : String(input),\n );\n\n const records: ExceptionRecord[] = [];\n let current: Error | undefined = error;\n let depth = 0;\n\n while (current && depth < MAX_CAUSE_DEPTH) {\n const value = current.message || 'Unknown error';\n const frames = current.stack ? parseStackBasic(current.stack) : undefined;\n records.push({\n type: current.name || 'Error',\n value: redactor ? redactor(value) : value,\n mechanism: { type: 'manual', handled: true },\n stacktrace: frames ? {\n frames: redactor\n ? frames.map((f) => ({\n ...f,\n abs_path: f.abs_path ? redactor(f.abs_path) : f.abs_path,\n }))\n : frames,\n } : undefined,\n });\n current = current.cause instanceof Error ? current.cause : undefined;\n depth++;\n }\n\n return records.toReversed();\n}\n\nfunction parseStackBasic(stack: string): StackFrame[] {\n const lines = stack.split('\\n');\n const frames: StackFrame[] = [];\n const re = /^\\s*at\\s+(?:(.+?)\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/;\n\n for (const line of lines) {\n const match = line.trim().match(re);\n if (match) {\n const [, fn, absPath, lineStr, colStr] = match;\n frames.push({\n function: fn || undefined,\n abs_path: absPath,\n filename: absPath.split('/').pop() || absPath,\n lineno: Number.parseInt(lineStr, 10),\n colno: Number.parseInt(colStr, 10),\n in_app: !absPath.includes('node_modules'),\n });\n }\n }\n\n return frames;\n}\n","/**\n * PostHog Subscriber for autotel\n *\n * Send events to PostHog for product events, feature flags, and A/B testing.\n *\n * @example Basic usage\n * ```typescript\n * import { Events } from 'autotel/events';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * const events = new Events('checkout', {\n * subscribers: [\n * new PostHogSubscriber({\n * apiKey: process.env.POSTHOG_API_KEY!,\n * host: 'https://us.i.posthog.com' // optional, defaults to US cloud\n * })\n * ]\n * });\n *\n * // Events go to both OpenTelemetry AND PostHog\n * events.trackEvent('order.completed', { userId: '123', amount: 99.99 });\n * ```\n *\n * @example Feature flags\n * ```typescript\n * const subscriber = new PostHogSubscriber({ apiKey: 'phc_...' });\n *\n * // Check if feature is enabled\n * const isEnabled = await subscriber.isFeatureEnabled('new-checkout', 'user-123');\n *\n * // Get feature flag value (string, boolean, number)\n * const variant = await subscriber.getFeatureFlag('experiment-variant', 'user-123');\n *\n * // Get all flags for a user\n * const allFlags = await subscriber.getAllFlags('user-123');\n * ```\n *\n * @example Person and group events\n * ```typescript\n * // Identify user and set properties\n * await subscriber.identify('user-123', {\n * email: 'user@example.com',\n * plan: 'premium'\n * });\n *\n * // Identify a group (e.g., organization)\n * await subscriber.groupIdentify('company', 'acme-corp', {\n * industry: 'saas',\n * employees: 500\n * });\n * ```\n *\n * @example Serverless configuration\n * ```typescript\n * // Optimized for AWS Lambda / Vercel Functions\n * const subscriber = new PostHogSubscriber({\n * apiKey: 'phc_...',\n * flushAt: 1, // Send immediately (don't batch)\n * flushInterval: 0, // Disable interval-based flushing\n * });\n * ```\n *\n * @example Custom PostHog client\n * ```typescript\n * import { PostHog } from 'posthog-node';\n *\n * const customClient = new PostHog('phc_...', {\n * host: 'https://eu.i.posthog.com',\n * // ... other PostHog options\n * });\n *\n * const subscriber = new PostHogSubscriber({\n * client: customClient\n * });\n * ```\n *\n * @example Error handling\n * ```typescript\n * const subscriber = new PostHogSubscriber({\n * apiKey: 'phc_...',\n * onError: (error) => {\n * console.error('PostHog error:', error);\n * // Send to error tracking service\n * }\n * });\n * ```\n */\n\nimport type { EventAttributes, EventAttributesInput } from 'autotel/event-subscriber';\nimport { EventSubscriber, type EventPayload } from './event-subscriber-base';\nimport { formatExceptionForPostHog, errorToExceptionList } from './posthog-error-formatter';\nimport slowRedact from 'slow-redact';\n\n// Type-only import to avoid runtime dependency\nimport type { PostHog } from 'posthog-node';\n\n/**\n * Error context for enhanced error handling\n *\n * Provides detailed context about the event that caused an error.\n */\nexport interface ErrorContext {\n /** The error that occurred */\n error: Error;\n\n /** Event name (if applicable) */\n eventName?: string;\n\n /** Event type (event, funnel, outcome, value) */\n eventType?: 'event' | 'funnel' | 'outcome' | 'value';\n\n /** Event attributes (filtered) */\n attributes?: EventAttributes;\n\n /** Subscriber name */\n subscriberName: string;\n}\n\ntype StringRedactor = (value: string) => string;\n\nexport interface PostHogConfig {\n /** PostHog API key (starts with phc_) - required if not providing custom client */\n apiKey?: string;\n\n /** PostHog host (defaults to US cloud) */\n host?: string;\n\n /** Enable/disable the subscriber */\n enabled?: boolean;\n\n /** Custom PostHog client instance (bypasses apiKey/host) */\n client?: PostHog;\n\n /**\n * Use global browser client (window.posthog)\n *\n * When true, uses the PostHog client already loaded on the page via script tag.\n * This is useful for Next.js apps that initialize PostHog in _app.tsx.\n *\n * @example\n * ```typescript\n * // Browser - uses window.posthog\n * const subscriber = new PostHogSubscriber({\n * useGlobalClient: true,\n * });\n * ```\n */\n useGlobalClient?: boolean;\n\n /**\n * Serverless mode preset (AWS Lambda, Vercel Functions, Next.js API routes)\n *\n * When true, auto-configures for serverless environments:\n * - flushAt: 1 (send immediately, don't batch)\n * - flushInterval: 0 (disable interval-based flushing)\n * - requestTimeout: 3000 (shorter timeout for fast responses)\n *\n * @example\n * ```typescript\n * // Vercel / Next.js API route\n * const subscriber = new PostHogSubscriber({\n * apiKey: 'phc_...',\n * serverless: true,\n * });\n * ```\n */\n serverless?: boolean;\n\n // Serverless optimizations\n /** Flush batch when it reaches this size (default: 20, set to 1 for immediate send) */\n flushAt?: number;\n\n /** Flush interval in milliseconds (default: 10000, set to 0 to disable) */\n flushInterval?: number;\n\n // Performance tuning\n /** Disable geoip lookup to reduce request size (default: false) */\n disableGeoip?: boolean;\n\n /** Request timeout in milliseconds (default: 10000) */\n requestTimeout?: number;\n\n /** Send feature flag evaluation events (default: true) */\n sendFeatureFlags?: boolean;\n\n /**\n * Automatically filter out undefined and null values from attributes\n *\n * When true (default), undefined and null values are removed before sending.\n * This improves DX when passing objects with optional properties.\n *\n * @default true\n *\n * @example\n * ```typescript\n * // With filterUndefinedValues: true (default)\n * subscriber.trackEvent('user.action', {\n * userId: user.id,\n * email: user.email, // might be undefined - will be filtered\n * plan: user.subscription, // might be null - will be filtered\n * });\n * ```\n */\n filterUndefinedValues?: boolean;\n\n // Error handling\n /** Error callback for debugging and monitoring */\n onError?: (error: Error) => void;\n\n /**\n * Enhanced error callback with event context\n *\n * Provides detailed context about the event that caused the error.\n * If both onError and onErrorWithContext are provided, both are called.\n *\n * @example\n * ```typescript\n * const subscriber = new PostHogSubscriber({\n * apiKey: 'phc_...',\n * onErrorWithContext: (ctx) => {\n * console.error(`Failed to track ${ctx.eventType}: ${ctx.eventName}`, ctx.error);\n * Sentry.captureException(ctx.error, { extra: ctx });\n * }\n * });\n * ```\n */\n onErrorWithContext?: (context: ErrorContext) => void;\n\n /** Known attribute paths to redact using slow-redact (path-based, immutable). */\n redactPaths?: string[];\n\n /** String redactor for value-based PII scanning. Applied after path-based redaction. */\n stringRedactor?: StringRedactor;\n\n /** Enable debug logging (default: false) */\n debug?: boolean;\n}\n\n/**\n * PostHog feature flag options\n */\nexport interface FeatureFlagOptions {\n /** Group context for group-based feature flags */\n groups?: Record<string, string | number>;\n\n /** Group properties for feature flag evaluation */\n groupProperties?: Record<string, Record<string, any>>;\n\n /** Person properties for feature flag evaluation */\n personProperties?: Record<string, any>;\n\n /** Only evaluate locally, don't send $feature_flag_called event */\n onlyEvaluateLocally?: boolean;\n\n /** Send feature flag events even if disabled globally */\n sendFeatureFlagEvents?: boolean;\n}\n\n/**\n * Person properties for identify calls\n */\nexport interface PersonProperties {\n /** Set properties (will update existing values) */\n $set?: Record<string, any>;\n\n /** Set properties only if they don't exist */\n $set_once?: Record<string, any>;\n\n /** Any custom properties */\n [key: string]: any;\n}\n\nexport class PostHogSubscriber extends EventSubscriber {\n readonly name = 'PostHogSubscriber';\n readonly version = '2.0.0';\n\n private posthog: PostHog | null = null;\n private config: PostHogConfig;\n private initPromise: Promise<void> | null = null;\n /** True when using browser's window.posthog (different API signature) */\n private isBrowserClient = false;\n private pathRedactor: ((obj: Record<string, unknown>) => Record<string, unknown>) | null = null;\n private stringRedactor: StringRedactor | null = null;\n\n constructor(config: PostHogConfig) {\n super();\n\n // Apply serverless preset first (can be overridden by explicit config)\n if (config.serverless) {\n config = {\n flushAt: 1,\n flushInterval: 0,\n requestTimeout: 3000,\n ...config, // User config overrides serverless defaults\n };\n }\n\n // Validate: need either apiKey, client, or useGlobalClient\n if (!config.apiKey && !config.client && !config.useGlobalClient) {\n throw new Error(\n 'PostHogSubscriber requires either apiKey, client, or useGlobalClient to be provided',\n );\n }\n\n this.enabled = config.enabled ?? true;\n // Default filterUndefinedValues to true\n this.config = {\n filterUndefinedValues: true,\n ...config,\n };\n\n if (this.config.redactPaths && this.config.redactPaths.length > 0) {\n this.pathRedactor = slowRedact({\n paths: this.config.redactPaths,\n serialize: false,\n }) as any;\n }\n if (this.config.stringRedactor) {\n this.stringRedactor = this.config.stringRedactor;\n }\n\n if (this.enabled) {\n // Start initialization immediately but don't block constructor\n this.initPromise = this.initialize();\n }\n }\n\n private async initialize(): Promise<void> {\n try {\n // Option 1: Use global browser client (window.posthog)\n if (this.config.useGlobalClient) {\n const globalWindow = typeof globalThis === 'undefined' ? undefined : (globalThis as Record<string, unknown>);\n if (globalWindow?.posthog) {\n this.posthog = globalWindow.posthog as PostHog;\n this.isBrowserClient = true;\n this.setupErrorHandling();\n return;\n }\n throw new Error(\n 'useGlobalClient enabled but window.posthog not found. ' +\n 'Ensure PostHog script is loaded before initializing the subscriber.',\n );\n }\n\n // Option 2: Use custom client if provided\n if (this.config.client) {\n this.posthog = this.config.client;\n this.setupErrorHandling();\n return;\n }\n\n // Option 3: Create new PostHog client with dynamic import\n const { PostHog } = await import('posthog-node');\n\n this.posthog = new PostHog(this.config.apiKey!, {\n host: this.config.host || 'https://us.i.posthog.com',\n flushAt: this.config.flushAt,\n flushInterval: this.config.flushInterval,\n requestTimeout: this.config.requestTimeout,\n disableGeoip: this.config.disableGeoip,\n sendFeatureFlagEvent: this.config.sendFeatureFlags,\n });\n\n this.setupErrorHandling();\n } catch (error) {\n console.error(\n 'PostHog subscriber failed to initialize. Install posthog-node: pnpm add posthog-node',\n error,\n );\n this.enabled = false;\n this.config.onError?.(error as Error);\n }\n }\n\n private setupErrorHandling(): void {\n if (this.config.debug) {\n this.posthog?.debug();\n }\n\n if (this.config.onError && this.posthog?.on) {\n this.posthog.on('error', this.config.onError);\n }\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise) {\n await this.initPromise;\n this.initPromise = null;\n }\n }\n\n private extractDistinctId(attributes?: EventAttributes): string {\n return (attributes?.userId || attributes?.user_id || 'anonymous') as string;\n }\n\n private redactProperties(properties: Record<string, unknown>): Record<string, unknown> {\n let result = properties;\n if (this.pathRedactor) {\n result = this.pathRedactor(properties) as Record<string, unknown>;\n }\n if (this.stringRedactor) {\n result = this.redactStringValues(result);\n }\n return result;\n }\n\n private redactStringValues(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === 'string') {\n result[key] = this.stringRedactor!(value);\n } else if (Array.isArray(value)) {\n result[key] = this.redactArray(value);\n } else if (value !== null && typeof value === 'object') {\n result[key] = this.redactStringValues(value as Record<string, unknown>);\n } else {\n result[key] = value;\n }\n }\n return result;\n }\n\n private redactArray(arr: unknown[]): unknown[] {\n return arr.map((item) => {\n if (typeof item === 'string') {\n return this.stringRedactor!(item);\n } else if (Array.isArray(item)) {\n return this.redactArray(item);\n } else if (item !== null && typeof item === 'object') {\n return this.redactStringValues(item as Record<string, unknown>);\n }\n return item;\n });\n }\n\n /**\n * Set the string redactor. Called by autotel init() when attributeRedactor is configured.\n * Can also be called manually.\n */\n setStringRedactor(redactor: StringRedactor): void {\n this.stringRedactor = redactor;\n }\n\n /**\n * Send payload to PostHog\n *\n * Maps autotel context to PostHog-specific field names:\n * - autotel.trace_id → $trace_id\n * - autotel.span_id → $span_id\n * - autotel.correlation_id → $correlation_id\n * - autotel.trace_url → $trace_url\n */\n protected async sendToDestination(payload: EventPayload): Promise<void> {\n await this.ensureInitialized();\n\n // Filter attributes if enabled (default: true)\n const filteredAttributes =\n this.config.filterUndefinedValues === false\n ? payload.attributes\n : this.filterAttributes(payload.attributes as EventAttributesInput);\n\n // Build properties object, including value and funnel metadata if present\n const properties: Record<string, unknown> = { ...filteredAttributes };\n if (payload.value !== undefined) {\n properties.value = payload.value;\n }\n // Add funnel progression metadata\n if (payload.stepNumber !== undefined) {\n properties.step_number = payload.stepNumber;\n }\n if (payload.stepName !== undefined) {\n properties.step_name = payload.stepName;\n }\n\n // Map autotel context to PostHog-specific field names\n if (payload.autotel) {\n if (payload.autotel.trace_id) {\n properties.$trace_id = payload.autotel.trace_id;\n }\n if (payload.autotel.span_id) {\n properties.$span_id = payload.autotel.span_id;\n }\n if (payload.autotel.correlation_id) {\n properties.$correlation_id = payload.autotel.correlation_id;\n }\n if (payload.autotel.trace_flags) {\n properties.$trace_flags = payload.autotel.trace_flags;\n }\n if (payload.autotel.trace_state) {\n properties.$trace_state = payload.autotel.trace_state;\n }\n if (payload.autotel.trace_url) {\n properties.$trace_url = payload.autotel.trace_url;\n }\n // Batch/fan-in context\n if (payload.autotel.linked_trace_id_count !== undefined) {\n properties.$linked_trace_id_count = payload.autotel.linked_trace_id_count;\n }\n if (payload.autotel.linked_trace_id_hash) {\n properties.$linked_trace_id_hash = payload.autotel.linked_trace_id_hash;\n }\n if (payload.autotel.linked_trace_ids) {\n properties.$linked_trace_ids = payload.autotel.linked_trace_ids;\n }\n }\n\n const redactedProperties = this.redactProperties(properties);\n\n if (payload.attributes?.['exception.list']) {\n try {\n const exceptionList = JSON.parse(payload.attributes['exception.list'] as string);\n const formatted = formatExceptionForPostHog(\n exceptionList,\n undefined,\n this.stringRedactor ?? undefined,\n );\n const exceptionProperties = {\n ...redactedProperties,\n ...formatted,\n };\n\n if (this.isBrowserClient) {\n (this.posthog as any)?.capture('$exception', exceptionProperties);\n } else {\n this.posthog?.capture({\n distinctId: this.extractDistinctId(filteredAttributes),\n event: '$exception',\n properties: exceptionProperties,\n });\n }\n } catch {\n // exception.list parsing failed, continue with normal event\n }\n }\n\n const distinctId = this.extractDistinctId(filteredAttributes);\n\n // Browser client has different API signature\n if (this.isBrowserClient) {\n // Browser API: capture(eventName, properties)\n (this.posthog as any)?.capture(payload.name, redactedProperties);\n } else {\n // Server API: capture({ distinctId, event, properties, groups })\n const capturePayload: any = {\n distinctId,\n event: payload.name,\n properties: redactedProperties,\n };\n\n // Add groups if present in attributes\n if (filteredAttributes?.groups) {\n capturePayload.groups = filteredAttributes.groups;\n }\n\n this.posthog?.capture(capturePayload);\n }\n }\n\n // Feature Flag Methods\n\n /**\n * Check if a feature flag is enabled for a user\n *\n * @param flagKey - Feature flag key\n * @param distinctId - User ID or anonymous ID\n * @param options - Feature flag evaluation options\n * @returns true if enabled, false otherwise\n *\n * @example\n * ```typescript\n * const isEnabled = await subscriber.isFeatureEnabled('new-checkout', 'user-123');\n *\n * // With groups\n * const isEnabled = await subscriber.isFeatureEnabled('beta-features', 'user-123', {\n * groups: { company: 'acme-corp' }\n * });\n * ```\n */\n async isFeatureEnabled(\n flagKey: string,\n distinctId: string,\n options?: FeatureFlagOptions,\n ): Promise<boolean> {\n if (!this.enabled) return false;\n await this.ensureInitialized();\n\n try {\n return await this.posthog?.isFeatureEnabled(flagKey, distinctId, options as any) ?? false;\n } catch (error) {\n this.config.onError?.(error as Error);\n return false;\n }\n }\n\n /**\n * Get feature flag value for a user\n *\n * @param flagKey - Feature flag key\n * @param distinctId - User ID or anonymous ID\n * @param options - Feature flag evaluation options\n * @returns Flag value (string, boolean, or undefined)\n *\n * @example\n * ```typescript\n * const variant = await subscriber.getFeatureFlag('experiment-variant', 'user-123');\n * // Returns: 'control' | 'test' | 'test-2' | undefined\n *\n * // With person properties\n * const variant = await subscriber.getFeatureFlag('premium-feature', 'user-123', {\n * personProperties: { plan: 'premium' }\n * });\n * ```\n */\n async getFeatureFlag(\n flagKey: string,\n distinctId: string,\n options?: FeatureFlagOptions,\n ): Promise<string | boolean | undefined> {\n if (!this.enabled) return undefined;\n await this.ensureInitialized();\n\n try {\n return await this.posthog?.getFeatureFlag(flagKey, distinctId, options as any);\n } catch (error) {\n this.config.onError?.(error as Error);\n return undefined;\n }\n }\n\n /**\n * Get all feature flags for a user\n *\n * @param distinctId - User ID or anonymous ID\n * @param options - Feature flag evaluation options\n * @returns Object mapping flag keys to their values\n *\n * @example\n * ```typescript\n * const flags = await subscriber.getAllFlags('user-123');\n * // Returns: { 'new-checkout': true, 'experiment-variant': 'test', ... }\n * ```\n */\n async getAllFlags(\n distinctId: string,\n options?: FeatureFlagOptions,\n ): Promise<Record<string, string | number | boolean>> {\n if (!this.enabled) return {};\n await this.ensureInitialized();\n\n try {\n const flags = await this.posthog?.getAllFlags(distinctId, options as any);\n return flags ?? {};\n } catch (error) {\n this.config.onError?.(error as Error);\n return {};\n }\n }\n\n /**\n * Reload feature flags from PostHog server\n *\n * Call this to refresh feature flag definitions without restarting.\n *\n * @example\n * ```typescript\n * await subscriber.reloadFeatureFlags();\n * ```\n */\n async reloadFeatureFlags(): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n try {\n await this.posthog?.reloadFeatureFlags();\n } catch (error) {\n this.config.onError?.(error as Error);\n }\n }\n\n // Person and Group Events\n\n /**\n * Identify a user and set their properties\n *\n * @param distinctId - User ID\n * @param properties - Person properties ($set, $set_once, or custom properties)\n *\n * @example\n * ```typescript\n * // Set properties (will update existing values)\n * await subscriber.identify('user-123', {\n * $set: {\n * email: 'user@example.com',\n * plan: 'premium'\n * }\n * });\n *\n * // Set properties only once (won't update if already exists)\n * await subscriber.identify('user-123', {\n * $set_once: {\n * signup_date: '2025-01-17'\n * }\n * });\n * ```\n */\n async identify(distinctId: string, properties?: PersonProperties): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n try {\n this.posthog?.identify({\n distinctId,\n properties,\n });\n } catch (error) {\n this.config.onError?.(error as Error);\n }\n }\n\n /**\n * Identify a group and set its properties\n *\n * Groups are useful for B2B SaaS to track organizations, teams, or accounts.\n *\n * @param groupType - Type of group (e.g., 'company', 'organization', 'team')\n * @param groupKey - Unique identifier for the group\n * @param properties - Group properties\n *\n * @example\n * ```typescript\n * await subscriber.groupIdentify('company', 'acme-corp', {\n * $set: {\n * name: 'Acme Corporation',\n * industry: 'saas',\n * employees: 500,\n * plan: 'enterprise'\n * }\n * });\n * ```\n */\n async groupIdentify(\n groupType: string,\n groupKey: string | number,\n properties?: Record<string, any>,\n ): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n try {\n this.posthog?.groupIdentify({\n groupType,\n groupKey: String(groupKey), // Convert to string for PostHog SDK\n properties,\n });\n } catch (error) {\n this.config.onError?.(error as Error);\n }\n }\n\n /**\n * Track an event with group context\n *\n * Use this to associate events with groups (e.g., organizations).\n *\n * @param name - Event name\n * @param attributes - Event attributes\n * @param groups - Group context (e.g., { company: 'acme-corp' })\n *\n * @example\n * ```typescript\n * await subscriber.trackEventWithGroups('feature.used', {\n * userId: 'user-123',\n * feature: 'advanced-events'\n * }, {\n * company: 'acme-corp'\n * });\n * ```\n */\n async trackEventWithGroups(\n name: string,\n attributes?: EventAttributes,\n groups?: Record<string, string | number>,\n ): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n const eventAttributes: EventAttributes = { ...attributes } as EventAttributes;\n if (groups) {\n (eventAttributes as any).groups = groups;\n }\n\n await this.trackEvent(name, eventAttributes);\n }\n\n /**\n * Capture an exception and send to PostHog error tracking.\n *\n * If using browser client (window.posthog), delegates to its captureException.\n * Otherwise, formats and sends via posthog-node capture API.\n */\n async captureException(\n error: unknown,\n options?: {\n distinctId?: string;\n additionalProperties?: Record<string, unknown>;\n },\n ): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n try {\n if (this.isBrowserClient) {\n const browserProps = options?.additionalProperties\n ? this.redactProperties(options.additionalProperties)\n : undefined;\n (this.posthog as any)?.captureException?.(error, browserProps);\n return;\n }\n\n const exceptionList = errorToExceptionList(error, this.stringRedactor ?? undefined);\n const formatted = formatExceptionForPostHog(exceptionList, 'node:javascript', this.stringRedactor ?? undefined);\n\n const properties = {\n ...formatted,\n ...options?.additionalProperties,\n };\n\n this.posthog?.capture({\n distinctId: options?.distinctId || 'anonymous',\n event: '$exception',\n properties: this.redactProperties(properties),\n });\n } catch (error_) {\n this.config.onError?.(error_ as Error);\n }\n }\n\n /**\n * Flush pending events and clean up resources\n */\n async shutdown(): Promise<void> {\n await super.shutdown(); // Drain pending requests first\n await this.ensureInitialized();\n\n if (this.posthog) {\n try {\n await this.posthog.shutdown();\n } catch (error) {\n this.config.onError?.(error as Error);\n }\n }\n }\n\n /**\n * Handle errors with custom error handler\n */\n protected handleError(error: Error, payload: EventPayload): void {\n // Call basic onError if provided\n this.config.onError?.(error);\n\n // Call enhanced onErrorWithContext if provided\n if (this.config.onErrorWithContext) {\n this.config.onErrorWithContext({\n error,\n eventName: payload.name,\n eventType: payload.type,\n attributes: payload.attributes,\n subscriberName: this.name,\n });\n }\n\n super.handleError(error, payload);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"posthog-C9M1c_oG.js","names":[],"sources":["../src/posthog-error-formatter.ts","../src/posthog.ts"],"sourcesContent":["/**\n * Format errors for PostHog's $exception event format.\n * Compatible with autotel-web's ExceptionList type.\n */\n\ntype StringRedactor = (value: string) => string;\n\ninterface StackFrame {\n filename?: string;\n function?: string;\n lineno?: number;\n colno?: number;\n abs_path?: string;\n in_app?: boolean;\n platform?: string;\n}\n\ninterface ExceptionRecord {\n type: string;\n value: string;\n mechanism: { type: string; handled: boolean };\n stacktrace?: { frames: StackFrame[] };\n}\n\ninterface PostHogExceptionProperties {\n $exception_list: Array<{\n type: string;\n value: string;\n mechanism: { type: string; handled: boolean };\n stacktrace: { frames: Array<StackFrame & { platform: string }> };\n }>;\n}\n\nconst MAX_CAUSE_DEPTH = 5;\n\nexport function formatExceptionForPostHog(\n exceptionList: ExceptionRecord[],\n platform: string = 'web:javascript',\n redactor?: StringRedactor,\n): PostHogExceptionProperties {\n return {\n $exception_list: exceptionList.map((ex) => ({\n type: ex.type,\n value: redactor ? redactor(ex.value) : ex.value,\n mechanism: ex.mechanism,\n stacktrace: {\n frames: (ex.stacktrace?.frames || []).map((frame) => ({\n ...frame,\n abs_path: frame.abs_path && redactor ? redactor(frame.abs_path) : frame.abs_path,\n platform,\n })),\n },\n })),\n };\n}\n\nexport function errorToExceptionList(\n input: unknown,\n redactor?: StringRedactor,\n): ExceptionRecord[] {\n const error = input instanceof Error ? input : new Error(\n input === null || input === undefined ? 'Unknown error' : String(input),\n );\n\n const records: ExceptionRecord[] = [];\n let current: Error | undefined = error;\n let depth = 0;\n\n while (current && depth < MAX_CAUSE_DEPTH) {\n const value = current.message || 'Unknown error';\n const frames = current.stack ? parseStackBasic(current.stack) : undefined;\n records.push({\n type: current.name || 'Error',\n value: redactor ? redactor(value) : value,\n mechanism: { type: 'manual', handled: true },\n stacktrace: frames ? {\n frames: redactor\n ? frames.map((f) => ({\n ...f,\n abs_path: f.abs_path ? redactor(f.abs_path) : f.abs_path,\n }))\n : frames,\n } : undefined,\n });\n current = current.cause instanceof Error ? current.cause : undefined;\n depth++;\n }\n\n return records.toReversed();\n}\n\nfunction parseStackBasic(stack: string): StackFrame[] {\n const lines = stack.split('\\n');\n const frames: StackFrame[] = [];\n const re = /^\\s*at\\s+(?:(.+?)\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/;\n\n for (const line of lines) {\n const match = line.trim().match(re);\n if (match) {\n const [, fn, absPath, lineStr, colStr] = match;\n frames.push({\n function: fn || undefined,\n abs_path: absPath,\n filename: absPath.split('/').pop() || absPath,\n lineno: Number.parseInt(lineStr, 10),\n colno: Number.parseInt(colStr, 10),\n in_app: !absPath.includes('node_modules'),\n });\n }\n }\n\n return frames;\n}\n","/**\n * PostHog Subscriber for autotel\n *\n * Send events to PostHog for product events, feature flags, and A/B testing.\n *\n * @example Basic usage\n * ```typescript\n * import { Events } from 'autotel/events';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * const events = new Events('checkout', {\n * subscribers: [\n * new PostHogSubscriber({\n * apiKey: process.env.POSTHOG_API_KEY!,\n * host: 'https://us.i.posthog.com' // optional, defaults to US cloud\n * })\n * ]\n * });\n *\n * // Events go to both OpenTelemetry AND PostHog\n * events.trackEvent('order.completed', { userId: '123', amount: 99.99 });\n * ```\n *\n * @example Feature flags\n * ```typescript\n * const subscriber = new PostHogSubscriber({ apiKey: 'phc_...' });\n *\n * // Check if feature is enabled\n * const isEnabled = await subscriber.isFeatureEnabled('new-checkout', 'user-123');\n *\n * // Get feature flag value (string, boolean, number)\n * const variant = await subscriber.getFeatureFlag('experiment-variant', 'user-123');\n *\n * // Get all flags for a user\n * const allFlags = await subscriber.getAllFlags('user-123');\n * ```\n *\n * @example Person and group events\n * ```typescript\n * // Identify user and set properties\n * await subscriber.identify('user-123', {\n * email: 'user@example.com',\n * plan: 'premium'\n * });\n *\n * // Identify a group (e.g., organization)\n * await subscriber.groupIdentify('company', 'acme-corp', {\n * industry: 'saas',\n * employees: 500\n * });\n * ```\n *\n * @example Serverless configuration\n * ```typescript\n * // Optimized for AWS Lambda / Vercel Functions\n * const subscriber = new PostHogSubscriber({\n * apiKey: 'phc_...',\n * flushAt: 1, // Send immediately (don't batch)\n * flushInterval: 0, // Disable interval-based flushing\n * });\n * ```\n *\n * @example Custom PostHog client\n * ```typescript\n * import { PostHog } from 'posthog-node';\n *\n * const customClient = new PostHog('phc_...', {\n * host: 'https://eu.i.posthog.com',\n * // ... other PostHog options\n * });\n *\n * const subscriber = new PostHogSubscriber({\n * client: customClient\n * });\n * ```\n *\n * @example Error handling\n * ```typescript\n * const subscriber = new PostHogSubscriber({\n * apiKey: 'phc_...',\n * onError: (error) => {\n * console.error('PostHog error:', error);\n * // Send to error tracking service\n * }\n * });\n * ```\n */\n\nimport type { EventAttributes, EventAttributesInput } from 'autotel/event-subscriber';\nimport { EventSubscriber, type EventPayload } from './event-subscriber-base';\nimport { formatExceptionForPostHog, errorToExceptionList } from './posthog-error-formatter';\nimport slowRedact from 'slow-redact';\n\n// Type-only import to avoid runtime dependency\nimport type { PostHog } from 'posthog-node';\n\n/**\n * Error context for enhanced error handling\n *\n * Provides detailed context about the event that caused an error.\n */\nexport interface ErrorContext {\n /** The error that occurred */\n error: Error;\n\n /** Event name (if applicable) */\n eventName?: string;\n\n /** Event type (event, funnel, outcome, value) */\n eventType?: 'event' | 'funnel' | 'outcome' | 'value';\n\n /** Event attributes (filtered) */\n attributes?: EventAttributes;\n\n /** Subscriber name */\n subscriberName: string;\n}\n\ntype StringRedactor = (value: string) => string;\n\nexport interface PostHogConfig {\n /** PostHog API key (starts with phc_) - required if not providing custom client */\n apiKey?: string;\n\n /** PostHog host (defaults to US cloud) */\n host?: string;\n\n /** Enable/disable the subscriber */\n enabled?: boolean;\n\n /** Custom PostHog client instance (bypasses apiKey/host) */\n client?: PostHog;\n\n /**\n * Use global browser client (window.posthog)\n *\n * When true, uses the PostHog client already loaded on the page via script tag.\n * This is useful for Next.js apps that initialize PostHog in _app.tsx.\n *\n * @example\n * ```typescript\n * // Browser - uses window.posthog\n * const subscriber = new PostHogSubscriber({\n * useGlobalClient: true,\n * });\n * ```\n */\n useGlobalClient?: boolean;\n\n /**\n * Serverless mode preset (AWS Lambda, Vercel Functions, Next.js API routes)\n *\n * When true, auto-configures for serverless environments:\n * - flushAt: 1 (send immediately, don't batch)\n * - flushInterval: 0 (disable interval-based flushing)\n * - requestTimeout: 3000 (shorter timeout for fast responses)\n *\n * @example\n * ```typescript\n * // Vercel / Next.js API route\n * const subscriber = new PostHogSubscriber({\n * apiKey: 'phc_...',\n * serverless: true,\n * });\n * ```\n */\n serverless?: boolean;\n\n // Serverless optimizations\n /** Flush batch when it reaches this size (default: 20, set to 1 for immediate send) */\n flushAt?: number;\n\n /** Flush interval in milliseconds (default: 10000, set to 0 to disable) */\n flushInterval?: number;\n\n // Performance tuning\n /** Disable geoip lookup to reduce request size (default: false) */\n disableGeoip?: boolean;\n\n /** Request timeout in milliseconds (default: 10000) */\n requestTimeout?: number;\n\n /** Send feature flag evaluation events (default: true) */\n sendFeatureFlags?: boolean;\n\n /**\n * Automatically filter out undefined and null values from attributes\n *\n * When true (default), undefined and null values are removed before sending.\n * This improves DX when passing objects with optional properties.\n *\n * @default true\n *\n * @example\n * ```typescript\n * // With filterUndefinedValues: true (default)\n * subscriber.trackEvent('user.action', {\n * userId: user.id,\n * email: user.email, // might be undefined - will be filtered\n * plan: user.subscription, // might be null - will be filtered\n * });\n * ```\n */\n filterUndefinedValues?: boolean;\n\n // Error handling\n /** Error callback for debugging and monitoring */\n onError?: (error: Error) => void;\n\n /**\n * Enhanced error callback with event context\n *\n * Provides detailed context about the event that caused the error.\n * If both onError and onErrorWithContext are provided, both are called.\n *\n * @example\n * ```typescript\n * const subscriber = new PostHogSubscriber({\n * apiKey: 'phc_...',\n * onErrorWithContext: (ctx) => {\n * console.error(`Failed to track ${ctx.eventType}: ${ctx.eventName}`, ctx.error);\n * Sentry.captureException(ctx.error, { extra: ctx });\n * }\n * });\n * ```\n */\n onErrorWithContext?: (context: ErrorContext) => void;\n\n /** Known attribute paths to redact using slow-redact (path-based, immutable). */\n redactPaths?: string[];\n\n /** String redactor for value-based PII scanning. Applied after path-based redaction. */\n stringRedactor?: StringRedactor;\n\n /** Enable debug logging (default: false) */\n debug?: boolean;\n}\n\n/**\n * PostHog feature flag options\n */\nexport interface FeatureFlagOptions {\n /** Group context for group-based feature flags */\n groups?: Record<string, string | number>;\n\n /** Group properties for feature flag evaluation */\n groupProperties?: Record<string, Record<string, any>>;\n\n /** Person properties for feature flag evaluation */\n personProperties?: Record<string, any>;\n\n /** Only evaluate locally, don't send $feature_flag_called event */\n onlyEvaluateLocally?: boolean;\n\n /** Send feature flag events even if disabled globally */\n sendFeatureFlagEvents?: boolean;\n}\n\n/**\n * Person properties for identify calls\n */\nexport interface PersonProperties {\n /** Set properties (will update existing values) */\n $set?: Record<string, any>;\n\n /** Set properties only if they don't exist */\n $set_once?: Record<string, any>;\n\n /** Any custom properties */\n [key: string]: any;\n}\n\nexport class PostHogSubscriber extends EventSubscriber {\n readonly name = 'PostHogSubscriber';\n readonly version = '2.0.0';\n\n private posthog: PostHog | null = null;\n private config: PostHogConfig;\n private initPromise: Promise<void> | null = null;\n /** True when using browser's window.posthog (different API signature) */\n private isBrowserClient = false;\n private pathRedactor: ((obj: Record<string, unknown>) => Record<string, unknown>) | null = null;\n private stringRedactor: StringRedactor | null = null;\n\n constructor(config: PostHogConfig) {\n super();\n\n // Apply serverless preset first (can be overridden by explicit config)\n if (config.serverless) {\n config = {\n flushAt: 1,\n flushInterval: 0,\n requestTimeout: 3000,\n ...config, // User config overrides serverless defaults\n };\n }\n\n // Validate: need either apiKey, client, or useGlobalClient\n if (!config.apiKey && !config.client && !config.useGlobalClient) {\n throw new Error(\n 'PostHogSubscriber requires either apiKey, client, or useGlobalClient to be provided',\n );\n }\n\n this.enabled = config.enabled ?? true;\n // Default filterUndefinedValues to true\n this.config = {\n filterUndefinedValues: true,\n ...config,\n };\n\n if (this.config.redactPaths && this.config.redactPaths.length > 0) {\n this.pathRedactor = slowRedact({\n paths: this.config.redactPaths,\n serialize: false,\n }) as any;\n }\n if (this.config.stringRedactor) {\n this.stringRedactor = this.config.stringRedactor;\n }\n\n if (this.enabled) {\n // Start initialization immediately but don't block constructor\n this.initPromise = this.initialize();\n }\n }\n\n private async initialize(): Promise<void> {\n try {\n // Option 1: Use global browser client (window.posthog)\n if (this.config.useGlobalClient) {\n const globalWindow = typeof globalThis === 'undefined' ? undefined : (globalThis as Record<string, unknown>);\n if (globalWindow?.posthog) {\n this.posthog = globalWindow.posthog as PostHog;\n this.isBrowserClient = true;\n this.setupErrorHandling();\n return;\n }\n throw new Error(\n 'useGlobalClient enabled but window.posthog not found. ' +\n 'Ensure PostHog script is loaded before initializing the subscriber.',\n );\n }\n\n // Option 2: Use custom client if provided\n if (this.config.client) {\n this.posthog = this.config.client;\n this.setupErrorHandling();\n return;\n }\n\n // Option 3: Create new PostHog client with dynamic import\n const { PostHog } = await import('posthog-node');\n\n this.posthog = new PostHog(this.config.apiKey!, {\n host: this.config.host || 'https://us.i.posthog.com',\n flushAt: this.config.flushAt,\n flushInterval: this.config.flushInterval,\n requestTimeout: this.config.requestTimeout,\n disableGeoip: this.config.disableGeoip,\n sendFeatureFlagEvent: this.config.sendFeatureFlags,\n });\n\n this.setupErrorHandling();\n } catch (error) {\n console.error(\n 'PostHog subscriber failed to initialize. Install posthog-node: pnpm add posthog-node',\n error,\n );\n this.enabled = false;\n this.config.onError?.(error as Error);\n }\n }\n\n private setupErrorHandling(): void {\n if (this.config.debug) {\n this.posthog?.debug();\n }\n\n if (this.config.onError && this.posthog?.on) {\n this.posthog.on('error', this.config.onError);\n }\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise) {\n await this.initPromise;\n this.initPromise = null;\n }\n }\n\n private extractDistinctId(attributes?: EventAttributes): string {\n return (attributes?.userId || attributes?.user_id || 'anonymous') as string;\n }\n\n private redactProperties(properties: Record<string, unknown>): Record<string, unknown> {\n let result = properties;\n if (this.pathRedactor) {\n result = this.pathRedactor(properties) as Record<string, unknown>;\n }\n if (this.stringRedactor) {\n result = this.redactStringValues(result);\n }\n return result;\n }\n\n private redactStringValues(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === 'string') {\n result[key] = this.stringRedactor!(value);\n } else if (Array.isArray(value)) {\n result[key] = this.redactArray(value);\n } else if (value !== null && typeof value === 'object') {\n result[key] = this.redactStringValues(value as Record<string, unknown>);\n } else {\n result[key] = value;\n }\n }\n return result;\n }\n\n private redactArray(arr: unknown[]): unknown[] {\n return arr.map((item) => {\n if (typeof item === 'string') {\n return this.stringRedactor!(item);\n } else if (Array.isArray(item)) {\n return this.redactArray(item);\n } else if (item !== null && typeof item === 'object') {\n return this.redactStringValues(item as Record<string, unknown>);\n }\n return item;\n });\n }\n\n /**\n * Set the string redactor. Called by autotel init() when attributeRedactor is configured.\n * Can also be called manually.\n */\n setStringRedactor(redactor: StringRedactor): void {\n this.stringRedactor = redactor;\n }\n\n /**\n * Send payload to PostHog\n *\n * Maps autotel context to PostHog-specific field names:\n * - autotel.trace_id → $trace_id\n * - autotel.span_id → $span_id\n * - autotel.correlation_id → $correlation_id\n * - autotel.trace_url → $trace_url\n */\n protected async sendToDestination(payload: EventPayload): Promise<void> {\n await this.ensureInitialized();\n\n // Filter attributes if enabled (default: true)\n const filteredAttributes =\n this.config.filterUndefinedValues === false\n ? payload.attributes\n : this.filterAttributes(payload.attributes as EventAttributesInput);\n\n // Build properties object, including value and funnel metadata if present\n const properties: Record<string, unknown> = { ...filteredAttributes };\n if (payload.value !== undefined) {\n properties.value = payload.value;\n }\n // Add funnel progression metadata\n if (payload.stepNumber !== undefined) {\n properties.step_number = payload.stepNumber;\n }\n if (payload.stepName !== undefined) {\n properties.step_name = payload.stepName;\n }\n\n // Map autotel context to PostHog-specific field names\n if (payload.autotel) {\n if (payload.autotel.trace_id) {\n properties.$trace_id = payload.autotel.trace_id;\n }\n if (payload.autotel.span_id) {\n properties.$span_id = payload.autotel.span_id;\n }\n if (payload.autotel.correlation_id) {\n properties.$correlation_id = payload.autotel.correlation_id;\n }\n if (payload.autotel.trace_flags) {\n properties.$trace_flags = payload.autotel.trace_flags;\n }\n if (payload.autotel.trace_state) {\n properties.$trace_state = payload.autotel.trace_state;\n }\n if (payload.autotel.trace_url) {\n properties.$trace_url = payload.autotel.trace_url;\n }\n // Batch/fan-in context\n if (payload.autotel.linked_trace_id_count !== undefined) {\n properties.$linked_trace_id_count = payload.autotel.linked_trace_id_count;\n }\n if (payload.autotel.linked_trace_id_hash) {\n properties.$linked_trace_id_hash = payload.autotel.linked_trace_id_hash;\n }\n if (payload.autotel.linked_trace_ids) {\n properties.$linked_trace_ids = payload.autotel.linked_trace_ids;\n }\n }\n\n const redactedProperties = this.redactProperties(properties);\n\n if (payload.attributes?.['exception.list']) {\n try {\n const exceptionList = JSON.parse(payload.attributes['exception.list'] as string);\n const formatted = formatExceptionForPostHog(\n exceptionList,\n undefined,\n this.stringRedactor ?? undefined,\n );\n const exceptionProperties = {\n ...redactedProperties,\n ...formatted,\n };\n\n if (this.isBrowserClient) {\n (this.posthog as any)?.capture('$exception', exceptionProperties);\n } else {\n this.posthog?.capture({\n distinctId: this.extractDistinctId(filteredAttributes),\n event: '$exception',\n properties: exceptionProperties,\n });\n }\n } catch {\n // exception.list parsing failed, continue with normal event\n }\n }\n\n const distinctId = this.extractDistinctId(filteredAttributes);\n\n // Browser client has different API signature\n if (this.isBrowserClient) {\n // Browser API: capture(eventName, properties)\n (this.posthog as any)?.capture(payload.name, redactedProperties);\n } else {\n // Server API: capture({ distinctId, event, properties, groups })\n const capturePayload: any = {\n distinctId,\n event: payload.name,\n properties: redactedProperties,\n };\n\n // Add groups if present in attributes\n if (filteredAttributes?.groups) {\n capturePayload.groups = filteredAttributes.groups;\n }\n\n this.posthog?.capture(capturePayload);\n }\n }\n\n // Feature Flag Methods\n\n /**\n * Check if a feature flag is enabled for a user\n *\n * @param flagKey - Feature flag key\n * @param distinctId - User ID or anonymous ID\n * @param options - Feature flag evaluation options\n * @returns true if enabled, false otherwise\n *\n * @example\n * ```typescript\n * const isEnabled = await subscriber.isFeatureEnabled('new-checkout', 'user-123');\n *\n * // With groups\n * const isEnabled = await subscriber.isFeatureEnabled('beta-features', 'user-123', {\n * groups: { company: 'acme-corp' }\n * });\n * ```\n */\n async isFeatureEnabled(\n flagKey: string,\n distinctId: string,\n options?: FeatureFlagOptions,\n ): Promise<boolean> {\n if (!this.enabled) return false;\n await this.ensureInitialized();\n\n try {\n return await this.posthog?.isFeatureEnabled(flagKey, distinctId, options as any) ?? false;\n } catch (error) {\n this.config.onError?.(error as Error);\n return false;\n }\n }\n\n /**\n * Get feature flag value for a user\n *\n * @param flagKey - Feature flag key\n * @param distinctId - User ID or anonymous ID\n * @param options - Feature flag evaluation options\n * @returns Flag value (string, boolean, or undefined)\n *\n * @example\n * ```typescript\n * const variant = await subscriber.getFeatureFlag('experiment-variant', 'user-123');\n * // Returns: 'control' | 'test' | 'test-2' | undefined\n *\n * // With person properties\n * const variant = await subscriber.getFeatureFlag('premium-feature', 'user-123', {\n * personProperties: { plan: 'premium' }\n * });\n * ```\n */\n async getFeatureFlag(\n flagKey: string,\n distinctId: string,\n options?: FeatureFlagOptions,\n ): Promise<string | boolean | undefined> {\n if (!this.enabled) return undefined;\n await this.ensureInitialized();\n\n try {\n return await this.posthog?.getFeatureFlag(flagKey, distinctId, options as any);\n } catch (error) {\n this.config.onError?.(error as Error);\n return undefined;\n }\n }\n\n /**\n * Get all feature flags for a user\n *\n * @param distinctId - User ID or anonymous ID\n * @param options - Feature flag evaluation options\n * @returns Object mapping flag keys to their values\n *\n * @example\n * ```typescript\n * const flags = await subscriber.getAllFlags('user-123');\n * // Returns: { 'new-checkout': true, 'experiment-variant': 'test', ... }\n * ```\n */\n async getAllFlags(\n distinctId: string,\n options?: FeatureFlagOptions,\n ): Promise<Record<string, string | number | boolean>> {\n if (!this.enabled) return {};\n await this.ensureInitialized();\n\n try {\n const flags = await this.posthog?.getAllFlags(distinctId, options as any);\n return flags ?? {};\n } catch (error) {\n this.config.onError?.(error as Error);\n return {};\n }\n }\n\n /**\n * Reload feature flags from PostHog server\n *\n * Call this to refresh feature flag definitions without restarting.\n *\n * @example\n * ```typescript\n * await subscriber.reloadFeatureFlags();\n * ```\n */\n async reloadFeatureFlags(): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n try {\n await this.posthog?.reloadFeatureFlags();\n } catch (error) {\n this.config.onError?.(error as Error);\n }\n }\n\n // Person and Group Events\n\n /**\n * Identify a user and set their properties\n *\n * @param distinctId - User ID\n * @param properties - Person properties ($set, $set_once, or custom properties)\n *\n * @example\n * ```typescript\n * // Set properties (will update existing values)\n * await subscriber.identify('user-123', {\n * $set: {\n * email: 'user@example.com',\n * plan: 'premium'\n * }\n * });\n *\n * // Set properties only once (won't update if already exists)\n * await subscriber.identify('user-123', {\n * $set_once: {\n * signup_date: '2025-01-17'\n * }\n * });\n * ```\n */\n async identify(distinctId: string, properties?: PersonProperties): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n try {\n this.posthog?.identify({\n distinctId,\n properties,\n });\n } catch (error) {\n this.config.onError?.(error as Error);\n }\n }\n\n /**\n * Identify a group and set its properties\n *\n * Groups are useful for B2B SaaS to track organizations, teams, or accounts.\n *\n * @param groupType - Type of group (e.g., 'company', 'organization', 'team')\n * @param groupKey - Unique identifier for the group\n * @param properties - Group properties\n *\n * @example\n * ```typescript\n * await subscriber.groupIdentify('company', 'acme-corp', {\n * $set: {\n * name: 'Acme Corporation',\n * industry: 'saas',\n * employees: 500,\n * plan: 'enterprise'\n * }\n * });\n * ```\n */\n async groupIdentify(\n groupType: string,\n groupKey: string | number,\n properties?: Record<string, any>,\n ): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n try {\n this.posthog?.groupIdentify({\n groupType,\n groupKey: String(groupKey), // Convert to string for PostHog SDK\n properties,\n });\n } catch (error) {\n this.config.onError?.(error as Error);\n }\n }\n\n /**\n * Track an event with group context\n *\n * Use this to associate events with groups (e.g., organizations).\n *\n * @param name - Event name\n * @param attributes - Event attributes\n * @param groups - Group context (e.g., { company: 'acme-corp' })\n *\n * @example\n * ```typescript\n * await subscriber.trackEventWithGroups('feature.used', {\n * userId: 'user-123',\n * feature: 'advanced-events'\n * }, {\n * company: 'acme-corp'\n * });\n * ```\n */\n async trackEventWithGroups(\n name: string,\n attributes?: EventAttributes,\n groups?: Record<string, string | number>,\n ): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n const eventAttributes: EventAttributes = { ...attributes } as EventAttributes;\n if (groups) {\n (eventAttributes as any).groups = groups;\n }\n\n await this.trackEvent(name, eventAttributes);\n }\n\n /**\n * Capture an exception and send to PostHog error tracking.\n *\n * If using browser client (window.posthog), delegates to its captureException.\n * Otherwise, formats and sends via posthog-node capture API.\n */\n async captureException(\n error: unknown,\n options?: {\n distinctId?: string;\n additionalProperties?: Record<string, unknown>;\n },\n ): Promise<void> {\n if (!this.enabled) return;\n await this.ensureInitialized();\n\n try {\n if (this.isBrowserClient) {\n const browserProps = options?.additionalProperties\n ? this.redactProperties(options.additionalProperties)\n : undefined;\n (this.posthog as any)?.captureException?.(error, browserProps);\n return;\n }\n\n const exceptionList = errorToExceptionList(error, this.stringRedactor ?? undefined);\n const formatted = formatExceptionForPostHog(exceptionList, 'node:javascript', this.stringRedactor ?? undefined);\n\n const properties = {\n ...formatted,\n ...options?.additionalProperties,\n };\n\n this.posthog?.capture({\n distinctId: options?.distinctId || 'anonymous',\n event: '$exception',\n properties: this.redactProperties(properties),\n });\n } catch (error_) {\n this.config.onError?.(error_ as Error);\n }\n }\n\n /**\n * Flush pending events and clean up resources\n */\n async shutdown(): Promise<void> {\n await super.shutdown(); // Drain pending requests first\n await this.ensureInitialized();\n\n if (this.posthog) {\n try {\n await this.posthog.shutdown();\n } catch (error) {\n this.config.onError?.(error as Error);\n }\n }\n }\n\n /**\n * Handle errors with custom error handler\n */\n protected handleError(error: Error, payload: EventPayload): void {\n // Call basic onError if provided\n this.config.onError?.(error);\n\n // Call enhanced onErrorWithContext if provided\n if (this.config.onErrorWithContext) {\n this.config.onErrorWithContext({\n error,\n eventName: payload.name,\n eventType: payload.type,\n attributes: payload.attributes,\n subscriberName: this.name,\n });\n }\n\n super.handleError(error, payload);\n }\n}\n"],"mappings":"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"}
|