posthog-node 5.8.0 → 5.8.1
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/edge/index.cjs +142 -163
- package/dist/edge/index.cjs.map +1 -1
- package/dist/edge/index.mjs +143 -164
- package/dist/edge/index.mjs.map +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/node/index.cjs +142 -163
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.mjs +143 -164
- package/dist/node/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/edge/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PostHogCoreStateless, getFeatureFlagValue } from '@posthog/core';
|
|
1
|
+
import { PostHogCoreStateless, getFeatureFlagValue, safeSetTimeout as safeSetTimeout$1 } from '@posthog/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @file Adapted from [posthog-js](https://github.com/PostHog/posthog-js/blob/8157df935a4d0e71d2fefef7127aa85ee51c82d1/src/extensions/sentry-integration.ts) with modifications for the Node SDK.
|
|
@@ -313,7 +313,7 @@ function makeUncaughtExceptionHandler(captureFn, onFatalFn) {
|
|
|
313
313
|
});
|
|
314
314
|
if (!calledFatalError && processWouldExit) {
|
|
315
315
|
calledFatalError = true;
|
|
316
|
-
onFatalFn();
|
|
316
|
+
onFatalFn(error);
|
|
317
317
|
}
|
|
318
318
|
}, {
|
|
319
319
|
_posthogErrorHandler: true
|
|
@@ -324,7 +324,7 @@ function addUncaughtExceptionListener(captureFn, onFatalFn) {
|
|
|
324
324
|
}
|
|
325
325
|
function addUnhandledRejectionListener(captureFn) {
|
|
326
326
|
global.process.on('unhandledRejection', reason => {
|
|
327
|
-
captureFn(reason, {
|
|
327
|
+
return captureFn(reason, {
|
|
328
328
|
mechanism: {
|
|
329
329
|
type: 'onunhandledrejection',
|
|
330
330
|
handled: false
|
|
@@ -341,8 +341,7 @@ let cachedFilenameChunkIds;
|
|
|
341
341
|
function getFilenameToChunkIdMap(stackParser) {
|
|
342
342
|
const chunkIdMap = globalThis._posthogChunkIds;
|
|
343
343
|
if (!chunkIdMap) {
|
|
344
|
-
|
|
345
|
-
return {};
|
|
344
|
+
return null;
|
|
346
345
|
}
|
|
347
346
|
const chunkIdKeys = Object.keys(chunkIdMap);
|
|
348
347
|
if (cachedFilenameChunkIds && chunkIdKeys.length === lastKeysCount) {
|
|
@@ -613,7 +612,7 @@ function parseStackFrames(stackParser, error) {
|
|
|
613
612
|
function applyChunkIds(frames, parser) {
|
|
614
613
|
const filenameChunkIdMap = getFilenameToChunkIdMap(parser);
|
|
615
614
|
frames.forEach(frame => {
|
|
616
|
-
if (frame.filename) {
|
|
615
|
+
if (frame.filename && filenameChunkIdMap) {
|
|
617
616
|
frame.chunk_id = filenameChunkIdMap[frame.filename];
|
|
618
617
|
}
|
|
619
618
|
});
|
|
@@ -642,6 +641,12 @@ function clampToRange(value, min, max, logger, fallbackValue) {
|
|
|
642
641
|
}
|
|
643
642
|
|
|
644
643
|
class BucketedRateLimiter {
|
|
644
|
+
stop() {
|
|
645
|
+
if (this._removeInterval) {
|
|
646
|
+
clearInterval(this._removeInterval);
|
|
647
|
+
this._removeInterval = void 0;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
645
650
|
constructor(_options){
|
|
646
651
|
this._options = _options;
|
|
647
652
|
this._buckets = {};
|
|
@@ -673,7 +678,7 @@ class BucketedRateLimiter {
|
|
|
673
678
|
this._bucketSize = clampToRange(this._options.bucketSize, 0, 100, this._options._logger);
|
|
674
679
|
this._refillRate = clampToRange(this._options.refillRate, 0, this._bucketSize, this._options._logger);
|
|
675
680
|
this._refillInterval = clampToRange(this._options.refillInterval, 0, 86400000, this._options._logger);
|
|
676
|
-
setInterval(()=>{
|
|
681
|
+
this._removeInterval = setInterval(()=>{
|
|
677
682
|
this._refillBuckets();
|
|
678
683
|
}, this._refillInterval);
|
|
679
684
|
}
|
|
@@ -687,6 +692,22 @@ function safeSetTimeout(fn, timeout) {
|
|
|
687
692
|
|
|
688
693
|
const SHUTDOWN_TIMEOUT = 2000;
|
|
689
694
|
class ErrorTracking {
|
|
695
|
+
constructor(client, options, _logger) {
|
|
696
|
+
this.client = client;
|
|
697
|
+
this._exceptionAutocaptureEnabled = options.enableExceptionAutocapture || false;
|
|
698
|
+
this._logger = _logger;
|
|
699
|
+
// by default captures ten exceptions before rate limiting by exception type
|
|
700
|
+
// refills at a rate of one token / 10 second period
|
|
701
|
+
// e.g. will capture 1 exception rate limited exception every 10 seconds until burst ends
|
|
702
|
+
this._rateLimiter = new BucketedRateLimiter({
|
|
703
|
+
refillRate: 1,
|
|
704
|
+
bucketSize: 10,
|
|
705
|
+
refillInterval: 10000,
|
|
706
|
+
// ten seconds in milliseconds
|
|
707
|
+
_logger: this._logger
|
|
708
|
+
});
|
|
709
|
+
this.startAutocaptureIfEnabled();
|
|
710
|
+
}
|
|
690
711
|
static async buildEventMessage(error, hint, distinctId, additionalProperties) {
|
|
691
712
|
const properties = {
|
|
692
713
|
...additionalProperties
|
|
@@ -706,31 +727,16 @@ class ErrorTracking {
|
|
|
706
727
|
}
|
|
707
728
|
};
|
|
708
729
|
}
|
|
709
|
-
constructor(client, options, _logger) {
|
|
710
|
-
this.client = client;
|
|
711
|
-
this._exceptionAutocaptureEnabled = options.enableExceptionAutocapture || false;
|
|
712
|
-
this._logger = _logger;
|
|
713
|
-
// by default captures ten exceptions before rate limiting by exception type
|
|
714
|
-
// refills at a rate of one token / 10 second period
|
|
715
|
-
// e.g. will capture 1 exception rate limited exception every 10 seconds until burst ends
|
|
716
|
-
this._rateLimiter = new BucketedRateLimiter({
|
|
717
|
-
refillRate: 1,
|
|
718
|
-
bucketSize: 10,
|
|
719
|
-
refillInterval: 10000,
|
|
720
|
-
// ten seconds in milliseconds
|
|
721
|
-
_logger: this._logger
|
|
722
|
-
});
|
|
723
|
-
this.startAutocaptureIfEnabled();
|
|
724
|
-
}
|
|
725
730
|
startAutocaptureIfEnabled() {
|
|
726
731
|
if (this.isEnabled()) {
|
|
727
732
|
addUncaughtExceptionListener(this.onException.bind(this), this.onFatalError.bind(this));
|
|
728
733
|
addUnhandledRejectionListener(this.onException.bind(this));
|
|
729
734
|
}
|
|
730
735
|
}
|
|
731
|
-
onException(exception, hint) {
|
|
732
|
-
|
|
733
|
-
const
|
|
736
|
+
async onException(exception, hint) {
|
|
737
|
+
this.client.addPendingPromise((async () => {
|
|
738
|
+
const eventMessage = await ErrorTracking.buildEventMessage(exception, hint);
|
|
739
|
+
const exceptionProperties = eventMessage.properties;
|
|
734
740
|
const exceptionType = exceptionProperties?.$exception_list[0].type ?? 'Exception';
|
|
735
741
|
const isRateLimited = this._rateLimiter.consumeRateLimit(exceptionType);
|
|
736
742
|
if (isRateLimited) {
|
|
@@ -739,15 +745,20 @@ class ErrorTracking {
|
|
|
739
745
|
});
|
|
740
746
|
return;
|
|
741
747
|
}
|
|
742
|
-
this.client.capture(
|
|
743
|
-
});
|
|
748
|
+
return this.client.capture(eventMessage);
|
|
749
|
+
})());
|
|
744
750
|
}
|
|
745
|
-
async onFatalError() {
|
|
751
|
+
async onFatalError(exception) {
|
|
752
|
+
console.error(exception);
|
|
746
753
|
await this.client.shutdown(SHUTDOWN_TIMEOUT);
|
|
754
|
+
process.exit(1);
|
|
747
755
|
}
|
|
748
756
|
isEnabled() {
|
|
749
757
|
return !this.client.isDisabled && this._exceptionAutocaptureEnabled;
|
|
750
758
|
}
|
|
759
|
+
shutdown() {
|
|
760
|
+
this._rateLimiter.stop();
|
|
761
|
+
}
|
|
751
762
|
}
|
|
752
763
|
|
|
753
764
|
function setupExpressErrorHandler(_posthog, app) {
|
|
@@ -767,7 +778,7 @@ function setupExpressErrorHandler(_posthog, app) {
|
|
|
767
778
|
});
|
|
768
779
|
}
|
|
769
780
|
|
|
770
|
-
var version = "5.8.
|
|
781
|
+
var version = "5.8.1";
|
|
771
782
|
|
|
772
783
|
/**
|
|
773
784
|
* A lazy value that is only computed when needed. Inspired by C#'s Lazy<T> class.
|
|
@@ -1732,146 +1743,43 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
1732
1743
|
if (typeof props === 'string') {
|
|
1733
1744
|
this.logMsgIfDebug(() => console.warn('Called capture() with a string as the first argument when an object was expected.'));
|
|
1734
1745
|
}
|
|
1735
|
-
|
|
1736
|
-
distinctId,
|
|
1737
|
-
event,
|
|
1738
|
-
properties,
|
|
1739
|
-
groups,
|
|
1740
|
-
sendFeatureFlags,
|
|
1741
|
-
timestamp,
|
|
1742
|
-
disableGeoip,
|
|
1743
|
-
uuid
|
|
1744
|
-
} = props;
|
|
1745
|
-
// Run before_send if configured
|
|
1746
|
-
const eventMessage = this._runBeforeSend({
|
|
1746
|
+
this.addPendingPromise(this.prepareEventMessage(props).then(({
|
|
1747
1747
|
distinctId,
|
|
1748
1748
|
event,
|
|
1749
1749
|
properties,
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
if (!eventMessage) {
|
|
1757
|
-
return;
|
|
1758
|
-
}
|
|
1759
|
-
const _capture = props => {
|
|
1760
|
-
super.captureStateless(eventMessage.distinctId, eventMessage.event, props, {
|
|
1761
|
-
timestamp: eventMessage.timestamp,
|
|
1762
|
-
disableGeoip: eventMessage.disableGeoip,
|
|
1763
|
-
uuid: eventMessage.uuid
|
|
1750
|
+
options
|
|
1751
|
+
}) => {
|
|
1752
|
+
return super.captureStateless(distinctId, event, properties, {
|
|
1753
|
+
timestamp: options.timestamp,
|
|
1754
|
+
disableGeoip: options.disableGeoip,
|
|
1755
|
+
uuid: options.uuid
|
|
1764
1756
|
});
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
if (sendFeatureFlags) {
|
|
1769
|
-
// If we are sending feature flags, we evaluate them locally if the user prefers it, otherwise we fall back to remote evaluation
|
|
1770
|
-
const sendFeatureFlagsOptions = typeof sendFeatureFlags === 'object' ? sendFeatureFlags : undefined;
|
|
1771
|
-
return await this.getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
|
|
1772
|
-
}
|
|
1773
|
-
if (event === '$feature_flag_called') {
|
|
1774
|
-
// If we're capturing a $feature_flag_called event, we don't want to enrich the event with cached flags that may be out of date.
|
|
1775
|
-
return {};
|
|
1776
|
-
}
|
|
1777
|
-
return {};
|
|
1778
|
-
}).then(flags => {
|
|
1779
|
-
// Derive the relevant flag properties to add
|
|
1780
|
-
const additionalProperties = {};
|
|
1781
|
-
if (flags) {
|
|
1782
|
-
for (const [feature, variant] of Object.entries(flags)) {
|
|
1783
|
-
additionalProperties[`$feature/${feature}`] = variant;
|
|
1784
|
-
}
|
|
1757
|
+
}).catch(err => {
|
|
1758
|
+
if (err) {
|
|
1759
|
+
console.error(err);
|
|
1785
1760
|
}
|
|
1786
|
-
|
|
1787
|
-
if (activeFlags.length > 0) {
|
|
1788
|
-
additionalProperties['$active_feature_flags'] = activeFlags;
|
|
1789
|
-
}
|
|
1790
|
-
return additionalProperties;
|
|
1791
|
-
}).catch(() => {
|
|
1792
|
-
// Something went wrong getting the flag info - we should capture the event anyways
|
|
1793
|
-
return {};
|
|
1794
|
-
}).then(additionalProperties => {
|
|
1795
|
-
// No matter what - capture the event
|
|
1796
|
-
_capture({
|
|
1797
|
-
...additionalProperties,
|
|
1798
|
-
...(eventMessage.properties || {}),
|
|
1799
|
-
$groups: eventMessage.groups || groups
|
|
1800
|
-
});
|
|
1801
|
-
});
|
|
1802
|
-
this.addPendingPromise(capturePromise);
|
|
1761
|
+
}));
|
|
1803
1762
|
}
|
|
1804
1763
|
async captureImmediate(props) {
|
|
1805
1764
|
if (typeof props === 'string') {
|
|
1806
|
-
this.logMsgIfDebug(() => console.warn('Called
|
|
1765
|
+
this.logMsgIfDebug(() => console.warn('Called captureImmediate() with a string as the first argument when an object was expected.'));
|
|
1807
1766
|
}
|
|
1808
|
-
|
|
1767
|
+
return this.addPendingPromise(this.prepareEventMessage(props).then(({
|
|
1809
1768
|
distinctId,
|
|
1810
1769
|
event,
|
|
1811
1770
|
properties,
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
// Run before_send if configured
|
|
1819
|
-
const eventMessage = this._runBeforeSend({
|
|
1820
|
-
distinctId,
|
|
1821
|
-
event,
|
|
1822
|
-
properties,
|
|
1823
|
-
groups,
|
|
1824
|
-
sendFeatureFlags,
|
|
1825
|
-
timestamp,
|
|
1826
|
-
disableGeoip,
|
|
1827
|
-
uuid
|
|
1828
|
-
});
|
|
1829
|
-
if (!eventMessage) {
|
|
1830
|
-
return;
|
|
1831
|
-
}
|
|
1832
|
-
const _capture = props => {
|
|
1833
|
-
return super.captureStatelessImmediate(eventMessage.distinctId, eventMessage.event, props, {
|
|
1834
|
-
timestamp: eventMessage.timestamp,
|
|
1835
|
-
disableGeoip: eventMessage.disableGeoip,
|
|
1836
|
-
uuid: eventMessage.uuid
|
|
1771
|
+
options
|
|
1772
|
+
}) => {
|
|
1773
|
+
return super.captureStatelessImmediate(distinctId, event, properties, {
|
|
1774
|
+
timestamp: options.timestamp,
|
|
1775
|
+
disableGeoip: options.disableGeoip,
|
|
1776
|
+
uuid: options.uuid
|
|
1837
1777
|
});
|
|
1838
|
-
}
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
// If we are sending feature flags, we evaluate them locally if the user prefers it, otherwise we fall back to remote evaluation
|
|
1842
|
-
const sendFeatureFlagsOptions = typeof sendFeatureFlags === 'object' ? sendFeatureFlags : undefined;
|
|
1843
|
-
return await this.getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
|
|
1844
|
-
}
|
|
1845
|
-
if (event === '$feature_flag_called') {
|
|
1846
|
-
// If we're capturing a $feature_flag_called event, we don't want to enrich the event with cached flags that may be out of date.
|
|
1847
|
-
return {};
|
|
1848
|
-
}
|
|
1849
|
-
return {};
|
|
1850
|
-
}).then(flags => {
|
|
1851
|
-
// Derive the relevant flag properties to add
|
|
1852
|
-
const additionalProperties = {};
|
|
1853
|
-
if (flags) {
|
|
1854
|
-
for (const [feature, variant] of Object.entries(flags)) {
|
|
1855
|
-
additionalProperties[`$feature/${feature}`] = variant;
|
|
1856
|
-
}
|
|
1778
|
+
}).catch(err => {
|
|
1779
|
+
if (err) {
|
|
1780
|
+
console.error(err);
|
|
1857
1781
|
}
|
|
1858
|
-
|
|
1859
|
-
if (activeFlags.length > 0) {
|
|
1860
|
-
additionalProperties['$active_feature_flags'] = activeFlags;
|
|
1861
|
-
}
|
|
1862
|
-
return additionalProperties;
|
|
1863
|
-
}).catch(() => {
|
|
1864
|
-
// Something went wrong getting the flag info - we should capture the event anyways
|
|
1865
|
-
return {};
|
|
1866
|
-
}).then(additionalProperties => {
|
|
1867
|
-
// No matter what - capture the event
|
|
1868
|
-
_capture({
|
|
1869
|
-
...additionalProperties,
|
|
1870
|
-
...(eventMessage.properties || {}),
|
|
1871
|
-
$groups: eventMessage.groups || groups
|
|
1872
|
-
});
|
|
1873
|
-
});
|
|
1874
|
-
await capturePromise;
|
|
1782
|
+
}));
|
|
1875
1783
|
}
|
|
1876
1784
|
identify({
|
|
1877
1785
|
distinctId,
|
|
@@ -2141,6 +2049,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2141
2049
|
}
|
|
2142
2050
|
async _shutdown(shutdownTimeoutMs) {
|
|
2143
2051
|
this.featureFlagsPoller?.stopPoller();
|
|
2052
|
+
this.errorTracking.shutdown();
|
|
2144
2053
|
return super._shutdown(shutdownTimeoutMs);
|
|
2145
2054
|
}
|
|
2146
2055
|
async _requestRemoteConfigPayload(flagKey) {
|
|
@@ -2159,7 +2068,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2159
2068
|
let abortTimeout = null;
|
|
2160
2069
|
if (this.options.requestTimeout && typeof this.options.requestTimeout === 'number') {
|
|
2161
2070
|
const controller = new AbortController();
|
|
2162
|
-
abortTimeout = safeSetTimeout(() => {
|
|
2071
|
+
abortTimeout = safeSetTimeout$1(() => {
|
|
2163
2072
|
controller.abort();
|
|
2164
2073
|
}, this.options.requestTimeout);
|
|
2165
2074
|
options.signal = controller.signal;
|
|
@@ -2268,18 +2177,88 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2268
2177
|
}
|
|
2269
2178
|
captureException(error, distinctId, additionalProperties) {
|
|
2270
2179
|
const syntheticException = new Error('PostHog syntheticException');
|
|
2271
|
-
ErrorTracking.buildEventMessage(error, {
|
|
2180
|
+
this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
|
|
2272
2181
|
syntheticException
|
|
2273
|
-
}, distinctId, additionalProperties).then(msg =>
|
|
2274
|
-
this.capture(msg);
|
|
2275
|
-
});
|
|
2182
|
+
}, distinctId, additionalProperties).then(msg => this.capture(msg)));
|
|
2276
2183
|
}
|
|
2277
2184
|
async captureExceptionImmediate(error, distinctId, additionalProperties) {
|
|
2278
2185
|
const syntheticException = new Error('PostHog syntheticException');
|
|
2279
|
-
|
|
2186
|
+
this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
|
|
2280
2187
|
syntheticException
|
|
2281
|
-
}, distinctId, additionalProperties);
|
|
2282
|
-
|
|
2188
|
+
}, distinctId, additionalProperties).then(msg => this.captureImmediate(msg)));
|
|
2189
|
+
}
|
|
2190
|
+
async prepareEventMessage(props) {
|
|
2191
|
+
const {
|
|
2192
|
+
distinctId,
|
|
2193
|
+
event,
|
|
2194
|
+
properties,
|
|
2195
|
+
groups,
|
|
2196
|
+
sendFeatureFlags,
|
|
2197
|
+
timestamp,
|
|
2198
|
+
disableGeoip,
|
|
2199
|
+
uuid
|
|
2200
|
+
} = props;
|
|
2201
|
+
// Run before_send if configured
|
|
2202
|
+
const eventMessage = this._runBeforeSend({
|
|
2203
|
+
distinctId,
|
|
2204
|
+
event,
|
|
2205
|
+
properties,
|
|
2206
|
+
groups,
|
|
2207
|
+
sendFeatureFlags,
|
|
2208
|
+
timestamp,
|
|
2209
|
+
disableGeoip,
|
|
2210
|
+
uuid
|
|
2211
|
+
});
|
|
2212
|
+
if (!eventMessage) {
|
|
2213
|
+
return Promise.reject(null);
|
|
2214
|
+
}
|
|
2215
|
+
// :TRICKY: If we flush, or need to shut down, to not lose events we want this promise to resolve before we flush
|
|
2216
|
+
const eventProperties = await Promise.resolve().then(async () => {
|
|
2217
|
+
if (sendFeatureFlags) {
|
|
2218
|
+
// If we are sending feature flags, we evaluate them locally if the user prefers it, otherwise we fall back to remote evaluation
|
|
2219
|
+
const sendFeatureFlagsOptions = typeof sendFeatureFlags === 'object' ? sendFeatureFlags : undefined;
|
|
2220
|
+
return await this.getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
|
|
2221
|
+
}
|
|
2222
|
+
if (event === '$feature_flag_called') {
|
|
2223
|
+
// If we're capturing a $feature_flag_called event, we don't want to enrich the event with cached flags that may be out of date.
|
|
2224
|
+
return {};
|
|
2225
|
+
}
|
|
2226
|
+
return {};
|
|
2227
|
+
}).then(flags => {
|
|
2228
|
+
// Derive the relevant flag properties to add
|
|
2229
|
+
const additionalProperties = {};
|
|
2230
|
+
if (flags) {
|
|
2231
|
+
for (const [feature, variant] of Object.entries(flags)) {
|
|
2232
|
+
additionalProperties[`$feature/${feature}`] = variant;
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
const activeFlags = Object.keys(flags || {}).filter(flag => flags?.[flag] !== false).sort();
|
|
2236
|
+
if (activeFlags.length > 0) {
|
|
2237
|
+
additionalProperties['$active_feature_flags'] = activeFlags;
|
|
2238
|
+
}
|
|
2239
|
+
return additionalProperties;
|
|
2240
|
+
}).catch(() => {
|
|
2241
|
+
// Something went wrong getting the flag info - we should capture the event anyways
|
|
2242
|
+
return {};
|
|
2243
|
+
}).then(additionalProperties => {
|
|
2244
|
+
// No matter what - capture the event
|
|
2245
|
+
const props = {
|
|
2246
|
+
...additionalProperties,
|
|
2247
|
+
...(eventMessage.properties || {}),
|
|
2248
|
+
$groups: eventMessage.groups || groups
|
|
2249
|
+
};
|
|
2250
|
+
return props;
|
|
2251
|
+
});
|
|
2252
|
+
return {
|
|
2253
|
+
distinctId: eventMessage.distinctId,
|
|
2254
|
+
event: eventMessage.event,
|
|
2255
|
+
properties: eventProperties,
|
|
2256
|
+
options: {
|
|
2257
|
+
timestamp: eventMessage.timestamp,
|
|
2258
|
+
disableGeoip: eventMessage.disableGeoip,
|
|
2259
|
+
uuid: eventMessage.uuid
|
|
2260
|
+
}
|
|
2261
|
+
};
|
|
2283
2262
|
}
|
|
2284
2263
|
_runBeforeSend(eventMessage) {
|
|
2285
2264
|
const beforeSend = this.options.before_send;
|