@rpcbase/server 0.521.0 → 0.522.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/dist/index.js +170 -88
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -448,6 +448,36 @@ const getDefaultRandom = () => ({
|
|
|
448
448
|
let defaultGenerator;
|
|
449
449
|
const uuidv7 = () => uuidv7obj().toString();
|
|
450
450
|
const uuidv7obj = () => (defaultGenerator || (defaultGenerator = new V7Generator())).generate();
|
|
451
|
+
var types_PostHogPersistedProperty = /* @__PURE__ */ (function(PostHogPersistedProperty) {
|
|
452
|
+
PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
|
|
453
|
+
PostHogPersistedProperty["DistinctId"] = "distinct_id";
|
|
454
|
+
PostHogPersistedProperty["Props"] = "props";
|
|
455
|
+
PostHogPersistedProperty["EnablePersonProcessing"] = "enable_person_processing";
|
|
456
|
+
PostHogPersistedProperty["PersonMode"] = "person_mode";
|
|
457
|
+
PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
|
|
458
|
+
PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
|
|
459
|
+
PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
|
|
460
|
+
PostHogPersistedProperty["BootstrapFeatureFlagDetails"] = "bootstrap_feature_flag_details";
|
|
461
|
+
PostHogPersistedProperty["BootstrapFeatureFlags"] = "bootstrap_feature_flags";
|
|
462
|
+
PostHogPersistedProperty["BootstrapFeatureFlagPayloads"] = "bootstrap_feature_flag_payloads";
|
|
463
|
+
PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
|
|
464
|
+
PostHogPersistedProperty["Queue"] = "queue";
|
|
465
|
+
PostHogPersistedProperty["OptedOut"] = "opted_out";
|
|
466
|
+
PostHogPersistedProperty["SessionId"] = "session_id";
|
|
467
|
+
PostHogPersistedProperty["SessionStartTimestamp"] = "session_start_timestamp";
|
|
468
|
+
PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
|
|
469
|
+
PostHogPersistedProperty["PersonProperties"] = "person_properties";
|
|
470
|
+
PostHogPersistedProperty["GroupProperties"] = "group_properties";
|
|
471
|
+
PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
|
|
472
|
+
PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
|
|
473
|
+
PostHogPersistedProperty["SessionReplay"] = "session_replay";
|
|
474
|
+
PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
|
|
475
|
+
PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
|
|
476
|
+
PostHogPersistedProperty["Surveys"] = "surveys";
|
|
477
|
+
PostHogPersistedProperty["RemoteConfig"] = "remote_config";
|
|
478
|
+
PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
|
|
479
|
+
return PostHogPersistedProperty;
|
|
480
|
+
})({});
|
|
451
481
|
const DEFAULT_BLOCKED_UA_STRS = [
|
|
452
482
|
"amazonbot",
|
|
453
483
|
"amazonproductbot",
|
|
@@ -535,36 +565,6 @@ const isBlockedUA = function(ua, customBlockedUserAgents = []) {
|
|
|
535
565
|
return -1 !== uaLower.indexOf(blockedUaLower);
|
|
536
566
|
});
|
|
537
567
|
};
|
|
538
|
-
var types_PostHogPersistedProperty = /* @__PURE__ */ (function(PostHogPersistedProperty) {
|
|
539
|
-
PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
|
|
540
|
-
PostHogPersistedProperty["DistinctId"] = "distinct_id";
|
|
541
|
-
PostHogPersistedProperty["Props"] = "props";
|
|
542
|
-
PostHogPersistedProperty["EnablePersonProcessing"] = "enable_person_processing";
|
|
543
|
-
PostHogPersistedProperty["PersonMode"] = "person_mode";
|
|
544
|
-
PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
|
|
545
|
-
PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
|
|
546
|
-
PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
|
|
547
|
-
PostHogPersistedProperty["BootstrapFeatureFlagDetails"] = "bootstrap_feature_flag_details";
|
|
548
|
-
PostHogPersistedProperty["BootstrapFeatureFlags"] = "bootstrap_feature_flags";
|
|
549
|
-
PostHogPersistedProperty["BootstrapFeatureFlagPayloads"] = "bootstrap_feature_flag_payloads";
|
|
550
|
-
PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
|
|
551
|
-
PostHogPersistedProperty["Queue"] = "queue";
|
|
552
|
-
PostHogPersistedProperty["OptedOut"] = "opted_out";
|
|
553
|
-
PostHogPersistedProperty["SessionId"] = "session_id";
|
|
554
|
-
PostHogPersistedProperty["SessionStartTimestamp"] = "session_start_timestamp";
|
|
555
|
-
PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
|
|
556
|
-
PostHogPersistedProperty["PersonProperties"] = "person_properties";
|
|
557
|
-
PostHogPersistedProperty["GroupProperties"] = "group_properties";
|
|
558
|
-
PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
|
|
559
|
-
PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
|
|
560
|
-
PostHogPersistedProperty["SessionReplay"] = "session_replay";
|
|
561
|
-
PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
|
|
562
|
-
PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
|
|
563
|
-
PostHogPersistedProperty["Surveys"] = "surveys";
|
|
564
|
-
PostHogPersistedProperty["RemoteConfig"] = "remote_config";
|
|
565
|
-
PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
|
|
566
|
-
return PostHogPersistedProperty;
|
|
567
|
-
})({});
|
|
568
568
|
const nativeIsArray = Array.isArray;
|
|
569
569
|
const ObjProto = Object.prototype;
|
|
570
570
|
const type_utils_toString = ObjProto.toString;
|
|
@@ -2111,7 +2111,8 @@ class ErrorTracking {
|
|
|
2111
2111
|
properties: {
|
|
2112
2112
|
...exceptionProperties,
|
|
2113
2113
|
...properties
|
|
2114
|
-
}
|
|
2114
|
+
},
|
|
2115
|
+
_originatedFromCaptureException: true
|
|
2115
2116
|
};
|
|
2116
2117
|
}
|
|
2117
2118
|
startAutocaptureIfEnabled() {
|
|
@@ -2146,7 +2147,7 @@ class ErrorTracking {
|
|
|
2146
2147
|
this._rateLimiter.stop();
|
|
2147
2148
|
}
|
|
2148
2149
|
}
|
|
2149
|
-
const version = "5.
|
|
2150
|
+
const version = "5.26.0";
|
|
2150
2151
|
const FeatureFlagError = {
|
|
2151
2152
|
ERRORS_WHILE_COMPUTING: "errors_while_computing_flags",
|
|
2152
2153
|
FLAG_MISSING: "flag_missing",
|
|
@@ -2220,32 +2221,47 @@ class FeatureFlagsPoller {
|
|
|
2220
2221
|
logMsgIfDebug(fn) {
|
|
2221
2222
|
if (this.debugMode) fn();
|
|
2222
2223
|
}
|
|
2224
|
+
createEvaluationContext(distinctId, groups = {}, personProperties = {}, groupProperties = {}, evaluationCache = {}) {
|
|
2225
|
+
return {
|
|
2226
|
+
distinctId,
|
|
2227
|
+
groups,
|
|
2228
|
+
personProperties,
|
|
2229
|
+
groupProperties,
|
|
2230
|
+
evaluationCache
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2223
2233
|
async getFeatureFlag(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
|
|
2224
2234
|
await this.loadFeatureFlags();
|
|
2225
2235
|
let response;
|
|
2226
2236
|
let featureFlag;
|
|
2227
2237
|
if (!this.loadedSuccessfullyOnce) return response;
|
|
2228
2238
|
featureFlag = this.featureFlagsByKey[key];
|
|
2229
|
-
if (void 0 !== featureFlag)
|
|
2230
|
-
const
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2239
|
+
if (void 0 !== featureFlag) {
|
|
2240
|
+
const evaluationContext = this.createEvaluationContext(distinctId, groups, personProperties, groupProperties);
|
|
2241
|
+
try {
|
|
2242
|
+
const result = await this.computeFlagAndPayloadLocally(featureFlag, evaluationContext);
|
|
2243
|
+
response = result.value;
|
|
2244
|
+
this.logMsgIfDebug(() => console.debug(`Successfully computed flag locally: ${key} -> ${response}`));
|
|
2245
|
+
} catch (e) {
|
|
2246
|
+
if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError) this.logMsgIfDebug(() => console.debug(`${e.name} when computing flag locally: ${key}: ${e.message}`));
|
|
2247
|
+
else if (e instanceof Error) this.onError?.(new Error(`Error computing flag locally: ${key}: ${e}`));
|
|
2248
|
+
}
|
|
2236
2249
|
}
|
|
2237
2250
|
return response;
|
|
2238
2251
|
}
|
|
2239
|
-
async getAllFlagsAndPayloads(
|
|
2252
|
+
async getAllFlagsAndPayloads(evaluationContext, flagKeysToExplicitlyEvaluate) {
|
|
2240
2253
|
await this.loadFeatureFlags();
|
|
2241
2254
|
const response = {};
|
|
2242
2255
|
const payloads = {};
|
|
2243
2256
|
let fallbackToFlags = 0 == this.featureFlags.length;
|
|
2244
2257
|
const flagsToEvaluate = flagKeysToExplicitlyEvaluate ? flagKeysToExplicitlyEvaluate.map((key) => this.featureFlagsByKey[key]).filter(Boolean) : this.featureFlags;
|
|
2245
|
-
const
|
|
2258
|
+
const sharedEvaluationContext = {
|
|
2259
|
+
...evaluationContext,
|
|
2260
|
+
evaluationCache: evaluationContext.evaluationCache ?? {}
|
|
2261
|
+
};
|
|
2246
2262
|
await Promise.all(flagsToEvaluate.map(async (flag) => {
|
|
2247
2263
|
try {
|
|
2248
|
-
const { value: matchValue, payload: matchPayload } = await this.computeFlagAndPayloadLocally(flag,
|
|
2264
|
+
const { value: matchValue, payload: matchPayload } = await this.computeFlagAndPayloadLocally(flag, sharedEvaluationContext);
|
|
2249
2265
|
response[flag.key] = matchValue;
|
|
2250
2266
|
if (matchPayload) payloads[flag.key] = matchPayload;
|
|
2251
2267
|
} catch (e) {
|
|
@@ -2260,27 +2276,28 @@ class FeatureFlagsPoller {
|
|
|
2260
2276
|
fallbackToFlags
|
|
2261
2277
|
};
|
|
2262
2278
|
}
|
|
2263
|
-
async computeFlagAndPayloadLocally(flag,
|
|
2279
|
+
async computeFlagAndPayloadLocally(flag, evaluationContext, options = {}) {
|
|
2280
|
+
const { matchValue, skipLoadCheck = false } = options;
|
|
2264
2281
|
if (!skipLoadCheck) await this.loadFeatureFlags();
|
|
2265
2282
|
if (!this.loadedSuccessfullyOnce) return {
|
|
2266
2283
|
value: false,
|
|
2267
2284
|
payload: null
|
|
2268
2285
|
};
|
|
2269
2286
|
let flagValue;
|
|
2270
|
-
flagValue = void 0 !== matchValue ? matchValue : await this.computeFlagValueLocally(flag,
|
|
2287
|
+
flagValue = void 0 !== matchValue ? matchValue : await this.computeFlagValueLocally(flag, evaluationContext);
|
|
2271
2288
|
const payload = this.getFeatureFlagPayload(flag.key, flagValue);
|
|
2272
2289
|
return {
|
|
2273
2290
|
value: flagValue,
|
|
2274
2291
|
payload
|
|
2275
2292
|
};
|
|
2276
2293
|
}
|
|
2277
|
-
async computeFlagValueLocally(flag,
|
|
2294
|
+
async computeFlagValueLocally(flag, evaluationContext) {
|
|
2295
|
+
const { distinctId, groups, personProperties, groupProperties } = evaluationContext;
|
|
2278
2296
|
if (flag.ensure_experience_continuity) throw new InconclusiveMatchError("Flag has experience continuity enabled");
|
|
2279
2297
|
if (!flag.active) return false;
|
|
2280
2298
|
const flagFilters = flag.filters || {};
|
|
2281
2299
|
const aggregation_group_type_index = flagFilters.aggregation_group_type_index;
|
|
2282
|
-
if (void 0
|
|
2283
|
-
{
|
|
2300
|
+
if (void 0 != aggregation_group_type_index) {
|
|
2284
2301
|
const groupName = this.groupTypeMapping[String(aggregation_group_type_index)];
|
|
2285
2302
|
if (!groupName) {
|
|
2286
2303
|
this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Unknown group type index ${aggregation_group_type_index} for feature flag ${flag.key}`));
|
|
@@ -2290,9 +2307,27 @@ class FeatureFlagsPoller {
|
|
|
2290
2307
|
this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Can't compute group feature flag: ${flag.key} without group names passed in`));
|
|
2291
2308
|
return false;
|
|
2292
2309
|
}
|
|
2310
|
+
if ("device_id" === flag.bucketing_identifier && (personProperties?.$device_id === void 0 || personProperties?.$device_id === null || personProperties?.$device_id === "")) this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Ignoring bucketing_identifier for group flag: ${flag.key}`));
|
|
2293
2311
|
const focusedGroupProperties = groupProperties[groupName];
|
|
2294
|
-
return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties,
|
|
2312
|
+
return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties, evaluationContext);
|
|
2295
2313
|
}
|
|
2314
|
+
{
|
|
2315
|
+
const bucketingValue = this.getBucketingValueForFlag(flag, distinctId, personProperties);
|
|
2316
|
+
if (void 0 === bucketingValue) {
|
|
2317
|
+
this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Can't compute feature flag: ${flag.key} without $device_id, falling back to server evaluation`));
|
|
2318
|
+
throw new InconclusiveMatchError(`Can't compute feature flag: ${flag.key} without $device_id`);
|
|
2319
|
+
}
|
|
2320
|
+
return await this.matchFeatureFlagProperties(flag, bucketingValue, personProperties, evaluationContext);
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
getBucketingValueForFlag(flag, distinctId, properties) {
|
|
2324
|
+
if (flag.filters?.aggregation_group_type_index != void 0) return distinctId;
|
|
2325
|
+
if ("device_id" === flag.bucketing_identifier) {
|
|
2326
|
+
const deviceId = properties?.$device_id;
|
|
2327
|
+
if (null == deviceId || "" === deviceId) return;
|
|
2328
|
+
return deviceId;
|
|
2329
|
+
}
|
|
2330
|
+
return distinctId;
|
|
2296
2331
|
}
|
|
2297
2332
|
getFeatureFlagPayload(key, flagValue) {
|
|
2298
2333
|
let payload = null;
|
|
@@ -2310,7 +2345,8 @@ class FeatureFlagsPoller {
|
|
|
2310
2345
|
}
|
|
2311
2346
|
return null;
|
|
2312
2347
|
}
|
|
2313
|
-
async evaluateFlagDependency(property,
|
|
2348
|
+
async evaluateFlagDependency(property, properties, evaluationContext) {
|
|
2349
|
+
const { evaluationCache } = evaluationContext;
|
|
2314
2350
|
const targetFlagKey = property.key;
|
|
2315
2351
|
if (!this.featureFlagsByKey) throw new InconclusiveMatchError("Feature flags not available for dependency evaluation");
|
|
2316
2352
|
if (!("dependency_chain" in property)) throw new InconclusiveMatchError(`Flag dependency property for '${targetFlagKey}' is missing required 'dependency_chain' field`);
|
|
@@ -2321,7 +2357,7 @@ class FeatureFlagsPoller {
|
|
|
2321
2357
|
if (!(depFlagKey in evaluationCache)) {
|
|
2322
2358
|
const depFlag = this.featureFlagsByKey[depFlagKey];
|
|
2323
2359
|
if (depFlag) if (depFlag.active) try {
|
|
2324
|
-
const depResult = await this.
|
|
2360
|
+
const depResult = await this.computeFlagValueLocally(depFlag, evaluationContext);
|
|
2325
2361
|
evaluationCache[depFlagKey] = depResult;
|
|
2326
2362
|
} catch (error) {
|
|
2327
2363
|
throw new InconclusiveMatchError(`Error evaluating flag dependency '${depFlagKey}' for flag '${targetFlagKey}': ${error}`);
|
|
@@ -2340,16 +2376,16 @@ class FeatureFlagsPoller {
|
|
|
2340
2376
|
if ("string" == typeof expectedValue) return flagValue === expectedValue;
|
|
2341
2377
|
return false;
|
|
2342
2378
|
}
|
|
2343
|
-
async matchFeatureFlagProperties(flag,
|
|
2379
|
+
async matchFeatureFlagProperties(flag, bucketingValue, properties, evaluationContext) {
|
|
2344
2380
|
const flagFilters = flag.filters || {};
|
|
2345
2381
|
const flagConditions = flagFilters.groups || [];
|
|
2346
2382
|
let isInconclusive = false;
|
|
2347
2383
|
let result;
|
|
2348
2384
|
for (const condition of flagConditions) try {
|
|
2349
|
-
if (await this.isConditionMatch(flag,
|
|
2385
|
+
if (await this.isConditionMatch(flag, bucketingValue, condition, properties, evaluationContext)) {
|
|
2350
2386
|
const variantOverride = condition.variant;
|
|
2351
2387
|
const flagVariants = flagFilters.multivariate?.variants || [];
|
|
2352
|
-
result = variantOverride && flagVariants.some((variant) => variant.key === variantOverride) ? variantOverride : await this.getMatchingVariant(flag,
|
|
2388
|
+
result = variantOverride && flagVariants.some((variant) => variant.key === variantOverride) ? variantOverride : await this.getMatchingVariant(flag, bucketingValue) || true;
|
|
2353
2389
|
break;
|
|
2354
2390
|
}
|
|
2355
2391
|
} catch (e) {
|
|
@@ -2361,7 +2397,7 @@ class FeatureFlagsPoller {
|
|
|
2361
2397
|
if (isInconclusive) throw new InconclusiveMatchError("Can't determine if feature flag is enabled or not with given properties");
|
|
2362
2398
|
return false;
|
|
2363
2399
|
}
|
|
2364
|
-
async isConditionMatch(flag,
|
|
2400
|
+
async isConditionMatch(flag, bucketingValue, condition, properties, evaluationContext) {
|
|
2365
2401
|
const rolloutPercentage = condition.rollout_percentage;
|
|
2366
2402
|
const warnFunction = (msg) => {
|
|
2367
2403
|
this.logMsgIfDebug(() => console.warn(msg));
|
|
@@ -2370,16 +2406,16 @@ class FeatureFlagsPoller {
|
|
|
2370
2406
|
for (const prop of condition.properties) {
|
|
2371
2407
|
const propertyType = prop.type;
|
|
2372
2408
|
let matches = false;
|
|
2373
|
-
matches = "cohort" === propertyType ? matchCohort(prop, properties, this.cohorts, this.debugMode) : "flag" === propertyType ? await this.evaluateFlagDependency(prop,
|
|
2409
|
+
matches = "cohort" === propertyType ? matchCohort(prop, properties, this.cohorts, this.debugMode) : "flag" === propertyType ? await this.evaluateFlagDependency(prop, properties, evaluationContext) : matchProperty(prop, properties, warnFunction);
|
|
2374
2410
|
if (!matches) return false;
|
|
2375
2411
|
}
|
|
2376
2412
|
if (void 0 == rolloutPercentage) return true;
|
|
2377
2413
|
}
|
|
2378
|
-
if (void 0 != rolloutPercentage && await _hash(flag.key,
|
|
2414
|
+
if (void 0 != rolloutPercentage && await _hash(flag.key, bucketingValue) > rolloutPercentage / 100) return false;
|
|
2379
2415
|
return true;
|
|
2380
2416
|
}
|
|
2381
|
-
async getMatchingVariant(flag,
|
|
2382
|
-
const hashValue = await _hash(flag.key,
|
|
2417
|
+
async getMatchingVariant(flag, bucketingValue) {
|
|
2418
|
+
const hashValue = await _hash(flag.key, bucketingValue, "variant");
|
|
2383
2419
|
const matchingVariant = this.variantLookupTable(flag).find((variant) => hashValue >= variant.valueMin && hashValue < variant.valueMax);
|
|
2384
2420
|
if (matchingVariant) return matchingVariant.key;
|
|
2385
2421
|
}
|
|
@@ -2567,8 +2603,8 @@ class FeatureFlagsPoller {
|
|
|
2567
2603
|
}
|
|
2568
2604
|
}
|
|
2569
2605
|
}
|
|
2570
|
-
async function _hash(key,
|
|
2571
|
-
const hashString = await hashSHA1(`${key}.${
|
|
2606
|
+
async function _hash(key, bucketingValue, salt = "") {
|
|
2607
|
+
const hashString = await hashSHA1(`${key}.${bucketingValue}${salt}`);
|
|
2572
2608
|
return parseInt(hashString.slice(0, 15), 16) / LONG_SCALE;
|
|
2573
2609
|
}
|
|
2574
2610
|
function matchProperty(property, propertyValues, warnFunction) {
|
|
@@ -2804,6 +2840,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2804
2840
|
}
|
|
2805
2841
|
capture(props) {
|
|
2806
2842
|
if ("string" == typeof props) this._logger.warn("Called capture() with a string as the first argument when an object was expected.");
|
|
2843
|
+
if ("$exception" === props.event && !props._originatedFromCaptureException) this._logger.warn("Using `posthog.capture('$exception')` is unreliable because it does not attach required metadata. Use `posthog.captureException(error)` instead, which attaches required metadata automatically.");
|
|
2807
2844
|
this.addPendingPromise(this.prepareEventMessage(props).then(({ distinctId, event, properties, options }) => super.captureStateless(distinctId, event, properties, {
|
|
2808
2845
|
timestamp: options.timestamp,
|
|
2809
2846
|
disableGeoip: options.disableGeoip,
|
|
@@ -2814,6 +2851,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2814
2851
|
}
|
|
2815
2852
|
async captureImmediate(props) {
|
|
2816
2853
|
if ("string" == typeof props) this._logger.warn("Called captureImmediate() with a string as the first argument when an object was expected.");
|
|
2854
|
+
if ("$exception" === props.event && !props._originatedFromCaptureException) this._logger.warn("Capturing a `$exception` event via `posthog.captureImmediate('$exception')` is unreliable because it does not attach required metadata. Use `posthog.captureExceptionImmediate(error)` instead, which attaches this metadata by default.");
|
|
2817
2855
|
return this.addPendingPromise(this.prepareEventMessage(props).then(({ distinctId, event, properties, options }) => super.captureStatelessImmediate(distinctId, event, properties, {
|
|
2818
2856
|
timestamp: options.timestamp,
|
|
2819
2857
|
disableGeoip: options.disableGeoip,
|
|
@@ -2876,6 +2914,16 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2876
2914
|
});
|
|
2877
2915
|
});
|
|
2878
2916
|
}
|
|
2917
|
+
_resolveDistinctId(distinctIdOrOptions, options) {
|
|
2918
|
+
if ("string" == typeof distinctIdOrOptions) return {
|
|
2919
|
+
distinctId: distinctIdOrOptions,
|
|
2920
|
+
options
|
|
2921
|
+
};
|
|
2922
|
+
return {
|
|
2923
|
+
distinctId: this.context?.get()?.distinctId,
|
|
2924
|
+
options: distinctIdOrOptions
|
|
2925
|
+
};
|
|
2926
|
+
}
|
|
2879
2927
|
async _getFeatureFlagResult(key, distinctId, options = {}, matchValue) {
|
|
2880
2928
|
const sendFeatureFlagEvents = options.sendFeatureFlagEvents ?? true;
|
|
2881
2929
|
if (void 0 !== this._flagOverrides && key in this._flagOverrides) {
|
|
@@ -2894,6 +2942,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2894
2942
|
const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
|
|
2895
2943
|
personProperties = adjustedProperties.allPersonProperties;
|
|
2896
2944
|
groupProperties = adjustedProperties.allGroupProperties;
|
|
2945
|
+
const evaluationContext = this.createFeatureFlagEvaluationContext(distinctId, groups, personProperties, groupProperties);
|
|
2897
2946
|
if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
|
|
2898
2947
|
let result;
|
|
2899
2948
|
let flagWasLocallyEvaluated = false;
|
|
@@ -2908,7 +2957,9 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2908
2957
|
await this.featureFlagsPoller?.loadFeatureFlags();
|
|
2909
2958
|
const flag = this.featureFlagsPoller?.featureFlagsByKey[key];
|
|
2910
2959
|
if (flag) try {
|
|
2911
|
-
const localResult = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag,
|
|
2960
|
+
const localResult = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag, evaluationContext, {
|
|
2961
|
+
matchValue
|
|
2962
|
+
});
|
|
2912
2963
|
if (localResult) {
|
|
2913
2964
|
flagWasLocallyEvaluated = true;
|
|
2914
2965
|
const value = localResult.value;
|
|
@@ -2927,7 +2978,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2927
2978
|
}
|
|
2928
2979
|
}
|
|
2929
2980
|
if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
|
|
2930
|
-
const flagsResponse = await super.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [
|
|
2981
|
+
const flagsResponse = await super.getFeatureFlagDetailsStateless(evaluationContext.distinctId, evaluationContext.groups, evaluationContext.personProperties, evaluationContext.groupProperties, disableGeoip, [
|
|
2931
2982
|
key
|
|
2932
2983
|
]);
|
|
2933
2984
|
if (void 0 === flagsResponse) featureFlagError = FeatureFlagError.UNKNOWN_ERROR;
|
|
@@ -3013,10 +3064,12 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3013
3064
|
if (void 0 === result) return;
|
|
3014
3065
|
return result.payload ?? null;
|
|
3015
3066
|
}
|
|
3016
|
-
async getFeatureFlagResult(key,
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3067
|
+
async getFeatureFlagResult(key, distinctIdOrOptions, options) {
|
|
3068
|
+
const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
|
|
3069
|
+
if (!resolvedDistinctId) return void this._logger.warn("[PostHog] distinctId is required — pass it explicitly or use withContext()");
|
|
3070
|
+
return this._getFeatureFlagResult(key, resolvedDistinctId, {
|
|
3071
|
+
...resolvedOptions,
|
|
3072
|
+
sendFeatureFlagEvents: resolvedOptions?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
|
|
3020
3073
|
});
|
|
3021
3074
|
}
|
|
3022
3075
|
async getRemoteConfigPayload(flagKey) {
|
|
@@ -3035,18 +3088,32 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3035
3088
|
if (void 0 === feat) return;
|
|
3036
3089
|
return !!feat || false;
|
|
3037
3090
|
}
|
|
3038
|
-
async getAllFlags(
|
|
3039
|
-
const
|
|
3091
|
+
async getAllFlags(distinctIdOrOptions, options) {
|
|
3092
|
+
const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
|
|
3093
|
+
if (!resolvedDistinctId) {
|
|
3094
|
+
this._logger.warn("[PostHog] distinctId is required to get feature flags — pass it explicitly or use withContext()");
|
|
3095
|
+
return {};
|
|
3096
|
+
}
|
|
3097
|
+
const response = await this.getAllFlagsAndPayloads(resolvedDistinctId, resolvedOptions);
|
|
3040
3098
|
return response.featureFlags || {};
|
|
3041
3099
|
}
|
|
3042
|
-
async getAllFlagsAndPayloads(
|
|
3043
|
-
const {
|
|
3044
|
-
|
|
3045
|
-
|
|
3100
|
+
async getAllFlagsAndPayloads(distinctIdOrOptions, options) {
|
|
3101
|
+
const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
|
|
3102
|
+
if (!resolvedDistinctId) {
|
|
3103
|
+
this._logger.warn("[PostHog] distinctId is required to get feature flags and payloads — pass it explicitly or use withContext()");
|
|
3104
|
+
return {
|
|
3105
|
+
featureFlags: {},
|
|
3106
|
+
featureFlagPayloads: {}
|
|
3107
|
+
};
|
|
3108
|
+
}
|
|
3109
|
+
const { groups, disableGeoip, flagKeys } = resolvedOptions || {};
|
|
3110
|
+
let { onlyEvaluateLocally, personProperties, groupProperties } = resolvedOptions || {};
|
|
3111
|
+
const adjustedProperties = this.addLocalPersonAndGroupProperties(resolvedDistinctId, groups, personProperties, groupProperties);
|
|
3046
3112
|
personProperties = adjustedProperties.allPersonProperties;
|
|
3047
3113
|
groupProperties = adjustedProperties.allGroupProperties;
|
|
3114
|
+
const evaluationContext = this.createFeatureFlagEvaluationContext(resolvedDistinctId, groups, personProperties, groupProperties);
|
|
3048
3115
|
if (void 0 == onlyEvaluateLocally) onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
|
|
3049
|
-
const localEvaluationResult = await this.featureFlagsPoller?.getAllFlagsAndPayloads(
|
|
3116
|
+
const localEvaluationResult = await this.featureFlagsPoller?.getAllFlagsAndPayloads(evaluationContext, flagKeys);
|
|
3050
3117
|
let featureFlags = {};
|
|
3051
3118
|
let featureFlagPayloads = {};
|
|
3052
3119
|
let fallbackToFlags = true;
|
|
@@ -3056,7 +3123,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3056
3123
|
fallbackToFlags = localEvaluationResult.fallbackToFlags;
|
|
3057
3124
|
}
|
|
3058
3125
|
if (fallbackToFlags && !onlyEvaluateLocally) {
|
|
3059
|
-
const remoteEvaluationResult = await super.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeys);
|
|
3126
|
+
const remoteEvaluationResult = await super.getFeatureFlagsAndPayloadsStateless(evaluationContext.distinctId, evaluationContext.groups, evaluationContext.personProperties, evaluationContext.groupProperties, disableGeoip, flagKeys);
|
|
3060
3127
|
featureFlags = {
|
|
3061
3128
|
...featureFlags,
|
|
3062
3129
|
...remoteEvaluationResult.flags || {}
|
|
@@ -3141,6 +3208,9 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3141
3208
|
getContext() {
|
|
3142
3209
|
return this.context?.get();
|
|
3143
3210
|
}
|
|
3211
|
+
enterContext(data, options) {
|
|
3212
|
+
this.context?.enter(data, options);
|
|
3213
|
+
}
|
|
3144
3214
|
async _shutdown(shutdownTimeoutMs) {
|
|
3145
3215
|
this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
|
|
3146
3216
|
this.errorTracking.shutdown();
|
|
@@ -3238,6 +3308,15 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3238
3308
|
allGroupProperties
|
|
3239
3309
|
};
|
|
3240
3310
|
}
|
|
3311
|
+
createFeatureFlagEvaluationContext(distinctId, groups, personProperties, groupProperties) {
|
|
3312
|
+
return {
|
|
3313
|
+
distinctId,
|
|
3314
|
+
groups: groups || {},
|
|
3315
|
+
personProperties: personProperties || {},
|
|
3316
|
+
groupProperties: groupProperties || {},
|
|
3317
|
+
evaluationCache: {}
|
|
3318
|
+
};
|
|
3319
|
+
}
|
|
3241
3320
|
captureException(error, distinctId, additionalProperties, uuid) {
|
|
3242
3321
|
if (!ErrorTracking.isPreviouslyCapturedError(error)) {
|
|
3243
3322
|
const syntheticException = new Error("PostHog syntheticException");
|
|
@@ -3262,6 +3341,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3262
3341
|
const contextData = this.context?.get();
|
|
3263
3342
|
let mergedDistinctId = distinctId || contextData?.distinctId;
|
|
3264
3343
|
const mergedProperties = {
|
|
3344
|
+
...this.props,
|
|
3265
3345
|
...contextData?.properties || {},
|
|
3266
3346
|
...properties || {}
|
|
3267
3347
|
};
|
|
@@ -3348,20 +3428,22 @@ class PostHogContext {
|
|
|
3348
3428
|
return this.storage.getStore();
|
|
3349
3429
|
}
|
|
3350
3430
|
run(context, fn, options) {
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3431
|
+
return this.storage.run(this.resolve(context, options), fn);
|
|
3432
|
+
}
|
|
3433
|
+
enter(context, options) {
|
|
3434
|
+
this.storage.enterWith(this.resolve(context, options));
|
|
3435
|
+
}
|
|
3436
|
+
resolve(context, options) {
|
|
3437
|
+
if (options?.fresh === true) return context;
|
|
3438
|
+
const current = this.get() || {};
|
|
3439
|
+
return {
|
|
3440
|
+
distinctId: context.distinctId ?? current.distinctId,
|
|
3441
|
+
sessionId: context.sessionId ?? current.sessionId,
|
|
3442
|
+
properties: {
|
|
3443
|
+
...current.properties || {},
|
|
3444
|
+
...context.properties || {}
|
|
3445
|
+
}
|
|
3446
|
+
};
|
|
3365
3447
|
}
|
|
3366
3448
|
}
|
|
3367
3449
|
function setupExpressErrorHandler(_posthog, app) {
|