@rpcbase/server 0.546.0 → 0.548.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 +532 -283
- package/dist/index.js.map +1 -1
- package/dist/initServer.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,8 @@ import { createClient } from "redis";
|
|
|
5
5
|
import { MongoClient } from "mongodb";
|
|
6
6
|
import env from "@rpcbase/env";
|
|
7
7
|
import { initApiClient, STATIC_RPCBASE_RTS_HYDRATION_DATA_KEY, RtsSsrRuntimeProvider, SsrErrorFallback, SSR_ERROR_STATE_GLOBAL_KEY, serializeSsrErrorState } from "@rpcbase/client";
|
|
8
|
-
import {
|
|
8
|
+
import { getMongoUrl } from "@rpcbase/db/mongo";
|
|
9
|
+
import { posix, dirname, sep, isAbsolute, relative } from "path";
|
|
9
10
|
import fs, { createReadStream, readFileSync } from "node:fs";
|
|
10
11
|
import { createInterface } from "node:readline";
|
|
11
12
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -290,194 +291,23 @@ const parsePayload = (response) => {
|
|
|
290
291
|
return response;
|
|
291
292
|
}
|
|
292
293
|
};
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
constructor(bytes) {
|
|
296
|
-
this.bytes = bytes;
|
|
297
|
-
}
|
|
298
|
-
static ofInner(bytes) {
|
|
299
|
-
if (16 === bytes.length) return new UUID(bytes);
|
|
300
|
-
throw new TypeError("not 128-bit length");
|
|
301
|
-
}
|
|
302
|
-
static fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
|
|
303
|
-
if (!Number.isInteger(unixTsMs) || !Number.isInteger(randA) || !Number.isInteger(randBHi) || !Number.isInteger(randBLo) || unixTsMs < 0 || randA < 0 || randBHi < 0 || randBLo < 0 || unixTsMs > 281474976710655 || randA > 4095 || randBHi > 1073741823 || randBLo > 4294967295) throw new RangeError("invalid field value");
|
|
304
|
-
const bytes = new Uint8Array(16);
|
|
305
|
-
bytes[0] = unixTsMs / 2 ** 40;
|
|
306
|
-
bytes[1] = unixTsMs / 2 ** 32;
|
|
307
|
-
bytes[2] = unixTsMs / 2 ** 24;
|
|
308
|
-
bytes[3] = unixTsMs / 2 ** 16;
|
|
309
|
-
bytes[4] = unixTsMs / 256;
|
|
310
|
-
bytes[5] = unixTsMs;
|
|
311
|
-
bytes[6] = 112 | randA >>> 8;
|
|
312
|
-
bytes[7] = randA;
|
|
313
|
-
bytes[8] = 128 | randBHi >>> 24;
|
|
314
|
-
bytes[9] = randBHi >>> 16;
|
|
315
|
-
bytes[10] = randBHi >>> 8;
|
|
316
|
-
bytes[11] = randBHi;
|
|
317
|
-
bytes[12] = randBLo >>> 24;
|
|
318
|
-
bytes[13] = randBLo >>> 16;
|
|
319
|
-
bytes[14] = randBLo >>> 8;
|
|
320
|
-
bytes[15] = randBLo;
|
|
321
|
-
return new UUID(bytes);
|
|
322
|
-
}
|
|
323
|
-
static parse(uuid) {
|
|
324
|
-
let hex;
|
|
325
|
-
switch (uuid.length) {
|
|
326
|
-
case 32:
|
|
327
|
-
hex = /^[0-9a-f]{32}$/i.exec(uuid)?.[0];
|
|
328
|
-
break;
|
|
329
|
-
case 36:
|
|
330
|
-
hex = /^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i.exec(uuid)?.slice(1, 6).join("");
|
|
331
|
-
break;
|
|
332
|
-
case 38:
|
|
333
|
-
hex = /^\{([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\}$/i.exec(uuid)?.slice(1, 6).join("");
|
|
334
|
-
break;
|
|
335
|
-
case 45:
|
|
336
|
-
hex = /^urn:uuid:([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i.exec(uuid)?.slice(1, 6).join("");
|
|
337
|
-
break;
|
|
338
|
-
}
|
|
339
|
-
if (hex) {
|
|
340
|
-
const inner = new Uint8Array(16);
|
|
341
|
-
for (let i = 0; i < 16; i += 4) {
|
|
342
|
-
const n = parseInt(hex.substring(2 * i, 2 * i + 8), 16);
|
|
343
|
-
inner[i + 0] = n >>> 24;
|
|
344
|
-
inner[i + 1] = n >>> 16;
|
|
345
|
-
inner[i + 2] = n >>> 8;
|
|
346
|
-
inner[i + 3] = n;
|
|
347
|
-
}
|
|
348
|
-
return new UUID(inner);
|
|
349
|
-
}
|
|
350
|
-
throw new SyntaxError("could not parse UUID string");
|
|
351
|
-
}
|
|
352
|
-
toString() {
|
|
353
|
-
let text = "";
|
|
354
|
-
for (let i = 0; i < this.bytes.length; i++) {
|
|
355
|
-
text += DIGITS.charAt(this.bytes[i] >>> 4);
|
|
356
|
-
text += DIGITS.charAt(15 & this.bytes[i]);
|
|
357
|
-
if (3 === i || 5 === i || 7 === i || 9 === i) text += "-";
|
|
358
|
-
}
|
|
359
|
-
return text;
|
|
360
|
-
}
|
|
361
|
-
toHex() {
|
|
362
|
-
let text = "";
|
|
363
|
-
for (let i = 0; i < this.bytes.length; i++) {
|
|
364
|
-
text += DIGITS.charAt(this.bytes[i] >>> 4);
|
|
365
|
-
text += DIGITS.charAt(15 & this.bytes[i]);
|
|
366
|
-
}
|
|
367
|
-
return text;
|
|
368
|
-
}
|
|
369
|
-
toJSON() {
|
|
370
|
-
return this.toString();
|
|
371
|
-
}
|
|
372
|
-
getVariant() {
|
|
373
|
-
const n = this.bytes[8] >>> 4;
|
|
374
|
-
if (n < 0) throw new Error("unreachable");
|
|
375
|
-
if (n <= 7) return this.bytes.every((e) => 0 === e) ? "NIL" : "VAR_0";
|
|
376
|
-
if (n <= 11) return "VAR_10";
|
|
377
|
-
if (n <= 13) return "VAR_110";
|
|
378
|
-
if (n <= 15) return this.bytes.every((e) => 255 === e) ? "MAX" : "VAR_RESERVED";
|
|
379
|
-
else throw new Error("unreachable");
|
|
380
|
-
}
|
|
381
|
-
getVersion() {
|
|
382
|
-
return "VAR_10" === this.getVariant() ? this.bytes[6] >>> 4 : void 0;
|
|
383
|
-
}
|
|
384
|
-
clone() {
|
|
385
|
-
return new UUID(this.bytes.slice(0));
|
|
386
|
-
}
|
|
387
|
-
equals(other) {
|
|
388
|
-
return 0 === this.compareTo(other);
|
|
389
|
-
}
|
|
390
|
-
compareTo(other) {
|
|
391
|
-
for (let i = 0; i < 16; i++) {
|
|
392
|
-
const diff = this.bytes[i] - other.bytes[i];
|
|
393
|
-
if (0 !== diff) return Math.sign(diff);
|
|
394
|
-
}
|
|
395
|
-
return 0;
|
|
396
|
-
}
|
|
294
|
+
function isGzipSupported() {
|
|
295
|
+
return "CompressionStream" in globalThis;
|
|
397
296
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
generateOrResetCore(unixTsMs, rollbackAllowance) {
|
|
411
|
-
let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
|
|
412
|
-
if (void 0 === value) {
|
|
413
|
-
this.timestamp = 0;
|
|
414
|
-
value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
|
|
415
|
-
}
|
|
416
|
-
return value;
|
|
417
|
-
}
|
|
418
|
-
generateOrAbortCore(unixTsMs, rollbackAllowance) {
|
|
419
|
-
const MAX_COUNTER = 4398046511103;
|
|
420
|
-
if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 281474976710655) throw new RangeError("`unixTsMs` must be a 48-bit positive integer");
|
|
421
|
-
if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655) throw new RangeError("`rollbackAllowance` out of reasonable range");
|
|
422
|
-
if (unixTsMs > this.timestamp) {
|
|
423
|
-
this.timestamp = unixTsMs;
|
|
424
|
-
this.resetCounter();
|
|
425
|
-
} else {
|
|
426
|
-
if (!(unixTsMs + rollbackAllowance >= this.timestamp)) return;
|
|
427
|
-
this.counter++;
|
|
428
|
-
if (this.counter > MAX_COUNTER) {
|
|
429
|
-
this.timestamp++;
|
|
430
|
-
this.resetCounter();
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & 2 ** 30 - 1, this.random.nextUint32());
|
|
434
|
-
}
|
|
435
|
-
resetCounter() {
|
|
436
|
-
this.counter = 1024 * this.random.nextUint32() + (1023 & this.random.nextUint32());
|
|
437
|
-
}
|
|
438
|
-
generateV4() {
|
|
439
|
-
const bytes = new Uint8Array(Uint32Array.of(this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32()).buffer);
|
|
440
|
-
bytes[6] = 64 | bytes[6] >>> 4;
|
|
441
|
-
bytes[8] = 128 | bytes[8] >>> 2;
|
|
442
|
-
return UUID.ofInner(bytes);
|
|
297
|
+
async function gzipCompress(input, isDebug = true, options) {
|
|
298
|
+
try {
|
|
299
|
+
const dataStream = new Blob([
|
|
300
|
+
input
|
|
301
|
+
], {
|
|
302
|
+
type: "text/plain"
|
|
303
|
+
}).stream();
|
|
304
|
+
const compressedStream = dataStream.pipeThrough(new CompressionStream("gzip"));
|
|
305
|
+
return await new Response(compressedStream).blob();
|
|
306
|
+
} catch (error) {
|
|
307
|
+
if (isDebug) console.error("Failed to gzip compress data", error);
|
|
308
|
+
return null;
|
|
443
309
|
}
|
|
444
310
|
}
|
|
445
|
-
const getDefaultRandom = () => ({
|
|
446
|
-
nextUint32: () => 65536 * Math.trunc(65536 * Math.random()) + Math.trunc(65536 * Math.random())
|
|
447
|
-
});
|
|
448
|
-
let defaultGenerator;
|
|
449
|
-
const uuidv7 = () => uuidv7obj().toString();
|
|
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
|
-
})({});
|
|
481
311
|
const DEFAULT_BLOCKED_UA_STRS = [
|
|
482
312
|
"amazonbot",
|
|
483
313
|
"amazonproductbot",
|
|
@@ -565,6 +395,37 @@ const isBlockedUA = function(ua, customBlockedUserAgents = []) {
|
|
|
565
395
|
return -1 !== uaLower.indexOf(blockedUaLower);
|
|
566
396
|
});
|
|
567
397
|
};
|
|
398
|
+
var types_PostHogPersistedProperty = /* @__PURE__ */ (function(PostHogPersistedProperty) {
|
|
399
|
+
PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
|
|
400
|
+
PostHogPersistedProperty["DistinctId"] = "distinct_id";
|
|
401
|
+
PostHogPersistedProperty["Props"] = "props";
|
|
402
|
+
PostHogPersistedProperty["EnablePersonProcessing"] = "enable_person_processing";
|
|
403
|
+
PostHogPersistedProperty["PersonMode"] = "person_mode";
|
|
404
|
+
PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
|
|
405
|
+
PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
|
|
406
|
+
PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
|
|
407
|
+
PostHogPersistedProperty["BootstrapFeatureFlagDetails"] = "bootstrap_feature_flag_details";
|
|
408
|
+
PostHogPersistedProperty["BootstrapFeatureFlags"] = "bootstrap_feature_flags";
|
|
409
|
+
PostHogPersistedProperty["BootstrapFeatureFlagPayloads"] = "bootstrap_feature_flag_payloads";
|
|
410
|
+
PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
|
|
411
|
+
PostHogPersistedProperty["Queue"] = "queue";
|
|
412
|
+
PostHogPersistedProperty["OptedOut"] = "opted_out";
|
|
413
|
+
PostHogPersistedProperty["SessionId"] = "session_id";
|
|
414
|
+
PostHogPersistedProperty["SessionStartTimestamp"] = "session_start_timestamp";
|
|
415
|
+
PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
|
|
416
|
+
PostHogPersistedProperty["PersonProperties"] = "person_properties";
|
|
417
|
+
PostHogPersistedProperty["GroupProperties"] = "group_properties";
|
|
418
|
+
PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
|
|
419
|
+
PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
|
|
420
|
+
PostHogPersistedProperty["SessionReplay"] = "session_replay";
|
|
421
|
+
PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
|
|
422
|
+
PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
|
|
423
|
+
PostHogPersistedProperty["Surveys"] = "surveys";
|
|
424
|
+
PostHogPersistedProperty["RemoteConfig"] = "remote_config";
|
|
425
|
+
PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
|
|
426
|
+
PostHogPersistedProperty["DeviceId"] = "device_id";
|
|
427
|
+
return PostHogPersistedProperty;
|
|
428
|
+
})({});
|
|
568
429
|
const nativeIsArray = Array.isArray;
|
|
569
430
|
const ObjProto = Object.prototype;
|
|
570
431
|
const type_utils_toString = ObjProto.toString;
|
|
@@ -572,7 +433,6 @@ const isArray = nativeIsArray || function(obj) {
|
|
|
572
433
|
return "[object Array]" === type_utils_toString.call(obj);
|
|
573
434
|
};
|
|
574
435
|
const isObject = (x) => x === Object(x) && !isArray(x);
|
|
575
|
-
const isUndefined = (x) => void 0 === x;
|
|
576
436
|
const isString = (x) => "[object String]" == type_utils_toString.call(x);
|
|
577
437
|
const isEmptyString = (x) => isString(x) && 0 === x.trim().length;
|
|
578
438
|
const isNumber = (x) => "[object Number]" == type_utils_toString.call(x) && x === x;
|
|
@@ -584,7 +444,7 @@ function isBuiltin(candidate, className) {
|
|
|
584
444
|
return Object.prototype.toString.call(candidate) === `[object ${className}]`;
|
|
585
445
|
}
|
|
586
446
|
function isEvent(candidate) {
|
|
587
|
-
return
|
|
447
|
+
return "undefined" != typeof Event && isInstanceOf(candidate, Event);
|
|
588
448
|
}
|
|
589
449
|
function isPlainObject(candidate) {
|
|
590
450
|
return isBuiltin(candidate, "Object");
|
|
@@ -651,6 +511,164 @@ class BucketedRateLimiter {
|
|
|
651
511
|
this._buckets = {};
|
|
652
512
|
}
|
|
653
513
|
}
|
|
514
|
+
const DIGITS = "0123456789abcdef";
|
|
515
|
+
class UUID {
|
|
516
|
+
constructor(bytes) {
|
|
517
|
+
this.bytes = bytes;
|
|
518
|
+
}
|
|
519
|
+
static ofInner(bytes) {
|
|
520
|
+
if (16 === bytes.length) return new UUID(bytes);
|
|
521
|
+
throw new TypeError("not 128-bit length");
|
|
522
|
+
}
|
|
523
|
+
static fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
|
|
524
|
+
if (!Number.isInteger(unixTsMs) || !Number.isInteger(randA) || !Number.isInteger(randBHi) || !Number.isInteger(randBLo) || unixTsMs < 0 || randA < 0 || randBHi < 0 || randBLo < 0 || unixTsMs > 281474976710655 || randA > 4095 || randBHi > 1073741823 || randBLo > 4294967295) throw new RangeError("invalid field value");
|
|
525
|
+
const bytes = new Uint8Array(16);
|
|
526
|
+
bytes[0] = unixTsMs / 2 ** 40;
|
|
527
|
+
bytes[1] = unixTsMs / 2 ** 32;
|
|
528
|
+
bytes[2] = unixTsMs / 2 ** 24;
|
|
529
|
+
bytes[3] = unixTsMs / 2 ** 16;
|
|
530
|
+
bytes[4] = unixTsMs / 256;
|
|
531
|
+
bytes[5] = unixTsMs;
|
|
532
|
+
bytes[6] = 112 | randA >>> 8;
|
|
533
|
+
bytes[7] = randA;
|
|
534
|
+
bytes[8] = 128 | randBHi >>> 24;
|
|
535
|
+
bytes[9] = randBHi >>> 16;
|
|
536
|
+
bytes[10] = randBHi >>> 8;
|
|
537
|
+
bytes[11] = randBHi;
|
|
538
|
+
bytes[12] = randBLo >>> 24;
|
|
539
|
+
bytes[13] = randBLo >>> 16;
|
|
540
|
+
bytes[14] = randBLo >>> 8;
|
|
541
|
+
bytes[15] = randBLo;
|
|
542
|
+
return new UUID(bytes);
|
|
543
|
+
}
|
|
544
|
+
static parse(uuid) {
|
|
545
|
+
let hex;
|
|
546
|
+
switch (uuid.length) {
|
|
547
|
+
case 32:
|
|
548
|
+
hex = /^[0-9a-f]{32}$/i.exec(uuid)?.[0];
|
|
549
|
+
break;
|
|
550
|
+
case 36:
|
|
551
|
+
hex = /^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i.exec(uuid)?.slice(1, 6).join("");
|
|
552
|
+
break;
|
|
553
|
+
case 38:
|
|
554
|
+
hex = /^\{([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\}$/i.exec(uuid)?.slice(1, 6).join("");
|
|
555
|
+
break;
|
|
556
|
+
case 45:
|
|
557
|
+
hex = /^urn:uuid:([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i.exec(uuid)?.slice(1, 6).join("");
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
if (hex) {
|
|
561
|
+
const inner = new Uint8Array(16);
|
|
562
|
+
for (let i = 0; i < 16; i += 4) {
|
|
563
|
+
const n = parseInt(hex.substring(2 * i, 2 * i + 8), 16);
|
|
564
|
+
inner[i + 0] = n >>> 24;
|
|
565
|
+
inner[i + 1] = n >>> 16;
|
|
566
|
+
inner[i + 2] = n >>> 8;
|
|
567
|
+
inner[i + 3] = n;
|
|
568
|
+
}
|
|
569
|
+
return new UUID(inner);
|
|
570
|
+
}
|
|
571
|
+
throw new SyntaxError("could not parse UUID string");
|
|
572
|
+
}
|
|
573
|
+
toString() {
|
|
574
|
+
let text = "";
|
|
575
|
+
for (let i = 0; i < this.bytes.length; i++) {
|
|
576
|
+
text += DIGITS.charAt(this.bytes[i] >>> 4);
|
|
577
|
+
text += DIGITS.charAt(15 & this.bytes[i]);
|
|
578
|
+
if (3 === i || 5 === i || 7 === i || 9 === i) text += "-";
|
|
579
|
+
}
|
|
580
|
+
return text;
|
|
581
|
+
}
|
|
582
|
+
toHex() {
|
|
583
|
+
let text = "";
|
|
584
|
+
for (let i = 0; i < this.bytes.length; i++) {
|
|
585
|
+
text += DIGITS.charAt(this.bytes[i] >>> 4);
|
|
586
|
+
text += DIGITS.charAt(15 & this.bytes[i]);
|
|
587
|
+
}
|
|
588
|
+
return text;
|
|
589
|
+
}
|
|
590
|
+
toJSON() {
|
|
591
|
+
return this.toString();
|
|
592
|
+
}
|
|
593
|
+
getVariant() {
|
|
594
|
+
const n = this.bytes[8] >>> 4;
|
|
595
|
+
if (n < 0) throw new Error("unreachable");
|
|
596
|
+
if (n <= 7) return this.bytes.every((e) => 0 === e) ? "NIL" : "VAR_0";
|
|
597
|
+
if (n <= 11) return "VAR_10";
|
|
598
|
+
if (n <= 13) return "VAR_110";
|
|
599
|
+
if (n <= 15) return this.bytes.every((e) => 255 === e) ? "MAX" : "VAR_RESERVED";
|
|
600
|
+
else throw new Error("unreachable");
|
|
601
|
+
}
|
|
602
|
+
getVersion() {
|
|
603
|
+
return "VAR_10" === this.getVariant() ? this.bytes[6] >>> 4 : void 0;
|
|
604
|
+
}
|
|
605
|
+
clone() {
|
|
606
|
+
return new UUID(this.bytes.slice(0));
|
|
607
|
+
}
|
|
608
|
+
equals(other) {
|
|
609
|
+
return 0 === this.compareTo(other);
|
|
610
|
+
}
|
|
611
|
+
compareTo(other) {
|
|
612
|
+
for (let i = 0; i < 16; i++) {
|
|
613
|
+
const diff = this.bytes[i] - other.bytes[i];
|
|
614
|
+
if (0 !== diff) return Math.sign(diff);
|
|
615
|
+
}
|
|
616
|
+
return 0;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
class V7Generator {
|
|
620
|
+
constructor(randomNumberGenerator) {
|
|
621
|
+
this.timestamp = 0;
|
|
622
|
+
this.counter = 0;
|
|
623
|
+
this.random = randomNumberGenerator ?? getDefaultRandom();
|
|
624
|
+
}
|
|
625
|
+
generate() {
|
|
626
|
+
return this.generateOrResetCore(Date.now(), 1e4);
|
|
627
|
+
}
|
|
628
|
+
generateOrAbort() {
|
|
629
|
+
return this.generateOrAbortCore(Date.now(), 1e4);
|
|
630
|
+
}
|
|
631
|
+
generateOrResetCore(unixTsMs, rollbackAllowance) {
|
|
632
|
+
let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
|
|
633
|
+
if (void 0 === value) {
|
|
634
|
+
this.timestamp = 0;
|
|
635
|
+
value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
|
|
636
|
+
}
|
|
637
|
+
return value;
|
|
638
|
+
}
|
|
639
|
+
generateOrAbortCore(unixTsMs, rollbackAllowance) {
|
|
640
|
+
const MAX_COUNTER = 4398046511103;
|
|
641
|
+
if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 281474976710655) throw new RangeError("`unixTsMs` must be a 48-bit positive integer");
|
|
642
|
+
if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655) throw new RangeError("`rollbackAllowance` out of reasonable range");
|
|
643
|
+
if (unixTsMs > this.timestamp) {
|
|
644
|
+
this.timestamp = unixTsMs;
|
|
645
|
+
this.resetCounter();
|
|
646
|
+
} else {
|
|
647
|
+
if (!(unixTsMs + rollbackAllowance >= this.timestamp)) return;
|
|
648
|
+
this.counter++;
|
|
649
|
+
if (this.counter > MAX_COUNTER) {
|
|
650
|
+
this.timestamp++;
|
|
651
|
+
this.resetCounter();
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & 2 ** 30 - 1, this.random.nextUint32());
|
|
655
|
+
}
|
|
656
|
+
resetCounter() {
|
|
657
|
+
this.counter = 1024 * this.random.nextUint32() + (1023 & this.random.nextUint32());
|
|
658
|
+
}
|
|
659
|
+
generateV4() {
|
|
660
|
+
const bytes = new Uint8Array(Uint32Array.of(this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32()).buffer);
|
|
661
|
+
bytes[6] = 64 | bytes[6] >>> 4;
|
|
662
|
+
bytes[8] = 128 | bytes[8] >>> 2;
|
|
663
|
+
return UUID.ofInner(bytes);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
const getDefaultRandom = () => ({
|
|
667
|
+
nextUint32: () => 65536 * Math.trunc(65536 * Math.random()) + Math.trunc(65536 * Math.random())
|
|
668
|
+
});
|
|
669
|
+
let defaultGenerator;
|
|
670
|
+
const uuidv7 = () => uuidv7obj().toString();
|
|
671
|
+
const uuidv7obj = () => (defaultGenerator || (defaultGenerator = new V7Generator())).generate();
|
|
654
672
|
class PromiseQueue {
|
|
655
673
|
add(promise) {
|
|
656
674
|
const promiseUUID = uuidv7();
|
|
@@ -715,13 +733,6 @@ function createLogger(prefix, maybeCall = passThrough) {
|
|
|
715
733
|
return _createLogger(prefix, maybeCall, createConsole());
|
|
716
734
|
}
|
|
717
735
|
const STRING_FORMAT = "utf8";
|
|
718
|
-
function assert(truthyValue, message) {
|
|
719
|
-
if (!truthyValue || "string" != typeof truthyValue || isEmpty(truthyValue)) throw new Error(message);
|
|
720
|
-
}
|
|
721
|
-
function isEmpty(truthyValue) {
|
|
722
|
-
if (0 === truthyValue.trim().length) return true;
|
|
723
|
-
return false;
|
|
724
|
-
}
|
|
725
736
|
function removeTrailingSlash(url) {
|
|
726
737
|
return url?.replace(/\/+$/, "");
|
|
727
738
|
}
|
|
@@ -774,23 +785,6 @@ class SimpleEventEmitter {
|
|
|
774
785
|
for (const listener of this.events["*"] || []) listener(event, payload);
|
|
775
786
|
}
|
|
776
787
|
}
|
|
777
|
-
function isGzipSupported() {
|
|
778
|
-
return "CompressionStream" in globalThis;
|
|
779
|
-
}
|
|
780
|
-
async function gzipCompress(input, isDebug = true) {
|
|
781
|
-
try {
|
|
782
|
-
const dataStream = new Blob([
|
|
783
|
-
input
|
|
784
|
-
], {
|
|
785
|
-
type: "text/plain"
|
|
786
|
-
}).stream();
|
|
787
|
-
const compressedStream = dataStream.pipeThrough(new CompressionStream("gzip"));
|
|
788
|
-
return await new Response(compressedStream).blob();
|
|
789
|
-
} catch (error) {
|
|
790
|
-
if (isDebug) console.error("Failed to gzip compress data", error);
|
|
791
|
-
return null;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
788
|
class PostHogFetchHttpError extends Error {
|
|
795
789
|
constructor(response, reqByteLength) {
|
|
796
790
|
super("HTTP error while fetching PostHog: status=" + response.status + ", reqByteLength=" + reqByteLength), this.response = response, this.reqByteLength = reqByteLength, this.name = "PostHogFetchHttpError";
|
|
@@ -836,9 +830,13 @@ class PostHogCoreStateless {
|
|
|
836
830
|
this.promiseQueue = new PromiseQueue();
|
|
837
831
|
this._events = new SimpleEventEmitter();
|
|
838
832
|
this._isInitialized = false;
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
833
|
+
const normalizedApiKey = "string" == typeof apiKey ? apiKey.trim() : "";
|
|
834
|
+
const normalizedHost = "string" == typeof options.host ? options.host.trim() : "";
|
|
835
|
+
const missingApiKey = !normalizedApiKey;
|
|
836
|
+
this._logger = createLogger("[PostHog]", this.logMsgIfDebug.bind(this));
|
|
837
|
+
if (missingApiKey) this._logger.error("You must pass your PostHog project's api key. The client will be disabled.");
|
|
838
|
+
this.apiKey = normalizedApiKey;
|
|
839
|
+
this.host = removeTrailingSlash(normalizedHost || "https://us.i.posthog.com");
|
|
842
840
|
this.flushAt = options.flushAt ? Math.max(options.flushAt, 1) : 20;
|
|
843
841
|
this.maxBatchSize = Math.max(this.flushAt, options.maxBatchSize ?? 100);
|
|
844
842
|
this.maxQueueSize = Math.max(this.flushAt, options.maxQueueSize ?? 1e3);
|
|
@@ -855,11 +853,10 @@ class PostHogCoreStateless {
|
|
|
855
853
|
this.featureFlagsRequestTimeoutMs = options.featureFlagsRequestTimeoutMs ?? 3e3;
|
|
856
854
|
this.remoteConfigRequestTimeoutMs = options.remoteConfigRequestTimeoutMs ?? 3e3;
|
|
857
855
|
this.disableGeoip = options.disableGeoip ?? true;
|
|
858
|
-
this.disabled = options.disabled ?? false;
|
|
856
|
+
this.disabled = (options.disabled ?? false) || missingApiKey;
|
|
859
857
|
this.historicalMigration = options?.historicalMigration ?? false;
|
|
860
858
|
this._initPromise = Promise.resolve();
|
|
861
859
|
this._isInitialized = true;
|
|
862
|
-
this._logger = createLogger("[PostHog]", this.logMsgIfDebug.bind(this));
|
|
863
860
|
this.evaluationContexts = options?.evaluationContexts ?? options?.evaluationEnvironments;
|
|
864
861
|
if (options?.evaluationEnvironments && !options?.evaluationContexts) this._logger.warn("evaluationEnvironments is deprecated. Use evaluationContexts instead. This property will be removed in a future version.");
|
|
865
862
|
this.disableCompression = !isGzipSupported() || (options?.disableCompression ?? false);
|
|
@@ -1024,7 +1021,7 @@ class PostHogCoreStateless {
|
|
|
1024
1021
|
this._events.emit("error", error);
|
|
1025
1022
|
});
|
|
1026
1023
|
}
|
|
1027
|
-
async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}, fetchConfig =
|
|
1024
|
+
async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}, fetchConfig = false) {
|
|
1028
1025
|
await this._initPromise;
|
|
1029
1026
|
const configParam = fetchConfig ? "&config=true" : "";
|
|
1030
1027
|
const url = `${this.host}/flags/?v=2${configParam}`;
|
|
@@ -1036,6 +1033,7 @@ class PostHogCoreStateless {
|
|
|
1036
1033
|
group_properties: groupProperties,
|
|
1037
1034
|
...extraPayload
|
|
1038
1035
|
};
|
|
1036
|
+
if (personProperties.$device_id) requestData.$device_id = personProperties.$device_id;
|
|
1039
1037
|
if (this.evaluationContexts && this.evaluationContexts.length > 0) requestData.evaluation_contexts = this.evaluationContexts;
|
|
1040
1038
|
const fetchOptions = {
|
|
1041
1039
|
method: "POST",
|
|
@@ -1383,11 +1381,6 @@ class PostHogCoreStateless {
|
|
|
1383
1381
|
this._events.emit("flush", sentMessages);
|
|
1384
1382
|
}
|
|
1385
1383
|
async fetchWithRetry(url, options, retryOptions, requestTimeout) {
|
|
1386
|
-
AbortSignal.timeout ??= function(ms) {
|
|
1387
|
-
const ctrl = new AbortController();
|
|
1388
|
-
setTimeout(() => ctrl.abort(), ms);
|
|
1389
|
-
return ctrl.signal;
|
|
1390
|
-
};
|
|
1391
1384
|
const body = options.body ? options.body : "";
|
|
1392
1385
|
let reqByteLength = -1;
|
|
1393
1386
|
try {
|
|
@@ -1400,14 +1393,19 @@ class PostHogCoreStateless {
|
|
|
1400
1393
|
}
|
|
1401
1394
|
}
|
|
1402
1395
|
return await retriable(async () => {
|
|
1396
|
+
const ctrl = new AbortController();
|
|
1397
|
+
const timeoutMs = requestTimeout ?? this.requestTimeout;
|
|
1398
|
+
const timer = safeSetTimeout(() => ctrl.abort(), timeoutMs);
|
|
1403
1399
|
let res = null;
|
|
1404
1400
|
try {
|
|
1405
1401
|
res = await this.fetch(url, {
|
|
1406
|
-
signal:
|
|
1402
|
+
signal: ctrl.signal,
|
|
1407
1403
|
...options
|
|
1408
1404
|
});
|
|
1409
1405
|
} catch (e) {
|
|
1410
1406
|
throw new PostHogFetchNetworkError(e);
|
|
1407
|
+
} finally {
|
|
1408
|
+
clearTimeout(timer);
|
|
1411
1409
|
}
|
|
1412
1410
|
const isNoCors = "no-cors" === options.mode;
|
|
1413
1411
|
if (!isNoCors && (res.status < 200 || res.status >= 400)) throw new PostHogFetchHttpError(res, reqByteLength);
|
|
@@ -1435,16 +1433,21 @@ class PostHogCoreStateless {
|
|
|
1435
1433
|
await logFlushError(e);
|
|
1436
1434
|
}
|
|
1437
1435
|
};
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1436
|
+
let timeoutHandle;
|
|
1437
|
+
try {
|
|
1438
|
+
return await Promise.race([
|
|
1439
|
+
new Promise((_, reject) => {
|
|
1440
|
+
timeoutHandle = safeSetTimeout(() => {
|
|
1441
|
+
this._logger.error("Timed out while shutting down PostHog");
|
|
1442
|
+
hasTimedOut = true;
|
|
1443
|
+
reject("Timeout while shutting down PostHog. Some events may not have been sent.");
|
|
1444
|
+
}, shutdownTimeoutMs);
|
|
1445
|
+
}),
|
|
1446
|
+
doShutdown()
|
|
1447
|
+
]);
|
|
1448
|
+
} finally {
|
|
1449
|
+
clearTimeout(timeoutHandle);
|
|
1450
|
+
}
|
|
1448
1451
|
}
|
|
1449
1452
|
async shutdown(shutdownTimeoutMs = 3e4) {
|
|
1450
1453
|
if (this.shutdownPromise) this._logger.warn("shutdown() called while already shutting down. shutdown() is meant to be called once before process exit - use flush() for per-request cleanup");
|
|
@@ -2051,6 +2054,17 @@ function snipLine(line, colno) {
|
|
|
2051
2054
|
if (end < lineLength) newLine += "...";
|
|
2052
2055
|
return newLine;
|
|
2053
2056
|
}
|
|
2057
|
+
function createRelativePathModifier(basePath = process.cwd()) {
|
|
2058
|
+
const isWindows = "\\" === sep;
|
|
2059
|
+
const toUnix = (p) => isWindows ? p.replace(/\\/g, "/") : p;
|
|
2060
|
+
const normalizedBase = toUnix(basePath);
|
|
2061
|
+
return async (frames) => {
|
|
2062
|
+
for (const frame of frames) if (!(!frame.filename || frame.filename.startsWith("node:") || frame.filename.startsWith("data:"))) {
|
|
2063
|
+
if (isAbsolute(frame.filename)) frame.filename = toUnix(relative(normalizedBase, toUnix(frame.filename)));
|
|
2064
|
+
}
|
|
2065
|
+
return frames;
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2054
2068
|
function makeUncaughtExceptionHandler(captureFn, onFatalFn) {
|
|
2055
2069
|
let calledFatalError = false;
|
|
2056
2070
|
return Object.assign((error) => {
|
|
@@ -2102,12 +2116,11 @@ class ErrorTracking {
|
|
|
2102
2116
|
const properties = {
|
|
2103
2117
|
...additionalProperties
|
|
2104
2118
|
};
|
|
2105
|
-
if (!distinctId) properties.$process_person_profile = false;
|
|
2106
2119
|
const exceptionProperties = this.errorPropertiesBuilder.buildFromUnknown(error, hint);
|
|
2107
2120
|
exceptionProperties.$exception_list = await this.errorPropertiesBuilder.modifyFrames(exceptionProperties.$exception_list);
|
|
2108
2121
|
return {
|
|
2109
2122
|
event: "$exception",
|
|
2110
|
-
distinctId
|
|
2123
|
+
distinctId,
|
|
2111
2124
|
properties: {
|
|
2112
2125
|
...exceptionProperties,
|
|
2113
2126
|
...properties
|
|
@@ -2147,7 +2160,7 @@ class ErrorTracking {
|
|
|
2147
2160
|
this._rateLimiter.stop();
|
|
2148
2161
|
}
|
|
2149
2162
|
}
|
|
2150
|
-
const version = "5.
|
|
2163
|
+
const version = "5.30.1";
|
|
2151
2164
|
const FeatureFlagError = {
|
|
2152
2165
|
ERRORS_WHILE_COMPUTING: "errors_while_computing_flags",
|
|
2153
2166
|
FLAG_MISSING: "flag_missing",
|
|
@@ -2476,6 +2489,9 @@ class FeatureFlagsPoller {
|
|
|
2476
2489
|
isLocalEvaluationReady() {
|
|
2477
2490
|
return (this.loadedSuccessfullyOnce ?? false) && (this.featureFlags?.length ?? 0) > 0;
|
|
2478
2491
|
}
|
|
2492
|
+
getFlagDefinitionsLoadedAt() {
|
|
2493
|
+
return this.flagDefinitionsLoadedAt;
|
|
2494
|
+
}
|
|
2479
2495
|
getPollingInterval() {
|
|
2480
2496
|
if (!this.shouldBeginExponentialBackoff) return this.pollingInterval;
|
|
2481
2497
|
return Math.min(SIXTY_SECONDS, this.pollingInterval * 2 ** this.backOffCount);
|
|
@@ -2543,6 +2559,7 @@ class FeatureFlagsPoller {
|
|
|
2543
2559
|
cohorts: responseJson.cohorts || {}
|
|
2544
2560
|
};
|
|
2545
2561
|
this.updateFlagState(flagData);
|
|
2562
|
+
this.flagDefinitionsLoadedAt = Date.now();
|
|
2546
2563
|
this.clearBackoff();
|
|
2547
2564
|
if (this.cacheProvider && shouldFetch) try {
|
|
2548
2565
|
await this.cacheProvider.onFlagDefinitionsReceived(flagData);
|
|
@@ -2573,7 +2590,7 @@ class FeatureFlagsPoller {
|
|
|
2573
2590
|
};
|
|
2574
2591
|
}
|
|
2575
2592
|
_requestFeatureFlagDefinitions() {
|
|
2576
|
-
const url = `${this.host}/
|
|
2593
|
+
const url = `${this.host}/flags/definitions?token=${this.projectApiKey}&send_cohorts`;
|
|
2577
2594
|
const options = this.getPersonalApiKeyRequestOptions("GET", this.flagsEtag);
|
|
2578
2595
|
let abortTimeout = null;
|
|
2579
2596
|
if (this.timeout && "number" == typeof this.timeout) {
|
|
@@ -2670,6 +2687,45 @@ function matchProperty(property, propertyValues, warnFunction) {
|
|
|
2670
2687
|
].includes(operator)) return overrideDate < parsedDate;
|
|
2671
2688
|
return overrideDate > parsedDate;
|
|
2672
2689
|
}
|
|
2690
|
+
case "semver_eq": {
|
|
2691
|
+
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
|
|
2692
|
+
return 0 === cmp;
|
|
2693
|
+
}
|
|
2694
|
+
case "semver_neq": {
|
|
2695
|
+
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
|
|
2696
|
+
return 0 !== cmp;
|
|
2697
|
+
}
|
|
2698
|
+
case "semver_gt": {
|
|
2699
|
+
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
|
|
2700
|
+
return cmp > 0;
|
|
2701
|
+
}
|
|
2702
|
+
case "semver_gte": {
|
|
2703
|
+
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
|
|
2704
|
+
return cmp >= 0;
|
|
2705
|
+
}
|
|
2706
|
+
case "semver_lt": {
|
|
2707
|
+
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
|
|
2708
|
+
return cmp < 0;
|
|
2709
|
+
}
|
|
2710
|
+
case "semver_lte": {
|
|
2711
|
+
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
|
|
2712
|
+
return cmp <= 0;
|
|
2713
|
+
}
|
|
2714
|
+
case "semver_tilde": {
|
|
2715
|
+
const overrideParsed = parseSemver(String(overrideValue));
|
|
2716
|
+
const { lower, upper } = computeTildeBounds(String(value));
|
|
2717
|
+
return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
|
|
2718
|
+
}
|
|
2719
|
+
case "semver_caret": {
|
|
2720
|
+
const overrideParsed = parseSemver(String(overrideValue));
|
|
2721
|
+
const { lower, upper } = computeCaretBounds(String(value));
|
|
2722
|
+
return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
|
|
2723
|
+
}
|
|
2724
|
+
case "semver_wildcard": {
|
|
2725
|
+
const overrideParsed = parseSemver(String(overrideValue));
|
|
2726
|
+
const { lower, upper } = computeWildcardBounds(String(value));
|
|
2727
|
+
return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
|
|
2728
|
+
}
|
|
2673
2729
|
default:
|
|
2674
2730
|
throw new InconclusiveMatchError(`Unknown operator: ${operator}`);
|
|
2675
2731
|
}
|
|
@@ -2738,6 +2794,115 @@ function isValidRegex(regex) {
|
|
|
2738
2794
|
return false;
|
|
2739
2795
|
}
|
|
2740
2796
|
}
|
|
2797
|
+
function parseSemver(value) {
|
|
2798
|
+
const text = String(value).trim().replace(/^[vV]/, "");
|
|
2799
|
+
const baseVersion = text.split("-")[0].split("+")[0];
|
|
2800
|
+
if (!baseVersion || baseVersion.startsWith(".")) throw new InconclusiveMatchError(`Invalid semver: ${value}`);
|
|
2801
|
+
const parts = baseVersion.split(".");
|
|
2802
|
+
const parsePart = (part) => {
|
|
2803
|
+
if (void 0 === part || "" === part) return 0;
|
|
2804
|
+
if (!/^\d+$/.test(part)) throw new InconclusiveMatchError(`Invalid semver: ${value}`);
|
|
2805
|
+
return parseInt(part, 10);
|
|
2806
|
+
};
|
|
2807
|
+
const major = parsePart(parts[0]);
|
|
2808
|
+
const minor = parsePart(parts[1]);
|
|
2809
|
+
const patch = parsePart(parts[2]);
|
|
2810
|
+
return [
|
|
2811
|
+
major,
|
|
2812
|
+
minor,
|
|
2813
|
+
patch
|
|
2814
|
+
];
|
|
2815
|
+
}
|
|
2816
|
+
function compareSemverTuples(a, b) {
|
|
2817
|
+
for (let i = 0; i < 3; i++) {
|
|
2818
|
+
if (a[i] < b[i]) return -1;
|
|
2819
|
+
if (a[i] > b[i]) return 1;
|
|
2820
|
+
}
|
|
2821
|
+
return 0;
|
|
2822
|
+
}
|
|
2823
|
+
function computeTildeBounds(value) {
|
|
2824
|
+
const parsed = parseSemver(value);
|
|
2825
|
+
const lower = [
|
|
2826
|
+
parsed[0],
|
|
2827
|
+
parsed[1],
|
|
2828
|
+
parsed[2]
|
|
2829
|
+
];
|
|
2830
|
+
const upper = [
|
|
2831
|
+
parsed[0],
|
|
2832
|
+
parsed[1] + 1,
|
|
2833
|
+
0
|
|
2834
|
+
];
|
|
2835
|
+
return {
|
|
2836
|
+
lower,
|
|
2837
|
+
upper
|
|
2838
|
+
};
|
|
2839
|
+
}
|
|
2840
|
+
function computeCaretBounds(value) {
|
|
2841
|
+
const parsed = parseSemver(value);
|
|
2842
|
+
const [major, minor, patch] = parsed;
|
|
2843
|
+
const lower = [
|
|
2844
|
+
major,
|
|
2845
|
+
minor,
|
|
2846
|
+
patch
|
|
2847
|
+
];
|
|
2848
|
+
let upper;
|
|
2849
|
+
upper = major > 0 ? [
|
|
2850
|
+
major + 1,
|
|
2851
|
+
0,
|
|
2852
|
+
0
|
|
2853
|
+
] : minor > 0 ? [
|
|
2854
|
+
0,
|
|
2855
|
+
minor + 1,
|
|
2856
|
+
0
|
|
2857
|
+
] : [
|
|
2858
|
+
0,
|
|
2859
|
+
0,
|
|
2860
|
+
patch + 1
|
|
2861
|
+
];
|
|
2862
|
+
return {
|
|
2863
|
+
lower,
|
|
2864
|
+
upper
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
function computeWildcardBounds(value) {
|
|
2868
|
+
const text = String(value).trim().replace(/^[vV]/, "");
|
|
2869
|
+
const cleanedText = text.replace(/\.\*$/, "").replace(/\*$/, "");
|
|
2870
|
+
if (!cleanedText) throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
|
|
2871
|
+
const parts = cleanedText.split(".");
|
|
2872
|
+
const major = parseInt(parts[0], 10);
|
|
2873
|
+
if (isNaN(major)) throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
|
|
2874
|
+
let lower;
|
|
2875
|
+
let upper;
|
|
2876
|
+
if (1 === parts.length) {
|
|
2877
|
+
lower = [
|
|
2878
|
+
major,
|
|
2879
|
+
0,
|
|
2880
|
+
0
|
|
2881
|
+
];
|
|
2882
|
+
upper = [
|
|
2883
|
+
major + 1,
|
|
2884
|
+
0,
|
|
2885
|
+
0
|
|
2886
|
+
];
|
|
2887
|
+
} else {
|
|
2888
|
+
const minor = parseInt(parts[1], 10);
|
|
2889
|
+
if (isNaN(minor)) throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
|
|
2890
|
+
lower = [
|
|
2891
|
+
major,
|
|
2892
|
+
minor,
|
|
2893
|
+
0
|
|
2894
|
+
];
|
|
2895
|
+
upper = [
|
|
2896
|
+
major,
|
|
2897
|
+
minor + 1,
|
|
2898
|
+
0
|
|
2899
|
+
];
|
|
2900
|
+
}
|
|
2901
|
+
return {
|
|
2902
|
+
lower,
|
|
2903
|
+
upper
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2741
2906
|
function convertToDateTime(value) {
|
|
2742
2907
|
if (value instanceof Date) return value;
|
|
2743
2908
|
if ("string" == typeof value || "number" == typeof value) {
|
|
@@ -2782,22 +2947,44 @@ class PostHogMemoryStorage {
|
|
|
2782
2947
|
const MINIMUM_POLLING_INTERVAL = 100;
|
|
2783
2948
|
const THIRTY_SECONDS = 3e4;
|
|
2784
2949
|
const MAX_CACHE_SIZE = 5e4;
|
|
2950
|
+
const WAITUNTIL_DEBOUNCE_MS = 50;
|
|
2951
|
+
const WAITUNTIL_MAX_WAIT_MS = 500;
|
|
2952
|
+
const DEFAULT_NODE_HOST = "https://us.i.posthog.com";
|
|
2953
|
+
function normalizeApiKey(value) {
|
|
2954
|
+
return "string" == typeof value ? value.trim() : "";
|
|
2955
|
+
}
|
|
2956
|
+
function normalizePersonalApiKey(value) {
|
|
2957
|
+
const normalizedValue = "string" == typeof value ? value.trim() : "";
|
|
2958
|
+
return normalizedValue || void 0;
|
|
2959
|
+
}
|
|
2960
|
+
function normalizeHost(value) {
|
|
2961
|
+
const normalizedValue = "string" == typeof value ? value.trim() : "";
|
|
2962
|
+
return normalizedValue || DEFAULT_NODE_HOST;
|
|
2963
|
+
}
|
|
2785
2964
|
class PostHogBackendClient extends PostHogCoreStateless {
|
|
2786
2965
|
constructor(apiKey, options = {}) {
|
|
2787
|
-
|
|
2788
|
-
|
|
2966
|
+
const normalizedApiKey = normalizeApiKey(apiKey);
|
|
2967
|
+
const normalizedOptions = {
|
|
2968
|
+
...options,
|
|
2969
|
+
host: normalizeHost(options.host),
|
|
2970
|
+
personalApiKey: normalizePersonalApiKey(options.personalApiKey)
|
|
2971
|
+
};
|
|
2972
|
+
super(normalizedApiKey, normalizedOptions), this._memoryStorage = new PostHogMemoryStorage();
|
|
2973
|
+
this.options = normalizedOptions;
|
|
2789
2974
|
this.context = this.initializeContext();
|
|
2790
|
-
this.options.featureFlagsPollingInterval = "number" == typeof
|
|
2791
|
-
if (options.
|
|
2792
|
-
|
|
2793
|
-
|
|
2975
|
+
this.options.featureFlagsPollingInterval = "number" == typeof normalizedOptions.featureFlagsPollingInterval ? Math.max(normalizedOptions.featureFlagsPollingInterval, MINIMUM_POLLING_INTERVAL) : THIRTY_SECONDS;
|
|
2976
|
+
if ("number" == typeof normalizedOptions.waitUntilDebounceMs) this.options.waitUntilDebounceMs = Math.max(normalizedOptions.waitUntilDebounceMs, 0);
|
|
2977
|
+
if ("number" == typeof normalizedOptions.waitUntilMaxWaitMs) this.options.waitUntilMaxWaitMs = Math.max(normalizedOptions.waitUntilMaxWaitMs, 0);
|
|
2978
|
+
if (normalizedOptions.personalApiKey) {
|
|
2979
|
+
if (normalizedOptions.personalApiKey.includes("phc_")) throw new Error('Your Personal API key is invalid. These keys are prefixed with "phx_" and can be created in PostHog project settings.');
|
|
2980
|
+
const shouldEnableLocalEvaluation = false !== normalizedOptions.enableLocalEvaluation;
|
|
2794
2981
|
if (shouldEnableLocalEvaluation) this.featureFlagsPoller = new FeatureFlagsPoller({
|
|
2795
2982
|
pollingInterval: this.options.featureFlagsPollingInterval,
|
|
2796
|
-
personalApiKey:
|
|
2797
|
-
projectApiKey:
|
|
2798
|
-
timeout:
|
|
2983
|
+
personalApiKey: normalizedOptions.personalApiKey,
|
|
2984
|
+
projectApiKey: normalizedApiKey,
|
|
2985
|
+
timeout: normalizedOptions.requestTimeout ?? 1e4,
|
|
2799
2986
|
host: this.host,
|
|
2800
|
-
fetch:
|
|
2987
|
+
fetch: normalizedOptions.fetch,
|
|
2801
2988
|
onError: (err) => {
|
|
2802
2989
|
this._events.emit("error", err);
|
|
2803
2990
|
},
|
|
@@ -2805,13 +2992,74 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2805
2992
|
this._events.emit("localEvaluationFlagsLoaded", count);
|
|
2806
2993
|
},
|
|
2807
2994
|
customHeaders: this.getCustomHeaders(),
|
|
2808
|
-
cacheProvider:
|
|
2809
|
-
strictLocalEvaluation:
|
|
2995
|
+
cacheProvider: normalizedOptions.flagDefinitionCacheProvider,
|
|
2996
|
+
strictLocalEvaluation: normalizedOptions.strictLocalEvaluation
|
|
2810
2997
|
});
|
|
2811
2998
|
}
|
|
2812
|
-
this.errorTracking = new ErrorTracking(this,
|
|
2999
|
+
this.errorTracking = new ErrorTracking(this, normalizedOptions, this._logger);
|
|
2813
3000
|
this.distinctIdHasSentFlagCalls = {};
|
|
2814
|
-
this.maxCacheSize =
|
|
3001
|
+
this.maxCacheSize = normalizedOptions.maxCacheSize || MAX_CACHE_SIZE;
|
|
3002
|
+
}
|
|
3003
|
+
enqueue(type, message, options) {
|
|
3004
|
+
super.enqueue(type, message, options);
|
|
3005
|
+
this.scheduleDebouncedFlush();
|
|
3006
|
+
}
|
|
3007
|
+
async flush() {
|
|
3008
|
+
const flushPromise = super.flush();
|
|
3009
|
+
const waitUntil = this.options.waitUntil;
|
|
3010
|
+
if (waitUntil && !this._waitUntilCycle) try {
|
|
3011
|
+
waitUntil(flushPromise.catch(() => {
|
|
3012
|
+
}));
|
|
3013
|
+
} catch {
|
|
3014
|
+
}
|
|
3015
|
+
return flushPromise;
|
|
3016
|
+
}
|
|
3017
|
+
scheduleDebouncedFlush() {
|
|
3018
|
+
const waitUntil = this.options.waitUntil;
|
|
3019
|
+
if (!waitUntil) return;
|
|
3020
|
+
if (this.disabled || this.optedOut) return;
|
|
3021
|
+
if (!this._waitUntilCycle) {
|
|
3022
|
+
let resolve;
|
|
3023
|
+
const promise = new Promise((r) => {
|
|
3024
|
+
resolve = r;
|
|
3025
|
+
});
|
|
3026
|
+
try {
|
|
3027
|
+
waitUntil(promise);
|
|
3028
|
+
} catch {
|
|
3029
|
+
return;
|
|
3030
|
+
}
|
|
3031
|
+
this._waitUntilCycle = {
|
|
3032
|
+
resolve,
|
|
3033
|
+
startedAt: Date.now(),
|
|
3034
|
+
timer: void 0
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
const elapsed = Date.now() - this._waitUntilCycle.startedAt;
|
|
3038
|
+
const maxWaitMs = this.options.waitUntilMaxWaitMs ?? WAITUNTIL_MAX_WAIT_MS;
|
|
3039
|
+
const flushNow = elapsed >= maxWaitMs;
|
|
3040
|
+
if (void 0 !== this._waitUntilCycle.timer) clearTimeout(this._waitUntilCycle.timer);
|
|
3041
|
+
if (flushNow) return void this.resolveWaitUntilFlush();
|
|
3042
|
+
const debounceMs = this.options.waitUntilDebounceMs ?? WAITUNTIL_DEBOUNCE_MS;
|
|
3043
|
+
this._waitUntilCycle.timer = safeSetTimeout(() => {
|
|
3044
|
+
this.resolveWaitUntilFlush();
|
|
3045
|
+
}, debounceMs);
|
|
3046
|
+
}
|
|
3047
|
+
_consumeWaitUntilCycle() {
|
|
3048
|
+
const cycle = this._waitUntilCycle;
|
|
3049
|
+
if (cycle) {
|
|
3050
|
+
clearTimeout(cycle.timer);
|
|
3051
|
+
this._waitUntilCycle = void 0;
|
|
3052
|
+
}
|
|
3053
|
+
return cycle?.resolve;
|
|
3054
|
+
}
|
|
3055
|
+
async resolveWaitUntilFlush() {
|
|
3056
|
+
const resolve = this._consumeWaitUntilCycle();
|
|
3057
|
+
try {
|
|
3058
|
+
await super.flush();
|
|
3059
|
+
} catch {
|
|
3060
|
+
} finally {
|
|
3061
|
+
resolve?.();
|
|
3062
|
+
}
|
|
2815
3063
|
}
|
|
2816
3064
|
getPersistedProperty(key) {
|
|
2817
3065
|
return this._memoryStorage.getProperty(key);
|
|
@@ -3028,8 +3276,12 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3028
3276
|
locally_evaluated: flagWasLocallyEvaluated,
|
|
3029
3277
|
[`$feature/${key}`]: response,
|
|
3030
3278
|
$feature_flag_request_id: requestId,
|
|
3031
|
-
$feature_flag_evaluated_at: evaluatedAt
|
|
3279
|
+
$feature_flag_evaluated_at: flagWasLocallyEvaluated ? Date.now() : evaluatedAt
|
|
3032
3280
|
};
|
|
3281
|
+
if (flagWasLocallyEvaluated && this.featureFlagsPoller) {
|
|
3282
|
+
const flagDefinitionsLoadedAt = this.featureFlagsPoller.getFlagDefinitionsLoadedAt();
|
|
3283
|
+
if (void 0 !== flagDefinitionsLoadedAt) properties.$feature_flag_definitions_loaded_at = flagDefinitionsLoadedAt;
|
|
3284
|
+
}
|
|
3033
3285
|
if (featureFlagError) properties.$feature_flag_error = featureFlagError;
|
|
3034
3286
|
this.capture({
|
|
3035
3287
|
distinctId,
|
|
@@ -3212,9 +3464,14 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3212
3464
|
this.context?.enter(data, options);
|
|
3213
3465
|
}
|
|
3214
3466
|
async _shutdown(shutdownTimeoutMs) {
|
|
3215
|
-
this.
|
|
3467
|
+
const resolve = this._consumeWaitUntilCycle();
|
|
3468
|
+
await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
|
|
3216
3469
|
this.errorTracking.shutdown();
|
|
3217
|
-
|
|
3470
|
+
try {
|
|
3471
|
+
return await super._shutdown(shutdownTimeoutMs);
|
|
3472
|
+
} finally {
|
|
3473
|
+
resolve?.();
|
|
3474
|
+
}
|
|
3218
3475
|
}
|
|
3219
3476
|
async _requestRemoteConfigPayload(flagKey) {
|
|
3220
3477
|
if (!this.options.personalApiKey) return;
|
|
@@ -3331,7 +3588,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3331
3588
|
async captureExceptionImmediate(error, distinctId, additionalProperties) {
|
|
3332
3589
|
if (!ErrorTracking.isPreviouslyCapturedError(error)) {
|
|
3333
3590
|
const syntheticException = new Error("PostHog syntheticException");
|
|
3334
|
-
this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
|
|
3591
|
+
return this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
|
|
3335
3592
|
syntheticException
|
|
3336
3593
|
}, distinctId, additionalProperties).then((msg) => this.captureImmediate(msg)));
|
|
3337
3594
|
}
|
|
@@ -3484,7 +3741,8 @@ ErrorTracking.errorPropertiesBuilder = new ErrorPropertiesBuilder([
|
|
|
3484
3741
|
new PrimitiveCoercer()
|
|
3485
3742
|
], createStackParser("node:javascript", nodeStackLineParser), [
|
|
3486
3743
|
createModulerModifier(),
|
|
3487
|
-
addSourceContext
|
|
3744
|
+
addSourceContext,
|
|
3745
|
+
createRelativePathModifier()
|
|
3488
3746
|
]);
|
|
3489
3747
|
class PostHog extends PostHogBackendClient {
|
|
3490
3748
|
getLibraryId() {
|
|
@@ -3815,30 +4073,30 @@ const shutdownSession = async (session2) => {
|
|
|
3815
4073
|
};
|
|
3816
4074
|
const toPosixPath = (input) => input.split(path.sep).join("/");
|
|
3817
4075
|
const isSubpath = (candidate, root) => {
|
|
3818
|
-
const
|
|
3819
|
-
return
|
|
4076
|
+
const relative2 = path.relative(root, candidate);
|
|
4077
|
+
return relative2 === "" || !relative2.startsWith("..") && !path.isAbsolute(relative2);
|
|
3820
4078
|
};
|
|
3821
4079
|
const classifyServerTarget = (absolutePath, projectRoot) => {
|
|
3822
4080
|
if (!isSubpath(absolutePath, projectRoot)) {
|
|
3823
4081
|
return "ssr";
|
|
3824
4082
|
}
|
|
3825
|
-
const
|
|
3826
|
-
if (
|
|
4083
|
+
const relative2 = toPosixPath(path.relative(projectRoot, absolutePath));
|
|
4084
|
+
if (relative2.startsWith("src/api/") || relative2.includes("/src/api/")) {
|
|
3827
4085
|
return "api";
|
|
3828
4086
|
}
|
|
3829
|
-
if (
|
|
4087
|
+
if (relative2.startsWith("src/worker/") || relative2.includes("/src/worker/")) {
|
|
3830
4088
|
return "worker";
|
|
3831
4089
|
}
|
|
3832
|
-
if (
|
|
4090
|
+
if (relative2.startsWith("src/server/") || relative2.includes("/src/server/")) {
|
|
3833
4091
|
return "ssr";
|
|
3834
4092
|
}
|
|
3835
|
-
if (
|
|
4093
|
+
if (relative2.startsWith("build/dist/api/") || relative2.includes("/build/dist/api/")) {
|
|
3836
4094
|
return "api";
|
|
3837
4095
|
}
|
|
3838
|
-
if (
|
|
4096
|
+
if (relative2.startsWith("build/dist/worker/") || relative2.includes("/build/dist/worker/")) {
|
|
3839
4097
|
return "worker";
|
|
3840
4098
|
}
|
|
3841
|
-
if (
|
|
4099
|
+
if (relative2.startsWith("build/dist/ssr/") || relative2.includes("/build/dist/ssr/")) {
|
|
3842
4100
|
return "ssr";
|
|
3843
4101
|
}
|
|
3844
4102
|
return "ssr";
|
|
@@ -3981,26 +4239,17 @@ process.env = {
|
|
|
3981
4239
|
};
|
|
3982
4240
|
const isProduction$1 = process.env.NODE_ENV === "production";
|
|
3983
4241
|
const SESSION_MAX_AGE_S = 3600 * 24 * 60;
|
|
3984
|
-
const
|
|
3985
|
-
const
|
|
3986
|
-
if (
|
|
3987
|
-
|
|
3988
|
-
}
|
|
3989
|
-
if (serverEnv.DB_PORT) {
|
|
3990
|
-
const host = serverEnv.DB_HOST ?? "localhost";
|
|
3991
|
-
const appName = serverEnv.APP_NAME?.trim();
|
|
3992
|
-
if (!appName) {
|
|
3993
|
-
throw new Error("Missing APP_NAME (required to build MongoDB session store DB name)");
|
|
3994
|
-
}
|
|
3995
|
-
return `mongodb://${host}:${serverEnv.DB_PORT}/${appName}-sessions`;
|
|
4242
|
+
const getMongoSessionUrl = (serverEnv) => {
|
|
4243
|
+
const appName = serverEnv.APP_NAME?.trim();
|
|
4244
|
+
if (!appName) {
|
|
4245
|
+
throw new Error("Missing APP_NAME (required to build MongoDB session store DB name)");
|
|
3996
4246
|
}
|
|
3997
|
-
return
|
|
4247
|
+
return getMongoUrl(serverEnv, {
|
|
4248
|
+
dbName: `${appName}-sessions`
|
|
4249
|
+
});
|
|
3998
4250
|
};
|
|
3999
4251
|
const createMongoSessionStore = async (serverEnv) => {
|
|
4000
|
-
const mongoUrl =
|
|
4001
|
-
if (!mongoUrl) {
|
|
4002
|
-
throw new Error("Missing REDIS_URL and Mongo connection details (MONGODB_URL/MONGO_URL/MONGODB_URI/DB_PORT)");
|
|
4003
|
-
}
|
|
4252
|
+
const mongoUrl = getMongoSessionUrl(serverEnv);
|
|
4004
4253
|
console.log("Using MongoDB session store");
|
|
4005
4254
|
const client2 = await MongoClient.connect(mongoUrl, {
|
|
4006
4255
|
family: 4,
|