posthog-node 3.2.0 → 3.3.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/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 3.3.0 - 2024-01-02
2
+
3
+ 1. Adds PostHogSentryIntegration to allow automatic capturing of exceptions reported via the @sentry/node package
4
+
5
+ # 3.2.1 - 2023-12-15
6
+
7
+ 1. Fixes issue where a background refresh of feature flags could throw an unhandled error. It now emits to be detected by `.on('error', ...)`
8
+
1
9
  # 3.2.0 - 2023-12-05
2
10
 
3
11
  1. Fixes issues with Axios imports for non-node environments like Cloudflare workers
package/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './src/posthog-node'
2
+ export * from './src/extensions/sentry-integration'
package/lib/index.cjs.js CHANGED
@@ -158,7 +158,7 @@ function __spreadArray(to, from, pack) {
158
158
  return to.concat(ar || Array.prototype.slice.call(from));
159
159
  }
160
160
 
161
- var version = "3.2.0";
161
+ var version = "3.3.0";
162
162
 
163
163
  var PostHogPersistedProperty;
164
164
  (function (PostHogPersistedProperty) {
@@ -1004,7 +1004,7 @@ var PostHogCoreStateless = /** @class */ (function () {
1004
1004
  var _this = this;
1005
1005
  var _a;
1006
1006
  if (this.optedOut) {
1007
- this._events.emit(type, "Library is disabled. Not sending event. To re-enable, call posthog.enable()");
1007
+ this._events.emit(type, "Library is disabled. Not sending event. To re-enable, call posthog.optIn()");
1008
1008
  return;
1009
1009
  }
1010
1010
  var message = __assign(__assign({}, _message), { type: type, library: this.getLibraryId(), library_version: this.getLibraryVersion(), timestamp: (options === null || options === void 0 ? void 0 : options.timestamp) ? options === null || options === void 0 ? void 0 : options.timestamp : currentISOTime() });
@@ -1747,6 +1747,7 @@ function () {
1747
1747
  this.poller = undefined; // NOTE: as any is required here as the AbortSignal typing is slightly misaligned but works just fine
1748
1748
 
1749
1749
  this.fetch = options.fetch || fetch$1;
1750
+ this.onError = options.onError;
1750
1751
  void this.loadFeatureFlags();
1751
1752
  }
1752
1753
 
@@ -1906,10 +1907,13 @@ function () {
1906
1907
  this.featureFlags.map(function (flag) {
1907
1908
  return __awaiter(_this, void 0, void 0, function () {
1908
1909
  var matchValue, matchPayload, e_1;
1909
- return __generator(this, function (_a) {
1910
- switch (_a.label) {
1910
+
1911
+ var _a;
1912
+
1913
+ return __generator(this, function (_b) {
1914
+ switch (_b.label) {
1911
1915
  case 0:
1912
- _a.trys.push([0, 2,, 3]);
1916
+ _b.trys.push([0, 2,, 3]);
1913
1917
 
1914
1918
  matchValue = this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties);
1915
1919
  response[flag.key] = matchValue;
@@ -1918,7 +1922,7 @@ function () {
1918
1922
  , this.computeFeatureFlagPayloadLocally(flag.key, matchValue)];
1919
1923
 
1920
1924
  case 1:
1921
- matchPayload = _a.sent();
1925
+ matchPayload = _b.sent();
1922
1926
 
1923
1927
  if (matchPayload) {
1924
1928
  payloads[flag.key] = matchPayload;
@@ -1929,10 +1933,10 @@ function () {
1929
1933
  , 3];
1930
1934
 
1931
1935
  case 2:
1932
- e_1 = _a.sent();
1936
+ e_1 = _b.sent();
1933
1937
 
1934
1938
  if (e_1 instanceof InconclusiveMatchError) ; else if (e_1 instanceof Error) {
1935
- console.error("Error computing flag locally: ".concat(flag.key, ": ").concat(e_1));
1939
+ (_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, new Error("Error computing flag locally: ".concat(flag.key, ": ").concat(e_1)));
1936
1940
  }
1937
1941
 
1938
1942
  fallbackToDecide = true;
@@ -2170,13 +2174,15 @@ function () {
2170
2174
  };
2171
2175
 
2172
2176
  FeatureFlagsPoller.prototype._loadFeatureFlags = function () {
2177
+ var _a;
2178
+
2173
2179
  return __awaiter(this, void 0, void 0, function () {
2174
2180
  var res, responseJson, err_1;
2175
2181
 
2176
2182
  var _this = this;
2177
2183
 
2178
- return __generator(this, function (_a) {
2179
- switch (_a.label) {
2184
+ return __generator(this, function (_b) {
2185
+ switch (_b.label) {
2180
2186
  case 0:
2181
2187
  if (this.poller) {
2182
2188
  clearTimeout(this.poller);
@@ -2186,17 +2192,17 @@ function () {
2186
2192
  this.poller = setTimeout(function () {
2187
2193
  return _this._loadFeatureFlags();
2188
2194
  }, this.pollingInterval);
2189
- _a.label = 1;
2195
+ _b.label = 1;
2190
2196
 
2191
2197
  case 1:
2192
- _a.trys.push([1, 4,, 5]);
2198
+ _b.trys.push([1, 4,, 5]);
2193
2199
 
2194
2200
  return [4
2195
2201
  /*yield*/
2196
2202
  , this._requestFeatureFlagDefinitions()];
2197
2203
 
2198
2204
  case 2:
2199
- res = _a.sent();
2205
+ res = _b.sent();
2200
2206
 
2201
2207
  if (res && res.status === 401) {
2202
2208
  throw new ClientError("Your personalApiKey is invalid. Are you sure you're not using your Project API key? More information: https://posthog.com/docs/api/overview");
@@ -2215,7 +2221,7 @@ function () {
2215
2221
  , res.json()];
2216
2222
 
2217
2223
  case 3:
2218
- responseJson = _a.sent();
2224
+ responseJson = _b.sent();
2219
2225
 
2220
2226
  if (!('flags' in responseJson)) {
2221
2227
  console.error("Invalid response when getting feature flags: ".concat(JSON.stringify(responseJson)));
@@ -2233,11 +2239,11 @@ function () {
2233
2239
  , 5];
2234
2240
 
2235
2241
  case 4:
2236
- err_1 = _a.sent(); // if an error that is not an instance of ClientError is thrown
2242
+ err_1 = _b.sent(); // if an error that is not an instance of ClientError is thrown
2237
2243
  // we silently ignore the error when reloading feature flags
2238
2244
 
2239
2245
  if (err_1 instanceof ClientError) {
2240
- throw err_1;
2246
+ (_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, err_1);
2241
2247
  }
2242
2248
 
2243
2249
  return [3
@@ -2562,7 +2568,10 @@ function (_super) {
2562
2568
  projectApiKey: apiKey,
2563
2569
  timeout: (_a = options.requestTimeout) !== null && _a !== void 0 ? _a : 10000,
2564
2570
  host: _this.host,
2565
- fetch: options.fetch
2571
+ fetch: options.fetch,
2572
+ onError: function (err) {
2573
+ _this._events.emit('error', err);
2574
+ }
2566
2575
  });
2567
2576
  }
2568
2577
 
@@ -3000,5 +3009,95 @@ function (_super) {
3000
3009
  return PostHog;
3001
3010
  }(PostHogCoreStateless);
3002
3011
 
3012
+ /**
3013
+ * Integrate Sentry with PostHog. This will add a direct link to the person in Sentry, and an $exception event in PostHog.
3014
+ *
3015
+ * ### Usage
3016
+ *
3017
+ * Sentry.init({
3018
+ * dsn: 'https://example',
3019
+ * integrations: [
3020
+ * new PostHogSentryIntegration(posthog)
3021
+ * ]
3022
+ * })
3023
+ *
3024
+ * Sentry.setTag(PostHogSentryIntegration.POSTHOG_ID_TAG, 'some distinct id');
3025
+ *
3026
+ * @param {Object} [posthog] The posthog object
3027
+ * @param {string} [organization] Optional: The Sentry organization, used to send a direct link from PostHog to Sentry
3028
+ * @param {Number} [projectId] Optional: The Sentry project id, used to send a direct link from PostHog to Sentry
3029
+ * @param {string} [prefix] Optional: Url of a self-hosted sentry instance (default: https://sentry.io/organizations/)
3030
+ */
3031
+ var PostHogSentryIntegration =
3032
+ /** @class */
3033
+ function () {
3034
+ function PostHogSentryIntegration(posthog, posthogHost, organization, prefix) {
3035
+ var _a;
3036
+
3037
+ this.posthog = posthog;
3038
+ this.posthogHost = posthogHost;
3039
+ this.organization = organization;
3040
+ this.prefix = prefix;
3041
+ this.name = 'posthog-node';
3042
+ this.posthogHost = (_a = posthog.options.host) !== null && _a !== void 0 ? _a : 'https://app.posthog.com';
3043
+ }
3044
+
3045
+ PostHogSentryIntegration.prototype.setupOnce = function (addGlobalEventProcessor, getCurrentHub) {
3046
+ var _this = this;
3047
+
3048
+ addGlobalEventProcessor(function (event) {
3049
+ var _a, _b, _c, _d, _e, _f, _g, _h;
3050
+
3051
+ if (((_a = event.exception) === null || _a === void 0 ? void 0 : _a.values) === undefined || event.exception.values.length === 0) {
3052
+ return event;
3053
+ }
3054
+
3055
+ if (!event.tags) {
3056
+ event.tags = {};
3057
+ }
3058
+
3059
+ var sentry = getCurrentHub(); // Get the PostHog user ID from a specific tag, which users can set on their Sentry scope as they need.
3060
+
3061
+ var userId = event.tags[PostHogSentryIntegration.POSTHOG_ID_TAG];
3062
+
3063
+ if (userId === undefined) {
3064
+ // If we can't find a user ID, don't bother linking the event. We won't be able to send anything meaningful to PostHog without it.
3065
+ return event;
3066
+ }
3067
+
3068
+ event.tags['PostHog Person URL'] = new URL("/person/".concat(userId), _this.posthogHost).toString();
3069
+ var properties = {
3070
+ // PostHog Exception Properties
3071
+ $exception_message: (_b = event.exception.values[0]) === null || _b === void 0 ? void 0 : _b.value,
3072
+ $exception_type: (_c = event.exception.values[0]) === null || _c === void 0 ? void 0 : _c.type,
3073
+ $exception_personURL: event.tags['PostHog Person URL'],
3074
+ // Sentry Exception Properties
3075
+ $sentry_event_id: event.event_id,
3076
+ $sentry_exception: event.exception,
3077
+ $sentry_exception_message: (_d = event.exception.values[0]) === null || _d === void 0 ? void 0 : _d.value,
3078
+ $sentry_exception_type: (_e = event.exception.values[0]) === null || _e === void 0 ? void 0 : _e.type,
3079
+ $sentry_tags: event.tags
3080
+ };
3081
+ var projectId = (_g = (_f = sentry.getClient()) === null || _f === void 0 ? void 0 : _f.getDsn()) === null || _g === void 0 ? void 0 : _g.projectId;
3082
+
3083
+ if (_this.organization !== undefined && projectId !== undefined && event.event_id !== undefined) {
3084
+ properties.$sentry_url = "".concat((_h = _this.prefix) !== null && _h !== void 0 ? _h : 'https://sentry.io/organizations', "/").concat(_this.organization, "/issues/?project=").concat(projectId, "&query=").concat(event.event_id);
3085
+ }
3086
+
3087
+ _this.posthog.capture({
3088
+ event: '$exception',
3089
+ distinctId: userId,
3090
+ properties: properties
3091
+ });
3092
+
3093
+ return event;
3094
+ });
3095
+ };
3096
+
3097
+ PostHogSentryIntegration.POSTHOG_ID_TAG = 'posthog_distinct_id';
3098
+ return PostHogSentryIntegration;
3099
+ }();
3100
+
3003
3101
  exports.PostHog = PostHog;
3102
+ exports.PostHogSentryIntegration = PostHogSentryIntegration;
3004
3103
  //# sourceMappingURL=index.cjs.js.map