posthog-node 4.2.3 → 4.3.1
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 +8 -0
- package/lib/index.cjs.js +141 -75
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +19 -27
- package/lib/index.esm.js +139 -76
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-node/src/extensions/sentry-integration.d.ts +26 -14
- package/package.json +1 -1
- package/src/extensions/sentry-integration.ts +142 -76
- package/src/posthog-node.ts +51 -30
- package/test/extensions/sentry-integration.spec.ts +13 -3
- package/test/posthog-node.spec.ts +35 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Next
|
|
2
2
|
|
|
3
|
+
# 4.3.1 - 2024-11-26
|
|
4
|
+
|
|
5
|
+
1. Fix bug where this SDK incorrectly sent `$feature_flag_called` events with null values when using `getFeatureFlagPayload`.
|
|
6
|
+
|
|
7
|
+
# 4.3.0 - 2024-11-25
|
|
8
|
+
|
|
9
|
+
1. Add Sentry v8 support to the Sentry integration
|
|
10
|
+
|
|
3
11
|
# 4.2.3 - 2024-11-21
|
|
4
12
|
|
|
5
13
|
1. fix: identify method allows passing a $set_once object
|
package/lib/index.cjs.js
CHANGED
|
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var rusha = require('rusha');
|
|
6
6
|
|
|
7
|
-
var version = "4.
|
|
7
|
+
var version = "4.3.1";
|
|
8
8
|
|
|
9
9
|
var PostHogPersistedProperty;
|
|
10
10
|
(function (PostHogPersistedProperty) {
|
|
@@ -2234,44 +2234,70 @@ class PostHog extends PostHogCoreStateless {
|
|
|
2234
2234
|
async getFeatureFlagPayload(key, distinctId, matchValue, options) {
|
|
2235
2235
|
const {
|
|
2236
2236
|
groups,
|
|
2237
|
-
disableGeoip
|
|
2238
|
-
|
|
2239
|
-
let {
|
|
2240
|
-
onlyEvaluateLocally,
|
|
2241
|
-
sendFeatureFlagEvents,
|
|
2237
|
+
disableGeoip,
|
|
2238
|
+
onlyEvaluateLocally = false,
|
|
2242
2239
|
personProperties,
|
|
2243
2240
|
groupProperties
|
|
2244
2241
|
} = options || {};
|
|
2245
|
-
const
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
if (!matchValue) {
|
|
2242
|
+
const {
|
|
2243
|
+
allPersonProperties,
|
|
2244
|
+
allGroupProperties
|
|
2245
|
+
} = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
|
|
2246
|
+
if (matchValue === undefined) {
|
|
2251
2247
|
matchValue = await this.getFeatureFlag(key, distinctId, {
|
|
2252
2248
|
...options,
|
|
2253
|
-
onlyEvaluateLocally: true
|
|
2249
|
+
onlyEvaluateLocally: true,
|
|
2250
|
+
sendFeatureFlagEvents: false
|
|
2254
2251
|
});
|
|
2255
2252
|
}
|
|
2253
|
+
let response;
|
|
2254
|
+
let payload;
|
|
2256
2255
|
if (matchValue) {
|
|
2257
|
-
response =
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
}
|
|
2263
|
-
if (sendFeatureFlagEvents == undefined) {
|
|
2264
|
-
sendFeatureFlagEvents = true;
|
|
2265
|
-
}
|
|
2266
|
-
// set defaults
|
|
2267
|
-
if (onlyEvaluateLocally == undefined) {
|
|
2268
|
-
onlyEvaluateLocally = false;
|
|
2256
|
+
response = matchValue;
|
|
2257
|
+
payload = await this.featureFlagsPoller?.computeFeatureFlagPayloadLocally(key, matchValue);
|
|
2258
|
+
} else {
|
|
2259
|
+
response = undefined;
|
|
2260
|
+
payload = undefined;
|
|
2269
2261
|
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2262
|
+
// Determine if the payload was evaluated locally
|
|
2263
|
+
const payloadWasLocallyEvaluated = payload !== undefined;
|
|
2264
|
+
// Fetch final flags and payloads either locally or from the remote server
|
|
2265
|
+
let fetchedOrLocalFlags;
|
|
2266
|
+
let fetchedOrLocalPayloads;
|
|
2267
|
+
if (payloadWasLocallyEvaluated || onlyEvaluateLocally) {
|
|
2268
|
+
if (response !== undefined) {
|
|
2269
|
+
fetchedOrLocalFlags = {
|
|
2270
|
+
[key]: response
|
|
2271
|
+
};
|
|
2272
|
+
fetchedOrLocalPayloads = {
|
|
2273
|
+
[key]: payload
|
|
2274
|
+
};
|
|
2275
|
+
} else {
|
|
2276
|
+
fetchedOrLocalFlags = {};
|
|
2277
|
+
fetchedOrLocalPayloads = {};
|
|
2278
|
+
}
|
|
2279
|
+
} else {
|
|
2280
|
+
const fetchedData = await super.getFeatureFlagsAndPayloadsStateless(distinctId, groups, allPersonProperties, allGroupProperties, disableGeoip);
|
|
2281
|
+
fetchedOrLocalFlags = fetchedData.flags || {};
|
|
2282
|
+
fetchedOrLocalPayloads = fetchedData.payloads || {};
|
|
2273
2283
|
}
|
|
2274
|
-
|
|
2284
|
+
const finalResponse = fetchedOrLocalFlags[key];
|
|
2285
|
+
const finalPayload = fetchedOrLocalPayloads[key];
|
|
2286
|
+
const finalLocallyEvaluated = payloadWasLocallyEvaluated;
|
|
2287
|
+
this.capture({
|
|
2288
|
+
distinctId,
|
|
2289
|
+
event: '$feature_flag_called',
|
|
2290
|
+
properties: {
|
|
2291
|
+
$feature_flag: key,
|
|
2292
|
+
$feature_flag_response: finalResponse,
|
|
2293
|
+
$feature_flag_payload: finalPayload,
|
|
2294
|
+
locally_evaluated: finalLocallyEvaluated,
|
|
2295
|
+
[`$feature/${key}`]: finalResponse
|
|
2296
|
+
},
|
|
2297
|
+
groups,
|
|
2298
|
+
disableGeoip
|
|
2299
|
+
});
|
|
2300
|
+
return finalPayload;
|
|
2275
2301
|
}
|
|
2276
2302
|
async isFeatureEnabled(key, distinctId, options) {
|
|
2277
2303
|
const feat = await this.getFeatureFlag(key, distinctId, options);
|
|
@@ -2365,6 +2391,9 @@ class PostHog extends PostHogCoreStateless {
|
|
|
2365
2391
|
}
|
|
2366
2392
|
}
|
|
2367
2393
|
|
|
2394
|
+
/**
|
|
2395
|
+
* @file Adapted from [posthog-js](https://github.com/PostHog/posthog-js/blob/8157df935a4d0e71d2fefef7127aa85ee51c82d1/src/extensions/sentry-integration.ts) with modifications for the Node SDK.
|
|
2396
|
+
*/
|
|
2368
2397
|
/**
|
|
2369
2398
|
* Integrate Sentry with PostHog. This will add a direct link to the person in Sentry, and an $exception event in PostHog.
|
|
2370
2399
|
*
|
|
@@ -2383,59 +2412,96 @@ class PostHog extends PostHogCoreStateless {
|
|
|
2383
2412
|
* @param {string} [organization] Optional: The Sentry organization, used to send a direct link from PostHog to Sentry
|
|
2384
2413
|
* @param {Number} [projectId] Optional: The Sentry project id, used to send a direct link from PostHog to Sentry
|
|
2385
2414
|
* @param {string} [prefix] Optional: Url of a self-hosted sentry instance (default: https://sentry.io/organizations/)
|
|
2415
|
+
* @param {SeverityLevel[] | '*'} [severityAllowList] Optional: send events matching the provided levels. Use '*' to send all events (default: ['error'])
|
|
2386
2416
|
*/
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
if (event.exception?.values === undefined || event.exception.values.length === 0) {
|
|
2399
|
-
return event;
|
|
2400
|
-
}
|
|
2401
|
-
if (!event.tags) {
|
|
2402
|
-
event.tags = {};
|
|
2403
|
-
}
|
|
2404
|
-
const sentry = getCurrentHub();
|
|
2405
|
-
// Get the PostHog user ID from a specific tag, which users can set on their Sentry scope as they need.
|
|
2406
|
-
const userId = event.tags[PostHogSentryIntegration.POSTHOG_ID_TAG];
|
|
2407
|
-
if (userId === undefined) {
|
|
2408
|
-
// 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.
|
|
2409
|
-
return event;
|
|
2410
|
-
}
|
|
2411
|
-
event.tags['PostHog Person URL'] = new URL(`/person/${userId}`, this.posthogHost).toString();
|
|
2412
|
-
const properties = {
|
|
2413
|
-
// PostHog Exception Properties
|
|
2414
|
-
$exception_message: event.exception.values[0]?.value,
|
|
2415
|
-
$exception_type: event.exception.values[0]?.type,
|
|
2416
|
-
$exception_personURL: event.tags['PostHog Person URL'],
|
|
2417
|
-
// Sentry Exception Properties
|
|
2418
|
-
$sentry_event_id: event.event_id,
|
|
2419
|
-
$sentry_exception: event.exception,
|
|
2420
|
-
$sentry_exception_message: event.exception.values[0]?.value,
|
|
2421
|
-
$sentry_exception_type: event.exception.values[0]?.type,
|
|
2422
|
-
$sentry_tags: event.tags
|
|
2423
|
-
};
|
|
2424
|
-
const projectId = sentry.getClient()?.getDsn()?.projectId;
|
|
2425
|
-
if (this.organization !== undefined && projectId !== undefined && event.event_id !== undefined) {
|
|
2426
|
-
properties.$sentry_url = `${this.prefix ?? 'https://sentry.io/organizations'}/${this.organization}/issues/?project=${projectId}&query=${event.event_id}`;
|
|
2427
|
-
}
|
|
2428
|
-
this.posthog.capture({
|
|
2429
|
-
event: '$exception',
|
|
2430
|
-
distinctId: userId,
|
|
2431
|
-
properties
|
|
2432
|
-
});
|
|
2417
|
+
const severityLevels = ['fatal', 'error', 'warning', 'log', 'info', 'debug'];
|
|
2418
|
+
const NAME = 'posthog-node';
|
|
2419
|
+
function createEventProcessor(_posthog, {
|
|
2420
|
+
organization,
|
|
2421
|
+
projectId,
|
|
2422
|
+
prefix,
|
|
2423
|
+
severityAllowList = ['error']
|
|
2424
|
+
} = {}) {
|
|
2425
|
+
return event => {
|
|
2426
|
+
const shouldProcessLevel = severityAllowList === '*' || severityAllowList.includes(event.level);
|
|
2427
|
+
if (!shouldProcessLevel) {
|
|
2433
2428
|
return event;
|
|
2429
|
+
}
|
|
2430
|
+
if (!event.tags) {
|
|
2431
|
+
event.tags = {};
|
|
2432
|
+
}
|
|
2433
|
+
// Get the PostHog user ID from a specific tag, which users can set on their Sentry scope as they need.
|
|
2434
|
+
const userId = event.tags[PostHogSentryIntegration.POSTHOG_ID_TAG];
|
|
2435
|
+
if (userId === undefined) {
|
|
2436
|
+
// 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.
|
|
2437
|
+
return event;
|
|
2438
|
+
}
|
|
2439
|
+
const uiHost = _posthog.options.host ?? 'https://us.i.posthog.com';
|
|
2440
|
+
const personUrl = new URL(`/project/${_posthog.apiKey}/person/${userId}`, uiHost).toString();
|
|
2441
|
+
event.tags['PostHog Person URL'] = personUrl;
|
|
2442
|
+
const exceptions = event.exception?.values || [];
|
|
2443
|
+
exceptions.map(exception => {
|
|
2444
|
+
if (exception.stacktrace) {
|
|
2445
|
+
exception.stacktrace.type = 'raw';
|
|
2446
|
+
}
|
|
2447
|
+
});
|
|
2448
|
+
const properties = {
|
|
2449
|
+
// PostHog Exception Properties,
|
|
2450
|
+
$exception_message: exceptions[0]?.value || event.message,
|
|
2451
|
+
$exception_type: exceptions[0]?.type,
|
|
2452
|
+
$exception_personURL: personUrl,
|
|
2453
|
+
$exception_level: event.level,
|
|
2454
|
+
$exception_list: exceptions,
|
|
2455
|
+
// Sentry Exception Properties
|
|
2456
|
+
$sentry_event_id: event.event_id,
|
|
2457
|
+
$sentry_exception: event.exception,
|
|
2458
|
+
$sentry_exception_message: exceptions[0]?.value || event.message,
|
|
2459
|
+
$sentry_exception_type: exceptions[0]?.type,
|
|
2460
|
+
$sentry_tags: event.tags
|
|
2461
|
+
};
|
|
2462
|
+
if (organization && projectId) {
|
|
2463
|
+
properties['$sentry_url'] = (prefix || 'https://sentry.io/organizations/') + organization + '/issues/?project=' + projectId + '&query=' + event.event_id;
|
|
2464
|
+
}
|
|
2465
|
+
_posthog.capture({
|
|
2466
|
+
event: '$exception',
|
|
2467
|
+
distinctId: userId,
|
|
2468
|
+
properties
|
|
2434
2469
|
});
|
|
2470
|
+
return event;
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
// V8 integration - function based
|
|
2474
|
+
function sentryIntegration(_posthog, options) {
|
|
2475
|
+
const processor = createEventProcessor(_posthog, options);
|
|
2476
|
+
return {
|
|
2477
|
+
name: NAME,
|
|
2478
|
+
processEvent(event) {
|
|
2479
|
+
return processor(event);
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
}
|
|
2483
|
+
// V7 integration - class based
|
|
2484
|
+
class PostHogSentryIntegration {
|
|
2485
|
+
constructor(_posthog, organization, prefix, severityAllowList) {
|
|
2486
|
+
this.name = NAME;
|
|
2487
|
+
// setupOnce gets called by Sentry when it intializes the plugin
|
|
2488
|
+
this.name = NAME;
|
|
2489
|
+
this.setupOnce = function (addGlobalEventProcessor, getCurrentHub) {
|
|
2490
|
+
const projectId = getCurrentHub()?.getClient()?.getDsn()?.projectId;
|
|
2491
|
+
addGlobalEventProcessor(createEventProcessor(_posthog, {
|
|
2492
|
+
organization,
|
|
2493
|
+
projectId,
|
|
2494
|
+
prefix,
|
|
2495
|
+
severityAllowList
|
|
2496
|
+
}));
|
|
2497
|
+
};
|
|
2435
2498
|
}
|
|
2436
2499
|
}
|
|
2437
2500
|
PostHogSentryIntegration.POSTHOG_ID_TAG = 'posthog_distinct_id';
|
|
2438
2501
|
|
|
2439
2502
|
exports.PostHog = PostHog;
|
|
2440
2503
|
exports.PostHogSentryIntegration = PostHogSentryIntegration;
|
|
2504
|
+
exports.createEventProcessor = createEventProcessor;
|
|
2505
|
+
exports.sentryIntegration = sentryIntegration;
|
|
2506
|
+
exports.severityLevels = severityLevels;
|
|
2441
2507
|
//# sourceMappingURL=index.cjs.js.map
|