@posthog/core 1.39.1 → 1.39.3
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/error-tracking/exception-steps.d.ts.map +1 -1
- package/dist/error-tracking/exception-steps.js +6 -24
- package/dist/error-tracking/exception-steps.mjs +7 -25
- package/dist/posthog-core-stateless.d.ts +4 -0
- package/dist/posthog-core-stateless.d.ts.map +1 -1
- package/dist/posthog-core-stateless.js +37 -7
- package/dist/posthog-core-stateless.mjs +38 -8
- package/dist/testing/PostHogCoreTestClient.d.ts +1 -0
- package/dist/testing/PostHogCoreTestClient.d.ts.map +1 -1
- package/dist/testing/PostHogCoreTestClient.js +3 -0
- package/dist/testing/PostHogCoreTestClient.mjs +3 -0
- package/dist/utils/promise-queue.d.ts +3 -0
- package/dist/utils/promise-queue.d.ts.map +1 -1
- package/dist/utils/promise-queue.js +15 -3
- package/dist/utils/promise-queue.mjs +15 -3
- package/dist/utils/string-utils.d.ts +1 -0
- package/dist/utils/string-utils.d.ts.map +1 -1
- package/dist/utils/string-utils.js +21 -0
- package/dist/utils/string-utils.mjs +19 -1
- package/package.json +1 -1
- package/src/error-tracking/exception-steps.ts +5 -42
- package/src/posthog-core-stateless.ts +56 -10
- package/src/testing/PostHogCoreTestClient.ts +4 -0
- package/src/utils/promise-queue.ts +17 -4
- package/src/utils/string-utils.spec.ts +38 -1
- package/src/utils/string-utils.ts +42 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exception-steps.d.ts","sourceRoot":"","sources":["../../src/error-tracking/exception-steps.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,8BAA8B;;;CAGjC,CAAA;AAOV,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,8BAA8B,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChD,CAAC,8BAA8B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC3D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB,CAAA;AAED,kGAAkG;AAClG,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,4BAA4B,GAAG;IACzC,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,eAAO,MAAM,8BAA8B,EAAE,4BAG5C,CAAA;AAED,wBAAgB,2BAA2B,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,IAAI,GAAG,4BAA4B,CAS9G;AAED,wBAAgB,gCAAgC,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG;IAC7F,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5C,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB,CAmBA;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,WAAW,CAAY;IAC/B,OAAO,CAAC,OAAO,CAA8B;gBAEjC,MAAM,CAAC,EAAE,oBAAoB,GAAG,IAAI;IAIzC,SAAS,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,IAAI,GAAG,IAAI;IAKrD,GAAG,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAgB9B,aAAa,IAAI,aAAa,EAAE;IAIhC,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,MAAM;IAIrB,OAAO,CAAC,eAAe;CAQxB;
|
|
1
|
+
{"version":3,"file":"exception-steps.d.ts","sourceRoot":"","sources":["../../src/error-tracking/exception-steps.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,8BAA8B;;;CAGjC,CAAA;AAOV,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,8BAA8B,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChD,CAAC,8BAA8B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC3D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB,CAAA;AAED,kGAAkG;AAClG,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,4BAA4B,GAAG;IACzC,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,eAAO,MAAM,8BAA8B,EAAE,4BAG5C,CAAA;AAED,wBAAgB,2BAA2B,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,IAAI,GAAG,4BAA4B,CAS9G;AAED,wBAAgB,gCAAgC,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG;IAC7F,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5C,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB,CAmBA;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,WAAW,CAAY;IAC/B,OAAO,CAAC,OAAO,CAA8B;gBAEjC,MAAM,CAAC,EAAE,oBAAoB,GAAG,IAAI;IAIzC,SAAS,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,IAAI,GAAG,IAAI;IAKrD,GAAG,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAgB9B,aAAa,IAAI,aAAa,EAAE;IAIhC,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,MAAM;IAIrB,OAAO,CAAC,eAAe;CAQxB;AAkDD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBvD"}
|
|
@@ -118,8 +118,12 @@ function normalizePositiveInteger(input, fallback) {
|
|
|
118
118
|
return normalized;
|
|
119
119
|
}
|
|
120
120
|
function normalizeAndSerializeStep(step) {
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
let json;
|
|
122
|
+
try {
|
|
123
|
+
json = (0, index_js_namespaceObject.safeJsonStringify)(step);
|
|
124
|
+
} catch {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
123
127
|
try {
|
|
124
128
|
const parsed = JSON.parse(json);
|
|
125
129
|
if (!(0, index_js_namespaceObject.isObject)(parsed)) return;
|
|
@@ -136,28 +140,6 @@ function normalizeAndSerializeStep(step) {
|
|
|
136
140
|
return;
|
|
137
141
|
}
|
|
138
142
|
}
|
|
139
|
-
function safeStringify(value) {
|
|
140
|
-
const seen = new WeakSet();
|
|
141
|
-
try {
|
|
142
|
-
return JSON.stringify(value, (_key, replacementValue)=>{
|
|
143
|
-
if ('bigint' == typeof replacementValue) return replacementValue.toString();
|
|
144
|
-
if ('function' == typeof replacementValue || 'symbol' == typeof replacementValue) return;
|
|
145
|
-
if (replacementValue instanceof Date) return replacementValue.toISOString();
|
|
146
|
-
if (replacementValue instanceof Error) return {
|
|
147
|
-
name: replacementValue.name,
|
|
148
|
-
message: replacementValue.message,
|
|
149
|
-
stack: replacementValue.stack
|
|
150
|
-
};
|
|
151
|
-
if (replacementValue && 'object' == typeof replacementValue) {
|
|
152
|
-
if (seen.has(replacementValue)) return '[Circular]';
|
|
153
|
-
seen.add(replacementValue);
|
|
154
|
-
}
|
|
155
|
-
return replacementValue;
|
|
156
|
-
});
|
|
157
|
-
} catch {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
143
|
function getUtf8ByteLength(value) {
|
|
162
144
|
if ('undefined' != typeof TextEncoder) return new TextEncoder().encode(value).length;
|
|
163
145
|
const encoded = encodeURIComponent(value);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isNumber, isObject, isString } from "../utils/index.mjs";
|
|
1
|
+
import { isNumber, isObject, isString, safeJsonStringify } from "../utils/index.mjs";
|
|
2
2
|
const EXCEPTION_STEP_INTERNAL_FIELDS = {
|
|
3
3
|
MESSAGE: '$message',
|
|
4
4
|
TIMESTAMP: '$timestamp'
|
|
@@ -85,8 +85,12 @@ function normalizePositiveInteger(input, fallback) {
|
|
|
85
85
|
return normalized;
|
|
86
86
|
}
|
|
87
87
|
function normalizeAndSerializeStep(step) {
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
let json;
|
|
89
|
+
try {
|
|
90
|
+
json = safeJsonStringify(step);
|
|
91
|
+
} catch {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
90
94
|
try {
|
|
91
95
|
const parsed = JSON.parse(json);
|
|
92
96
|
if (!isObject(parsed)) return;
|
|
@@ -103,28 +107,6 @@ function normalizeAndSerializeStep(step) {
|
|
|
103
107
|
return;
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
|
-
function safeStringify(value) {
|
|
107
|
-
const seen = new WeakSet();
|
|
108
|
-
try {
|
|
109
|
-
return JSON.stringify(value, (_key, replacementValue)=>{
|
|
110
|
-
if ('bigint' == typeof replacementValue) return replacementValue.toString();
|
|
111
|
-
if ('function' == typeof replacementValue || 'symbol' == typeof replacementValue) return;
|
|
112
|
-
if (replacementValue instanceof Date) return replacementValue.toISOString();
|
|
113
|
-
if (replacementValue instanceof Error) return {
|
|
114
|
-
name: replacementValue.name,
|
|
115
|
-
message: replacementValue.message,
|
|
116
|
-
stack: replacementValue.stack
|
|
117
|
-
};
|
|
118
|
-
if (replacementValue && 'object' == typeof replacementValue) {
|
|
119
|
-
if (seen.has(replacementValue)) return '[Circular]';
|
|
120
|
-
seen.add(replacementValue);
|
|
121
|
-
}
|
|
122
|
-
return replacementValue;
|
|
123
|
-
});
|
|
124
|
-
} catch {
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
110
|
function getUtf8ByteLength(value) {
|
|
129
111
|
if ('undefined' != typeof TextEncoder) return new TextEncoder().encode(value).length;
|
|
130
112
|
const encoded = encodeURIComponent(value);
|
|
@@ -55,6 +55,7 @@ export declare abstract class PostHogCoreStateless {
|
|
|
55
55
|
private maxQueueSize;
|
|
56
56
|
private flushInterval;
|
|
57
57
|
private flushPromise;
|
|
58
|
+
private flushPromises;
|
|
58
59
|
private shutdownPromise;
|
|
59
60
|
private requestTimeout;
|
|
60
61
|
private featureFlagsRequestTimeoutMs;
|
|
@@ -222,6 +223,7 @@ export declare abstract class PostHogCoreStateless {
|
|
|
222
223
|
* Avoids unnecessary promise errors
|
|
223
224
|
*/
|
|
224
225
|
private flushBackground;
|
|
226
|
+
private waitForPendingPromises;
|
|
225
227
|
/**
|
|
226
228
|
* Flushes the queue of pending events.
|
|
227
229
|
*
|
|
@@ -250,7 +252,9 @@ export declare abstract class PostHogCoreStateless {
|
|
|
250
252
|
* @throws PostHogFetchNetworkError
|
|
251
253
|
* @throws Error
|
|
252
254
|
*/
|
|
255
|
+
protected flushWithPendingPromises(): Promise<void>;
|
|
253
256
|
flush(): Promise<void>;
|
|
257
|
+
private flushInternal;
|
|
254
258
|
protected getCustomHeaders(): {
|
|
255
259
|
[key: string]: string;
|
|
256
260
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-core-stateless.d.ts","sourceRoot":"","sources":["../src/posthog-core-stateless.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAGnD,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAGhB,yBAAyB,EACzB,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EAExB,MAAM,EACN,cAAc,EAEf,MAAM,SAAS,CAAA;AAChB,OAAO,EAML,gBAAgB,
|
|
1
|
+
{"version":3,"file":"posthog-core-stateless.d.ts","sourceRoot":"","sources":["../src/posthog-core-stateless.ts"],"names":[],"mappings":"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"}
|
|
@@ -113,6 +113,7 @@ class PostHogCoreStateless {
|
|
|
113
113
|
}
|
|
114
114
|
constructor(apiKey, options = {}){
|
|
115
115
|
this.flushPromise = null;
|
|
116
|
+
this.flushPromises = new Set();
|
|
116
117
|
this.shutdownPromise = null;
|
|
117
118
|
this.promiseQueue = new index_js_namespaceObject.PromiseQueue();
|
|
118
119
|
this._events = new external_eventemitter_js_namespaceObject.SimpleEventEmitter();
|
|
@@ -555,7 +556,7 @@ class PostHogCoreStateless {
|
|
|
555
556
|
sent_at: (0, index_js_namespaceObject.currentISOTime)()
|
|
556
557
|
};
|
|
557
558
|
if (this.historicalMigration) data.historical_migration = true;
|
|
558
|
-
const payload =
|
|
559
|
+
const payload = (0, index_js_namespaceObject.safeJsonStringify)(data);
|
|
559
560
|
const url = `${this.host}/batch/`;
|
|
560
561
|
const gzippedPayload = this.disableCompression ? null : await (0, external_gzip_js_namespaceObject.gzipCompress)(payload, this.isDebug);
|
|
561
562
|
const fetchOptions = {
|
|
@@ -619,16 +620,45 @@ class PostHogCoreStateless {
|
|
|
619
620
|
await logFlushError(err);
|
|
620
621
|
});
|
|
621
622
|
}
|
|
622
|
-
async
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
623
|
+
async waitForPendingPromises(maxPromiseId, ignoredPromises = []) {
|
|
624
|
+
const ignoredPendingPromises = ignoredPromises.filter((promise)=>!!promise);
|
|
625
|
+
let iteration = 0;
|
|
626
|
+
while(true){
|
|
627
|
+
const promises = this.promiseQueue.getPromises([
|
|
628
|
+
...ignoredPendingPromises,
|
|
629
|
+
...this.flushPromises
|
|
630
|
+
], maxPromiseId);
|
|
631
|
+
if (0 === promises.length) return;
|
|
632
|
+
if (iteration > 0) this._logger.debug(`flush() re-checking ${promises.length} pending promise(s) before flushing`);
|
|
633
|
+
await Promise.all(promises.map((promise)=>promise.catch(()=>{})));
|
|
634
|
+
iteration++;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
flushWithPendingPromises() {
|
|
638
|
+
return this.flushInternal(true);
|
|
639
|
+
}
|
|
640
|
+
flush() {
|
|
641
|
+
return this.flushInternal(false);
|
|
642
|
+
}
|
|
643
|
+
flushInternal(waitForPendingPromises) {
|
|
644
|
+
if (this.disabled) return Promise.resolve();
|
|
645
|
+
const previousFlushPromise = this.flushPromise;
|
|
646
|
+
const maxPromiseId = this.promiseQueue.maxId;
|
|
647
|
+
const nextFlushPromise = Promise.resolve().then(()=>{
|
|
648
|
+
if (waitForPendingPromises) return this.waitForPendingPromises(maxPromiseId, [
|
|
649
|
+
previousFlushPromise,
|
|
650
|
+
nextFlushPromise
|
|
651
|
+
]);
|
|
652
|
+
}).then(()=>(0, index_js_namespaceObject.allSettled)([
|
|
653
|
+
previousFlushPromise
|
|
654
|
+
])).then(()=>this._flush());
|
|
627
655
|
this.flushPromise = nextFlushPromise;
|
|
656
|
+
this.flushPromises.add(nextFlushPromise);
|
|
628
657
|
this.addPendingPromise(nextFlushPromise);
|
|
629
658
|
(0, index_js_namespaceObject.allSettled)([
|
|
630
659
|
nextFlushPromise
|
|
631
660
|
]).then(()=>{
|
|
661
|
+
this.flushPromises.delete(nextFlushPromise);
|
|
632
662
|
if (this.flushPromise === nextFlushPromise) this.flushPromise = null;
|
|
633
663
|
});
|
|
634
664
|
return nextFlushPromise;
|
|
@@ -662,7 +692,7 @@ class PostHogCoreStateless {
|
|
|
662
692
|
sent_at: (0, index_js_namespaceObject.currentISOTime)()
|
|
663
693
|
};
|
|
664
694
|
if (this.historicalMigration) data.historical_migration = true;
|
|
665
|
-
const payload =
|
|
695
|
+
const payload = (0, index_js_namespaceObject.safeJsonStringify)(data);
|
|
666
696
|
const url = `${this.host}/batch/`;
|
|
667
697
|
const gzippedPayload = this.disableCompression ? null : await (0, external_gzip_js_namespaceObject.gzipCompress)(payload, this.isDebug);
|
|
668
698
|
const fetchOptions = {
|
|
@@ -2,7 +2,7 @@ import { SimpleEventEmitter } from "./eventemitter.mjs";
|
|
|
2
2
|
import { getFeatureFlagValue, normalizeFlagsResponse } from "./featureFlagUtils.mjs";
|
|
3
3
|
import { gzipCompress, isGzipSupported } from "./gzip.mjs";
|
|
4
4
|
import { PostHogPersistedProperty } from "./types.mjs";
|
|
5
|
-
import { PromiseQueue, STRING_FORMAT, allSettled, createLogger, currentISOTime, getEventUuid, removeTrailingSlash, retriable, safeSetTimeout } from "./utils/index.mjs";
|
|
5
|
+
import { PromiseQueue, STRING_FORMAT, allSettled, createLogger, currentISOTime, getEventUuid, removeTrailingSlash, retriable, safeJsonStringify, safeSetTimeout } from "./utils/index.mjs";
|
|
6
6
|
import { uuidv7 } from "./vendor/uuidv7.mjs";
|
|
7
7
|
import { ErrorCoercer, ErrorPropertiesBuilder, ObjectCoercer, PrimitiveCoercer, StringCoercer, createDefaultStackParser } from "./error-tracking/index.mjs";
|
|
8
8
|
class PostHogFetchHttpError extends Error {
|
|
@@ -81,6 +81,7 @@ class PostHogCoreStateless {
|
|
|
81
81
|
}
|
|
82
82
|
constructor(apiKey, options = {}){
|
|
83
83
|
this.flushPromise = null;
|
|
84
|
+
this.flushPromises = new Set();
|
|
84
85
|
this.shutdownPromise = null;
|
|
85
86
|
this.promiseQueue = new PromiseQueue();
|
|
86
87
|
this._events = new SimpleEventEmitter();
|
|
@@ -523,7 +524,7 @@ class PostHogCoreStateless {
|
|
|
523
524
|
sent_at: currentISOTime()
|
|
524
525
|
};
|
|
525
526
|
if (this.historicalMigration) data.historical_migration = true;
|
|
526
|
-
const payload =
|
|
527
|
+
const payload = safeJsonStringify(data);
|
|
527
528
|
const url = `${this.host}/batch/`;
|
|
528
529
|
const gzippedPayload = this.disableCompression ? null : await gzipCompress(payload, this.isDebug);
|
|
529
530
|
const fetchOptions = {
|
|
@@ -587,16 +588,45 @@ class PostHogCoreStateless {
|
|
|
587
588
|
await logFlushError(err);
|
|
588
589
|
});
|
|
589
590
|
}
|
|
590
|
-
async
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
591
|
+
async waitForPendingPromises(maxPromiseId, ignoredPromises = []) {
|
|
592
|
+
const ignoredPendingPromises = ignoredPromises.filter((promise)=>!!promise);
|
|
593
|
+
let iteration = 0;
|
|
594
|
+
while(true){
|
|
595
|
+
const promises = this.promiseQueue.getPromises([
|
|
596
|
+
...ignoredPendingPromises,
|
|
597
|
+
...this.flushPromises
|
|
598
|
+
], maxPromiseId);
|
|
599
|
+
if (0 === promises.length) return;
|
|
600
|
+
if (iteration > 0) this._logger.debug(`flush() re-checking ${promises.length} pending promise(s) before flushing`);
|
|
601
|
+
await Promise.all(promises.map((promise)=>promise.catch(()=>{})));
|
|
602
|
+
iteration++;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
flushWithPendingPromises() {
|
|
606
|
+
return this.flushInternal(true);
|
|
607
|
+
}
|
|
608
|
+
flush() {
|
|
609
|
+
return this.flushInternal(false);
|
|
610
|
+
}
|
|
611
|
+
flushInternal(waitForPendingPromises) {
|
|
612
|
+
if (this.disabled) return Promise.resolve();
|
|
613
|
+
const previousFlushPromise = this.flushPromise;
|
|
614
|
+
const maxPromiseId = this.promiseQueue.maxId;
|
|
615
|
+
const nextFlushPromise = Promise.resolve().then(()=>{
|
|
616
|
+
if (waitForPendingPromises) return this.waitForPendingPromises(maxPromiseId, [
|
|
617
|
+
previousFlushPromise,
|
|
618
|
+
nextFlushPromise
|
|
619
|
+
]);
|
|
620
|
+
}).then(()=>allSettled([
|
|
621
|
+
previousFlushPromise
|
|
622
|
+
])).then(()=>this._flush());
|
|
595
623
|
this.flushPromise = nextFlushPromise;
|
|
624
|
+
this.flushPromises.add(nextFlushPromise);
|
|
596
625
|
this.addPendingPromise(nextFlushPromise);
|
|
597
626
|
allSettled([
|
|
598
627
|
nextFlushPromise
|
|
599
628
|
]).then(()=>{
|
|
629
|
+
this.flushPromises.delete(nextFlushPromise);
|
|
600
630
|
if (this.flushPromise === nextFlushPromise) this.flushPromise = null;
|
|
601
631
|
});
|
|
602
632
|
return nextFlushPromise;
|
|
@@ -630,7 +660,7 @@ class PostHogCoreStateless {
|
|
|
630
660
|
sent_at: currentISOTime()
|
|
631
661
|
};
|
|
632
662
|
if (this.historicalMigration) data.historical_migration = true;
|
|
633
|
-
const payload =
|
|
663
|
+
const payload = safeJsonStringify(data);
|
|
634
664
|
const url = `${this.host}/batch/`;
|
|
635
665
|
const gzippedPayload = this.disableCompression ? null : await gzipCompress(payload, this.isDebug);
|
|
636
666
|
const fetchOptions = {
|
|
@@ -12,6 +12,7 @@ export declare class PostHogCoreTestClient extends PostHogCore {
|
|
|
12
12
|
_cachedDistinctId?: string;
|
|
13
13
|
constructor(mocks: PostHogCoreTestClientMocks, apiKey: string, options?: PostHogCoreOptions);
|
|
14
14
|
getFlags(distinctId: string, groups?: Record<string, string | number>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>, extraPayload?: Record<string, any>): Promise<GetFlagsResult>;
|
|
15
|
+
flushWithPendingPromises(): Promise<void>;
|
|
15
16
|
getPersistedProperty<T>(key: string): T;
|
|
16
17
|
setPersistedProperty<T>(key: string, value: T | null): void;
|
|
17
18
|
fetch(url: string, options: PostHogFetchOptions): Promise<PostHogFetchResponse>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostHogCoreTestClient.d.ts","sourceRoot":"","sources":["../../src/testing/PostHogCoreTestClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAItH,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAA;IAC9E,OAAO,EAAE;QACP,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;QAC7C,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC,CAAA;KAC/C,CAAA;CACF;AAED,qBAAa,qBAAsB,SAAQ,WAAW;IAIlD,OAAO,CAAC,KAAK;IAHR,iBAAiB,CAAC,EAAE,MAAM,CAAA;gBAGvB,KAAK,EAAE,0BAA0B,EACzC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,kBAAkB;IAQvB,QAAQ,CACb,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAM,EAC5C,gBAAgB,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EAC7C,eAAe,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EAC5D,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GACrC,OAAO,CAAC,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"PostHogCoreTestClient.d.ts","sourceRoot":"","sources":["../../src/testing/PostHogCoreTestClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAItH,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAA;IAC9E,OAAO,EAAE;QACP,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;QAC7C,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC,CAAA;KAC/C,CAAA;CACF;AAED,qBAAa,qBAAsB,SAAQ,WAAW;IAIlD,OAAO,CAAC,KAAK;IAHR,iBAAiB,CAAC,EAAE,MAAM,CAAA;gBAGvB,KAAK,EAAE,0BAA0B,EACzC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,kBAAkB;IAQvB,QAAQ,CACb,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAM,EAC5C,gBAAgB,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EAC7C,eAAe,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EAC5D,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GACrC,OAAO,CAAC,cAAc,CAAC;IAInB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhD,oBAAoB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC;IAGvC,oBAAoB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;IAG3D,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAG/E,YAAY,IAAI,MAAM;IAGtB,iBAAiB,IAAI,MAAM;IAG3B,kBAAkB,IAAI,MAAM;CAG7B;AAED,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,MAAM,EACd,UAAU,kBAAkB,EAC5B,aAAa,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,EACxD,eAAc;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;CAAO,KACtD,CAAC,qBAAqB,EAAE,0BAA0B,CAsBpD,CAAA"}
|
|
@@ -37,6 +37,9 @@ class PostHogCoreTestClient extends external_posthog_core_js_namespaceObject.Pos
|
|
|
37
37
|
getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}) {
|
|
38
38
|
return super.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload);
|
|
39
39
|
}
|
|
40
|
+
flushWithPendingPromises() {
|
|
41
|
+
return super.flushWithPendingPromises();
|
|
42
|
+
}
|
|
40
43
|
getPersistedProperty(key) {
|
|
41
44
|
return this.mocks.storage.getItem(key);
|
|
42
45
|
}
|
|
@@ -8,6 +8,9 @@ class PostHogCoreTestClient extends PostHogCore {
|
|
|
8
8
|
getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}) {
|
|
9
9
|
return super.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload);
|
|
10
10
|
}
|
|
11
|
+
flushWithPendingPromises() {
|
|
12
|
+
return super.flushWithPendingPromises();
|
|
13
|
+
}
|
|
11
14
|
getPersistedProperty(key) {
|
|
12
15
|
return this.mocks.storage.getItem(key);
|
|
13
16
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export declare class PromiseQueue {
|
|
2
2
|
private promiseByIds;
|
|
3
|
+
private nextId;
|
|
3
4
|
add(promise: Promise<any>): Promise<any>;
|
|
4
5
|
join(): Promise<void>;
|
|
6
|
+
getPromises(ignoredPromises?: Promise<any>[], maxId?: number): Promise<any>[];
|
|
7
|
+
get maxId(): number;
|
|
5
8
|
get length(): number;
|
|
6
9
|
}
|
|
7
10
|
//# sourceMappingURL=promise-queue.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promise-queue.d.ts","sourceRoot":"","sources":["../../src/utils/promise-queue.ts"],"names":[],"mappings":"AAEA,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,
|
|
1
|
+
{"version":3,"file":"promise-queue.d.ts","sourceRoot":"","sources":["../../src/utils/promise-queue.ts"],"names":[],"mappings":"AAEA,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAA4D;IAChF,OAAO,CAAC,MAAM,CAAY;IAEnB,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAYlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B,WAAW,CAAC,eAAe,GAAE,OAAO,CAAC,GAAG,CAAC,EAAO,EAAE,KAAK,GAAE,MAAoB,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE;IAOrG,IAAW,KAAK,IAAI,MAAM,CAEzB;IAED,IAAW,MAAM,IAAI,MAAM,CAE1B;CACF"}
|
|
@@ -30,26 +30,38 @@ const uuidv7_js_namespaceObject = require("../vendor/uuidv7.js");
|
|
|
30
30
|
class PromiseQueue {
|
|
31
31
|
add(promise) {
|
|
32
32
|
const promiseUUID = (0, uuidv7_js_namespaceObject.uuidv7)();
|
|
33
|
-
|
|
33
|
+
const id = ++this.nextId;
|
|
34
|
+
this.promiseByIds[promiseUUID] = {
|
|
35
|
+
id,
|
|
36
|
+
promise
|
|
37
|
+
};
|
|
34
38
|
promise.catch(()=>{}).finally(()=>{
|
|
35
39
|
delete this.promiseByIds[promiseUUID];
|
|
36
40
|
});
|
|
37
41
|
return promise;
|
|
38
42
|
}
|
|
39
43
|
async join() {
|
|
40
|
-
let promises = Object.values(this.promiseByIds);
|
|
44
|
+
let promises = Object.values(this.promiseByIds).map((item)=>item.promise);
|
|
41
45
|
let length = promises.length;
|
|
42
46
|
while(length > 0){
|
|
43
47
|
await Promise.all(promises);
|
|
44
|
-
promises = Object.values(this.promiseByIds);
|
|
48
|
+
promises = Object.values(this.promiseByIds).map((item)=>item.promise);
|
|
45
49
|
length = promises.length;
|
|
46
50
|
}
|
|
47
51
|
}
|
|
52
|
+
getPromises(ignoredPromises = [], maxId = this.nextId) {
|
|
53
|
+
const ignoredPromiseSet = new Set(ignoredPromises);
|
|
54
|
+
return Object.values(this.promiseByIds).filter((item)=>item.id <= maxId && !ignoredPromiseSet.has(item.promise)).map((item)=>item.promise);
|
|
55
|
+
}
|
|
56
|
+
get maxId() {
|
|
57
|
+
return this.nextId;
|
|
58
|
+
}
|
|
48
59
|
get length() {
|
|
49
60
|
return Object.keys(this.promiseByIds).length;
|
|
50
61
|
}
|
|
51
62
|
constructor(){
|
|
52
63
|
this.promiseByIds = {};
|
|
64
|
+
this.nextId = 0;
|
|
53
65
|
}
|
|
54
66
|
}
|
|
55
67
|
exports.PromiseQueue = __webpack_exports__.PromiseQueue;
|
|
@@ -2,26 +2,38 @@ import { uuidv7 } from "../vendor/uuidv7.mjs";
|
|
|
2
2
|
class PromiseQueue {
|
|
3
3
|
add(promise) {
|
|
4
4
|
const promiseUUID = uuidv7();
|
|
5
|
-
|
|
5
|
+
const id = ++this.nextId;
|
|
6
|
+
this.promiseByIds[promiseUUID] = {
|
|
7
|
+
id,
|
|
8
|
+
promise
|
|
9
|
+
};
|
|
6
10
|
promise.catch(()=>{}).finally(()=>{
|
|
7
11
|
delete this.promiseByIds[promiseUUID];
|
|
8
12
|
});
|
|
9
13
|
return promise;
|
|
10
14
|
}
|
|
11
15
|
async join() {
|
|
12
|
-
let promises = Object.values(this.promiseByIds);
|
|
16
|
+
let promises = Object.values(this.promiseByIds).map((item)=>item.promise);
|
|
13
17
|
let length = promises.length;
|
|
14
18
|
while(length > 0){
|
|
15
19
|
await Promise.all(promises);
|
|
16
|
-
promises = Object.values(this.promiseByIds);
|
|
20
|
+
promises = Object.values(this.promiseByIds).map((item)=>item.promise);
|
|
17
21
|
length = promises.length;
|
|
18
22
|
}
|
|
19
23
|
}
|
|
24
|
+
getPromises(ignoredPromises = [], maxId = this.nextId) {
|
|
25
|
+
const ignoredPromiseSet = new Set(ignoredPromises);
|
|
26
|
+
return Object.values(this.promiseByIds).filter((item)=>item.id <= maxId && !ignoredPromiseSet.has(item.promise)).map((item)=>item.promise);
|
|
27
|
+
}
|
|
28
|
+
get maxId() {
|
|
29
|
+
return this.nextId;
|
|
30
|
+
}
|
|
20
31
|
get length() {
|
|
21
32
|
return Object.keys(this.promiseByIds).length;
|
|
22
33
|
}
|
|
23
34
|
constructor(){
|
|
24
35
|
this.promiseByIds = {};
|
|
36
|
+
this.nextId = 0;
|
|
25
37
|
}
|
|
26
38
|
}
|
|
27
39
|
export { PromiseQueue };
|
|
@@ -4,6 +4,7 @@ export declare function includes<T>(arr: T[], needle: T): boolean;
|
|
|
4
4
|
export declare const trim: (str: string) => string;
|
|
5
5
|
export declare const stripLeadingDollar: (s: string) => string;
|
|
6
6
|
export declare function isDistinctIdStringLike(value: string): boolean;
|
|
7
|
+
export declare function safeJsonStringify(value: unknown): string;
|
|
7
8
|
/**
|
|
8
9
|
* Creates a hash string from distinct_id and person properties.
|
|
9
10
|
* Used to detect if person properties have changed to avoid duplicate $set events.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string-utils.d.ts","sourceRoot":"","sources":["../../src/utils/string-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;AAC9D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,CAAA;AAKzD,eAAO,MAAM,IAAI,GAAa,KAAK,MAAM,KAAG,MAM3C,CAAA;AAID,eAAO,MAAM,kBAAkB,GAAa,GAAG,MAAM,KAAG,MAEvD,CAAA;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE7D;AAuBD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,mBAAmB,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,EACjD,uBAAuB,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,GACpD,MAAM,CAMR"}
|
|
1
|
+
{"version":3,"file":"string-utils.d.ts","sourceRoot":"","sources":["../../src/utils/string-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;AAC9D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,CAAA;AAKzD,eAAO,MAAM,IAAI,GAAa,KAAK,MAAM,KAAG,MAM3C,CAAA;AAID,eAAO,MAAM,kBAAkB,GAAa,GAAG,MAAM,KAAG,MAEvD,CAAA;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAwCxD;AAuBD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,mBAAmB,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,EACjD,uBAAuB,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,GACpD,MAAM,CAMR"}
|
|
@@ -27,6 +27,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
27
27
|
getPersonPropertiesHash: ()=>getPersonPropertiesHash,
|
|
28
28
|
includes: ()=>includes,
|
|
29
29
|
isDistinctIdStringLike: ()=>isDistinctIdStringLike,
|
|
30
|
+
safeJsonStringify: ()=>safeJsonStringify,
|
|
30
31
|
stripLeadingDollar: ()=>stripLeadingDollar,
|
|
31
32
|
trim: ()=>trim
|
|
32
33
|
});
|
|
@@ -45,6 +46,24 @@ function isDistinctIdStringLike(value) {
|
|
|
45
46
|
'distinctid'
|
|
46
47
|
].includes(value.toLowerCase());
|
|
47
48
|
}
|
|
49
|
+
function safeJsonStringify(value) {
|
|
50
|
+
const ancestors = [];
|
|
51
|
+
return JSON.stringify(value, function(_key, replacementValue) {
|
|
52
|
+
if ('bigint' == typeof replacementValue) return replacementValue.toString();
|
|
53
|
+
if ('function' == typeof replacementValue || 'symbol' == typeof replacementValue) return;
|
|
54
|
+
if (replacementValue instanceof Error) return {
|
|
55
|
+
name: replacementValue.name,
|
|
56
|
+
message: replacementValue.message,
|
|
57
|
+
stack: replacementValue.stack
|
|
58
|
+
};
|
|
59
|
+
if (replacementValue && 'object' == typeof replacementValue) {
|
|
60
|
+
while(ancestors.length > 0 && ancestors[ancestors.length - 1] !== this)ancestors.pop();
|
|
61
|
+
if (ancestors.includes(replacementValue)) return '[Circular]';
|
|
62
|
+
ancestors.push(replacementValue);
|
|
63
|
+
}
|
|
64
|
+
return replacementValue;
|
|
65
|
+
}) ?? 'null';
|
|
66
|
+
}
|
|
48
67
|
function deepSortKeys(value) {
|
|
49
68
|
if (null === value || 'object' != typeof value) return value;
|
|
50
69
|
if (Array.isArray(value)) return value.map(deepSortKeys);
|
|
@@ -63,12 +82,14 @@ function getPersonPropertiesHash(distinct_id, userPropertiesToSet, userPropertie
|
|
|
63
82
|
exports.getPersonPropertiesHash = __webpack_exports__.getPersonPropertiesHash;
|
|
64
83
|
exports.includes = __webpack_exports__.includes;
|
|
65
84
|
exports.isDistinctIdStringLike = __webpack_exports__.isDistinctIdStringLike;
|
|
85
|
+
exports.safeJsonStringify = __webpack_exports__.safeJsonStringify;
|
|
66
86
|
exports.stripLeadingDollar = __webpack_exports__.stripLeadingDollar;
|
|
67
87
|
exports.trim = __webpack_exports__.trim;
|
|
68
88
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
69
89
|
"getPersonPropertiesHash",
|
|
70
90
|
"includes",
|
|
71
91
|
"isDistinctIdStringLike",
|
|
92
|
+
"safeJsonStringify",
|
|
72
93
|
"stripLeadingDollar",
|
|
73
94
|
"trim"
|
|
74
95
|
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
@@ -13,6 +13,24 @@ function isDistinctIdStringLike(value) {
|
|
|
13
13
|
'distinctid'
|
|
14
14
|
].includes(value.toLowerCase());
|
|
15
15
|
}
|
|
16
|
+
function safeJsonStringify(value) {
|
|
17
|
+
const ancestors = [];
|
|
18
|
+
return JSON.stringify(value, function(_key, replacementValue) {
|
|
19
|
+
if ('bigint' == typeof replacementValue) return replacementValue.toString();
|
|
20
|
+
if ('function' == typeof replacementValue || 'symbol' == typeof replacementValue) return;
|
|
21
|
+
if (replacementValue instanceof Error) return {
|
|
22
|
+
name: replacementValue.name,
|
|
23
|
+
message: replacementValue.message,
|
|
24
|
+
stack: replacementValue.stack
|
|
25
|
+
};
|
|
26
|
+
if (replacementValue && 'object' == typeof replacementValue) {
|
|
27
|
+
while(ancestors.length > 0 && ancestors[ancestors.length - 1] !== this)ancestors.pop();
|
|
28
|
+
if (ancestors.includes(replacementValue)) return '[Circular]';
|
|
29
|
+
ancestors.push(replacementValue);
|
|
30
|
+
}
|
|
31
|
+
return replacementValue;
|
|
32
|
+
}) ?? 'null';
|
|
33
|
+
}
|
|
16
34
|
function deepSortKeys(value) {
|
|
17
35
|
if (null === value || 'object' != typeof value) return value;
|
|
18
36
|
if (Array.isArray(value)) return value.map(deepSortKeys);
|
|
@@ -28,4 +46,4 @@ function getPersonPropertiesHash(distinct_id, userPropertiesToSet, userPropertie
|
|
|
28
46
|
userPropertiesToSetOnce: userPropertiesToSetOnce ? deepSortKeys(userPropertiesToSetOnce) : void 0
|
|
29
47
|
});
|
|
30
48
|
}
|
|
31
|
-
export { getPersonPropertiesHash, includes, isDistinctIdStringLike, stripLeadingDollar, trim };
|
|
49
|
+
export { getPersonPropertiesHash, includes, isDistinctIdStringLike, safeJsonStringify, stripLeadingDollar, trim };
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isArray, isNumber, isObject, isString } from '@/utils'
|
|
1
|
+
import { isArray, isNumber, isObject, isString, safeJsonStringify } from '@/utils'
|
|
2
2
|
|
|
3
3
|
export const EXCEPTION_STEP_INTERNAL_FIELDS = {
|
|
4
4
|
MESSAGE: '$message',
|
|
@@ -134,8 +134,10 @@ function normalizePositiveInteger(input: number | undefined, fallback: number):
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
function normalizeAndSerializeStep(step: ExceptionStep): { step: ExceptionStep; json: string } | undefined {
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
let json: string
|
|
138
|
+
try {
|
|
139
|
+
json = safeJsonStringify(step)
|
|
140
|
+
} catch {
|
|
139
141
|
return undefined
|
|
140
142
|
}
|
|
141
143
|
|
|
@@ -166,45 +168,6 @@ function normalizeAndSerializeStep(step: ExceptionStep): { step: ExceptionStep;
|
|
|
166
168
|
}
|
|
167
169
|
}
|
|
168
170
|
|
|
169
|
-
function safeStringify(value: unknown): string | undefined {
|
|
170
|
-
const seen = new WeakSet<object>()
|
|
171
|
-
|
|
172
|
-
try {
|
|
173
|
-
return JSON.stringify(value, (_key, replacementValue: unknown) => {
|
|
174
|
-
if (typeof replacementValue === 'bigint') {
|
|
175
|
-
return replacementValue.toString()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (typeof replacementValue === 'function' || typeof replacementValue === 'symbol') {
|
|
179
|
-
return undefined
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (replacementValue instanceof Date) {
|
|
183
|
-
return replacementValue.toISOString()
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (replacementValue instanceof Error) {
|
|
187
|
-
return {
|
|
188
|
-
name: replacementValue.name,
|
|
189
|
-
message: replacementValue.message,
|
|
190
|
-
stack: replacementValue.stack,
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (replacementValue && typeof replacementValue === 'object') {
|
|
195
|
-
if (seen.has(replacementValue)) {
|
|
196
|
-
return '[Circular]'
|
|
197
|
-
}
|
|
198
|
-
seen.add(replacementValue)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return replacementValue
|
|
202
|
-
})
|
|
203
|
-
} catch {
|
|
204
|
-
return undefined
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
171
|
export function getUtf8ByteLength(value: string): number {
|
|
209
172
|
if (typeof TextEncoder !== 'undefined') {
|
|
210
173
|
return new TextEncoder().encode(value).length
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
STRING_FORMAT,
|
|
35
35
|
createLogger,
|
|
36
36
|
getEventUuid,
|
|
37
|
+
safeJsonStringify,
|
|
37
38
|
} from './utils'
|
|
38
39
|
import { uuidv7 } from './vendor/uuidv7'
|
|
39
40
|
import {
|
|
@@ -170,6 +171,7 @@ export abstract class PostHogCoreStateless {
|
|
|
170
171
|
private maxQueueSize: number
|
|
171
172
|
private flushInterval: number
|
|
172
173
|
private flushPromise: Promise<any> | null = null
|
|
174
|
+
private flushPromises: Set<Promise<any>> = new Set()
|
|
173
175
|
private shutdownPromise: Promise<void> | null = null
|
|
174
176
|
private requestTimeout: number
|
|
175
177
|
private featureFlagsRequestTimeoutMs: number
|
|
@@ -1082,7 +1084,7 @@ export abstract class PostHogCoreStateless {
|
|
|
1082
1084
|
data.historical_migration = true
|
|
1083
1085
|
}
|
|
1084
1086
|
|
|
1085
|
-
const payload =
|
|
1087
|
+
const payload = safeJsonStringify(data)
|
|
1086
1088
|
|
|
1087
1089
|
const url = `${this.host}/batch/`
|
|
1088
1090
|
|
|
@@ -1173,6 +1175,28 @@ export abstract class PostHogCoreStateless {
|
|
|
1173
1175
|
})
|
|
1174
1176
|
}
|
|
1175
1177
|
|
|
1178
|
+
private async waitForPendingPromises(
|
|
1179
|
+
maxPromiseId: number,
|
|
1180
|
+
ignoredPromises: (Promise<any> | null | undefined)[] = []
|
|
1181
|
+
): Promise<void> {
|
|
1182
|
+
const ignoredPendingPromises = ignoredPromises.filter((promise): promise is Promise<any> => !!promise)
|
|
1183
|
+
let iteration = 0
|
|
1184
|
+
|
|
1185
|
+
while (true) {
|
|
1186
|
+
const promises = this.promiseQueue.getPromises([...ignoredPendingPromises, ...this.flushPromises], maxPromiseId)
|
|
1187
|
+
if (promises.length === 0) {
|
|
1188
|
+
return
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
if (iteration > 0) {
|
|
1192
|
+
this._logger.debug(`flush() re-checking ${promises.length} pending promise(s) before flushing`)
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
await Promise.all(promises.map((promise) => promise.catch(() => {})))
|
|
1196
|
+
iteration++
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1176
1200
|
/**
|
|
1177
1201
|
* Flushes the queue of pending events.
|
|
1178
1202
|
*
|
|
@@ -1201,22 +1225,44 @@ export abstract class PostHogCoreStateless {
|
|
|
1201
1225
|
* @throws PostHogFetchNetworkError
|
|
1202
1226
|
* @throws Error
|
|
1203
1227
|
*/
|
|
1204
|
-
|
|
1228
|
+
protected flushWithPendingPromises(): Promise<void> {
|
|
1229
|
+
return this.flushInternal(true)
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
flush(): Promise<void> {
|
|
1233
|
+
return this.flushInternal(false)
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
private flushInternal(waitForPendingPromises: boolean): Promise<void> {
|
|
1205
1237
|
if (this.disabled) {
|
|
1206
|
-
return
|
|
1238
|
+
return Promise.resolve()
|
|
1207
1239
|
}
|
|
1208
1240
|
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1241
|
+
const previousFlushPromise = this.flushPromise
|
|
1242
|
+
const maxPromiseId = this.promiseQueue.maxId
|
|
1243
|
+
|
|
1244
|
+
// Register this flush in the promise queue synchronously so shutdown() can't miss it,
|
|
1245
|
+
// but exclude it from the pending-work wait to avoid self-waiting.
|
|
1246
|
+
const nextFlushPromise: Promise<void> = Promise.resolve()
|
|
1247
|
+
.then(() => {
|
|
1248
|
+
if (waitForPendingPromises) {
|
|
1249
|
+
return this.waitForPendingPromises(maxPromiseId, [previousFlushPromise, nextFlushPromise])
|
|
1250
|
+
}
|
|
1251
|
+
})
|
|
1252
|
+
// Wait for the current flush operation to finish (regardless of success or failure), then try to flush again.
|
|
1253
|
+
// Use allSettled instead of finally to be defensive around flush throwing errors immediately rather than rejecting.
|
|
1254
|
+
// Use a custom allSettled implementation to avoid issues with patching Promise on RN
|
|
1255
|
+
.then(() => allSettled([previousFlushPromise]))
|
|
1256
|
+
.then(() => {
|
|
1257
|
+
return this._flush()
|
|
1258
|
+
})
|
|
1215
1259
|
|
|
1216
1260
|
this.flushPromise = nextFlushPromise
|
|
1261
|
+
this.flushPromises.add(nextFlushPromise)
|
|
1217
1262
|
void this.addPendingPromise(nextFlushPromise)
|
|
1218
1263
|
|
|
1219
1264
|
allSettled([nextFlushPromise]).then(() => {
|
|
1265
|
+
this.flushPromises.delete(nextFlushPromise)
|
|
1220
1266
|
// If there are no others waiting to flush, clear the promise.
|
|
1221
1267
|
// We don't strictly need to do this, but it could make debugging easier
|
|
1222
1268
|
if (this.flushPromise === nextFlushPromise) {
|
|
@@ -1278,7 +1324,7 @@ export abstract class PostHogCoreStateless {
|
|
|
1278
1324
|
data.historical_migration = true
|
|
1279
1325
|
}
|
|
1280
1326
|
|
|
1281
|
-
const payload =
|
|
1327
|
+
const payload = safeJsonStringify(data)
|
|
1282
1328
|
|
|
1283
1329
|
const url = `${this.host}/batch/`
|
|
1284
1330
|
|
|
@@ -35,6 +35,10 @@ export class PostHogCoreTestClient extends PostHogCore {
|
|
|
35
35
|
return super.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
public flushWithPendingPromises(): Promise<void> {
|
|
39
|
+
return super.flushWithPendingPromises()
|
|
40
|
+
}
|
|
41
|
+
|
|
38
42
|
getPersistedProperty<T>(key: string): T {
|
|
39
43
|
return this.mocks.storage.getItem(key)
|
|
40
44
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { uuidv7 } from '../vendor/uuidv7'
|
|
2
2
|
|
|
3
3
|
export class PromiseQueue {
|
|
4
|
-
private promiseByIds: Record<string, Promise<any
|
|
4
|
+
private promiseByIds: Record<string, { id: number; promise: Promise<any> }> = {}
|
|
5
|
+
private nextId: number = 0
|
|
5
6
|
|
|
6
7
|
public add(promise: Promise<any>): Promise<any> {
|
|
7
8
|
const promiseUUID = uuidv7()
|
|
8
|
-
|
|
9
|
+
const id = ++this.nextId
|
|
10
|
+
this.promiseByIds[promiseUUID] = { id, promise }
|
|
9
11
|
promise
|
|
10
12
|
.catch(() => {})
|
|
11
13
|
.finally(() => {
|
|
@@ -15,15 +17,26 @@ export class PromiseQueue {
|
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
public async join(): Promise<void> {
|
|
18
|
-
let promises = Object.values(this.promiseByIds)
|
|
20
|
+
let promises = Object.values(this.promiseByIds).map((item) => item.promise)
|
|
19
21
|
let length = promises.length
|
|
20
22
|
while (length > 0) {
|
|
21
23
|
await Promise.all(promises)
|
|
22
|
-
promises = Object.values(this.promiseByIds)
|
|
24
|
+
promises = Object.values(this.promiseByIds).map((item) => item.promise)
|
|
23
25
|
length = promises.length
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
public getPromises(ignoredPromises: Promise<any>[] = [], maxId: number = this.nextId): Promise<any>[] {
|
|
30
|
+
const ignoredPromiseSet = new Set(ignoredPromises)
|
|
31
|
+
return Object.values(this.promiseByIds)
|
|
32
|
+
.filter((item) => item.id <= maxId && !ignoredPromiseSet.has(item.promise))
|
|
33
|
+
.map((item) => item.promise)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public get maxId(): number {
|
|
37
|
+
return this.nextId
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
public get length(): number {
|
|
28
41
|
return Object.keys(this.promiseByIds).length
|
|
29
42
|
}
|
|
@@ -1,6 +1,43 @@
|
|
|
1
|
-
import { getPersonPropertiesHash } from './string-utils'
|
|
1
|
+
import { getPersonPropertiesHash, safeJsonStringify } from './string-utils'
|
|
2
2
|
|
|
3
3
|
describe('string-utils', () => {
|
|
4
|
+
describe('safeJsonStringify', () => {
|
|
5
|
+
it.each([
|
|
6
|
+
[
|
|
7
|
+
'replaces circular references',
|
|
8
|
+
() => {
|
|
9
|
+
const circular: Record<string, any> = { foo: 'bar' }
|
|
10
|
+
circular.self = circular
|
|
11
|
+
return {
|
|
12
|
+
value: circular,
|
|
13
|
+
expected: { foo: 'bar', self: '[Circular]' },
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
[
|
|
18
|
+
'preserves shared non-circular references',
|
|
19
|
+
() => {
|
|
20
|
+
const shared = { id: 1 }
|
|
21
|
+
return {
|
|
22
|
+
value: { a: shared, b: shared },
|
|
23
|
+
expected: { a: { id: 1 }, b: { id: 1 } },
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
'serializes bigint values as strings',
|
|
29
|
+
() => ({
|
|
30
|
+
value: { count: BigInt(123) },
|
|
31
|
+
expected: { count: '123' },
|
|
32
|
+
}),
|
|
33
|
+
],
|
|
34
|
+
])('%s', (_description, buildCase) => {
|
|
35
|
+
const { value, expected } = buildCase()
|
|
36
|
+
|
|
37
|
+
expect(JSON.parse(safeJsonStringify(value))).toEqual(expected)
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
4
41
|
describe('getPersonPropertiesHash', () => {
|
|
5
42
|
it('should return consistent hash regardless of top-level key order', () => {
|
|
6
43
|
const hash1 = getPersonPropertiesHash('user-1', { b: 'value-b', a: 'value-a' })
|
|
@@ -24,6 +24,48 @@ export function isDistinctIdStringLike(value: string): boolean {
|
|
|
24
24
|
return ['distinct_id', 'distinctid'].includes(value.toLowerCase())
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export function safeJsonStringify(value: unknown): string {
|
|
28
|
+
// Browser replay has `circularReferenceReplacer`, which uses this same
|
|
29
|
+
// ancestor-chain approach to replace only true cycles. Keep this core helper
|
|
30
|
+
// separate so Node/RN/core payload serialization does not depend on browser
|
|
31
|
+
// replay internals, and so we can also handle BigInt and Error values here.
|
|
32
|
+
const ancestors: object[] = []
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
JSON.stringify(value, function (this: unknown, _key: string, replacementValue: unknown) {
|
|
36
|
+
if (typeof replacementValue === 'bigint') {
|
|
37
|
+
return replacementValue.toString()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (typeof replacementValue === 'function' || typeof replacementValue === 'symbol') {
|
|
41
|
+
return undefined
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (replacementValue instanceof Error) {
|
|
45
|
+
return {
|
|
46
|
+
name: replacementValue.name,
|
|
47
|
+
message: replacementValue.message,
|
|
48
|
+
stack: replacementValue.stack,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (replacementValue && typeof replacementValue === 'object') {
|
|
53
|
+
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) {
|
|
54
|
+
ancestors.pop()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (ancestors.includes(replacementValue)) {
|
|
58
|
+
return '[Circular]'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
ancestors.push(replacementValue)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return replacementValue
|
|
65
|
+
}) ?? 'null'
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
27
69
|
/**
|
|
28
70
|
* Recursively sorts all keys in an object and its nested objects/arrays.
|
|
29
71
|
* Used to ensure deterministic JSON serialization regardless of object construction order.
|