posthog-node 5.32.1 → 5.33.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/dist/client.d.ts +101 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +202 -46
- package/dist/client.mjs +199 -46
- package/dist/exports.d.ts +1 -0
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +13 -3
- package/dist/exports.mjs +2 -1
- package/dist/feature-flag-evaluations.d.ts +151 -0
- package/dist/feature-flag-evaluations.d.ts.map +1 -0
- package/dist/feature-flag-evaluations.js +151 -0
- package/dist/feature-flag-evaluations.mjs +117 -0
- package/dist/types.d.ts +64 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +2 -2
- package/src/client.ts +440 -75
- package/src/exports.ts +2 -0
- package/src/feature-flag-evaluations.ts +321 -0
- package/src/types.ts +65 -4
- package/src/version.ts +1 -1
package/dist/client.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { version } from "./version.mjs";
|
|
2
2
|
import { PostHogCoreStateless, isBlockedUA, isPlainObject, safeSetTimeout, uuidv7 } from "@posthog/core";
|
|
3
3
|
import { FeatureFlagError } from "./types.mjs";
|
|
4
|
+
import { FeatureFlagEvaluations } from "./feature-flag-evaluations.mjs";
|
|
4
5
|
import { FeatureFlagsPoller, InconclusiveMatchError, RequiresServerEvaluation } from "./extensions/feature-flags/feature-flags.mjs";
|
|
5
6
|
import error_tracking from "./extensions/error-tracking/index.mjs";
|
|
6
7
|
import { PostHogMemoryStorage } from "./storage-memory.mjs";
|
|
@@ -10,6 +11,15 @@ const MAX_CACHE_SIZE = 50000;
|
|
|
10
11
|
const WAITUNTIL_DEBOUNCE_MS = 50;
|
|
11
12
|
const WAITUNTIL_MAX_WAIT_MS = 500;
|
|
12
13
|
const DEFAULT_NODE_HOST = 'https://us.i.posthog.com';
|
|
14
|
+
const _emittedDeprecations = new Set();
|
|
15
|
+
function emitDeprecationWarningOnce(id, message) {
|
|
16
|
+
if (_emittedDeprecations.has(id)) return;
|
|
17
|
+
_emittedDeprecations.add(id);
|
|
18
|
+
console.warn(`[PostHog] ${message}`);
|
|
19
|
+
}
|
|
20
|
+
function _resetDeprecationWarningsForTests() {
|
|
21
|
+
_emittedDeprecations.clear();
|
|
22
|
+
}
|
|
13
23
|
function normalizeApiKey(value) {
|
|
14
24
|
return 'string' == typeof value ? value.trim() : '';
|
|
15
25
|
}
|
|
@@ -21,6 +31,14 @@ function normalizeHost(value) {
|
|
|
21
31
|
const normalizedValue = 'string' == typeof value ? value.trim() : '';
|
|
22
32
|
return normalizedValue || DEFAULT_NODE_HOST;
|
|
23
33
|
}
|
|
34
|
+
function buildFlagEventProperties(flagValues) {
|
|
35
|
+
if (!flagValues) return {};
|
|
36
|
+
const additionalProperties = {};
|
|
37
|
+
for (const [feature, variant] of Object.entries(flagValues))additionalProperties[`$feature/${feature}`] = variant;
|
|
38
|
+
const activeFlags = Object.keys(flagValues).filter((flag)=>false !== flagValues[flag]).sort();
|
|
39
|
+
if (activeFlags.length > 0) additionalProperties['$active_feature_flags'] = activeFlags;
|
|
40
|
+
return additionalProperties;
|
|
41
|
+
}
|
|
24
42
|
class PostHogBackendClient extends PostHogCoreStateless {
|
|
25
43
|
constructor(apiKey, options = {}){
|
|
26
44
|
const normalizedApiKey = normalizeApiKey(apiKey);
|
|
@@ -317,37 +335,30 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
317
335
|
}
|
|
318
336
|
if (sendFeatureFlagEvents) {
|
|
319
337
|
const response = void 0 === result ? void 0 : false === result.enabled ? false : result.variant ?? true;
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
[`$feature/${key}`]: response,
|
|
335
|
-
$feature_flag_request_id: requestId,
|
|
336
|
-
$feature_flag_evaluated_at: flagWasLocallyEvaluated ? Date.now() : evaluatedAt
|
|
337
|
-
};
|
|
338
|
-
if (flagWasLocallyEvaluated && this.featureFlagsPoller) {
|
|
339
|
-
const flagDefinitionsLoadedAt = this.featureFlagsPoller.getFlagDefinitionsLoadedAt();
|
|
340
|
-
if (void 0 !== flagDefinitionsLoadedAt) properties.$feature_flag_definitions_loaded_at = flagDefinitionsLoadedAt;
|
|
341
|
-
}
|
|
342
|
-
if (featureFlagError) properties.$feature_flag_error = featureFlagError;
|
|
343
|
-
this.capture({
|
|
344
|
-
distinctId,
|
|
345
|
-
event: '$feature_flag_called',
|
|
346
|
-
properties,
|
|
347
|
-
groups,
|
|
348
|
-
disableGeoip
|
|
349
|
-
});
|
|
338
|
+
const properties = {
|
|
339
|
+
$feature_flag: key,
|
|
340
|
+
$feature_flag_response: response,
|
|
341
|
+
$feature_flag_id: flagId,
|
|
342
|
+
$feature_flag_version: flagVersion,
|
|
343
|
+
$feature_flag_reason: flagReason,
|
|
344
|
+
locally_evaluated: flagWasLocallyEvaluated,
|
|
345
|
+
[`$feature/${key}`]: response,
|
|
346
|
+
$feature_flag_request_id: requestId,
|
|
347
|
+
$feature_flag_evaluated_at: flagWasLocallyEvaluated ? Date.now() : evaluatedAt
|
|
348
|
+
};
|
|
349
|
+
if (flagWasLocallyEvaluated && this.featureFlagsPoller) {
|
|
350
|
+
const flagDefinitionsLoadedAt = this.featureFlagsPoller.getFlagDefinitionsLoadedAt();
|
|
351
|
+
if (void 0 !== flagDefinitionsLoadedAt) properties.$feature_flag_definitions_loaded_at = flagDefinitionsLoadedAt;
|
|
350
352
|
}
|
|
353
|
+
if (featureFlagError) properties.$feature_flag_error = featureFlagError;
|
|
354
|
+
this._captureFlagCalledEventIfNeeded({
|
|
355
|
+
distinctId,
|
|
356
|
+
key,
|
|
357
|
+
response,
|
|
358
|
+
groups,
|
|
359
|
+
disableGeoip,
|
|
360
|
+
properties
|
|
361
|
+
});
|
|
351
362
|
}
|
|
352
363
|
if (void 0 !== result && void 0 !== this._payloadOverrides && key in this._payloadOverrides) result = {
|
|
353
364
|
...result,
|
|
@@ -356,6 +367,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
356
367
|
return result;
|
|
357
368
|
}
|
|
358
369
|
async getFeatureFlag(key, distinctId, options) {
|
|
370
|
+
emitDeprecationWarningOnce('getFeatureFlag', "`getFeatureFlag` is deprecated and will be removed in a future major version. Use `posthog.evaluateFlags(distinctId, ...)` and call `flags.getFlag(key)` instead — this consolidates flag evaluation into a single `/flags` request per incoming request.");
|
|
359
371
|
const result = await this._getFeatureFlagResult(key, distinctId, {
|
|
360
372
|
...options,
|
|
361
373
|
sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
|
|
@@ -365,6 +377,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
365
377
|
return result.variant ?? true;
|
|
366
378
|
}
|
|
367
379
|
async getFeatureFlagPayload(key, distinctId, matchValue, options) {
|
|
380
|
+
emitDeprecationWarningOnce('getFeatureFlagPayload', "`getFeatureFlagPayload` is deprecated and will be removed in a future major version. Use `posthog.evaluateFlags(distinctId, ...)` and call `flags.getFlagPayload(key)` instead — this consolidates flag evaluation into a single `/flags` request per incoming request.");
|
|
368
381
|
if (void 0 !== this._payloadOverrides && key in this._payloadOverrides) return this._payloadOverrides[key];
|
|
369
382
|
const result = await this._getFeatureFlagResult(key, distinctId, {
|
|
370
383
|
...options,
|
|
@@ -392,8 +405,14 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
392
405
|
return parsed;
|
|
393
406
|
}
|
|
394
407
|
async isFeatureEnabled(key, distinctId, options) {
|
|
395
|
-
|
|
396
|
-
|
|
408
|
+
emitDeprecationWarningOnce('isFeatureEnabled', "`isFeatureEnabled` is deprecated and will be removed in a future major version. Use `posthog.evaluateFlags(distinctId, ...)` and call `flags.isEnabled(key)` instead — this consolidates flag evaluation into a single `/flags` request per incoming request.");
|
|
409
|
+
const result = await this._getFeatureFlagResult(key, distinctId, {
|
|
410
|
+
...options,
|
|
411
|
+
sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
|
|
412
|
+
});
|
|
413
|
+
if (void 0 === result) return;
|
|
414
|
+
if (false === result.enabled) return false;
|
|
415
|
+
const feat = result.variant ?? true;
|
|
397
416
|
return !!feat || false;
|
|
398
417
|
}
|
|
399
418
|
async getAllFlags(distinctIdOrOptions, options) {
|
|
@@ -454,6 +473,136 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
454
473
|
featureFlagPayloads
|
|
455
474
|
};
|
|
456
475
|
}
|
|
476
|
+
async evaluateFlags(distinctIdOrOptions, options) {
|
|
477
|
+
const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
|
|
478
|
+
if (!resolvedDistinctId) {
|
|
479
|
+
this._logger.warn("[PostHog] distinctId is required to evaluate feature flags \u2014 pass it explicitly or use withContext()");
|
|
480
|
+
return new FeatureFlagEvaluations({
|
|
481
|
+
host: this._getFeatureFlagEvaluationsHost(),
|
|
482
|
+
distinctId: '',
|
|
483
|
+
flags: {}
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
const { groups, disableGeoip, flagKeys } = resolvedOptions || {};
|
|
487
|
+
let { onlyEvaluateLocally, personProperties, groupProperties } = resolvedOptions || {};
|
|
488
|
+
const adjustedProperties = this.addLocalPersonAndGroupProperties(resolvedDistinctId, groups, personProperties, groupProperties);
|
|
489
|
+
personProperties = adjustedProperties.allPersonProperties;
|
|
490
|
+
groupProperties = adjustedProperties.allGroupProperties;
|
|
491
|
+
const evaluationContext = this.createFeatureFlagEvaluationContext(resolvedDistinctId, groups, personProperties, groupProperties);
|
|
492
|
+
if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
|
|
493
|
+
const records = {};
|
|
494
|
+
let requestId;
|
|
495
|
+
let evaluatedAt;
|
|
496
|
+
let errorsWhileComputing = false;
|
|
497
|
+
let quotaLimited = false;
|
|
498
|
+
const localResult = await this.featureFlagsPoller?.getAllFlagsAndPayloads(evaluationContext, flagKeys);
|
|
499
|
+
const locallyEvaluatedKeys = new Set();
|
|
500
|
+
if (localResult) for (const [key, value] of Object.entries(localResult.response)){
|
|
501
|
+
const flagDef = this.featureFlagsPoller?.featureFlagsByKey[key];
|
|
502
|
+
records[key] = {
|
|
503
|
+
key,
|
|
504
|
+
enabled: false !== value,
|
|
505
|
+
variant: 'string' == typeof value ? value : void 0,
|
|
506
|
+
payload: localResult.payloads[key],
|
|
507
|
+
id: flagDef?.id,
|
|
508
|
+
version: void 0,
|
|
509
|
+
reason: 'Evaluated locally',
|
|
510
|
+
locallyEvaluated: true
|
|
511
|
+
};
|
|
512
|
+
locallyEvaluatedKeys.add(key);
|
|
513
|
+
}
|
|
514
|
+
const fallbackToFlags = localResult ? localResult.fallbackToFlags : true;
|
|
515
|
+
if (fallbackToFlags && !onlyEvaluateLocally) {
|
|
516
|
+
const details = await super.getFeatureFlagDetailsStateless(evaluationContext.distinctId, evaluationContext.groups, evaluationContext.personProperties, evaluationContext.groupProperties, disableGeoip, flagKeys);
|
|
517
|
+
if (details) {
|
|
518
|
+
requestId = details.requestId;
|
|
519
|
+
evaluatedAt = details.evaluatedAt;
|
|
520
|
+
errorsWhileComputing = Boolean(details.errorsWhileComputingFlags);
|
|
521
|
+
quotaLimited = Array.isArray(details.quotaLimited) && details.quotaLimited.includes('feature_flags');
|
|
522
|
+
for (const [key, detail] of Object.entries(details.flags)){
|
|
523
|
+
if (locallyEvaluatedKeys.has(key)) continue;
|
|
524
|
+
let parsedPayload;
|
|
525
|
+
if (detail.metadata?.payload !== void 0) try {
|
|
526
|
+
parsedPayload = JSON.parse(detail.metadata.payload);
|
|
527
|
+
} catch {
|
|
528
|
+
parsedPayload = detail.metadata.payload;
|
|
529
|
+
}
|
|
530
|
+
records[key] = {
|
|
531
|
+
key,
|
|
532
|
+
enabled: detail.enabled,
|
|
533
|
+
variant: detail.variant,
|
|
534
|
+
payload: parsedPayload,
|
|
535
|
+
id: detail.metadata?.id,
|
|
536
|
+
version: detail.metadata?.version,
|
|
537
|
+
reason: detail.reason?.description ?? detail.reason?.code,
|
|
538
|
+
locallyEvaluated: false
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
if (void 0 !== this._flagOverrides) for (const [key, value] of Object.entries(this._flagOverrides)){
|
|
544
|
+
if (void 0 === value) {
|
|
545
|
+
delete records[key];
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
const existing = records[key];
|
|
549
|
+
records[key] = {
|
|
550
|
+
key,
|
|
551
|
+
enabled: false !== value,
|
|
552
|
+
variant: 'string' == typeof value ? value : void 0,
|
|
553
|
+
payload: existing?.payload,
|
|
554
|
+
id: existing?.id,
|
|
555
|
+
version: existing?.version,
|
|
556
|
+
reason: existing?.reason,
|
|
557
|
+
locallyEvaluated: existing?.locallyEvaluated ?? false
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
if (void 0 !== this._payloadOverrides) for (const [key, payload] of Object.entries(this._payloadOverrides)){
|
|
561
|
+
const existing = records[key];
|
|
562
|
+
if (existing) records[key] = {
|
|
563
|
+
...existing,
|
|
564
|
+
payload
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
return new FeatureFlagEvaluations({
|
|
568
|
+
host: this._getFeatureFlagEvaluationsHost(),
|
|
569
|
+
distinctId: resolvedDistinctId,
|
|
570
|
+
groups,
|
|
571
|
+
disableGeoip,
|
|
572
|
+
flags: records,
|
|
573
|
+
requestId,
|
|
574
|
+
evaluatedAt,
|
|
575
|
+
flagDefinitionsLoadedAt: this.featureFlagsPoller?.getFlagDefinitionsLoadedAt(),
|
|
576
|
+
errorsWhileComputing,
|
|
577
|
+
quotaLimited
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
_captureFlagCalledEventIfNeeded(params) {
|
|
581
|
+
const { distinctId, key, response, groups, disableGeoip, properties } = params;
|
|
582
|
+
const featureFlagReportedKey = `${key}_${response}`;
|
|
583
|
+
if (distinctId in this.distinctIdHasSentFlagCalls && this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey)) return;
|
|
584
|
+
if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) this.distinctIdHasSentFlagCalls = {};
|
|
585
|
+
if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
|
|
586
|
+
else this.distinctIdHasSentFlagCalls[distinctId] = [
|
|
587
|
+
featureFlagReportedKey
|
|
588
|
+
];
|
|
589
|
+
this.capture({
|
|
590
|
+
distinctId,
|
|
591
|
+
event: '$feature_flag_called',
|
|
592
|
+
properties,
|
|
593
|
+
groups,
|
|
594
|
+
disableGeoip
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
_getFeatureFlagEvaluationsHost() {
|
|
598
|
+
if (!this._featureFlagEvaluationsHost) this._featureFlagEvaluationsHost = {
|
|
599
|
+
captureFlagCalledEventIfNeeded: (params)=>this._captureFlagCalledEventIfNeeded(params),
|
|
600
|
+
logWarning: (message)=>{
|
|
601
|
+
if (false !== this.options.featureFlagsLogWarnings) console.warn(`[PostHog] ${message}`);
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
return this._featureFlagEvaluationsHost;
|
|
605
|
+
}
|
|
457
606
|
groupIdentify({ groupType, groupKey, properties, distinctId, disableGeoip }) {
|
|
458
607
|
super.groupIdentifyStateless(groupType, groupKey, properties, {
|
|
459
608
|
disableGeoip
|
|
@@ -630,27 +779,31 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
630
779
|
evaluationCache: {}
|
|
631
780
|
};
|
|
632
781
|
}
|
|
633
|
-
captureException(error, distinctId, additionalProperties, uuid) {
|
|
782
|
+
captureException(error, distinctId, additionalProperties, uuid, flags) {
|
|
634
783
|
if (!error_tracking.isPreviouslyCapturedError(error)) {
|
|
635
784
|
const syntheticException = new Error('PostHog syntheticException');
|
|
636
785
|
this.addPendingPromise(error_tracking.buildEventMessage(error, {
|
|
637
786
|
syntheticException
|
|
638
787
|
}, distinctId, additionalProperties).then((msg)=>this.capture({
|
|
639
788
|
...msg,
|
|
640
|
-
uuid
|
|
789
|
+
uuid,
|
|
790
|
+
flags
|
|
641
791
|
})));
|
|
642
792
|
}
|
|
643
793
|
}
|
|
644
|
-
async captureExceptionImmediate(error, distinctId, additionalProperties) {
|
|
794
|
+
async captureExceptionImmediate(error, distinctId, additionalProperties, flags) {
|
|
645
795
|
if (!error_tracking.isPreviouslyCapturedError(error)) {
|
|
646
796
|
const syntheticException = new Error('PostHog syntheticException');
|
|
647
797
|
return this.addPendingPromise(error_tracking.buildEventMessage(error, {
|
|
648
798
|
syntheticException
|
|
649
|
-
}, distinctId, additionalProperties).then((msg)=>this.captureImmediate(
|
|
799
|
+
}, distinctId, additionalProperties).then((msg)=>this.captureImmediate({
|
|
800
|
+
...msg,
|
|
801
|
+
flags
|
|
802
|
+
})));
|
|
650
803
|
}
|
|
651
804
|
}
|
|
652
805
|
async prepareEventMessage(props) {
|
|
653
|
-
const { distinctId, event, properties, groups, sendFeatureFlags, timestamp, disableGeoip, uuid } = props;
|
|
806
|
+
const { distinctId, event, properties, groups, flags, sendFeatureFlags, timestamp, disableGeoip, uuid } = props;
|
|
654
807
|
const contextData = this.context?.get();
|
|
655
808
|
let mergedDistinctId = distinctId || contextData?.distinctId;
|
|
656
809
|
const mergedProperties = {
|
|
@@ -668,6 +821,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
668
821
|
event,
|
|
669
822
|
properties: mergedProperties,
|
|
670
823
|
groups,
|
|
824
|
+
flags,
|
|
671
825
|
sendFeatureFlags,
|
|
672
826
|
timestamp,
|
|
673
827
|
disableGeoip,
|
|
@@ -675,18 +829,17 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
675
829
|
});
|
|
676
830
|
if (!eventMessage) return Promise.reject(null);
|
|
677
831
|
const eventProperties = await Promise.resolve().then(async ()=>{
|
|
832
|
+
if (flags) {
|
|
833
|
+
if (sendFeatureFlags) console.warn('[PostHog] Both `flags` and `sendFeatureFlags` were passed to capture(); using `flags` and ignoring `sendFeatureFlags`.');
|
|
834
|
+
return flags._getEventProperties();
|
|
835
|
+
}
|
|
678
836
|
if (sendFeatureFlags) {
|
|
837
|
+
emitDeprecationWarningOnce('sendFeatureFlags', "`sendFeatureFlags` is deprecated and will be removed in a future major version. Pass a `flags` snapshot from `posthog.evaluateFlags(...)` instead — it avoids a second `/flags` request per capture and guarantees the event carries the exact flag values your code branched on.");
|
|
679
838
|
const sendFeatureFlagsOptions = 'object' == typeof sendFeatureFlags ? sendFeatureFlags : void 0;
|
|
680
|
-
|
|
839
|
+
const flagValues = await this.getFeatureFlagsForEvent(eventMessage.distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
|
|
840
|
+
return buildFlagEventProperties(flagValues);
|
|
681
841
|
}
|
|
682
|
-
eventMessage.event;
|
|
683
842
|
return {};
|
|
684
|
-
}).then((flags)=>{
|
|
685
|
-
const additionalProperties = {};
|
|
686
|
-
if (flags) for (const [feature, variant] of Object.entries(flags))additionalProperties[`$feature/${feature}`] = variant;
|
|
687
|
-
const activeFlags = Object.keys(flags || {}).filter((flag)=>flags?.[flag] !== false).sort();
|
|
688
|
-
if (activeFlags.length > 0) additionalProperties['$active_feature_flags'] = activeFlags;
|
|
689
|
-
return additionalProperties;
|
|
690
843
|
}).catch(()=>({})).then((additionalProperties)=>{
|
|
691
844
|
const props = {
|
|
692
845
|
...additionalProperties,
|
|
@@ -733,4 +886,4 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
733
886
|
return result;
|
|
734
887
|
}
|
|
735
888
|
}
|
|
736
|
-
export { PostHogBackendClient };
|
|
889
|
+
export { PostHogBackendClient, _resetDeprecationWarningsForTests };
|
package/dist/exports.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './extensions/sentry-integration';
|
|
2
2
|
export * from './extensions/express';
|
|
3
3
|
export * from './types';
|
|
4
|
+
export { FeatureFlagEvaluations } from './feature-flag-evaluations';
|
|
4
5
|
export { FeatureFlagError } from '@posthog/core';
|
|
5
6
|
export type { FeatureFlagErrorType } from '@posthog/core';
|
|
6
7
|
//# sourceMappingURL=exports.d.ts.map
|
package/dist/exports.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAA;AAC/C,cAAc,sBAAsB,CAAA;AACpC,cAAc,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAA;AAC/C,cAAc,sBAAsB,CAAA;AACpC,cAAc,SAAS,CAAA;AAEvB,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAInE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAChD,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA"}
|
package/dist/exports.js
CHANGED
|
@@ -6,6 +6,9 @@ var __webpack_modules__ = {
|
|
|
6
6
|
"./extensions/sentry-integration": function(module) {
|
|
7
7
|
module.exports = require("./extensions/sentry-integration.js");
|
|
8
8
|
},
|
|
9
|
+
"./feature-flag-evaluations": function(module) {
|
|
10
|
+
module.exports = require("./feature-flag-evaluations.js");
|
|
11
|
+
},
|
|
9
12
|
"./types": function(module) {
|
|
10
13
|
module.exports = require("./types.js");
|
|
11
14
|
},
|
|
@@ -57,11 +60,13 @@ var __webpack_exports__ = {};
|
|
|
57
60
|
(()=>{
|
|
58
61
|
__webpack_require__.r(__webpack_exports__);
|
|
59
62
|
__webpack_require__.d(__webpack_exports__, {
|
|
60
|
-
FeatureFlagError: ()=>
|
|
63
|
+
FeatureFlagError: ()=>_posthog_core__WEBPACK_IMPORTED_MODULE_4__.FeatureFlagError,
|
|
64
|
+
FeatureFlagEvaluations: ()=>_feature_flag_evaluations__WEBPACK_IMPORTED_MODULE_3__.FeatureFlagEvaluations
|
|
61
65
|
});
|
|
62
66
|
var _extensions_sentry_integration__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./extensions/sentry-integration");
|
|
63
67
|
var __WEBPACK_REEXPORT_OBJECT__ = {};
|
|
64
68
|
for(var __WEBPACK_IMPORT_KEY__ in _extensions_sentry_integration__WEBPACK_IMPORTED_MODULE_0__)if ([
|
|
69
|
+
"FeatureFlagEvaluations",
|
|
65
70
|
"FeatureFlagError",
|
|
66
71
|
"default"
|
|
67
72
|
].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
|
|
@@ -71,6 +76,7 @@ var __webpack_exports__ = {};
|
|
|
71
76
|
var _extensions_express__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./extensions/express");
|
|
72
77
|
var __WEBPACK_REEXPORT_OBJECT__ = {};
|
|
73
78
|
for(var __WEBPACK_IMPORT_KEY__ in _extensions_express__WEBPACK_IMPORTED_MODULE_1__)if ([
|
|
79
|
+
"FeatureFlagEvaluations",
|
|
74
80
|
"FeatureFlagError",
|
|
75
81
|
"default"
|
|
76
82
|
].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
|
|
@@ -80,17 +86,21 @@ var __webpack_exports__ = {};
|
|
|
80
86
|
var _types__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./types");
|
|
81
87
|
var __WEBPACK_REEXPORT_OBJECT__ = {};
|
|
82
88
|
for(var __WEBPACK_IMPORT_KEY__ in _types__WEBPACK_IMPORTED_MODULE_2__)if ([
|
|
89
|
+
"FeatureFlagEvaluations",
|
|
83
90
|
"FeatureFlagError",
|
|
84
91
|
"default"
|
|
85
92
|
].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
|
|
86
93
|
return _types__WEBPACK_IMPORTED_MODULE_2__[key];
|
|
87
94
|
}).bind(0, __WEBPACK_IMPORT_KEY__);
|
|
88
95
|
__webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
|
|
89
|
-
var
|
|
96
|
+
var _feature_flag_evaluations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__("./feature-flag-evaluations");
|
|
97
|
+
var _posthog_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__("@posthog/core");
|
|
90
98
|
})();
|
|
91
99
|
exports.FeatureFlagError = __webpack_exports__.FeatureFlagError;
|
|
100
|
+
exports.FeatureFlagEvaluations = __webpack_exports__.FeatureFlagEvaluations;
|
|
92
101
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
93
|
-
"FeatureFlagError"
|
|
102
|
+
"FeatureFlagError",
|
|
103
|
+
"FeatureFlagEvaluations"
|
|
94
104
|
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
95
105
|
Object.defineProperty(exports, '__esModule', {
|
|
96
106
|
value: true
|
package/dist/exports.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { FeatureFlagEvaluations } from "./feature-flag-evaluations.mjs";
|
|
1
2
|
import { FeatureFlagError } from "@posthog/core";
|
|
2
3
|
export * from "./extensions/sentry-integration.mjs";
|
|
3
4
|
export * from "./extensions/express.mjs";
|
|
4
5
|
export * from "./types.mjs";
|
|
5
|
-
export { FeatureFlagError };
|
|
6
|
+
export { FeatureFlagError, FeatureFlagEvaluations };
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { FeatureFlagValue, JsonType } from '@posthog/core';
|
|
2
|
+
/**
|
|
3
|
+
* Internal per-flag record stored by a {@link FeatureFlagEvaluations} instance.
|
|
4
|
+
* Not part of the public API.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export type EvaluatedFlagRecord = {
|
|
9
|
+
key: string;
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
variant: string | undefined;
|
|
12
|
+
payload: JsonType | undefined;
|
|
13
|
+
id: number | undefined;
|
|
14
|
+
version: number | undefined;
|
|
15
|
+
reason: string | undefined;
|
|
16
|
+
locallyEvaluated: boolean;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Parameters passed to the host when a `$feature_flag_called` event should be captured.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export type FlagCalledEventParams = {
|
|
24
|
+
distinctId: string;
|
|
25
|
+
key: string;
|
|
26
|
+
response: FeatureFlagValue | undefined;
|
|
27
|
+
groups: Record<string, string | number> | undefined;
|
|
28
|
+
disableGeoip: boolean | undefined;
|
|
29
|
+
properties: Record<string, any>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Thin interface the evaluations object uses to talk back to the PostHog client.
|
|
33
|
+
* Keeps the class decoupled from the full client surface area.
|
|
34
|
+
*
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export interface FeatureFlagEvaluationsHost {
|
|
38
|
+
captureFlagCalledEventIfNeeded(params: FlagCalledEventParams): void;
|
|
39
|
+
logWarning(message: string): void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A snapshot of feature flag evaluations for a single distinctId at a point in time.
|
|
43
|
+
*
|
|
44
|
+
* Returned by {@link IPostHog.evaluateFlags} — branch on `isEnabled()` / `getFlag()`
|
|
45
|
+
* and pass the same object to `capture()` via the `flags` option so the captured event
|
|
46
|
+
* carries the exact flag values the code branched on.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* const flags = await posthog.evaluateFlags(distinctId, { personProperties: { plan: 'enterprise' } })
|
|
50
|
+
*
|
|
51
|
+
* if (flags.isEnabled('new-dashboard')) {
|
|
52
|
+
* renderNewDashboard()
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* posthog.capture({ distinctId, event: 'page_viewed', flags })
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* To narrow the set of flags that get attached to a captured event, use the in-memory
|
|
59
|
+
* helpers `only([...])` and `onlyAccessed()`. To narrow the set of flags requested from
|
|
60
|
+
* the server in the first place, pass `flagKeys` to `evaluateFlags()`.
|
|
61
|
+
*/
|
|
62
|
+
export declare class FeatureFlagEvaluations {
|
|
63
|
+
private readonly _host;
|
|
64
|
+
private readonly _distinctId;
|
|
65
|
+
private readonly _groups;
|
|
66
|
+
private readonly _disableGeoip;
|
|
67
|
+
private readonly _flags;
|
|
68
|
+
private readonly _requestId;
|
|
69
|
+
private readonly _evaluatedAt;
|
|
70
|
+
private readonly _flagDefinitionsLoadedAt;
|
|
71
|
+
private readonly _errorsWhileComputing;
|
|
72
|
+
private readonly _quotaLimited;
|
|
73
|
+
private readonly _accessed;
|
|
74
|
+
private readonly _isSlice;
|
|
75
|
+
/**
|
|
76
|
+
* @internal — instances are created by the SDK via `posthog.evaluateFlags()`.
|
|
77
|
+
*/
|
|
78
|
+
constructor(init: {
|
|
79
|
+
host: FeatureFlagEvaluationsHost;
|
|
80
|
+
distinctId: string;
|
|
81
|
+
groups?: Record<string, string | number>;
|
|
82
|
+
disableGeoip?: boolean;
|
|
83
|
+
flags: Record<string, EvaluatedFlagRecord>;
|
|
84
|
+
requestId?: string;
|
|
85
|
+
evaluatedAt?: number;
|
|
86
|
+
flagDefinitionsLoadedAt?: number;
|
|
87
|
+
errorsWhileComputing?: boolean;
|
|
88
|
+
quotaLimited?: boolean;
|
|
89
|
+
accessed?: Set<string>;
|
|
90
|
+
isSlice?: boolean;
|
|
91
|
+
});
|
|
92
|
+
/**
|
|
93
|
+
* Check whether a feature flag is enabled. Fires a `$feature_flag_called` event
|
|
94
|
+
* on the first access per (distinctId, flag, value) tuple, deduped via the SDK's
|
|
95
|
+
* existing cache.
|
|
96
|
+
*
|
|
97
|
+
* Flags that were not returned from the underlying evaluation are treated as
|
|
98
|
+
* disabled (returns `false`).
|
|
99
|
+
*/
|
|
100
|
+
isEnabled(key: string): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Get the evaluated value of a feature flag. Fires a `$feature_flag_called` event
|
|
103
|
+
* on the first access per (distinctId, flag, value) tuple.
|
|
104
|
+
*
|
|
105
|
+
* Returns the variant string for multivariate flags, `true` for enabled flags
|
|
106
|
+
* without a variant, `false` for disabled flags, and `undefined` for flags that
|
|
107
|
+
* were not returned by the evaluation.
|
|
108
|
+
*/
|
|
109
|
+
getFlag(key: string): FeatureFlagValue | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Get the payload associated with a feature flag. Does not count as an access
|
|
112
|
+
* for `onlyAccessed()` and does not fire any event.
|
|
113
|
+
*/
|
|
114
|
+
getFlagPayload(key: string): JsonType | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* Return a filtered copy containing only flags that have been accessed via
|
|
117
|
+
* `isEnabled()` or `getFlag()` before this call.
|
|
118
|
+
*
|
|
119
|
+
* Order-dependent: if nothing has been accessed yet, the returned snapshot is
|
|
120
|
+
* empty. The method honors its name — pre-access if you want a populated result.
|
|
121
|
+
*
|
|
122
|
+
* **Note:** the returned snapshot is intended for `capture()`, not for further
|
|
123
|
+
* branching. Calling `isEnabled()` / `getFlag()` on it for a key that was filtered
|
|
124
|
+
* out is a no-op (no event is fired) — the flag wasn't actually missing, it was
|
|
125
|
+
* excluded from the slice.
|
|
126
|
+
*/
|
|
127
|
+
onlyAccessed(): FeatureFlagEvaluations;
|
|
128
|
+
/**
|
|
129
|
+
* Return a filtered copy containing only flags with the given keys. Keys that
|
|
130
|
+
* are not present in the evaluation are dropped and logged as a warning.
|
|
131
|
+
*
|
|
132
|
+
* **Note:** like `onlyAccessed()`, the returned snapshot is intended for `capture()`.
|
|
133
|
+
* Branching on a filtered key that was excluded from the slice is a no-op.
|
|
134
|
+
*/
|
|
135
|
+
only(keys: string[]): FeatureFlagEvaluations;
|
|
136
|
+
/**
|
|
137
|
+
* Returns the flag keys that are part of this evaluation.
|
|
138
|
+
*/
|
|
139
|
+
get keys(): string[];
|
|
140
|
+
/**
|
|
141
|
+
* Build the `$feature/*` and `$active_feature_flags` event properties derived
|
|
142
|
+
* from the current flag set. Called by `capture()` when an event is captured
|
|
143
|
+
* with `flags: ...`.
|
|
144
|
+
*
|
|
145
|
+
* @internal
|
|
146
|
+
*/
|
|
147
|
+
_getEventProperties(): Record<string, any>;
|
|
148
|
+
private _cloneWith;
|
|
149
|
+
private _recordAccess;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=feature-flag-evaluations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-flag-evaluations.d.ts","sourceRoot":"","sources":["../src/feature-flag-evaluations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAI1D;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAA;IAC7B,EAAE,EAAE,MAAM,GAAG,SAAS,CAAA;IACtB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,gBAAgB,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,gBAAgB,GAAG,SAAS,CAAA;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,SAAS,CAAA;IACnD,YAAY,EAAE,OAAO,GAAG,SAAS,CAAA;IACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAChC,CAAA;AAED;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC,8BAA8B,CAAC,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAA;IACnE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAClC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6C;IACrE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAoB;IAC7D,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;IAGvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC;;OAEG;gBACS,IAAI,EAAE;QAChB,IAAI,EAAE,0BAA0B,CAAA;QAChC,UAAU,EAAE,MAAM,CAAA;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;QACxC,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;QAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,uBAAuB,CAAC,EAAE,MAAM,CAAA;QAChC,oBAAoB,CAAC,EAAE,OAAO,CAAA;QAC9B,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;QACtB,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB;IAeD;;;;;;;OAOG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAM/B;;;;;;;OAOG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAYlD;;;OAGG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIjD;;;;;;;;;;;OAWG;IACH,YAAY,IAAI,sBAAsB;IAWtC;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,sBAAsB;IAmB5C;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,EAAE,CAEnB;IAED;;;;;;OAMG;IACH,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAiB1C,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,aAAa;CAgEtB"}
|