autotel-subscribers 27.0.1 → 28.0.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.
@@ -12,6 +12,7 @@ var https = require('https');
12
12
  var buffer = require('buffer');
13
13
  var util = require('util');
14
14
  var crypto2 = require('crypto');
15
+ var slowRedact = require('slow-redact');
15
16
 
16
17
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
17
18
 
@@ -40,6 +41,7 @@ var http__namespace = /*#__PURE__*/_interopNamespace(http);
40
41
  var https__namespace = /*#__PURE__*/_interopNamespace(https);
41
42
  var util__namespace = /*#__PURE__*/_interopNamespace(util);
42
43
  var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
44
+ var slowRedact__default = /*#__PURE__*/_interopDefault(slowRedact);
43
45
 
44
46
  var __create = Object.create;
45
47
  var __defProp = Object.defineProperty;
@@ -13855,7 +13857,70 @@ var EventSubscriber = class {
13855
13857
  }
13856
13858
  };
13857
13859
 
13858
- // src/posthog.ts
13860
+ // src/posthog-error-formatter.ts
13861
+ var MAX_CAUSE_DEPTH = 5;
13862
+ function formatExceptionForPostHog(exceptionList, platform = "web:javascript", redactor) {
13863
+ return {
13864
+ $exception_list: exceptionList.map((ex) => ({
13865
+ type: ex.type,
13866
+ value: redactor ? redactor(ex.value) : ex.value,
13867
+ mechanism: ex.mechanism,
13868
+ stacktrace: {
13869
+ frames: (ex.stacktrace?.frames || []).map((frame) => ({
13870
+ ...frame,
13871
+ abs_path: frame.abs_path && redactor ? redactor(frame.abs_path) : frame.abs_path,
13872
+ platform
13873
+ }))
13874
+ }
13875
+ }))
13876
+ };
13877
+ }
13878
+ function errorToExceptionList(input, redactor) {
13879
+ const error = input instanceof Error ? input : new Error(
13880
+ input === null || input === void 0 ? "Unknown error" : String(input)
13881
+ );
13882
+ const records = [];
13883
+ let current = error;
13884
+ let depth = 0;
13885
+ while (current && depth < MAX_CAUSE_DEPTH) {
13886
+ const value = current.message || "Unknown error";
13887
+ const frames = current.stack ? parseStackBasic(current.stack) : void 0;
13888
+ records.push({
13889
+ type: current.name || "Error",
13890
+ value: redactor ? redactor(value) : value,
13891
+ mechanism: { type: "manual", handled: true },
13892
+ stacktrace: frames ? {
13893
+ frames: redactor ? frames.map((f) => ({
13894
+ ...f,
13895
+ abs_path: f.abs_path ? redactor(f.abs_path) : f.abs_path
13896
+ })) : frames
13897
+ } : void 0
13898
+ });
13899
+ current = current.cause instanceof Error ? current.cause : void 0;
13900
+ depth++;
13901
+ }
13902
+ return records.toReversed();
13903
+ }
13904
+ function parseStackBasic(stack) {
13905
+ const lines = stack.split("\n");
13906
+ const frames = [];
13907
+ const re = /^\s*at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/;
13908
+ for (const line of lines) {
13909
+ const match = line.trim().match(re);
13910
+ if (match) {
13911
+ const [, fn, absPath, lineStr, colStr] = match;
13912
+ frames.push({
13913
+ function: fn || void 0,
13914
+ abs_path: absPath,
13915
+ filename: absPath.split("/").pop() || absPath,
13916
+ lineno: Number.parseInt(lineStr, 10),
13917
+ colno: Number.parseInt(colStr, 10),
13918
+ in_app: !absPath.includes("node_modules")
13919
+ });
13920
+ }
13921
+ }
13922
+ return frames;
13923
+ }
13859
13924
  var PostHogSubscriber = class extends EventSubscriber {
13860
13925
  name = "PostHogSubscriber";
13861
13926
  version = "2.0.0";
@@ -13864,6 +13929,8 @@ var PostHogSubscriber = class extends EventSubscriber {
13864
13929
  initPromise = null;
13865
13930
  /** True when using browser's window.posthog (different API signature) */
13866
13931
  isBrowserClient = false;
13932
+ pathRedactor = null;
13933
+ stringRedactor = null;
13867
13934
  constructor(config) {
13868
13935
  super();
13869
13936
  if (config.serverless) {
@@ -13885,6 +13952,15 @@ var PostHogSubscriber = class extends EventSubscriber {
13885
13952
  filterUndefinedValues: true,
13886
13953
  ...config
13887
13954
  };
13955
+ if (this.config.redactPaths && this.config.redactPaths.length > 0) {
13956
+ this.pathRedactor = slowRedact__default.default({
13957
+ paths: this.config.redactPaths,
13958
+ serialize: false
13959
+ });
13960
+ }
13961
+ if (this.config.stringRedactor) {
13962
+ this.stringRedactor = this.config.stringRedactor;
13963
+ }
13888
13964
  if (this.enabled) {
13889
13965
  this.initPromise = this.initialize();
13890
13966
  }
@@ -13944,6 +14020,50 @@ var PostHogSubscriber = class extends EventSubscriber {
13944
14020
  extractDistinctId(attributes) {
13945
14021
  return attributes?.userId || attributes?.user_id || "anonymous";
13946
14022
  }
14023
+ redactProperties(properties) {
14024
+ let result = properties;
14025
+ if (this.pathRedactor) {
14026
+ result = this.pathRedactor(properties);
14027
+ }
14028
+ if (this.stringRedactor) {
14029
+ result = this.redactStringValues(result);
14030
+ }
14031
+ return result;
14032
+ }
14033
+ redactStringValues(obj) {
14034
+ const result = {};
14035
+ for (const [key, value] of Object.entries(obj)) {
14036
+ if (typeof value === "string") {
14037
+ result[key] = this.stringRedactor(value);
14038
+ } else if (Array.isArray(value)) {
14039
+ result[key] = this.redactArray(value);
14040
+ } else if (value !== null && typeof value === "object") {
14041
+ result[key] = this.redactStringValues(value);
14042
+ } else {
14043
+ result[key] = value;
14044
+ }
14045
+ }
14046
+ return result;
14047
+ }
14048
+ redactArray(arr) {
14049
+ return arr.map((item) => {
14050
+ if (typeof item === "string") {
14051
+ return this.stringRedactor(item);
14052
+ } else if (Array.isArray(item)) {
14053
+ return this.redactArray(item);
14054
+ } else if (item !== null && typeof item === "object") {
14055
+ return this.redactStringValues(item);
14056
+ }
14057
+ return item;
14058
+ });
14059
+ }
14060
+ /**
14061
+ * Set the string redactor. Called by autotel init() when attributeRedactor is configured.
14062
+ * Can also be called manually.
14063
+ */
14064
+ setStringRedactor(redactor) {
14065
+ this.stringRedactor = redactor;
14066
+ }
13947
14067
  /**
13948
14068
  * Send payload to PostHog
13949
14069
  *
@@ -13995,14 +14115,39 @@ var PostHogSubscriber = class extends EventSubscriber {
13995
14115
  properties.$linked_trace_ids = payload.autotel.linked_trace_ids;
13996
14116
  }
13997
14117
  }
14118
+ const redactedProperties = this.redactProperties(properties);
14119
+ if (payload.attributes?.["exception.list"]) {
14120
+ try {
14121
+ const exceptionList = JSON.parse(payload.attributes["exception.list"]);
14122
+ const formatted = formatExceptionForPostHog(
14123
+ exceptionList,
14124
+ void 0,
14125
+ this.stringRedactor ?? void 0
14126
+ );
14127
+ const exceptionProperties = {
14128
+ ...redactedProperties,
14129
+ ...formatted
14130
+ };
14131
+ if (this.isBrowserClient) {
14132
+ this.posthog?.capture("$exception", exceptionProperties);
14133
+ } else {
14134
+ this.posthog?.capture({
14135
+ distinctId: this.extractDistinctId(filteredAttributes),
14136
+ event: "$exception",
14137
+ properties: exceptionProperties
14138
+ });
14139
+ }
14140
+ } catch {
14141
+ }
14142
+ }
13998
14143
  const distinctId = this.extractDistinctId(filteredAttributes);
13999
14144
  if (this.isBrowserClient) {
14000
- this.posthog?.capture(payload.name, properties);
14145
+ this.posthog?.capture(payload.name, redactedProperties);
14001
14146
  } else {
14002
14147
  const capturePayload = {
14003
14148
  distinctId,
14004
14149
  event: payload.name,
14005
- properties
14150
+ properties: redactedProperties
14006
14151
  };
14007
14152
  if (filteredAttributes?.groups) {
14008
14153
  capturePayload.groups = filteredAttributes.groups;
@@ -14211,6 +14356,36 @@ var PostHogSubscriber = class extends EventSubscriber {
14211
14356
  }
14212
14357
  await this.trackEvent(name, eventAttributes);
14213
14358
  }
14359
+ /**
14360
+ * Capture an exception and send to PostHog error tracking.
14361
+ *
14362
+ * If using browser client (window.posthog), delegates to its captureException.
14363
+ * Otherwise, formats and sends via posthog-node capture API.
14364
+ */
14365
+ async captureException(error, options) {
14366
+ if (!this.enabled) return;
14367
+ await this.ensureInitialized();
14368
+ try {
14369
+ if (this.isBrowserClient) {
14370
+ const browserProps = options?.additionalProperties ? this.redactProperties(options.additionalProperties) : void 0;
14371
+ this.posthog?.captureException?.(error, browserProps);
14372
+ return;
14373
+ }
14374
+ const exceptionList = errorToExceptionList(error, this.stringRedactor ?? void 0);
14375
+ const formatted = formatExceptionForPostHog(exceptionList, "node:javascript", this.stringRedactor ?? void 0);
14376
+ const properties = {
14377
+ ...formatted,
14378
+ ...options?.additionalProperties
14379
+ };
14380
+ this.posthog?.capture({
14381
+ distinctId: options?.distinctId || "anonymous",
14382
+ event: "$exception",
14383
+ properties: this.redactProperties(properties)
14384
+ });
14385
+ } catch (error_) {
14386
+ this.config.onError?.(error_);
14387
+ }
14388
+ }
14214
14389
  /**
14215
14390
  * Flush pending events and clean up resources
14216
14391
  */