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/lib/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
- import { posix, dirname, sep } from 'node:path';
1
+ import { posix, dirname, sep } from 'path';
2
2
 
3
- var version = "4.11.6";
3
+ var version = "4.12.0";
4
4
 
5
5
  var PostHogPersistedProperty;
6
6
  (function (PostHogPersistedProperty) {
@@ -172,6 +172,90 @@ const parsePayload = (response) => {
172
172
  }
173
173
  };
174
174
 
175
+ // Rollout constants
176
+ const NEW_FLAGS_ROLLOUT_PERCENTAGE = 1;
177
+ // The fnv1a hashes of the tokens that are explicitly excluded from the rollout
178
+ // see https://github.com/PostHog/posthog-js-lite/blob/main/posthog-core/src/utils.ts#L84
179
+ // are hashed API tokens from our top 10 for each category supported by this SDK.
180
+ const NEW_FLAGS_EXCLUDED_HASHES = new Set([
181
+ // Node
182
+ '61be3dd8',
183
+ '96f6df5f',
184
+ '8cfdba9b',
185
+ 'bf027177',
186
+ 'e59430a8',
187
+ '7fa5500b',
188
+ '569798e9',
189
+ '04809ff7',
190
+ '0ebc61a5',
191
+ '32de7f98',
192
+ '3beeb69a',
193
+ '12d34ad9',
194
+ '733853ec',
195
+ '0645bb64',
196
+ '5dcbee21',
197
+ 'b1f95fa3',
198
+ '2189e408',
199
+ '82b460c2',
200
+ '3a8cc979',
201
+ '29ef8843',
202
+ '2cdbf767',
203
+ '38084b54',
204
+ // React Native
205
+ '50f9f8de',
206
+ '41d0df91',
207
+ '5c236689',
208
+ 'c11aedd3',
209
+ 'ada46672',
210
+ 'f4331ee1',
211
+ '42fed62a',
212
+ 'c957462c',
213
+ 'd62f705a',
214
+ // Web (lots of teams per org, hence lots of API tokens)
215
+ 'e0162666',
216
+ '01b3e5cf',
217
+ '441cef7f',
218
+ 'bb9cafee',
219
+ '8f348eb0',
220
+ 'b2553f3a',
221
+ '97469d7d',
222
+ '39f21a76',
223
+ '03706dcc',
224
+ '27d50569',
225
+ '307584a7',
226
+ '6433e92e',
227
+ '150c7fbb',
228
+ '49f57f22',
229
+ '3772f65b',
230
+ '01eb8256',
231
+ '3c9e9234',
232
+ 'f853c7f7',
233
+ 'c0ac4b67',
234
+ 'cd609d40',
235
+ '10ca9b1a',
236
+ '8a87f11b',
237
+ '8e8e5216',
238
+ '1f6b63b3',
239
+ 'db7943dd',
240
+ '79b7164c',
241
+ '07f78e33',
242
+ '2d21b6fd',
243
+ '952db5ee',
244
+ 'a7d3b43f',
245
+ '1924dd9c',
246
+ '84e1b8f6',
247
+ 'dff631b6',
248
+ 'c5aa8a79',
249
+ 'fa133a95',
250
+ '498a4508',
251
+ '24748755',
252
+ '98f3d658',
253
+ '21bbda67',
254
+ '7dbfed69',
255
+ 'be3ec24c',
256
+ 'fc80b8e2',
257
+ '75cc0998',
258
+ ]);
175
259
  function assert(truthyValue, message) {
176
260
  if (!truthyValue || typeof truthyValue !== 'string' || isEmpty(truthyValue)) {
177
261
  throw new Error(message);
@@ -222,6 +306,30 @@ function safeSetTimeout(fn, timeout) {
222
306
  }
223
307
  function getFetch() {
224
308
  return typeof fetch !== 'undefined' ? fetch : typeof global.fetch !== 'undefined' ? global.fetch : undefined;
309
+ }
310
+ // FNV-1a hash function
311
+ // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
312
+ // I know, I know, I'm rolling my own hash function, but I didn't want to take on
313
+ // a crypto dependency and this is just temporary anyway
314
+ function fnv1a(str) {
315
+ let hash = 0x811c9dc5; // FNV offset basis
316
+ for (let i = 0; i < str.length; i++) {
317
+ hash ^= str.charCodeAt(i);
318
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
319
+ }
320
+ // Convert to hex string, padding to 8 chars
321
+ return (hash >>> 0).toString(16).padStart(8, '0');
322
+ }
323
+ function isTokenInRollout(token, percentage = 0, excludedHashes) {
324
+ const tokenHash = fnv1a(token);
325
+ // Check excluded hashes (we're explicitly including these tokens from the rollout)
326
+ if (excludedHashes?.has(tokenHash)) {
327
+ return false;
328
+ }
329
+ // Convert hash to int and divide by max value to get number between 0-1
330
+ const hashInt = parseInt(tokenHash, 16);
331
+ const hashFloat = hashInt / 0xffffffff;
332
+ return hashFloat < percentage;
225
333
  }
226
334
 
227
335
  // Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
@@ -1301,7 +1409,11 @@ class PostHogCoreStateless {
1301
1409
  ***/
1302
1410
  async getDecide(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}) {
1303
1411
  await this._initPromise;
1304
- const url = `${this.host}/decide/?v=4`;
1412
+ // Check if the API token is in the new flags rollout
1413
+ // This is a temporary measure to ensure that we can still use the old flags API
1414
+ // while we migrate to the new flags API
1415
+ const useFlags = isTokenInRollout(this.apiKey, NEW_FLAGS_ROLLOUT_PERCENTAGE, NEW_FLAGS_EXCLUDED_HASHES);
1416
+ const url = useFlags ? `${this.host}/flags/?v=2` : `${this.host}/decide/?v=4`;
1305
1417
  const fetchOptions = {
1306
1418
  method: 'POST',
1307
1419
  headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
@@ -2580,7 +2692,7 @@ class ReduceableCache {
2580
2692
  // Portions of this file are derived from getsentry/sentry-javascript by Software, Inc. dba Sentry
2581
2693
  const nodeFs = new Lazy(async () => {
2582
2694
  try {
2583
- return await import('node:fs');
2695
+ return await import('fs');
2584
2696
  } catch {
2585
2697
  return undefined;
2586
2698
  }
@@ -2590,7 +2702,7 @@ async function getNodeFs() {
2590
2702
  }
2591
2703
  const nodeReadline = new Lazy(async () => {
2592
2704
  try {
2593
- return await import('node:readline');
2705
+ return await import('readline');
2594
2706
  } catch {
2595
2707
  return undefined;
2596
2708
  }