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/lib/index.d.ts
CHANGED
|
@@ -435,40 +435,32 @@ declare class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
435
435
|
* @file Adapted from [posthog-js](https://github.com/PostHog/posthog-js/blob/8157df935a4d0e71d2fefef7127aa85ee51c82d1/src/extensions/sentry-integration.ts) with modifications for the Node SDK.
|
|
436
436
|
*/
|
|
437
437
|
|
|
438
|
+
declare const severityLevels: readonly ["fatal", "error", "warning", "log", "info", "debug"];
|
|
439
|
+
declare type SeverityLevel = (typeof severityLevels)[number];
|
|
440
|
+
type _SentryEvent = any;
|
|
438
441
|
type _SentryEventProcessor = any;
|
|
439
442
|
type _SentryHub = any;
|
|
440
443
|
interface _SentryIntegration {
|
|
444
|
+
name: string;
|
|
445
|
+
processEvent(event: _SentryEvent): _SentryEvent;
|
|
446
|
+
}
|
|
447
|
+
interface _SentryIntegrationClass {
|
|
441
448
|
name: string;
|
|
442
449
|
setupOnce(addGlobalEventProcessor: (callback: _SentryEventProcessor) => void, getCurrentHub: () => _SentryHub): void;
|
|
443
450
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
*
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
* ]
|
|
454
|
-
* })
|
|
455
|
-
*
|
|
456
|
-
* Sentry.setTag(PostHogSentryIntegration.POSTHOG_ID_TAG, 'some distinct id');
|
|
457
|
-
*
|
|
458
|
-
* @param {Object} [posthog] The posthog object
|
|
459
|
-
* @param {string} [organization] Optional: The Sentry organization, used to send a direct link from PostHog to Sentry
|
|
460
|
-
* @param {Number} [projectId] Optional: The Sentry project id, used to send a direct link from PostHog to Sentry
|
|
461
|
-
* @param {string} [prefix] Optional: Url of a self-hosted sentry instance (default: https://sentry.io/organizations/)
|
|
462
|
-
*/
|
|
463
|
-
declare class PostHogSentryIntegration implements _SentryIntegration {
|
|
464
|
-
private readonly posthog;
|
|
465
|
-
private readonly posthogHost?;
|
|
466
|
-
private readonly organization?;
|
|
467
|
-
private readonly prefix?;
|
|
451
|
+
type SentryIntegrationOptions = {
|
|
452
|
+
organization?: string;
|
|
453
|
+
projectId?: number;
|
|
454
|
+
prefix?: string;
|
|
455
|
+
severityAllowList?: SeverityLevel[] | '*';
|
|
456
|
+
};
|
|
457
|
+
declare function createEventProcessor(_posthog: PostHog, { organization, projectId, prefix, severityAllowList }?: SentryIntegrationOptions): (event: _SentryEvent) => _SentryEvent;
|
|
458
|
+
declare function sentryIntegration(_posthog: PostHog, options?: SentryIntegrationOptions): _SentryIntegration;
|
|
459
|
+
declare class PostHogSentryIntegration implements _SentryIntegrationClass {
|
|
468
460
|
readonly name = "posthog-node";
|
|
469
461
|
static readonly POSTHOG_ID_TAG = "posthog_distinct_id";
|
|
470
|
-
|
|
471
|
-
|
|
462
|
+
setupOnce: (addGlobalEventProcessor: (callback: _SentryEventProcessor) => void, getCurrentHub: () => _SentryHub) => void;
|
|
463
|
+
constructor(_posthog: PostHog, organization?: string, prefix?: string, severityAllowList?: SeverityLevel[] | '*');
|
|
472
464
|
}
|
|
473
465
|
|
|
474
|
-
export { PostHog, PostHogOptions, PostHogSentryIntegration };
|
|
466
|
+
export { PostHog, PostHogOptions, PostHogSentryIntegration, SentryIntegrationOptions, SeverityLevel, createEventProcessor, sentryIntegration, severityLevels };
|
package/lib/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'rusha';
|
|
2
2
|
|
|
3
|
-
var version = "4.
|
|
3
|
+
var version = "4.3.1";
|
|
4
4
|
|
|
5
5
|
var PostHogPersistedProperty;
|
|
6
6
|
(function (PostHogPersistedProperty) {
|
|
@@ -2230,44 +2230,70 @@ class PostHog extends PostHogCoreStateless {
|
|
|
2230
2230
|
async getFeatureFlagPayload(key, distinctId, matchValue, options) {
|
|
2231
2231
|
const {
|
|
2232
2232
|
groups,
|
|
2233
|
-
disableGeoip
|
|
2234
|
-
|
|
2235
|
-
let {
|
|
2236
|
-
onlyEvaluateLocally,
|
|
2237
|
-
sendFeatureFlagEvents,
|
|
2233
|
+
disableGeoip,
|
|
2234
|
+
onlyEvaluateLocally = false,
|
|
2238
2235
|
personProperties,
|
|
2239
2236
|
groupProperties
|
|
2240
2237
|
} = options || {};
|
|
2241
|
-
const
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
if (!matchValue) {
|
|
2238
|
+
const {
|
|
2239
|
+
allPersonProperties,
|
|
2240
|
+
allGroupProperties
|
|
2241
|
+
} = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
|
|
2242
|
+
if (matchValue === undefined) {
|
|
2247
2243
|
matchValue = await this.getFeatureFlag(key, distinctId, {
|
|
2248
2244
|
...options,
|
|
2249
|
-
onlyEvaluateLocally: true
|
|
2245
|
+
onlyEvaluateLocally: true,
|
|
2246
|
+
sendFeatureFlagEvents: false
|
|
2250
2247
|
});
|
|
2251
2248
|
}
|
|
2249
|
+
let response;
|
|
2250
|
+
let payload;
|
|
2252
2251
|
if (matchValue) {
|
|
2253
|
-
response =
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
}
|
|
2259
|
-
if (sendFeatureFlagEvents == undefined) {
|
|
2260
|
-
sendFeatureFlagEvents = true;
|
|
2261
|
-
}
|
|
2262
|
-
// set defaults
|
|
2263
|
-
if (onlyEvaluateLocally == undefined) {
|
|
2264
|
-
onlyEvaluateLocally = false;
|
|
2252
|
+
response = matchValue;
|
|
2253
|
+
payload = await this.featureFlagsPoller?.computeFeatureFlagPayloadLocally(key, matchValue);
|
|
2254
|
+
} else {
|
|
2255
|
+
response = undefined;
|
|
2256
|
+
payload = undefined;
|
|
2265
2257
|
}
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2258
|
+
// Determine if the payload was evaluated locally
|
|
2259
|
+
const payloadWasLocallyEvaluated = payload !== undefined;
|
|
2260
|
+
// Fetch final flags and payloads either locally or from the remote server
|
|
2261
|
+
let fetchedOrLocalFlags;
|
|
2262
|
+
let fetchedOrLocalPayloads;
|
|
2263
|
+
if (payloadWasLocallyEvaluated || onlyEvaluateLocally) {
|
|
2264
|
+
if (response !== undefined) {
|
|
2265
|
+
fetchedOrLocalFlags = {
|
|
2266
|
+
[key]: response
|
|
2267
|
+
};
|
|
2268
|
+
fetchedOrLocalPayloads = {
|
|
2269
|
+
[key]: payload
|
|
2270
|
+
};
|
|
2271
|
+
} else {
|
|
2272
|
+
fetchedOrLocalFlags = {};
|
|
2273
|
+
fetchedOrLocalPayloads = {};
|
|
2274
|
+
}
|
|
2275
|
+
} else {
|
|
2276
|
+
const fetchedData = await super.getFeatureFlagsAndPayloadsStateless(distinctId, groups, allPersonProperties, allGroupProperties, disableGeoip);
|
|
2277
|
+
fetchedOrLocalFlags = fetchedData.flags || {};
|
|
2278
|
+
fetchedOrLocalPayloads = fetchedData.payloads || {};
|
|
2269
2279
|
}
|
|
2270
|
-
|
|
2280
|
+
const finalResponse = fetchedOrLocalFlags[key];
|
|
2281
|
+
const finalPayload = fetchedOrLocalPayloads[key];
|
|
2282
|
+
const finalLocallyEvaluated = payloadWasLocallyEvaluated;
|
|
2283
|
+
this.capture({
|
|
2284
|
+
distinctId,
|
|
2285
|
+
event: '$feature_flag_called',
|
|
2286
|
+
properties: {
|
|
2287
|
+
$feature_flag: key,
|
|
2288
|
+
$feature_flag_response: finalResponse,
|
|
2289
|
+
$feature_flag_payload: finalPayload,
|
|
2290
|
+
locally_evaluated: finalLocallyEvaluated,
|
|
2291
|
+
[`$feature/${key}`]: finalResponse
|
|
2292
|
+
},
|
|
2293
|
+
groups,
|
|
2294
|
+
disableGeoip
|
|
2295
|
+
});
|
|
2296
|
+
return finalPayload;
|
|
2271
2297
|
}
|
|
2272
2298
|
async isFeatureEnabled(key, distinctId, options) {
|
|
2273
2299
|
const feat = await this.getFeatureFlag(key, distinctId, options);
|
|
@@ -2361,6 +2387,9 @@ class PostHog extends PostHogCoreStateless {
|
|
|
2361
2387
|
}
|
|
2362
2388
|
}
|
|
2363
2389
|
|
|
2390
|
+
/**
|
|
2391
|
+
* @file Adapted from [posthog-js](https://github.com/PostHog/posthog-js/blob/8157df935a4d0e71d2fefef7127aa85ee51c82d1/src/extensions/sentry-integration.ts) with modifications for the Node SDK.
|
|
2392
|
+
*/
|
|
2364
2393
|
/**
|
|
2365
2394
|
* Integrate Sentry with PostHog. This will add a direct link to the person in Sentry, and an $exception event in PostHog.
|
|
2366
2395
|
*
|
|
@@ -2379,58 +2408,92 @@ class PostHog extends PostHogCoreStateless {
|
|
|
2379
2408
|
* @param {string} [organization] Optional: The Sentry organization, used to send a direct link from PostHog to Sentry
|
|
2380
2409
|
* @param {Number} [projectId] Optional: The Sentry project id, used to send a direct link from PostHog to Sentry
|
|
2381
2410
|
* @param {string} [prefix] Optional: Url of a self-hosted sentry instance (default: https://sentry.io/organizations/)
|
|
2411
|
+
* @param {SeverityLevel[] | '*'} [severityAllowList] Optional: send events matching the provided levels. Use '*' to send all events (default: ['error'])
|
|
2382
2412
|
*/
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
if (event.exception?.values === undefined || event.exception.values.length === 0) {
|
|
2395
|
-
return event;
|
|
2396
|
-
}
|
|
2397
|
-
if (!event.tags) {
|
|
2398
|
-
event.tags = {};
|
|
2399
|
-
}
|
|
2400
|
-
const sentry = getCurrentHub();
|
|
2401
|
-
// Get the PostHog user ID from a specific tag, which users can set on their Sentry scope as they need.
|
|
2402
|
-
const userId = event.tags[PostHogSentryIntegration.POSTHOG_ID_TAG];
|
|
2403
|
-
if (userId === undefined) {
|
|
2404
|
-
// 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.
|
|
2405
|
-
return event;
|
|
2406
|
-
}
|
|
2407
|
-
event.tags['PostHog Person URL'] = new URL(`/person/${userId}`, this.posthogHost).toString();
|
|
2408
|
-
const properties = {
|
|
2409
|
-
// PostHog Exception Properties
|
|
2410
|
-
$exception_message: event.exception.values[0]?.value,
|
|
2411
|
-
$exception_type: event.exception.values[0]?.type,
|
|
2412
|
-
$exception_personURL: event.tags['PostHog Person URL'],
|
|
2413
|
-
// Sentry Exception Properties
|
|
2414
|
-
$sentry_event_id: event.event_id,
|
|
2415
|
-
$sentry_exception: event.exception,
|
|
2416
|
-
$sentry_exception_message: event.exception.values[0]?.value,
|
|
2417
|
-
$sentry_exception_type: event.exception.values[0]?.type,
|
|
2418
|
-
$sentry_tags: event.tags
|
|
2419
|
-
};
|
|
2420
|
-
const projectId = sentry.getClient()?.getDsn()?.projectId;
|
|
2421
|
-
if (this.organization !== undefined && projectId !== undefined && event.event_id !== undefined) {
|
|
2422
|
-
properties.$sentry_url = `${this.prefix ?? 'https://sentry.io/organizations'}/${this.organization}/issues/?project=${projectId}&query=${event.event_id}`;
|
|
2423
|
-
}
|
|
2424
|
-
this.posthog.capture({
|
|
2425
|
-
event: '$exception',
|
|
2426
|
-
distinctId: userId,
|
|
2427
|
-
properties
|
|
2428
|
-
});
|
|
2413
|
+
const severityLevels = ['fatal', 'error', 'warning', 'log', 'info', 'debug'];
|
|
2414
|
+
const NAME = 'posthog-node';
|
|
2415
|
+
function createEventProcessor(_posthog, {
|
|
2416
|
+
organization,
|
|
2417
|
+
projectId,
|
|
2418
|
+
prefix,
|
|
2419
|
+
severityAllowList = ['error']
|
|
2420
|
+
} = {}) {
|
|
2421
|
+
return event => {
|
|
2422
|
+
const shouldProcessLevel = severityAllowList === '*' || severityAllowList.includes(event.level);
|
|
2423
|
+
if (!shouldProcessLevel) {
|
|
2429
2424
|
return event;
|
|
2425
|
+
}
|
|
2426
|
+
if (!event.tags) {
|
|
2427
|
+
event.tags = {};
|
|
2428
|
+
}
|
|
2429
|
+
// Get the PostHog user ID from a specific tag, which users can set on their Sentry scope as they need.
|
|
2430
|
+
const userId = event.tags[PostHogSentryIntegration.POSTHOG_ID_TAG];
|
|
2431
|
+
if (userId === undefined) {
|
|
2432
|
+
// 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.
|
|
2433
|
+
return event;
|
|
2434
|
+
}
|
|
2435
|
+
const uiHost = _posthog.options.host ?? 'https://us.i.posthog.com';
|
|
2436
|
+
const personUrl = new URL(`/project/${_posthog.apiKey}/person/${userId}`, uiHost).toString();
|
|
2437
|
+
event.tags['PostHog Person URL'] = personUrl;
|
|
2438
|
+
const exceptions = event.exception?.values || [];
|
|
2439
|
+
exceptions.map(exception => {
|
|
2440
|
+
if (exception.stacktrace) {
|
|
2441
|
+
exception.stacktrace.type = 'raw';
|
|
2442
|
+
}
|
|
2443
|
+
});
|
|
2444
|
+
const properties = {
|
|
2445
|
+
// PostHog Exception Properties,
|
|
2446
|
+
$exception_message: exceptions[0]?.value || event.message,
|
|
2447
|
+
$exception_type: exceptions[0]?.type,
|
|
2448
|
+
$exception_personURL: personUrl,
|
|
2449
|
+
$exception_level: event.level,
|
|
2450
|
+
$exception_list: exceptions,
|
|
2451
|
+
// Sentry Exception Properties
|
|
2452
|
+
$sentry_event_id: event.event_id,
|
|
2453
|
+
$sentry_exception: event.exception,
|
|
2454
|
+
$sentry_exception_message: exceptions[0]?.value || event.message,
|
|
2455
|
+
$sentry_exception_type: exceptions[0]?.type,
|
|
2456
|
+
$sentry_tags: event.tags
|
|
2457
|
+
};
|
|
2458
|
+
if (organization && projectId) {
|
|
2459
|
+
properties['$sentry_url'] = (prefix || 'https://sentry.io/organizations/') + organization + '/issues/?project=' + projectId + '&query=' + event.event_id;
|
|
2460
|
+
}
|
|
2461
|
+
_posthog.capture({
|
|
2462
|
+
event: '$exception',
|
|
2463
|
+
distinctId: userId,
|
|
2464
|
+
properties
|
|
2430
2465
|
});
|
|
2466
|
+
return event;
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2469
|
+
// V8 integration - function based
|
|
2470
|
+
function sentryIntegration(_posthog, options) {
|
|
2471
|
+
const processor = createEventProcessor(_posthog, options);
|
|
2472
|
+
return {
|
|
2473
|
+
name: NAME,
|
|
2474
|
+
processEvent(event) {
|
|
2475
|
+
return processor(event);
|
|
2476
|
+
}
|
|
2477
|
+
};
|
|
2478
|
+
}
|
|
2479
|
+
// V7 integration - class based
|
|
2480
|
+
class PostHogSentryIntegration {
|
|
2481
|
+
constructor(_posthog, organization, prefix, severityAllowList) {
|
|
2482
|
+
this.name = NAME;
|
|
2483
|
+
// setupOnce gets called by Sentry when it intializes the plugin
|
|
2484
|
+
this.name = NAME;
|
|
2485
|
+
this.setupOnce = function (addGlobalEventProcessor, getCurrentHub) {
|
|
2486
|
+
const projectId = getCurrentHub()?.getClient()?.getDsn()?.projectId;
|
|
2487
|
+
addGlobalEventProcessor(createEventProcessor(_posthog, {
|
|
2488
|
+
organization,
|
|
2489
|
+
projectId,
|
|
2490
|
+
prefix,
|
|
2491
|
+
severityAllowList
|
|
2492
|
+
}));
|
|
2493
|
+
};
|
|
2431
2494
|
}
|
|
2432
2495
|
}
|
|
2433
2496
|
PostHogSentryIntegration.POSTHOG_ID_TAG = 'posthog_distinct_id';
|
|
2434
2497
|
|
|
2435
|
-
export { PostHog, PostHogSentryIntegration };
|
|
2498
|
+
export { PostHog, PostHogSentryIntegration, createEventProcessor, sentryIntegration, severityLevels };
|
|
2436
2499
|
//# sourceMappingURL=index.esm.js.map
|