@statsig/client-core 0.0.1-beta.1 → 0.0.1-beta.10

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/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Statsig - Core
2
2
 
3
+ > [!IMPORTANT]
4
+ > This version of the SDK is still in beta. The non-beta version can be found [here](https://github.com/statsig-io/js-client).
5
+
3
6
  The package that contains all the common logic shared by the various Statsig Javascript packages.
4
7
 
5
- Learn more by visiting: https://docs.statsig.com/client/jsClientSDK
8
+ Learn more by visiting: https://docs.statsig.com/client/javascript-sdk
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statsig/client-core",
3
- "version": "0.0.1-beta.1",
3
+ "version": "0.0.1-beta.10",
4
4
  "dependencies": {},
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -1,11 +1,14 @@
1
1
  import { EvaluationOptions } from './StatsigClientBase';
2
2
  import { StatsigClientEventEmitterInterface } from './StatsigClientEventEmitter';
3
+ import { StatsigDataAdapter } from './StatsigDataAdapter';
3
4
  import { StatsigEvent } from './StatsigEvent';
4
5
  import { DynamicConfig, Experiment, FeatureGate, Layer } from './StatsigTypes';
5
6
  import { StatsigUser } from './StatsigUser';
6
7
  export interface StatsigClientCommonInterface extends StatsigClientEventEmitterInterface {
7
- initialize(): Promise<void>;
8
+ initializeSync(): void;
9
+ initializeAsync(): Promise<void>;
8
10
  shutdown(): Promise<void>;
11
+ getDataAdapter(): StatsigDataAdapter;
9
12
  }
10
13
  export interface OnDeviceEvaluationsInterface extends StatsigClientCommonInterface {
11
14
  checkGate(name: string, user: StatsigUser, options: EvaluationOptions): boolean;
@@ -17,7 +20,8 @@ export interface OnDeviceEvaluationsInterface extends StatsigClientCommonInterfa
17
20
  }
18
21
  export interface PrecomputedEvaluationsInterface extends StatsigClientCommonInterface {
19
22
  getCurrentUser(): StatsigUser;
20
- updateUser(user: StatsigUser): Promise<void>;
23
+ updateUserSync(user: StatsigUser): void;
24
+ updateUserAsync(user: StatsigUser): Promise<void>;
21
25
  checkGate(name: string, options: EvaluationOptions): boolean;
22
26
  getFeatureGate(name: string, options: EvaluationOptions): FeatureGate;
23
27
  getDynamicConfig(name: string, options: EvaluationOptions): DynamicConfig;
@@ -0,0 +1,33 @@
1
+ import { ErrorBoundary } from './ErrorBoundary';
2
+ import { StatsigDataAdapter, StatsigDataAdapterResult } from './StatsigDataAdapter';
3
+ import { StatsigOptionsCommon } from './StatsigOptionsCommon';
4
+ import { StatsigUser } from './StatsigUser';
5
+ type UpdatesAwareObject = {
6
+ has_updates?: boolean;
7
+ };
8
+ export declare abstract class DataAdapterCore<T extends UpdatesAwareObject> implements StatsigDataAdapter {
9
+ private _className;
10
+ private _cacheSuffix;
11
+ protected _errorBoundary: ErrorBoundary | null;
12
+ private _sdkKey;
13
+ private _inMemoryCache;
14
+ private _lastModifiedStoreKey;
15
+ protected constructor(_className: string, _cacheSuffix: string);
16
+ attach(sdkKey: string, _options: StatsigOptionsCommon | null): void;
17
+ getDataSync(user?: StatsigUser | undefined): StatsigDataAdapterResult | null;
18
+ getDataAsync(current: StatsigDataAdapterResult | null, user?: StatsigUser): Promise<StatsigDataAdapterResult | null>;
19
+ /**
20
+ * (Internal Use Only) - Used by @statsig/react-native-bindings to prime the cache from AsyncStorage
21
+ * @param {Record<string, StatsigDataAdapterResult>} cache The values to set for _inMemoryCache
22
+ */
23
+ _setInMemoryCache(cache: Record<string, StatsigDataAdapterResult>): void;
24
+ protected abstract _fetchFromNetwork(current: string | null, user?: StatsigUser): Promise<string | null>;
25
+ private _fetchLatest;
26
+ protected _getSdkKey(): string;
27
+ protected _getCacheKey(user?: StatsigUser): string;
28
+ protected _addToInMemoryCache(cacheKey: string, result: StatsigDataAdapterResult): void;
29
+ private _loadFromCache;
30
+ private _writeToCache;
31
+ private _runLocalStorageCacheEviction;
32
+ }
33
+ export {};
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.DataAdapterCore = void 0;
51
+ var ErrorBoundary_1 = require("./ErrorBoundary");
52
+ var Log_1 = require("./Log");
53
+ var Monitoring_1 = require("./Monitoring");
54
+ var StatsigDataAdapter_1 = require("./StatsigDataAdapter");
55
+ var StatsigUser_1 = require("./StatsigUser");
56
+ var StorageProvider_1 = require("./StorageProvider");
57
+ var CACHE_LIMIT = 10;
58
+ var DataAdapterCore = /** @class */ (function () {
59
+ function DataAdapterCore(_className, _cacheSuffix) {
60
+ this._className = _className;
61
+ this._cacheSuffix = _cacheSuffix;
62
+ this._errorBoundary = null;
63
+ this._sdkKey = null;
64
+ this._inMemoryCache = {};
65
+ this._lastModifiedStoreKey = "statsig.last_modified_time.".concat(_cacheSuffix);
66
+ }
67
+ DataAdapterCore.prototype.attach = function (sdkKey, _options) {
68
+ this._sdkKey = sdkKey;
69
+ this._errorBoundary = new ErrorBoundary_1.ErrorBoundary(sdkKey);
70
+ (0, Monitoring_1.monitorClass)(this._errorBoundary, this);
71
+ };
72
+ DataAdapterCore.prototype.getDataSync = function (user) {
73
+ var cacheKey = this._getCacheKey(user);
74
+ var result = this._inMemoryCache[cacheKey];
75
+ if (result) {
76
+ return result;
77
+ }
78
+ var cache = this._loadFromCache(cacheKey);
79
+ if (cache) {
80
+ this._addToInMemoryCache(cacheKey, cache);
81
+ return this._inMemoryCache[cacheKey];
82
+ }
83
+ return null;
84
+ };
85
+ DataAdapterCore.prototype.getDataAsync = function (current, user) {
86
+ var _a;
87
+ return __awaiter(this, void 0, void 0, function () {
88
+ var cache, latest, cacheKey;
89
+ return __generator(this, function (_b) {
90
+ switch (_b.label) {
91
+ case 0:
92
+ cache = current !== null && current !== void 0 ? current : this.getDataSync(user);
93
+ return [4 /*yield*/, this._fetchLatest((_a = cache === null || cache === void 0 ? void 0 : cache.data) !== null && _a !== void 0 ? _a : null, user)];
94
+ case 1:
95
+ latest = _b.sent();
96
+ cacheKey = this._getCacheKey(user);
97
+ if (latest) {
98
+ this._addToInMemoryCache(cacheKey, latest);
99
+ }
100
+ if (!((latest === null || latest === void 0 ? void 0 : latest.source) === 'Network' ||
101
+ (latest === null || latest === void 0 ? void 0 : latest.source) === 'NetworkNotModified')) return [3 /*break*/, 3];
102
+ return [4 /*yield*/, this._writeToCache(cacheKey, latest)];
103
+ case 2:
104
+ _b.sent();
105
+ _b.label = 3;
106
+ case 3: return [2 /*return*/, latest];
107
+ }
108
+ });
109
+ });
110
+ };
111
+ /**
112
+ * (Internal Use Only) - Used by @statsig/react-native-bindings to prime the cache from AsyncStorage
113
+ * @param {Record<string, StatsigDataAdapterResult>} cache The values to set for _inMemoryCache
114
+ */
115
+ DataAdapterCore.prototype._setInMemoryCache = function (cache) {
116
+ this._inMemoryCache = cache;
117
+ };
118
+ DataAdapterCore.prototype._fetchLatest = function (current, user) {
119
+ return __awaiter(this, void 0, void 0, function () {
120
+ var latest, response;
121
+ return __generator(this, function (_a) {
122
+ switch (_a.label) {
123
+ case 0: return [4 /*yield*/, this._fetchFromNetwork(current, user)];
124
+ case 1:
125
+ latest = _a.sent();
126
+ if (!latest) {
127
+ Log_1.Log.debug('No response returned for latest value');
128
+ return [2 /*return*/, null];
129
+ }
130
+ try {
131
+ response = JSON.parse(latest);
132
+ if (current && response.has_updates === false) {
133
+ return [2 /*return*/, {
134
+ source: 'NetworkNotModified',
135
+ data: current,
136
+ receivedAt: Date.now(),
137
+ }];
138
+ }
139
+ if (response.has_updates !== true) {
140
+ return [2 /*return*/, null];
141
+ }
142
+ return [2 /*return*/, { source: 'Network', data: latest, receivedAt: Date.now() }];
143
+ }
144
+ catch (_b) {
145
+ Log_1.Log.debug('Failure while attempting to persist latest value');
146
+ }
147
+ return [2 /*return*/, null];
148
+ }
149
+ });
150
+ });
151
+ };
152
+ DataAdapterCore.prototype._getSdkKey = function () {
153
+ if (this._sdkKey) {
154
+ return this._sdkKey;
155
+ }
156
+ Log_1.Log.error("".concat(this._className, " is not attached to a Client"));
157
+ return '';
158
+ };
159
+ DataAdapterCore.prototype._getCacheKey = function (user) {
160
+ var key = (0, StatsigUser_1.getUserStorageKey)(this._getSdkKey(), user);
161
+ return "".concat(StatsigDataAdapter_1.DataAdapterCachePrefix, ".").concat(this._cacheSuffix, ".").concat(key);
162
+ };
163
+ DataAdapterCore.prototype._addToInMemoryCache = function (cacheKey, result) {
164
+ var entries = Object.entries(this._inMemoryCache);
165
+ if (entries.length < CACHE_LIMIT) {
166
+ this._inMemoryCache[cacheKey] = result;
167
+ return;
168
+ }
169
+ var oldest = entries.reduce(function (acc, curr) {
170
+ return curr[1] < acc[1] ? curr : acc;
171
+ })[0];
172
+ delete this._inMemoryCache[oldest];
173
+ this._inMemoryCache[cacheKey] = result;
174
+ };
175
+ DataAdapterCore.prototype._loadFromCache = function (cacheKey) {
176
+ if (typeof window === 'undefined' || !window.localStorage) {
177
+ return null;
178
+ }
179
+ var cache = window.localStorage.getItem(cacheKey);
180
+ if (cache == null) {
181
+ return null;
182
+ }
183
+ try {
184
+ var result = JSON.parse(cache);
185
+ return __assign(__assign({}, result), { source: 'Cache' });
186
+ }
187
+ catch (e) {
188
+ Log_1.Log.error('Failed to parse cached result');
189
+ return null;
190
+ }
191
+ };
192
+ DataAdapterCore.prototype._writeToCache = function (cacheKey, result) {
193
+ return __awaiter(this, void 0, void 0, function () {
194
+ return __generator(this, function (_a) {
195
+ switch (_a.label) {
196
+ case 0: return [4 /*yield*/, StorageProvider_1.Storage.setItem(cacheKey, JSON.stringify(result))];
197
+ case 1:
198
+ _a.sent();
199
+ return [4 /*yield*/, this._runLocalStorageCacheEviction(cacheKey)];
200
+ case 2:
201
+ _a.sent();
202
+ return [2 /*return*/];
203
+ }
204
+ });
205
+ });
206
+ };
207
+ DataAdapterCore.prototype._runLocalStorageCacheEviction = function (cacheKey) {
208
+ var _a;
209
+ return __awaiter(this, void 0, void 0, function () {
210
+ var lastModifiedTimeMap, entries, oldest;
211
+ return __generator(this, function (_b) {
212
+ switch (_b.label) {
213
+ case 0: return [4 /*yield*/, (0, StorageProvider_1.getObjectFromStorage)(this._lastModifiedStoreKey)];
214
+ case 1:
215
+ lastModifiedTimeMap = (_a = (_b.sent())) !== null && _a !== void 0 ? _a : {};
216
+ lastModifiedTimeMap[cacheKey] = Date.now();
217
+ entries = Object.entries(lastModifiedTimeMap);
218
+ if (!(entries.length <= CACHE_LIMIT)) return [3 /*break*/, 3];
219
+ return [4 /*yield*/, (0, StorageProvider_1.setObjectInStorage)(this._lastModifiedStoreKey, lastModifiedTimeMap)];
220
+ case 2:
221
+ _b.sent();
222
+ return [2 /*return*/];
223
+ case 3:
224
+ oldest = entries.reduce(function (acc, current) {
225
+ return current[1] < acc[1] ? current : acc;
226
+ });
227
+ delete lastModifiedTimeMap[oldest[0]];
228
+ return [4 /*yield*/, StorageProvider_1.Storage.removeItem(oldest[0])];
229
+ case 4:
230
+ _b.sent();
231
+ return [4 /*yield*/, (0, StorageProvider_1.setObjectInStorage)(this._lastModifiedStoreKey, lastModifiedTimeMap)];
232
+ case 5:
233
+ _b.sent();
234
+ return [2 /*return*/];
235
+ }
236
+ });
237
+ });
238
+ };
239
+ return DataAdapterCore;
240
+ }());
241
+ exports.DataAdapterCore = DataAdapterCore;
@@ -5,5 +5,6 @@ export declare class ErrorBoundary {
5
5
  private _seen;
6
6
  constructor(_sdkKey: string);
7
7
  capture(tag: string, task: () => unknown, emitter?: StatsigClientEmitEventFunc): unknown;
8
+ logError(tag: string, error: unknown): void;
8
9
  private _onError;
9
10
  }
@@ -70,6 +70,9 @@ var ErrorBoundary = /** @class */ (function () {
70
70
  return null;
71
71
  }
72
72
  };
73
+ ErrorBoundary.prototype.logError = function (tag, error) {
74
+ this._onError(tag, error);
75
+ };
73
76
  ErrorBoundary.prototype._onError = function (tag, error, emitter) {
74
77
  var _this = this;
75
78
  try {
@@ -13,18 +13,24 @@ export declare class EventLogger {
13
13
  private _lastExposureMap;
14
14
  private _maxQueueSize;
15
15
  private _failedLogs;
16
+ private _hasRunQuickFlush;
17
+ private _creationTime;
16
18
  constructor(_sdkKey: string, _emitter: StatsigClientEmitEventFunc, _network: NetworkCore, _options: StatsigOptionsCommon | null);
17
19
  enqueue(event: StatsigEventInternal): void;
18
20
  reset(): void;
19
21
  onVisibilityChanged(visibility: Visibility): void;
20
22
  shutdown(): Promise<void>;
23
+ /**
24
+ * We 'Quick Flush' following the very first event enqueued
25
+ * within the quick flush window
26
+ */
27
+ private _quickFlushIfNeeded;
21
28
  private _shouldLogEvent;
22
29
  private _flushAndForget;
23
30
  private _flush;
24
31
  private _sendEvents;
25
32
  private _sendEventsViaPost;
26
33
  private _sendEventsViaBeacon;
27
- private _isBeaconSupported;
28
34
  private _saveFailedLogsToStorage;
29
35
  private _retryFailedLogs;
30
36
  private _getStorageKey;
@@ -60,6 +60,7 @@ var MAX_DEDUPER_KEYS = 1000;
60
60
  var DEDUPER_WINDOW_DURATION_MS = 60000;
61
61
  var MAX_FAILED_LOGS = 500;
62
62
  var DEFAULT_API = 'https://api.statsig.com/v1';
63
+ var QUICK_FLUSH_WINDOW_MS = 200;
63
64
  var EventLogger = /** @class */ (function () {
64
65
  function EventLogger(_sdkKey, _emitter, _network, _options) {
65
66
  var _this = this;
@@ -70,6 +71,8 @@ var EventLogger = /** @class */ (function () {
70
71
  this._options = _options;
71
72
  this._queue = [];
72
73
  this._lastExposureMap = {};
74
+ this._hasRunQuickFlush = false;
75
+ this._creationTime = Date.now();
73
76
  this._maxQueueSize = (_a = _options === null || _options === void 0 ? void 0 : _options.loggingBufferMaxSize) !== null && _a !== void 0 ? _a : DEFAULT_QUEUE_SIZE;
74
77
  var flushInterval = (_b = _options === null || _options === void 0 ? void 0 : _options.loggingIntervalMs) !== null && _b !== void 0 ? _b : DEFAULT_FLUSH_INTERVAL_MS;
75
78
  this._flushTimer = setInterval(function () { return _this._flushAndForget(); }, flushInterval);
@@ -87,6 +90,7 @@ var EventLogger = /** @class */ (function () {
87
90
  }
88
91
  var _a = StatsigMetadata_1.StatsigMetadataProvider.get(), sdkType = _a.sdkType, sdkVersion = _a.sdkVersion;
89
92
  this._queue.push(__assign(__assign({}, event), { statsigMetadata: { sdkType: sdkType, sdkVersion: sdkVersion } }));
93
+ this._quickFlushIfNeeded();
90
94
  if (this._queue.length > this._maxQueueSize) {
91
95
  this._flushAndForget();
92
96
  }
@@ -116,6 +120,21 @@ var EventLogger = /** @class */ (function () {
116
120
  });
117
121
  });
118
122
  };
123
+ /**
124
+ * We 'Quick Flush' following the very first event enqueued
125
+ * within the quick flush window
126
+ */
127
+ EventLogger.prototype._quickFlushIfNeeded = function () {
128
+ var _this = this;
129
+ if (this._hasRunQuickFlush) {
130
+ return;
131
+ }
132
+ this._hasRunQuickFlush = true;
133
+ if (Date.now() - this._creationTime > QUICK_FLUSH_WINDOW_MS) {
134
+ return;
135
+ }
136
+ setTimeout(function () { return _this._flushAndForget(); }, QUICK_FLUSH_WINDOW_MS);
137
+ };
119
138
  EventLogger.prototype._shouldLogEvent = function (event) {
120
139
  var _a, _b, _c, _d;
121
140
  if (!(0, StatsigEvent_1.isExposureEvent)(event)) {
@@ -170,17 +189,19 @@ var EventLogger = /** @class */ (function () {
170
189
  return __generator(this, function (_e) {
171
190
  switch (_e.label) {
172
191
  case 0:
173
- _e.trys.push([0, 4, , 5]);
192
+ _e.trys.push([0, 5, , 6]);
174
193
  isInForeground = VisibilityChangeObserver_1.VisibilityChangeObserver.isCurrentlyVisible();
175
194
  api = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.api) !== null && _b !== void 0 ? _b : DEFAULT_API;
176
- if (!(!isInForeground && this._isBeaconSupported())) return [3 /*break*/, 1];
177
- _c = this._sendEventsViaBeacon(api, events);
178
- return [3 /*break*/, 3];
179
- case 1: return [4 /*yield*/, this._sendEventsViaPost(api, events)];
180
- case 2:
195
+ if (!(!isInForeground && this._network.isBeaconSupported())) return [3 /*break*/, 2];
196
+ return [4 /*yield*/, this._sendEventsViaBeacon(api, events)];
197
+ case 1:
181
198
  _c = _e.sent();
182
- _e.label = 3;
199
+ return [3 /*break*/, 4];
200
+ case 2: return [4 /*yield*/, this._sendEventsViaPost(api, events)];
183
201
  case 3:
202
+ _c = _e.sent();
203
+ _e.label = 4;
204
+ case 4:
184
205
  response = _c;
185
206
  if (response.success) {
186
207
  this._emitter({
@@ -191,12 +212,12 @@ var EventLogger = /** @class */ (function () {
191
212
  else {
192
213
  this._saveFailedLogsToStorage(events);
193
214
  }
194
- return [3 /*break*/, 5];
195
- case 4:
215
+ return [3 /*break*/, 6];
216
+ case 5:
196
217
  _d = _e.sent();
197
218
  Log_1.Log.warn('Failed to flush events.');
198
- return [3 /*break*/, 5];
199
- case 5: return [2 /*return*/];
219
+ return [3 /*break*/, 6];
220
+ case 6: return [2 /*return*/];
200
221
  }
201
222
  });
202
223
  });
@@ -213,15 +234,15 @@ var EventLogger = /** @class */ (function () {
213
234
  },
214
235
  url: "".concat(api, "/rgstr"),
215
236
  retries: 3,
216
- headers: {
217
- 'Content-Type': 'application/json',
218
- 'STATSIG-EVENT-COUNT': String(events.length),
237
+ params: {
238
+ // ec = Event Count
239
+ ec: String(events.length),
219
240
  },
220
241
  })];
221
242
  case 1:
222
243
  result = _a.sent();
223
- if (result) {
224
- return [2 /*return*/, JSON.parse(result)];
244
+ if (result === null || result === void 0 ? void 0 : result.body) {
245
+ return [2 /*return*/, JSON.parse(result.body)];
225
246
  }
226
247
  return [2 /*return*/, { success: false }];
227
248
  }
@@ -229,19 +250,24 @@ var EventLogger = /** @class */ (function () {
229
250
  });
230
251
  };
231
252
  EventLogger.prototype._sendEventsViaBeacon = function (api, events) {
232
- return {
233
- success: this._network.beacon({
234
- sdkKey: this._sdkKey,
235
- data: {
236
- events: events,
237
- },
238
- url: "".concat(api, "/log_event_beacon"),
239
- }),
240
- };
241
- };
242
- EventLogger.prototype._isBeaconSupported = function () {
243
- return (typeof navigator !== 'undefined' &&
244
- typeof (navigator === null || navigator === void 0 ? void 0 : navigator.sendBeacon) === 'function');
253
+ return __awaiter(this, void 0, void 0, function () {
254
+ var _a;
255
+ return __generator(this, function (_b) {
256
+ switch (_b.label) {
257
+ case 0:
258
+ _a = {};
259
+ return [4 /*yield*/, this._network.beacon({
260
+ sdkKey: this._sdkKey,
261
+ data: {
262
+ events: events,
263
+ },
264
+ url: "".concat(api, "/log_event_beacon"),
265
+ })];
266
+ case 1: return [2 /*return*/, (_a.success = _b.sent(),
267
+ _a)];
268
+ }
269
+ });
270
+ });
245
271
  };
246
272
  EventLogger.prototype._saveFailedLogsToStorage = function (events) {
247
273
  var _a;
@@ -1,3 +1,2 @@
1
1
  import { ErrorBoundary } from './ErrorBoundary';
2
- export declare function monitorClass<T extends new (...args: any[]) => any>(errorBoundary: ErrorBoundary, target: T, instance: unknown): void;
3
- export declare function monitorFunction<T>(errorBoundary: ErrorBoundary, tag: string, func: () => T, instance: unknown): T;
2
+ export declare function monitorClass(errorBoundary: ErrorBoundary, instance: object): void;
package/src/Monitoring.js CHANGED
@@ -1,13 +1,57 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.monitorFunction = exports.monitorClass = void 0;
3
+ exports.monitorClass = void 0;
4
4
  var Diagnostics_1 = require("./Diagnostics");
5
5
  var StatsigClientBase_1 = require("./StatsigClientBase");
6
- function monitorClass(errorBoundary, target, instance) {
7
- var methods = Object.getOwnPropertyNames(target.prototype);
6
+ function monitorClass(errorBoundary, instance) {
7
+ try {
8
+ _monitorClassImpl(errorBoundary, instance);
9
+ }
10
+ catch (error) {
11
+ errorBoundary.logError('monitorClass', error);
12
+ }
13
+ }
14
+ exports.monitorClass = monitorClass;
15
+ function _monitorFunction(errorBoundary, tag, func, instance) {
16
+ var client = instance instanceof StatsigClientBase_1.StatsigClientBase ? instance['emit'] : undefined;
17
+ return errorBoundary.capture(tag, function () { return (0, Diagnostics_1.captureDiagnostics)(tag, function () { return func.apply(instance); }); }, client);
18
+ }
19
+ function _getProtoSafe(instance) {
20
+ if (typeof instance === 'object') {
21
+ var proto = Object.getPrototypeOf(instance);
22
+ return proto && typeof proto === 'object'
23
+ ? proto
24
+ : null;
25
+ }
26
+ return null;
27
+ }
28
+ function _getAllInstanceMethodNames(instance) {
29
+ var names = new Set();
30
+ var proto = _getProtoSafe(instance);
31
+ while (proto && proto !== Object.prototype) {
32
+ Object.getOwnPropertyNames(proto)
33
+ .filter(function (prop) { return typeof (proto === null || proto === void 0 ? void 0 : proto[prop]) === 'function'; })
34
+ .forEach(function (name) { return names.add(name); });
35
+ proto = Object.getPrototypeOf(proto);
36
+ }
37
+ return Array.from(names);
38
+ }
39
+ function _getAllStaticMethodNames(instance) {
40
+ var names = new Set();
41
+ var proto = _getProtoSafe(instance);
42
+ Object.getOwnPropertyNames((proto === null || proto === void 0 ? void 0 : proto.constructor) || {})
43
+ .filter(function (prop) {
44
+ var _a;
45
+ return typeof ((_a = proto === null || proto === void 0 ? void 0 : proto.constructor) === null || _a === void 0 ? void 0 : _a[prop]) === 'function';
46
+ })
47
+ .forEach(function (name) { return names.add(name); });
48
+ return Array.from(names);
49
+ }
50
+ function _monitorClassImpl(errorBoundary, instance) {
51
+ var _a;
8
52
  var obj = instance;
9
53
  var _loop_1 = function (method) {
10
- if (method === 'constructor' || typeof obj[method] !== 'function') {
54
+ if (method === 'constructor') {
11
55
  return "continue";
12
56
  }
13
57
  var original = obj[method];
@@ -17,17 +61,26 @@ function monitorClass(errorBoundary, target, instance) {
17
61
  for (var _i = 0; _i < arguments.length; _i++) {
18
62
  args[_i] = arguments[_i];
19
63
  }
20
- return monitorFunction(errorBoundary, method, function () { return original.apply(_this, args); }, instance);
64
+ return _monitorFunction(errorBoundary, method, function () { return original.apply(_this, args); }, instance);
21
65
  };
22
66
  };
23
- for (var _i = 0, methods_1 = methods; _i < methods_1.length; _i++) {
24
- var method = methods_1[_i];
67
+ for (var _i = 0, _b = _getAllInstanceMethodNames(obj); _i < _b.length; _i++) {
68
+ var method = _b[_i];
25
69
  _loop_1(method);
26
70
  }
71
+ var _loop_2 = function (method) {
72
+ var original = (_a = obj === null || obj === void 0 ? void 0 : obj.constructor) === null || _a === void 0 ? void 0 : _a[method];
73
+ (obj === null || obj === void 0 ? void 0 : obj.constructor)[method] =
74
+ function () {
75
+ var args = [];
76
+ for (var _i = 0; _i < arguments.length; _i++) {
77
+ args[_i] = arguments[_i];
78
+ }
79
+ return _monitorFunction(errorBoundary, "".concat(obj.constructor.name, ".").concat(method), function () { return original.apply(obj.constructor, args); }, instance);
80
+ };
81
+ };
82
+ for (var _c = 0, _d = _getAllStaticMethodNames(obj); _c < _d.length; _c++) {
83
+ var method = _d[_c];
84
+ _loop_2(method);
85
+ }
27
86
  }
28
- exports.monitorClass = monitorClass;
29
- function monitorFunction(errorBoundary, tag, func, instance) {
30
- var client = instance instanceof StatsigClientBase_1.StatsigClientBase ? instance['emit'] : undefined;
31
- return errorBoundary.capture(tag, function () { return (0, Diagnostics_1.captureDiagnostics)(tag, function () { return func.apply(instance); }); }, client);
32
- }
33
- exports.monitorFunction = monitorFunction;
@@ -1,22 +1,31 @@
1
+ import { StatsigClientEmitEventFunc } from './StatsigClientBase';
1
2
  import { StatsigOptionsCommon } from './StatsigOptionsCommon';
2
3
  type RequestArgs = {
3
4
  sdkKey: string;
4
5
  url: string;
5
6
  timeoutMs?: number;
6
7
  retries?: number;
8
+ params?: Record<string, string>;
7
9
  headers?: Record<string, string>;
8
10
  };
9
11
  type RequestArgsWithData = RequestArgs & {
10
12
  data: Record<string, unknown>;
11
13
  };
14
+ type NetworkResponse = {
15
+ body: string | null;
16
+ code: number;
17
+ };
12
18
  export declare class NetworkCore {
13
19
  private _options;
20
+ private _emitter?;
14
21
  private readonly _timeout;
15
- constructor(_options: StatsigOptionsCommon | null);
16
- post(args: RequestArgsWithData): Promise<string | null>;
17
- get(args: RequestArgs): Promise<string | null>;
18
- beacon(args: RequestArgsWithData): boolean;
22
+ constructor(_options: StatsigOptionsCommon | null, _emitter?: StatsigClientEmitEventFunc | undefined);
23
+ post(args: RequestArgsWithData): Promise<NetworkResponse | null>;
24
+ get(args: RequestArgs): Promise<NetworkResponse | null>;
25
+ isBeaconSupported(): boolean;
26
+ beacon(args: RequestArgsWithData): Promise<boolean>;
19
27
  private _sendRequest;
20
28
  private _getPopulatedURL;
29
+ private _getPopulatedBody;
21
30
  }
22
31
  export {};