posthog-js-lite 3.5.1 → 3.6.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 +7 -0
- package/lib/index.cjs +89 -39
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +44 -37
- package/lib/index.mjs +89 -39
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/posthog-web.ts +7 -2
package/CHANGELOG.md
CHANGED
package/lib/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var version = "3.
|
|
5
|
+
var version = "3.6.0";
|
|
6
6
|
|
|
7
7
|
var PostHogPersistedProperty;
|
|
8
8
|
(function (PostHogPersistedProperty) {
|
|
@@ -19,6 +19,7 @@ var PostHogPersistedProperty;
|
|
|
19
19
|
PostHogPersistedProperty["Queue"] = "queue";
|
|
20
20
|
PostHogPersistedProperty["OptedOut"] = "opted_out";
|
|
21
21
|
PostHogPersistedProperty["SessionId"] = "session_id";
|
|
22
|
+
PostHogPersistedProperty["SessionStartTimestamp"] = "session_start_timestamp";
|
|
22
23
|
PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
|
|
23
24
|
PostHogPersistedProperty["PersonProperties"] = "person_properties";
|
|
24
25
|
PostHogPersistedProperty["GroupProperties"] = "group_properties";
|
|
@@ -371,6 +372,9 @@ function isTokenInRollout(token, percentage = 0, excludedHashes) {
|
|
|
371
372
|
const hashInt = parseInt(tokenHash, 16);
|
|
372
373
|
const hashFloat = hashInt / 0xffffffff;
|
|
373
374
|
return hashFloat < percentage;
|
|
375
|
+
}
|
|
376
|
+
function allSettled(promises) {
|
|
377
|
+
return Promise.all(promises.map((p) => (p ?? Promise.resolve()).then((value) => ({ status: 'fulfilled', value }), (reason) => ({ status: 'rejected', reason }))));
|
|
374
378
|
}
|
|
375
379
|
|
|
376
380
|
// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
|
|
@@ -1261,6 +1265,7 @@ class PostHogFetchNetworkError extends Error {
|
|
|
1261
1265
|
this.name = 'PostHogFetchNetworkError';
|
|
1262
1266
|
}
|
|
1263
1267
|
}
|
|
1268
|
+
const maybeAdd = (key, value) => value !== undefined ? { [key]: value } : {};
|
|
1264
1269
|
async function logFlushError(err) {
|
|
1265
1270
|
if (err instanceof PostHogFetchHttpError) {
|
|
1266
1271
|
let text = '';
|
|
@@ -1521,6 +1526,7 @@ class PostHogCoreStateless {
|
|
|
1521
1526
|
...extraPayload,
|
|
1522
1527
|
}),
|
|
1523
1528
|
};
|
|
1529
|
+
this.logMsgIfDebug(() => console.log('PostHog Debug', 'Decide URL', url));
|
|
1524
1530
|
// Don't retry /decide API calls
|
|
1525
1531
|
return this.fetchWithRetry(url, fetchOptions, { retryCount: 0 }, this.featureFlagsRequestTimeoutMs)
|
|
1526
1532
|
.then((response) => response.json())
|
|
@@ -1638,7 +1644,7 @@ class PostHogCoreStateless {
|
|
|
1638
1644
|
async getSurveysStateless() {
|
|
1639
1645
|
await this._initPromise;
|
|
1640
1646
|
if (this.disableSurveys === true) {
|
|
1641
|
-
this.logMsgIfDebug(() => console.log('Loading surveys is disabled.'));
|
|
1647
|
+
this.logMsgIfDebug(() => console.log('PostHog Debug', 'Loading surveys is disabled.'));
|
|
1642
1648
|
return [];
|
|
1643
1649
|
}
|
|
1644
1650
|
const url = `${this.host}/api/surveys/?token=${this.apiKey}`;
|
|
@@ -1761,7 +1767,6 @@ class PostHogCoreStateless {
|
|
|
1761
1767
|
}
|
|
1762
1768
|
catch (err) {
|
|
1763
1769
|
this._events.emit('error', err);
|
|
1764
|
-
throw err;
|
|
1765
1770
|
}
|
|
1766
1771
|
}
|
|
1767
1772
|
prepareMessage(type, _message, options) {
|
|
@@ -1801,15 +1806,38 @@ class PostHogCoreStateless {
|
|
|
1801
1806
|
await logFlushError(err);
|
|
1802
1807
|
});
|
|
1803
1808
|
}
|
|
1809
|
+
/**
|
|
1810
|
+
* Flushes the queue
|
|
1811
|
+
*
|
|
1812
|
+
* This function will return a promise that will resolve when the flush is complete,
|
|
1813
|
+
* or reject if there was an error (for example if the server or network is down).
|
|
1814
|
+
*
|
|
1815
|
+
* If there is already a flush in progress, this function will wait for that flush to complete.
|
|
1816
|
+
*
|
|
1817
|
+
* It's recommended to do error handling in the callback of the promise.
|
|
1818
|
+
*
|
|
1819
|
+
* @example
|
|
1820
|
+
* posthog.flush().then(() => {
|
|
1821
|
+
* console.log('Flush complete')
|
|
1822
|
+
* }).catch((err) => {
|
|
1823
|
+
* console.error('Flush failed', err)
|
|
1824
|
+
* })
|
|
1825
|
+
*
|
|
1826
|
+
*
|
|
1827
|
+
* @throws PostHogFetchHttpError
|
|
1828
|
+
* @throws PostHogFetchNetworkError
|
|
1829
|
+
* @throws Error
|
|
1830
|
+
*/
|
|
1804
1831
|
async flush() {
|
|
1805
1832
|
// Wait for the current flush operation to finish (regardless of success or failure), then try to flush again.
|
|
1806
1833
|
// Use allSettled instead of finally to be defensive around flush throwing errors immediately rather than rejecting.
|
|
1807
|
-
|
|
1834
|
+
// Use a custom allSettled implementation to avoid issues with patching Promise on RN
|
|
1835
|
+
const nextFlushPromise = allSettled([this.flushPromise]).then(() => {
|
|
1808
1836
|
return this._flush();
|
|
1809
1837
|
});
|
|
1810
1838
|
this.flushPromise = nextFlushPromise;
|
|
1811
1839
|
void this.addPendingPromise(nextFlushPromise);
|
|
1812
|
-
|
|
1840
|
+
allSettled([nextFlushPromise]).then(() => {
|
|
1813
1841
|
// If there are no others waiting to flush, clear the promise.
|
|
1814
1842
|
// We don't strictly need to do this, but it could make debugging easier
|
|
1815
1843
|
if (this.flushPromise === nextFlushPromise) {
|
|
@@ -1835,7 +1863,7 @@ class PostHogCoreStateless {
|
|
|
1835
1863
|
await this._initPromise;
|
|
1836
1864
|
let queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
|
|
1837
1865
|
if (!queue.length) {
|
|
1838
|
-
return
|
|
1866
|
+
return;
|
|
1839
1867
|
}
|
|
1840
1868
|
const sentMessages = [];
|
|
1841
1869
|
const originalQueueLength = queue.length;
|
|
@@ -1906,7 +1934,6 @@ class PostHogCoreStateless {
|
|
|
1906
1934
|
sentMessages.push(...batchMessages);
|
|
1907
1935
|
}
|
|
1908
1936
|
this._events.emit('flush', sentMessages);
|
|
1909
|
-
return sentMessages;
|
|
1910
1937
|
}
|
|
1911
1938
|
async fetchWithRetry(url, options, retryOptions, requestTimeout) {
|
|
1912
1939
|
var _a;
|
|
@@ -1916,7 +1943,14 @@ class PostHogCoreStateless {
|
|
|
1916
1943
|
return ctrl.signal;
|
|
1917
1944
|
});
|
|
1918
1945
|
const body = options.body ? options.body : '';
|
|
1919
|
-
|
|
1946
|
+
let reqByteLength = -1;
|
|
1947
|
+
try {
|
|
1948
|
+
reqByteLength = Buffer.byteLength(body, STRING_FORMAT);
|
|
1949
|
+
}
|
|
1950
|
+
catch {
|
|
1951
|
+
const encoded = new TextEncoder().encode(body);
|
|
1952
|
+
reqByteLength = encoded.length;
|
|
1953
|
+
}
|
|
1920
1954
|
return await retriable(async () => {
|
|
1921
1955
|
let res = null;
|
|
1922
1956
|
try {
|
|
@@ -2005,6 +2039,7 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2005
2039
|
const featureFlagsRequestTimeoutMs = options?.featureFlagsRequestTimeoutMs ?? 10000; // 10 seconds
|
|
2006
2040
|
super(apiKey, { ...options, disableGeoip: disableGeoipOption, featureFlagsRequestTimeoutMs });
|
|
2007
2041
|
this.flagCallReported = {};
|
|
2042
|
+
this._sessionMaxLengthSeconds = 24 * 60 * 60; // 24 hours
|
|
2008
2043
|
this.sessionProps = {};
|
|
2009
2044
|
this.sendFeatureFlagEvent = options?.sendFeatureFlagEvent ?? true;
|
|
2010
2045
|
this._sessionExpirationTimeSeconds = options?.sessionExpirationTimeSeconds ?? 1800; // 30 minutes
|
|
@@ -2078,7 +2113,7 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2078
2113
|
}
|
|
2079
2114
|
}
|
|
2080
2115
|
return {
|
|
2081
|
-
$active_feature_flags
|
|
2116
|
+
...maybeAdd('$active_feature_flags', featureFlags ? Object.keys(featureFlags) : undefined),
|
|
2082
2117
|
...featureVariantProperties,
|
|
2083
2118
|
...super.getCommonEventProperties(),
|
|
2084
2119
|
};
|
|
@@ -2100,18 +2135,26 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2100
2135
|
return '';
|
|
2101
2136
|
}
|
|
2102
2137
|
let sessionId = this.getPersistedProperty(PostHogPersistedProperty.SessionId);
|
|
2103
|
-
const
|
|
2104
|
-
|
|
2138
|
+
const sessionLastTimestamp = this.getPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp) || 0;
|
|
2139
|
+
const sessionStartTimestamp = this.getPersistedProperty(PostHogPersistedProperty.SessionStartTimestamp) || 0;
|
|
2140
|
+
const now = Date.now();
|
|
2141
|
+
const sessionLastDif = now - sessionLastTimestamp;
|
|
2142
|
+
const sessionStartDif = now - sessionStartTimestamp;
|
|
2143
|
+
if (!sessionId ||
|
|
2144
|
+
sessionLastDif > this._sessionExpirationTimeSeconds * 1000 ||
|
|
2145
|
+
sessionStartDif > this._sessionMaxLengthSeconds * 1000) {
|
|
2105
2146
|
sessionId = uuidv7();
|
|
2106
2147
|
this.setPersistedProperty(PostHogPersistedProperty.SessionId, sessionId);
|
|
2148
|
+
this.setPersistedProperty(PostHogPersistedProperty.SessionStartTimestamp, now);
|
|
2107
2149
|
}
|
|
2108
|
-
this.setPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp,
|
|
2150
|
+
this.setPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp, now);
|
|
2109
2151
|
return sessionId;
|
|
2110
2152
|
}
|
|
2111
2153
|
resetSessionId() {
|
|
2112
2154
|
this.wrap(() => {
|
|
2113
2155
|
this.setPersistedProperty(PostHogPersistedProperty.SessionId, null);
|
|
2114
2156
|
this.setPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp, null);
|
|
2157
|
+
this.setPersistedProperty(PostHogPersistedProperty.SessionStartTimestamp, null);
|
|
2115
2158
|
});
|
|
2116
2159
|
}
|
|
2117
2160
|
/**
|
|
@@ -2163,8 +2206,8 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2163
2206
|
const userProps = properties?.$set || properties;
|
|
2164
2207
|
const allProperties = this.enrichProperties({
|
|
2165
2208
|
$anon_distinct_id: this.getAnonymousId(),
|
|
2166
|
-
$set
|
|
2167
|
-
$set_once
|
|
2209
|
+
...maybeAdd('$set', userProps),
|
|
2210
|
+
...maybeAdd('$set_once', userPropsOnce),
|
|
2168
2211
|
});
|
|
2169
2212
|
if (distinctId !== previousDistinctId) {
|
|
2170
2213
|
// We keep the AnonymousId to be used by decide calls and identify to link the previousId
|
|
@@ -2312,14 +2355,16 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2312
2355
|
}
|
|
2313
2356
|
return this._decideAsync(sendAnonDistinctId);
|
|
2314
2357
|
}
|
|
2315
|
-
cacheSessionReplay(response) {
|
|
2358
|
+
cacheSessionReplay(source, response) {
|
|
2316
2359
|
const sessionReplay = response?.sessionRecording;
|
|
2317
2360
|
if (sessionReplay) {
|
|
2318
2361
|
this.setPersistedProperty(PostHogPersistedProperty.SessionReplay, sessionReplay);
|
|
2319
|
-
this.logMsgIfDebug(() => console.log('PostHog Debug',
|
|
2362
|
+
this.logMsgIfDebug(() => console.log('PostHog Debug', `Session replay config from ${source}: `, JSON.stringify(sessionReplay)));
|
|
2320
2363
|
}
|
|
2321
|
-
else {
|
|
2322
|
-
|
|
2364
|
+
else if (typeof sessionReplay === 'boolean' && sessionReplay === false) {
|
|
2365
|
+
// if session replay is disabled, we don't need to cache it
|
|
2366
|
+
// we need to check for this because the response might be undefined (/flags does not return sessionRecording yet)
|
|
2367
|
+
this.logMsgIfDebug(() => console.info('PostHog Debug', `Session replay config from ${source} disabled.`));
|
|
2323
2368
|
this.setPersistedProperty(PostHogPersistedProperty.SessionReplay, null);
|
|
2324
2369
|
}
|
|
2325
2370
|
}
|
|
@@ -2333,25 +2378,30 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2333
2378
|
const remoteConfigWithoutSurveys = { ...response };
|
|
2334
2379
|
delete remoteConfigWithoutSurveys.surveys;
|
|
2335
2380
|
this.logMsgIfDebug(() => console.log('PostHog Debug', 'Fetched remote config: ', JSON.stringify(remoteConfigWithoutSurveys)));
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2381
|
+
if (this.disableSurveys === false) {
|
|
2382
|
+
const surveys = response.surveys;
|
|
2383
|
+
let hasSurveys = true;
|
|
2384
|
+
if (!Array.isArray(surveys)) {
|
|
2385
|
+
// If surveys is not an array, it means there are no surveys (its a boolean instead)
|
|
2386
|
+
this.logMsgIfDebug(() => console.log('PostHog Debug', 'There are no surveys.'));
|
|
2387
|
+
hasSurveys = false;
|
|
2388
|
+
}
|
|
2389
|
+
else {
|
|
2390
|
+
this.logMsgIfDebug(() => console.log('PostHog Debug', 'Surveys fetched from remote config: ', JSON.stringify(surveys)));
|
|
2391
|
+
}
|
|
2392
|
+
if (hasSurveys) {
|
|
2393
|
+
this.setPersistedProperty(PostHogPersistedProperty.Surveys, surveys);
|
|
2394
|
+
}
|
|
2395
|
+
else {
|
|
2396
|
+
this.setPersistedProperty(PostHogPersistedProperty.Surveys, null);
|
|
2397
|
+
}
|
|
2348
2398
|
}
|
|
2349
2399
|
else {
|
|
2350
2400
|
this.setPersistedProperty(PostHogPersistedProperty.Surveys, null);
|
|
2351
2401
|
}
|
|
2352
2402
|
// we cache the surveys in its own storage key
|
|
2353
2403
|
this.setPersistedProperty(PostHogPersistedProperty.RemoteConfig, remoteConfigWithoutSurveys);
|
|
2354
|
-
this.cacheSessionReplay(response);
|
|
2404
|
+
this.cacheSessionReplay('remote config', response);
|
|
2355
2405
|
// we only dont load flags if the remote config has no feature flags
|
|
2356
2406
|
if (response.hasFeatureFlags === false) {
|
|
2357
2407
|
// resetting flags to empty object
|
|
@@ -2408,7 +2458,7 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2408
2458
|
this.setKnownFeatureFlagDetails(newFeatureFlagDetails);
|
|
2409
2459
|
// Mark that we hit the /decide endpoint so we can capture this in the $feature_flag_called event
|
|
2410
2460
|
this.setPersistedProperty(PostHogPersistedProperty.DecideEndpointWasHit, true);
|
|
2411
|
-
this.cacheSessionReplay(res);
|
|
2461
|
+
this.cacheSessionReplay('decide/flags', res);
|
|
2412
2462
|
}
|
|
2413
2463
|
return res;
|
|
2414
2464
|
})
|
|
@@ -2494,14 +2544,14 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2494
2544
|
this.capture('$feature_flag_called', {
|
|
2495
2545
|
$feature_flag: key,
|
|
2496
2546
|
$feature_flag_response: response,
|
|
2497
|
-
$feature_flag_id
|
|
2498
|
-
$feature_flag_version
|
|
2499
|
-
$feature_flag_reason
|
|
2500
|
-
$feature_flag_bootstrapped_response
|
|
2501
|
-
$feature_flag_bootstrapped_payload
|
|
2547
|
+
...maybeAdd('$feature_flag_id', featureFlag?.metadata?.id),
|
|
2548
|
+
...maybeAdd('$feature_flag_version', featureFlag?.metadata?.version),
|
|
2549
|
+
...maybeAdd('$feature_flag_reason', featureFlag?.reason?.description ?? featureFlag?.reason?.code),
|
|
2550
|
+
...maybeAdd('$feature_flag_bootstrapped_response', bootstrappedResponse),
|
|
2551
|
+
...maybeAdd('$feature_flag_bootstrapped_payload', bootstrappedPayload),
|
|
2502
2552
|
// If we haven't yet received a response from the /decide endpoint, we must have used the bootstrapped value
|
|
2503
2553
|
$used_bootstrap_value: !this.getPersistedProperty(PostHogPersistedProperty.DecideEndpointWasHit),
|
|
2504
|
-
$feature_flag_request_id
|
|
2554
|
+
...maybeAdd('$feature_flag_request_id', details.requestId),
|
|
2505
2555
|
});
|
|
2506
2556
|
}
|
|
2507
2557
|
// If we have flags we either return the value (true or string) or false
|
|
@@ -2575,7 +2625,7 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2575
2625
|
.catch((e) => {
|
|
2576
2626
|
cb?.(e, undefined);
|
|
2577
2627
|
if (!cb) {
|
|
2578
|
-
this.logMsgIfDebug(() => console.log('
|
|
2628
|
+
this.logMsgIfDebug(() => console.log('PostHog Debug', 'Error reloading feature flags', e));
|
|
2579
2629
|
}
|
|
2580
2630
|
});
|
|
2581
2631
|
}
|