posthog-node 4.11.6 → 4.12.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 +8 -0
- package/lib/index.cjs.js +119 -7
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.esm.js +117 -5
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-core/src/utils.d.ts +3 -0
- package/lib/posthog-node/src/extensions/error-tracking/context-lines.d.ts +2 -2
- package/package.json +1 -1
- package/src/crypto-helpers.ts +1 -1
- package/src/extensions/error-tracking/context-lines.ts +4 -4
- package/src/extensions/error-tracking/stack-trace.ts +1 -1
- package/src/feature-flags.ts +1 -1
- package/test/feature-flags.decide.spec.ts +5 -5
- package/test/feature-flags.spec.ts +6 -6
- package/test/posthog-node.spec.ts +16 -16
- package/test/test-utils.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
# 4.12.0 – 2025-04-17
|
|
2
|
+
|
|
3
|
+
1. chore: roll out new feature flag evaluation backend to majority of customers
|
|
4
|
+
|
|
5
|
+
# 4.11.7 - 2025-04-16
|
|
6
|
+
|
|
7
|
+
1. fix: do not reference `node:` prefix as it is not supported by Next.js edge runtime
|
|
8
|
+
|
|
1
9
|
# 4.11.6 - 2025-04-15
|
|
2
10
|
|
|
3
11
|
## Fixed
|
package/lib/index.cjs.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var path = require('path');
|
|
6
6
|
|
|
7
7
|
function _interopNamespace(e) {
|
|
8
8
|
if (e && e.__esModule) return e;
|
|
@@ -22,7 +22,7 @@ function _interopNamespace(e) {
|
|
|
22
22
|
return Object.freeze(n);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
var version = "4.
|
|
25
|
+
var version = "4.12.0";
|
|
26
26
|
|
|
27
27
|
var PostHogPersistedProperty;
|
|
28
28
|
(function (PostHogPersistedProperty) {
|
|
@@ -194,6 +194,90 @@ const parsePayload = (response) => {
|
|
|
194
194
|
}
|
|
195
195
|
};
|
|
196
196
|
|
|
197
|
+
// Rollout constants
|
|
198
|
+
const NEW_FLAGS_ROLLOUT_PERCENTAGE = 1;
|
|
199
|
+
// The fnv1a hashes of the tokens that are explicitly excluded from the rollout
|
|
200
|
+
// see https://github.com/PostHog/posthog-js-lite/blob/main/posthog-core/src/utils.ts#L84
|
|
201
|
+
// are hashed API tokens from our top 10 for each category supported by this SDK.
|
|
202
|
+
const NEW_FLAGS_EXCLUDED_HASHES = new Set([
|
|
203
|
+
// Node
|
|
204
|
+
'61be3dd8',
|
|
205
|
+
'96f6df5f',
|
|
206
|
+
'8cfdba9b',
|
|
207
|
+
'bf027177',
|
|
208
|
+
'e59430a8',
|
|
209
|
+
'7fa5500b',
|
|
210
|
+
'569798e9',
|
|
211
|
+
'04809ff7',
|
|
212
|
+
'0ebc61a5',
|
|
213
|
+
'32de7f98',
|
|
214
|
+
'3beeb69a',
|
|
215
|
+
'12d34ad9',
|
|
216
|
+
'733853ec',
|
|
217
|
+
'0645bb64',
|
|
218
|
+
'5dcbee21',
|
|
219
|
+
'b1f95fa3',
|
|
220
|
+
'2189e408',
|
|
221
|
+
'82b460c2',
|
|
222
|
+
'3a8cc979',
|
|
223
|
+
'29ef8843',
|
|
224
|
+
'2cdbf767',
|
|
225
|
+
'38084b54',
|
|
226
|
+
// React Native
|
|
227
|
+
'50f9f8de',
|
|
228
|
+
'41d0df91',
|
|
229
|
+
'5c236689',
|
|
230
|
+
'c11aedd3',
|
|
231
|
+
'ada46672',
|
|
232
|
+
'f4331ee1',
|
|
233
|
+
'42fed62a',
|
|
234
|
+
'c957462c',
|
|
235
|
+
'd62f705a',
|
|
236
|
+
// Web (lots of teams per org, hence lots of API tokens)
|
|
237
|
+
'e0162666',
|
|
238
|
+
'01b3e5cf',
|
|
239
|
+
'441cef7f',
|
|
240
|
+
'bb9cafee',
|
|
241
|
+
'8f348eb0',
|
|
242
|
+
'b2553f3a',
|
|
243
|
+
'97469d7d',
|
|
244
|
+
'39f21a76',
|
|
245
|
+
'03706dcc',
|
|
246
|
+
'27d50569',
|
|
247
|
+
'307584a7',
|
|
248
|
+
'6433e92e',
|
|
249
|
+
'150c7fbb',
|
|
250
|
+
'49f57f22',
|
|
251
|
+
'3772f65b',
|
|
252
|
+
'01eb8256',
|
|
253
|
+
'3c9e9234',
|
|
254
|
+
'f853c7f7',
|
|
255
|
+
'c0ac4b67',
|
|
256
|
+
'cd609d40',
|
|
257
|
+
'10ca9b1a',
|
|
258
|
+
'8a87f11b',
|
|
259
|
+
'8e8e5216',
|
|
260
|
+
'1f6b63b3',
|
|
261
|
+
'db7943dd',
|
|
262
|
+
'79b7164c',
|
|
263
|
+
'07f78e33',
|
|
264
|
+
'2d21b6fd',
|
|
265
|
+
'952db5ee',
|
|
266
|
+
'a7d3b43f',
|
|
267
|
+
'1924dd9c',
|
|
268
|
+
'84e1b8f6',
|
|
269
|
+
'dff631b6',
|
|
270
|
+
'c5aa8a79',
|
|
271
|
+
'fa133a95',
|
|
272
|
+
'498a4508',
|
|
273
|
+
'24748755',
|
|
274
|
+
'98f3d658',
|
|
275
|
+
'21bbda67',
|
|
276
|
+
'7dbfed69',
|
|
277
|
+
'be3ec24c',
|
|
278
|
+
'fc80b8e2',
|
|
279
|
+
'75cc0998',
|
|
280
|
+
]);
|
|
197
281
|
function assert(truthyValue, message) {
|
|
198
282
|
if (!truthyValue || typeof truthyValue !== 'string' || isEmpty(truthyValue)) {
|
|
199
283
|
throw new Error(message);
|
|
@@ -244,6 +328,30 @@ function safeSetTimeout(fn, timeout) {
|
|
|
244
328
|
}
|
|
245
329
|
function getFetch() {
|
|
246
330
|
return typeof fetch !== 'undefined' ? fetch : typeof global.fetch !== 'undefined' ? global.fetch : undefined;
|
|
331
|
+
}
|
|
332
|
+
// FNV-1a hash function
|
|
333
|
+
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
|
334
|
+
// I know, I know, I'm rolling my own hash function, but I didn't want to take on
|
|
335
|
+
// a crypto dependency and this is just temporary anyway
|
|
336
|
+
function fnv1a(str) {
|
|
337
|
+
let hash = 0x811c9dc5; // FNV offset basis
|
|
338
|
+
for (let i = 0; i < str.length; i++) {
|
|
339
|
+
hash ^= str.charCodeAt(i);
|
|
340
|
+
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
|
|
341
|
+
}
|
|
342
|
+
// Convert to hex string, padding to 8 chars
|
|
343
|
+
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
344
|
+
}
|
|
345
|
+
function isTokenInRollout(token, percentage = 0, excludedHashes) {
|
|
346
|
+
const tokenHash = fnv1a(token);
|
|
347
|
+
// Check excluded hashes (we're explicitly including these tokens from the rollout)
|
|
348
|
+
if (excludedHashes?.has(tokenHash)) {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
// Convert hash to int and divide by max value to get number between 0-1
|
|
352
|
+
const hashInt = parseInt(tokenHash, 16);
|
|
353
|
+
const hashFloat = hashInt / 0xffffffff;
|
|
354
|
+
return hashFloat < percentage;
|
|
247
355
|
}
|
|
248
356
|
|
|
249
357
|
// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
|
|
@@ -1323,7 +1431,11 @@ class PostHogCoreStateless {
|
|
|
1323
1431
|
***/
|
|
1324
1432
|
async getDecide(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}) {
|
|
1325
1433
|
await this._initPromise;
|
|
1326
|
-
|
|
1434
|
+
// Check if the API token is in the new flags rollout
|
|
1435
|
+
// This is a temporary measure to ensure that we can still use the old flags API
|
|
1436
|
+
// while we migrate to the new flags API
|
|
1437
|
+
const useFlags = isTokenInRollout(this.apiKey, NEW_FLAGS_ROLLOUT_PERCENTAGE, NEW_FLAGS_EXCLUDED_HASHES);
|
|
1438
|
+
const url = useFlags ? `${this.host}/flags/?v=2` : `${this.host}/decide/?v=4`;
|
|
1327
1439
|
const fetchOptions = {
|
|
1328
1440
|
method: 'POST',
|
|
1329
1441
|
headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
|
|
@@ -2602,7 +2714,7 @@ class ReduceableCache {
|
|
|
2602
2714
|
// Portions of this file are derived from getsentry/sentry-javascript by Software, Inc. dba Sentry
|
|
2603
2715
|
const nodeFs = new Lazy(async () => {
|
|
2604
2716
|
try {
|
|
2605
|
-
return await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('
|
|
2717
|
+
return await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('fs')); });
|
|
2606
2718
|
} catch {
|
|
2607
2719
|
return undefined;
|
|
2608
2720
|
}
|
|
@@ -2612,7 +2724,7 @@ async function getNodeFs() {
|
|
|
2612
2724
|
}
|
|
2613
2725
|
const nodeReadline = new Lazy(async () => {
|
|
2614
2726
|
try {
|
|
2615
|
-
return await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('
|
|
2727
|
+
return await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('readline')); });
|
|
2616
2728
|
} catch {
|
|
2617
2729
|
return undefined;
|
|
2618
2730
|
}
|
|
@@ -3260,7 +3372,7 @@ function nodeStackLineParser(getModule) {
|
|
|
3260
3372
|
}
|
|
3261
3373
|
const defaultStackParser = createStackParser(nodeStackLineParser(createGetModuleFromFilename()));
|
|
3262
3374
|
/** Creates a function that gets the module name from a filename */
|
|
3263
|
-
function createGetModuleFromFilename(basePath = process.argv[1] ?
|
|
3375
|
+
function createGetModuleFromFilename(basePath = process.argv[1] ? path.dirname(process.argv[1]) : process.cwd(), isWindows = path.sep === '\\') {
|
|
3264
3376
|
const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
|
|
3265
3377
|
return filename => {
|
|
3266
3378
|
if (!filename) {
|
|
@@ -3272,7 +3384,7 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? node_path.dirn
|
|
|
3272
3384
|
dir,
|
|
3273
3385
|
base: file,
|
|
3274
3386
|
ext
|
|
3275
|
-
} =
|
|
3387
|
+
} = path.posix.parse(normalizedFilename);
|
|
3276
3388
|
if (ext === '.js' || ext === '.mjs' || ext === '.cjs') {
|
|
3277
3389
|
file = file.slice(0, ext.length * -1);
|
|
3278
3390
|
}
|