sdk-garden-js 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -23
- package/dist/index.d.mts +72 -21
- package/dist/index.d.ts +72 -21
- package/dist/index.js +699 -141
- package/dist/index.mjs +698 -141
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -26,26 +26,70 @@ module.exports = __toCommonJS(index_exports);
|
|
|
26
26
|
var _config = null;
|
|
27
27
|
var _queue = [];
|
|
28
28
|
var _sessionId = "";
|
|
29
|
+
var _customer = null;
|
|
29
30
|
var _flushTimer = null;
|
|
30
|
-
var
|
|
31
|
-
var
|
|
31
|
+
var _exiting = false;
|
|
32
|
+
var _exitDrains = 0;
|
|
33
|
+
var _exitStartedAt = 0;
|
|
34
|
+
var _exitActiveAt = 0;
|
|
35
|
+
var _exitSendFailed = false;
|
|
36
|
+
var _exitTurn = false;
|
|
37
|
+
var _exitTurnCount = 0;
|
|
38
|
+
var _exitProbe = null;
|
|
39
|
+
var _exitProbeDueAt = Infinity;
|
|
40
|
+
var _pending = /* @__PURE__ */ new Set();
|
|
41
|
+
var _registered = /* @__PURE__ */ new Set();
|
|
42
|
+
var _undeclared = [];
|
|
43
|
+
var _declareScheduled = false;
|
|
44
|
+
var DEFAULT_ENDPOINT = "https://ingest.sdkgarden.com/track";
|
|
45
|
+
var MAX_BATCH_SIZE = 100;
|
|
46
|
+
var MAX_QUEUE_SIZE = 1e3;
|
|
47
|
+
var MAX_DRAIN_REQUESTS = 10;
|
|
48
|
+
var MAX_EVENT_BYTES = 64 * 1024;
|
|
49
|
+
var MAX_REQUEST_BYTES = 512 * 1024;
|
|
50
|
+
var MAX_ERROR_MESSAGE_BYTES = 1e3;
|
|
51
|
+
var MAX_EMAIL_LENGTH = 254;
|
|
52
|
+
var MAX_EVENT_NAME_LENGTH = 100;
|
|
53
|
+
var MAX_CUSTOMER_ID_LENGTH = 128;
|
|
54
|
+
var MAX_CUSTOMER_NAME_LENGTH = 200;
|
|
55
|
+
var MAX_EXIT_DRAINS = 3;
|
|
56
|
+
var NEXT_BATCH_DELAY_MS = 10;
|
|
57
|
+
var EXIT_PROBE_MS = 100;
|
|
58
|
+
var EXIT_FROZEN_MS = 250;
|
|
59
|
+
var EXIT_QUIET_MS = 1e3;
|
|
60
|
+
var KEEPALIVE_BUDGET_BYTES = 32 * 1024;
|
|
61
|
+
var WAIT_TIMEOUT_MS = 2e3;
|
|
62
|
+
var MAX_TIMER_MS = 2147483647;
|
|
32
63
|
var MODULE_LOADED_AT = Date.now();
|
|
64
|
+
var MAX_SURFACE_METHODS = 500;
|
|
65
|
+
var MAX_METHOD_NAME_LENGTH = 255;
|
|
66
|
+
var MAX_SURFACE_CHARS = 32 * 1024;
|
|
67
|
+
function _clamp(value, min, max, fallback) {
|
|
68
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
69
|
+
return Math.min(max, Math.max(min, Math.floor(value)));
|
|
70
|
+
}
|
|
33
71
|
function _mergeDefaults(config) {
|
|
34
|
-
var _a, _b
|
|
72
|
+
var _a, _b;
|
|
35
73
|
return {
|
|
36
74
|
apiKey: config.apiKey,
|
|
37
75
|
sdkName: config.sdkName,
|
|
38
76
|
sdkVersion: config.sdkVersion,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
77
|
+
// An empty endpoint would POST to the host page's own URL.
|
|
78
|
+
endpoint: typeof config.endpoint === "string" && config.endpoint !== "" ? config.endpoint : DEFAULT_ENDPOINT,
|
|
79
|
+
debug: (_a = config.debug) != null ? _a : false,
|
|
80
|
+
disabled: (_b = config.disabled) != null ? _b : false,
|
|
81
|
+
// A batch size below 1 would never empty the queue; above 100 the endpoint rejects it.
|
|
82
|
+
batchSize: _clamp(config.batchSize, 1, MAX_BATCH_SIZE, 10),
|
|
83
|
+
// A tiny interval would send constantly; one too large for a timer would fire every 1 ms.
|
|
84
|
+
flushInterval: _clamp(config.flushInterval, 100, MAX_TIMER_MS, 5e3)
|
|
44
85
|
};
|
|
45
86
|
}
|
|
46
87
|
function _generateSessionId() {
|
|
47
|
-
|
|
48
|
-
|
|
88
|
+
try {
|
|
89
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
90
|
+
return crypto.randomUUID();
|
|
91
|
+
}
|
|
92
|
+
} catch (e) {
|
|
49
93
|
}
|
|
50
94
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
51
95
|
}
|
|
@@ -79,11 +123,67 @@ function _getMetadata() {
|
|
|
79
123
|
}
|
|
80
124
|
return meta;
|
|
81
125
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
|
|
126
|
+
var EMAIL_PATTERN = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/;
|
|
127
|
+
function _customerField(value, maxLength) {
|
|
128
|
+
if (typeof value !== "string") return "";
|
|
129
|
+
return value.replace(/[\u0000-\u001f\u007f-\u009f]/g, "").trim().slice(0, maxLength).trim();
|
|
130
|
+
}
|
|
131
|
+
function _cleanCustomer(customer) {
|
|
132
|
+
if (customer === null || typeof customer !== "object") return null;
|
|
133
|
+
const c = customer;
|
|
134
|
+
const id = _customerField(c["id"], MAX_CUSTOMER_ID_LENGTH);
|
|
135
|
+
if (id === "") {
|
|
136
|
+
_log("Ignored a customer without an id");
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
if (EMAIL_PATTERN.test(id)) {
|
|
140
|
+
_log("Ignored a customer id that contains an email address");
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
const name = _customerField(c["name"], MAX_CUSTOMER_NAME_LENGTH);
|
|
144
|
+
if (name !== "" && EMAIL_PATTERN.test(name)) {
|
|
145
|
+
_log("Left out a customer name that contains an email address");
|
|
146
|
+
return { id };
|
|
147
|
+
}
|
|
148
|
+
return name !== "" ? { id, name } : { id };
|
|
149
|
+
}
|
|
150
|
+
function _truncateUtf8(str, maxBytes) {
|
|
151
|
+
let bytes = 0;
|
|
152
|
+
for (let i = 0; i < str.length; i++) {
|
|
153
|
+
const code = str.charCodeAt(i);
|
|
154
|
+
let size = code < 128 ? 1 : code < 2048 ? 2 : 3;
|
|
155
|
+
if (code >= 55296 && code <= 56319 && i + 1 < str.length) {
|
|
156
|
+
const next = str.charCodeAt(i + 1);
|
|
157
|
+
if (next >= 56320 && next <= 57343) size = 4;
|
|
158
|
+
}
|
|
159
|
+
if (bytes + size > maxBytes) return str.slice(0, i);
|
|
160
|
+
bytes += size;
|
|
161
|
+
if (size === 4) i++;
|
|
162
|
+
}
|
|
163
|
+
return str;
|
|
164
|
+
}
|
|
165
|
+
function _errorMessage(error) {
|
|
166
|
+
const message = error == null ? void 0 : error.message;
|
|
167
|
+
if (typeof message !== "string") return message;
|
|
168
|
+
const searched = message.slice(0, MAX_ERROR_MESSAGE_BYTES + MAX_EMAIL_LENGTH);
|
|
169
|
+
const pattern = new RegExp(EMAIL_PATTERN.source, "g");
|
|
170
|
+
let scrubbed = "";
|
|
171
|
+
let end = 0;
|
|
172
|
+
let match = pattern.exec(searched);
|
|
173
|
+
while (match && match.index < MAX_ERROR_MESSAGE_BYTES) {
|
|
174
|
+
scrubbed += searched.slice(end, match.index) + "[REDACTED]";
|
|
175
|
+
end = match.index + match[0].length;
|
|
176
|
+
match = pattern.exec(searched);
|
|
177
|
+
}
|
|
178
|
+
if (end < MAX_ERROR_MESSAGE_BYTES) scrubbed += searched.slice(end, MAX_ERROR_MESSAGE_BYTES);
|
|
179
|
+
return _truncateUtf8(scrubbed.replace(/\u0000/g, "\uFFFD"), MAX_ERROR_MESSAGE_BYTES);
|
|
180
|
+
}
|
|
181
|
+
var JSON_ESCAPE = /\\(?:u(0000|d[89ab][0-9a-f]{2}(?:\\ud[c-f][0-9a-f]{2})?|d[c-f][0-9a-f]{2})|[\s\S])/g;
|
|
182
|
+
function _sanitizeJson(json) {
|
|
183
|
+
if (json.indexOf("\\u") === -1) return json;
|
|
184
|
+
return json.replace(
|
|
185
|
+
JSON_ESCAPE,
|
|
186
|
+
(escape, code) => code !== void 0 && code.length === 4 ? "\\ufffd" : escape
|
|
87
187
|
);
|
|
88
188
|
}
|
|
89
189
|
function _sanitizeConfig(config) {
|
|
@@ -97,109 +197,520 @@ function _sanitizeConfig(config) {
|
|
|
97
197
|
return sanitized;
|
|
98
198
|
}
|
|
99
199
|
function _log(...args) {
|
|
100
|
-
if (_config == null ? void 0 : _config.debug)
|
|
200
|
+
if (!(_config == null ? void 0 : _config.debug)) return;
|
|
201
|
+
try {
|
|
101
202
|
console.log("[SDK Garden]", ...args);
|
|
203
|
+
} catch (e) {
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function _now() {
|
|
207
|
+
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
208
|
+
}
|
|
209
|
+
function _unref(timer) {
|
|
210
|
+
try {
|
|
211
|
+
if (timer !== null && typeof timer === "object" && typeof timer.unref === "function") {
|
|
212
|
+
timer.unref();
|
|
213
|
+
return true;
|
|
214
|
+
} else if (typeof timer === "number" && typeof Deno !== "undefined" && typeof (Deno == null ? void 0 : Deno.unrefTimer) === "function") {
|
|
215
|
+
Deno.unrefTimer(timer);
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
} catch (e) {
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
function _requestTimeoutMs() {
|
|
223
|
+
return typeof window === "undefined" ? 2e3 : 1e4;
|
|
224
|
+
}
|
|
225
|
+
function _utf8Length(str) {
|
|
226
|
+
let bytes = str.length;
|
|
227
|
+
for (let i = 0; i < str.length; i++) {
|
|
228
|
+
const code = str.charCodeAt(i);
|
|
229
|
+
if (code > 127) bytes += code > 2047 ? 2 : 1;
|
|
102
230
|
}
|
|
231
|
+
return bytes;
|
|
103
232
|
}
|
|
104
233
|
function _enqueue(event) {
|
|
105
|
-
|
|
234
|
+
_checkExit();
|
|
235
|
+
if (typeof event.event !== "string" || event.event.length > MAX_EVENT_NAME_LENGTH) {
|
|
236
|
+
_log("Dropped an event whose name is not a string of at most 100 characters");
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (_queue.length >= MAX_QUEUE_SIZE) {
|
|
240
|
+
_log("Queue full; dropped event", event.event);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (_customer) event.customer = _customer;
|
|
244
|
+
let json;
|
|
245
|
+
try {
|
|
246
|
+
json = JSON.stringify(event);
|
|
247
|
+
} catch (e) {
|
|
248
|
+
_log("Dropped an event that cannot be serialized", event.event);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (json.length <= MAX_EVENT_BYTES) json = _sanitizeJson(json);
|
|
252
|
+
const bytes = _utf8Length(json);
|
|
253
|
+
if (bytes > MAX_EVENT_BYTES) {
|
|
254
|
+
_log("Dropped an event larger than 64 KiB", event.event);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
_queue.push({ json, bytes });
|
|
106
258
|
_log("Event tracked", event.event);
|
|
107
|
-
if (_config && _queue.length >= _config.batchSize) {
|
|
108
|
-
|
|
259
|
+
if (_config && _queue.length >= _config.batchSize && !_exiting) {
|
|
260
|
+
_pump();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function _safely(fn) {
|
|
264
|
+
try {
|
|
265
|
+
fn();
|
|
266
|
+
} catch (e) {
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function _trackSuccess(methodName, startTime, isAsync, argsCount) {
|
|
270
|
+
_safely(
|
|
271
|
+
() => SdkGarden.track("method_success", {
|
|
272
|
+
method: methodName,
|
|
273
|
+
duration_ms: Math.round(_now() - startTime),
|
|
274
|
+
is_async: isAsync,
|
|
275
|
+
args_count: argsCount
|
|
276
|
+
})
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
function _trackFailure(methodName, error, startTime, isAsync) {
|
|
280
|
+
_safely(() => {
|
|
281
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
282
|
+
SdkGarden.trackError(err, {
|
|
283
|
+
method: methodName,
|
|
284
|
+
duration_ms: Math.round(_now() - startTime),
|
|
285
|
+
is_async: isAsync
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
var NATIVE_PROMISE_PROTOTYPE = Object.getPrototypeOf((async () => {
|
|
290
|
+
})());
|
|
291
|
+
function _watchPromise(value, onFulfilled, onRejected) {
|
|
292
|
+
try {
|
|
293
|
+
if (value === null || typeof value !== "object") return false;
|
|
294
|
+
const proto = Object.getPrototypeOf(value);
|
|
295
|
+
if (proto === NATIVE_PROMISE_PROTOTYPE || proto === Promise.prototype) {
|
|
296
|
+
if (value.then !== proto.then || value.constructor !== proto.constructor) return false;
|
|
297
|
+
value.then(onFulfilled, onRejected);
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
if (Object.getPrototypeOf(Object.getPrototypeOf(proto)) !== null || value.constructor !== proto.constructor || Object.prototype.toString.call(value) !== "[object Promise]") {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
NATIVE_PROMISE_PROTOTYPE.then.call(value, onFulfilled, onRejected);
|
|
304
|
+
return true;
|
|
305
|
+
} catch (e) {
|
|
306
|
+
return false;
|
|
109
307
|
}
|
|
110
308
|
}
|
|
111
309
|
function _createWrapper(methodName, fn) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
310
|
+
if (typeof fn !== "function" || typeof Proxy !== "function") return fn;
|
|
311
|
+
const wrapped = new Proxy(fn, {
|
|
312
|
+
apply(target, thisArg, args) {
|
|
313
|
+
if (!_config) return Reflect.apply(target, thisArg, args);
|
|
314
|
+
const startTime = _now();
|
|
315
|
+
_safely(() => SdkGarden.track("method_called", { method: methodName, args_count: args.length }));
|
|
316
|
+
let result;
|
|
317
|
+
try {
|
|
318
|
+
result = Reflect.apply(target, thisArg, args);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
_trackFailure(methodName, error, startTime, false);
|
|
321
|
+
throw error;
|
|
322
|
+
}
|
|
323
|
+
const watched = _watchPromise(
|
|
324
|
+
result,
|
|
325
|
+
() => _trackSuccess(methodName, startTime, true, args.length),
|
|
326
|
+
(error) => _trackFailure(methodName, error, startTime, true)
|
|
327
|
+
);
|
|
328
|
+
if (!watched) _trackSuccess(methodName, startTime, false, args.length);
|
|
329
|
+
return result;
|
|
330
|
+
},
|
|
331
|
+
construct(target, args, newTarget) {
|
|
332
|
+
return Reflect.construct(target, args, newTarget === wrapped ? target : newTarget);
|
|
333
|
+
},
|
|
334
|
+
get(target, key) {
|
|
335
|
+
if (key === Symbol.hasInstance) return (value) => value instanceof target;
|
|
336
|
+
return Reflect.get(target, key);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
return wrapped;
|
|
340
|
+
}
|
|
341
|
+
function _isMethodName(name) {
|
|
342
|
+
return typeof name === "string" && name.trim() !== "" && name.length <= MAX_METHOD_NAME_LENGTH;
|
|
343
|
+
}
|
|
344
|
+
function _surfaceList(names) {
|
|
345
|
+
const out = /* @__PURE__ */ new Set();
|
|
346
|
+
let chars = 0;
|
|
347
|
+
for (const name of names) {
|
|
348
|
+
if (out.size >= MAX_SURFACE_METHODS) break;
|
|
349
|
+
if (!_isMethodName(name) || out.has(name)) continue;
|
|
350
|
+
if (chars + name.length > MAX_SURFACE_CHARS) break;
|
|
351
|
+
out.add(name);
|
|
352
|
+
chars += name.length;
|
|
353
|
+
}
|
|
354
|
+
return Array.from(out);
|
|
355
|
+
}
|
|
356
|
+
function _register(methodName) {
|
|
357
|
+
if (!_isMethodName(methodName) || _registered.has(methodName) || _registered.size >= MAX_SURFACE_METHODS) return;
|
|
358
|
+
_registered.add(methodName);
|
|
359
|
+
if (!_config) return;
|
|
360
|
+
_undeclared.push(methodName);
|
|
361
|
+
if (_declareScheduled) return;
|
|
362
|
+
_declareScheduled = true;
|
|
363
|
+
Promise.resolve().then(
|
|
364
|
+
() => _safely(() => {
|
|
365
|
+
_declareScheduled = false;
|
|
366
|
+
const methods = _surfaceList(_undeclared);
|
|
367
|
+
_undeclared = [];
|
|
368
|
+
if (methods.length > 0) SdkGarden.track("api_surface", { api_surface: methods });
|
|
369
|
+
})
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
function _keepaliveBytesInFlight() {
|
|
373
|
+
let total = 0;
|
|
374
|
+
_pending.forEach((request) => {
|
|
375
|
+
total += request.keepaliveBytes;
|
|
376
|
+
});
|
|
377
|
+
return total;
|
|
378
|
+
}
|
|
379
|
+
function _takeBatch(events, maxEvents) {
|
|
380
|
+
let count = 0;
|
|
381
|
+
let bytes = 0;
|
|
382
|
+
while (count < events.length && count < maxEvents && (count === 0 || bytes + events[count].bytes <= MAX_REQUEST_BYTES)) {
|
|
383
|
+
bytes += events[count].bytes + 1;
|
|
384
|
+
count++;
|
|
385
|
+
}
|
|
386
|
+
return events.splice(0, count).map((event) => event.json);
|
|
387
|
+
}
|
|
388
|
+
function _send(config, batch, keepalive) {
|
|
389
|
+
var _a;
|
|
390
|
+
if (typeof fetch !== "function") {
|
|
391
|
+
_log("No global fetch() in this runtime; dropping", batch.length, "events");
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const body = `{"api_key":${JSON.stringify(String((_a = config.apiKey) != null ? _a : ""))},"events":[${batch.join(",")}]}`;
|
|
395
|
+
let keepaliveBytes = keepalive ? _utf8Length(body) : 0;
|
|
396
|
+
if (keepaliveBytes > 0 && _keepaliveBytesInFlight() + keepaliveBytes > KEEPALIVE_BUDGET_BYTES) {
|
|
397
|
+
keepaliveBytes = 0;
|
|
398
|
+
}
|
|
399
|
+
const controller = typeof AbortController === "function" ? new AbortController() : null;
|
|
400
|
+
let settle = () => {
|
|
401
|
+
};
|
|
402
|
+
let delivered = false;
|
|
403
|
+
const request = {
|
|
404
|
+
done: new Promise((resolve) => {
|
|
405
|
+
settle = resolve;
|
|
406
|
+
}),
|
|
407
|
+
keepaliveBytes,
|
|
408
|
+
abort() {
|
|
409
|
+
try {
|
|
410
|
+
controller == null ? void 0 : controller.abort();
|
|
411
|
+
} catch (e) {
|
|
412
|
+
}
|
|
413
|
+
settle();
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
let timer;
|
|
417
|
+
try {
|
|
418
|
+
timer = setTimeout(request.abort, _requestTimeoutMs());
|
|
419
|
+
_unref(timer);
|
|
420
|
+
} catch (e) {
|
|
421
|
+
}
|
|
422
|
+
_pending.add(request);
|
|
423
|
+
request.done.then(
|
|
424
|
+
() => _safely(() => {
|
|
425
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
426
|
+
if (!_pending.delete(request)) return;
|
|
427
|
+
if (_exiting) {
|
|
428
|
+
_exitActiveAt = _now();
|
|
429
|
+
if (!delivered) _exitSendFailed = true;
|
|
430
|
+
} else if (delivered && _config && _queue.length >= _config.batchSize) {
|
|
431
|
+
_pumpSoon();
|
|
432
|
+
}
|
|
433
|
+
})
|
|
434
|
+
);
|
|
435
|
+
_log("Sending events", batch.length);
|
|
436
|
+
try {
|
|
437
|
+
fetch(config.endpoint, {
|
|
438
|
+
method: "POST",
|
|
439
|
+
headers: { "Content-Type": "application/json" },
|
|
440
|
+
body,
|
|
441
|
+
keepalive: keepaliveBytes > 0,
|
|
442
|
+
signal: controller == null ? void 0 : controller.signal
|
|
443
|
+
}).then(
|
|
444
|
+
(response) => {
|
|
445
|
+
let discarded;
|
|
446
|
+
try {
|
|
447
|
+
delivered = Boolean(response && response.ok);
|
|
448
|
+
const stream = response == null ? void 0 : response.body;
|
|
449
|
+
if (stream && typeof stream.cancel === "function") discarded = stream.cancel();
|
|
450
|
+
} catch (e) {
|
|
451
|
+
}
|
|
452
|
+
Promise.resolve(discarded).then(settle, settle);
|
|
453
|
+
},
|
|
454
|
+
() => settle()
|
|
455
|
+
// Silent failure — locked by CLIENT-01 "fail silently on network errors".
|
|
456
|
+
);
|
|
457
|
+
} catch (e) {
|
|
458
|
+
settle();
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function _pump() {
|
|
462
|
+
const config = _config;
|
|
463
|
+
if (!config || _exiting || _pending.size > 0 || _queue.length === 0) return;
|
|
464
|
+
_send(config, _takeBatch(_queue, config.batchSize), false);
|
|
465
|
+
}
|
|
466
|
+
function _pumpSoon() {
|
|
467
|
+
try {
|
|
468
|
+
_unref(setTimeout(_pump, NEXT_BATCH_DELAY_MS));
|
|
469
|
+
} catch (e) {
|
|
470
|
+
_pump();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
function _drainAll(keepalive, all = false) {
|
|
474
|
+
const config = _config;
|
|
475
|
+
if (!config || _queue.length === 0) return;
|
|
476
|
+
if (_exiting && _exitTurn && !all) {
|
|
477
|
+
if (_exitDrains >= MAX_EXIT_DRAINS || _exitSendFailed || _now() - _exitStartedAt >= WAIT_TIMEOUT_MS) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
_exitDrains++;
|
|
481
|
+
}
|
|
482
|
+
const events = _queue;
|
|
483
|
+
_queue = [];
|
|
484
|
+
const size = Math.min(
|
|
485
|
+
MAX_BATCH_SIZE,
|
|
486
|
+
Math.max(config.batchSize, Math.ceil(events.length / MAX_DRAIN_REQUESTS))
|
|
487
|
+
);
|
|
488
|
+
for (let i = 0; (all || i < MAX_DRAIN_REQUESTS) && events.length > 0; i++) {
|
|
489
|
+
_send(config, _takeBatch(events, size), keepalive);
|
|
490
|
+
}
|
|
491
|
+
if (events.length > 0) _queue = events.concat(_queue);
|
|
492
|
+
}
|
|
493
|
+
function _waitForPending(timeoutMs, abortLate) {
|
|
494
|
+
const requests = Array.from(_pending);
|
|
495
|
+
const waitMs = timeoutMs > 0 ? Math.min(timeoutMs, _requestTimeoutMs()) : 0;
|
|
496
|
+
if (requests.length === 0 || waitMs === 0) {
|
|
497
|
+
if (abortLate) requests.forEach((request) => request.abort());
|
|
498
|
+
return Promise.resolve();
|
|
499
|
+
}
|
|
500
|
+
return new Promise((resolve) => {
|
|
501
|
+
let timer;
|
|
117
502
|
try {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
503
|
+
timer = setTimeout(() => {
|
|
504
|
+
if (abortLate) requests.forEach((request) => request.abort());
|
|
505
|
+
resolve();
|
|
506
|
+
}, waitMs);
|
|
507
|
+
_unref(timer);
|
|
508
|
+
} catch (e) {
|
|
124
509
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
510
|
+
Promise.all(requests.map((request) => request.done)).then(() => {
|
|
511
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
512
|
+
resolve();
|
|
513
|
+
});
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
function _onNextLoopTurn(fn) {
|
|
517
|
+
try {
|
|
518
|
+
_unref(typeof setImmediate === "function" ? setImmediate(fn) : setTimeout(fn, 0));
|
|
519
|
+
} catch (e) {
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function _afterMicrotasks(fn) {
|
|
523
|
+
Promise.resolve().then(() => {
|
|
524
|
+
if (typeof process !== "undefined" && typeof (process == null ? void 0 : process.nextTick) === "function") {
|
|
525
|
+
process.nextTick(() => _safely(fn));
|
|
526
|
+
} else {
|
|
527
|
+
_safely(fn);
|
|
141
528
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
function _onBeforeExit() {
|
|
532
|
+
_safely(() => {
|
|
533
|
+
_checkExit();
|
|
534
|
+
if (!_exiting) {
|
|
535
|
+
_exiting = true;
|
|
536
|
+
_exitStartedAt = _now();
|
|
537
|
+
}
|
|
538
|
+
_exitActiveAt = _now();
|
|
539
|
+
_beginExitTurn();
|
|
540
|
+
_watchExit();
|
|
541
|
+
_keepListenerFirst();
|
|
542
|
+
const session = _sessionId;
|
|
543
|
+
_afterMicrotasks(() => {
|
|
544
|
+
if (_sessionId !== session) return;
|
|
545
|
+
_drainAll(false);
|
|
546
|
+
void _waitForPending(WAIT_TIMEOUT_MS, true);
|
|
148
547
|
});
|
|
149
|
-
|
|
150
|
-
};
|
|
548
|
+
});
|
|
151
549
|
}
|
|
152
|
-
function
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
fetch(_config.endpoint, {
|
|
158
|
-
method: "POST",
|
|
159
|
-
headers: { "Content-Type": "application/json" },
|
|
160
|
-
body: payload,
|
|
161
|
-
keepalive: true
|
|
162
|
-
}).catch(() => {
|
|
550
|
+
function _beginExitTurn() {
|
|
551
|
+
_exitTurn = true;
|
|
552
|
+
const turn = ++_exitTurnCount;
|
|
553
|
+
_onNextLoopTurn(() => {
|
|
554
|
+
if (turn === _exitTurnCount) _exitTurn = false;
|
|
163
555
|
});
|
|
164
556
|
}
|
|
557
|
+
function _keepListenerFirst() {
|
|
558
|
+
try {
|
|
559
|
+
const proc = typeof process !== "undefined" ? process : void 0;
|
|
560
|
+
if (!proc || typeof proc.listeners !== "function" || typeof proc.prependListener !== "function" || typeof proc.removeListener !== "function" || proc.listeners("beforeExit")[0] === _onBeforeExit) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
proc.removeListener("beforeExit", _onBeforeExit);
|
|
564
|
+
proc.prependListener("beforeExit", _onBeforeExit);
|
|
565
|
+
} catch (e) {
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
function _watchExit() {
|
|
569
|
+
if (_exitProbe !== null) clearTimeout(_exitProbe);
|
|
570
|
+
_exitProbe = null;
|
|
571
|
+
_exitProbeDueAt = Infinity;
|
|
572
|
+
try {
|
|
573
|
+
const timer = setTimeout(_onExitProbe, EXIT_PROBE_MS);
|
|
574
|
+
if (!_unref(timer)) {
|
|
575
|
+
clearTimeout(timer);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
_exitProbe = timer;
|
|
579
|
+
_exitProbeDueAt = _now() + EXIT_PROBE_MS;
|
|
580
|
+
} catch (e) {
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
function _onExitProbe() {
|
|
584
|
+
_safely(() => {
|
|
585
|
+
_checkExit();
|
|
586
|
+
if (_exiting) _watchExit();
|
|
587
|
+
else _pump();
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
function _checkExit() {
|
|
591
|
+
if (!_exiting) return;
|
|
592
|
+
const now = _now();
|
|
593
|
+
const frozen = now - _exitProbeDueAt >= EXIT_FROZEN_MS;
|
|
594
|
+
const quiet = _pending.size === 0 && now - _exitActiveAt >= EXIT_QUIET_MS;
|
|
595
|
+
if (frozen || quiet) _endExit();
|
|
596
|
+
}
|
|
597
|
+
function _endExit() {
|
|
598
|
+
_exiting = false;
|
|
599
|
+
_exitDrains = 0;
|
|
600
|
+
_exitSendFailed = false;
|
|
601
|
+
_exitTurn = false;
|
|
602
|
+
if (_exitProbe !== null) clearTimeout(_exitProbe);
|
|
603
|
+
_exitProbe = null;
|
|
604
|
+
_exitProbeDueAt = Infinity;
|
|
605
|
+
}
|
|
606
|
+
function _onTick() {
|
|
607
|
+
_checkExit();
|
|
608
|
+
if (!_exiting) _pump();
|
|
609
|
+
}
|
|
610
|
+
function _onPageHide() {
|
|
611
|
+
_drainAll(true);
|
|
612
|
+
}
|
|
613
|
+
function _onVisibilityChange() {
|
|
614
|
+
if (typeof document !== "undefined" && document.visibilityState === "hidden") {
|
|
615
|
+
_drainAll(true);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function _addLifecycleListeners() {
|
|
619
|
+
if (typeof process !== "undefined") {
|
|
620
|
+
if (typeof (process == null ? void 0 : process.prependListener) === "function") {
|
|
621
|
+
process.prependListener("beforeExit", _onBeforeExit);
|
|
622
|
+
} else if (typeof (process == null ? void 0 : process.on) === "function") {
|
|
623
|
+
process.on("beforeExit", _onBeforeExit);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (typeof window !== "undefined" && typeof (window == null ? void 0 : window.addEventListener) === "function") {
|
|
627
|
+
window.addEventListener("pagehide", _onPageHide);
|
|
628
|
+
}
|
|
629
|
+
if (typeof document !== "undefined" && typeof (document == null ? void 0 : document.addEventListener) === "function") {
|
|
630
|
+
document.addEventListener("visibilitychange", _onVisibilityChange);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
function _removeLifecycleListeners() {
|
|
634
|
+
if (typeof process !== "undefined" && typeof (process == null ? void 0 : process.removeListener) === "function") {
|
|
635
|
+
process.removeListener("beforeExit", _onBeforeExit);
|
|
636
|
+
}
|
|
637
|
+
if (typeof window !== "undefined" && typeof (window == null ? void 0 : window.removeEventListener) === "function") {
|
|
638
|
+
window.removeEventListener("pagehide", _onPageHide);
|
|
639
|
+
}
|
|
640
|
+
if (typeof document !== "undefined" && typeof (document == null ? void 0 : document.removeEventListener) === "function") {
|
|
641
|
+
document.removeEventListener("visibilitychange", _onVisibilityChange);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
function _teardown() {
|
|
645
|
+
if (_flushTimer !== null) {
|
|
646
|
+
clearInterval(_flushTimer);
|
|
647
|
+
_flushTimer = null;
|
|
648
|
+
}
|
|
649
|
+
_removeLifecycleListeners();
|
|
650
|
+
_config = null;
|
|
651
|
+
_queue = [];
|
|
652
|
+
_sessionId = "";
|
|
653
|
+
_customer = null;
|
|
654
|
+
_endExit();
|
|
655
|
+
}
|
|
656
|
+
function _start(config) {
|
|
657
|
+
var _a;
|
|
658
|
+
let carried = [];
|
|
659
|
+
if (_config && !config.disabled) {
|
|
660
|
+
const next = _mergeDefaults(config);
|
|
661
|
+
if (next.apiKey === _config.apiKey && next.endpoint === _config.endpoint) {
|
|
662
|
+
carried = _queue.slice(0, MAX_QUEUE_SIZE - 1);
|
|
663
|
+
} else {
|
|
664
|
+
_drainAll(false, true);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
_teardown();
|
|
668
|
+
if (config.disabled) {
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
const initStartedAt = (_a = config.startedAt) != null ? _a : MODULE_LOADED_AT;
|
|
672
|
+
_config = _mergeDefaults(config);
|
|
673
|
+
_queue = carried;
|
|
674
|
+
_sessionId = _generateSessionId();
|
|
675
|
+
_customer = config.customer === void 0 ? null : _cleanCustomer(config.customer);
|
|
676
|
+
_undeclared = [];
|
|
677
|
+
const apiSurface = _surfaceList([
|
|
678
|
+
...Array.isArray(config.methods) ? config.methods : [],
|
|
679
|
+
..._registered
|
|
680
|
+
]);
|
|
681
|
+
_log("Initialised", _sanitizeConfig(_config));
|
|
682
|
+
_enqueue({
|
|
683
|
+
event: "sdk_initialized",
|
|
684
|
+
sdk: { name: _config.sdkName, version: _config.sdkVersion },
|
|
685
|
+
session_id: _sessionId,
|
|
686
|
+
timestamp: Date.now(),
|
|
687
|
+
properties: {
|
|
688
|
+
environment: _getEnvironment(),
|
|
689
|
+
time_to_init_ms: Math.max(0, Date.now() - initStartedAt),
|
|
690
|
+
...apiSurface.length > 0 ? { api_surface: apiSurface } : {}
|
|
691
|
+
},
|
|
692
|
+
meta: _getMetadata()
|
|
693
|
+
});
|
|
694
|
+
try {
|
|
695
|
+
_flushTimer = setInterval(_onTick, _config.flushInterval);
|
|
696
|
+
_unref(_flushTimer);
|
|
697
|
+
} catch (e) {
|
|
698
|
+
}
|
|
699
|
+
_addLifecycleListeners();
|
|
700
|
+
}
|
|
165
701
|
var SdkGarden = {
|
|
166
702
|
/**
|
|
167
703
|
* Initialize the SDK Garden client.
|
|
168
|
-
* Must be called once before any
|
|
169
|
-
* When config.disabled is true,
|
|
704
|
+
* Must be called once before any events are recorded. Calling it again
|
|
705
|
+
* starts a new session. When config.disabled is true, any running client is
|
|
706
|
+
* stopped (its queued events are dropped) and everything stays a no-op.
|
|
707
|
+
* Never throws: if the runtime refuses what init needs, the client stays off.
|
|
170
708
|
*/
|
|
171
709
|
init(config) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (_flushTimer !== null) {
|
|
177
|
-
clearInterval(_flushTimer);
|
|
178
|
-
_flushTimer = null;
|
|
179
|
-
}
|
|
180
|
-
const initStartedAt = (_a = config.startedAt) != null ? _a : MODULE_LOADED_AT;
|
|
181
|
-
_config = _mergeDefaults(config);
|
|
182
|
-
_queue = [];
|
|
183
|
-
_sessionId = _generateSessionId();
|
|
184
|
-
_log("Initialised", _sanitizeConfig(_config));
|
|
185
|
-
_enqueue({
|
|
186
|
-
event: "sdk_initialized",
|
|
187
|
-
sdk: { name: _config.sdkName, version: _config.sdkVersion },
|
|
188
|
-
session_id: _sessionId,
|
|
189
|
-
timestamp: Date.now(),
|
|
190
|
-
properties: {
|
|
191
|
-
environment: _getEnvironment(),
|
|
192
|
-
time_to_init_ms: Math.max(0, Date.now() - initStartedAt)
|
|
193
|
-
},
|
|
194
|
-
meta: _getMetadata()
|
|
195
|
-
});
|
|
196
|
-
_flushTimer = setInterval(_flush, _config.flushInterval);
|
|
197
|
-
if (typeof window !== "undefined") {
|
|
198
|
-
if (_unloadHandler) {
|
|
199
|
-
window.removeEventListener("beforeunload", _unloadHandler);
|
|
200
|
-
}
|
|
201
|
-
_unloadHandler = () => _flush();
|
|
202
|
-
window.addEventListener("beforeunload", _unloadHandler);
|
|
710
|
+
try {
|
|
711
|
+
_start(config);
|
|
712
|
+
} catch (e) {
|
|
713
|
+
_teardown();
|
|
203
714
|
}
|
|
204
715
|
},
|
|
205
716
|
/**
|
|
@@ -207,20 +718,24 @@ var SdkGarden = {
|
|
|
207
718
|
* No-op if SDK has not been initialised or is disabled.
|
|
208
719
|
*/
|
|
209
720
|
track(eventName, properties) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
721
|
+
const config = _config;
|
|
722
|
+
if (!config) return;
|
|
723
|
+
_safely(
|
|
724
|
+
() => _enqueue({
|
|
725
|
+
event: eventName,
|
|
726
|
+
sdk: { name: config.sdkName, version: config.sdkVersion },
|
|
727
|
+
session_id: _sessionId,
|
|
728
|
+
timestamp: Date.now(),
|
|
729
|
+
properties: properties != null ? properties : {},
|
|
730
|
+
meta: _getMetadata()
|
|
731
|
+
})
|
|
732
|
+
);
|
|
219
733
|
},
|
|
220
734
|
/**
|
|
221
735
|
* Instrument a method with call, success, and error telemetry.
|
|
222
736
|
*
|
|
223
|
-
* **Two-argument form** — wraps a standalone function
|
|
737
|
+
* **Two-argument form** — wraps a standalone function. Safe to call before
|
|
738
|
+
* init(), for example at module level; calls are recorded once init() runs:
|
|
224
739
|
* ```ts
|
|
225
740
|
* function processPayment(amount: number): Receipt { ... }
|
|
226
741
|
* export const trackedProcessPayment = SdkGarden.trackMethod('processPayment', processPayment);
|
|
@@ -233,17 +748,17 @@ var SdkGarden = {
|
|
|
233
748
|
* processPayment(amount: number): Receipt { ... }
|
|
234
749
|
* }
|
|
235
750
|
* ```
|
|
236
|
-
*
|
|
237
|
-
* **Async limitation (v1):** For async functions in the two-argument form,
|
|
238
|
-
* `method_success` is recorded only when the caller awaits or chains `.then()`.
|
|
239
|
-
* Class method decorators do not have this limitation.
|
|
240
751
|
*/
|
|
241
752
|
trackMethod(methodName, fn) {
|
|
753
|
+
_safely(() => _register(methodName));
|
|
242
754
|
if (fn !== void 0) {
|
|
243
|
-
if (!_config || _config.disabled) return fn;
|
|
244
755
|
return _createWrapper(methodName, fn);
|
|
245
756
|
}
|
|
246
|
-
return function(target, _context) {
|
|
757
|
+
return function(target, _context, descriptor) {
|
|
758
|
+
if (descriptor !== null && typeof descriptor === "object") {
|
|
759
|
+
if (typeof descriptor.value !== "function") return descriptor;
|
|
760
|
+
return { ...descriptor, value: _createWrapper(methodName, descriptor.value) };
|
|
761
|
+
}
|
|
247
762
|
return _createWrapper(methodName, target);
|
|
248
763
|
};
|
|
249
764
|
},
|
|
@@ -253,42 +768,85 @@ var SdkGarden = {
|
|
|
253
768
|
* No-op if SDK is uninitialised or disabled.
|
|
254
769
|
*/
|
|
255
770
|
trackError(error, context) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
771
|
+
const config = _config;
|
|
772
|
+
if (!config) return;
|
|
773
|
+
_safely(
|
|
774
|
+
() => _enqueue({
|
|
775
|
+
event: "sdk_error",
|
|
776
|
+
sdk: { name: config.sdkName, version: config.sdkVersion },
|
|
777
|
+
session_id: _sessionId,
|
|
778
|
+
timestamp: Date.now(),
|
|
779
|
+
properties: {
|
|
780
|
+
error_message: _errorMessage(error),
|
|
781
|
+
error_type: error == null ? void 0 : error.name,
|
|
782
|
+
...context != null ? context : {}
|
|
783
|
+
},
|
|
784
|
+
meta: _getMetadata()
|
|
785
|
+
})
|
|
786
|
+
);
|
|
787
|
+
},
|
|
788
|
+
/**
|
|
789
|
+
* Attribute the session to one of your customers: an app or account, by an
|
|
790
|
+
* ID from your own system. Every event tracked afterwards carries it, so the
|
|
791
|
+
* dashboard can show which customers are on old versions, still call
|
|
792
|
+
* deprecated methods or hit errors. Pass null to stop. Lasts until the next
|
|
793
|
+
* init() or shutdown(); no-op before init().
|
|
794
|
+
*
|
|
795
|
+
* Never pass an email address or other personal data: an ID containing an
|
|
796
|
+
* email address is ignored.
|
|
797
|
+
*
|
|
798
|
+
* @example
|
|
799
|
+
* SdkGarden.setCustomer({ id: account.id, name: account.displayName });
|
|
800
|
+
*/
|
|
801
|
+
setCustomer(customer) {
|
|
802
|
+
if (!_config) return;
|
|
803
|
+
_safely(() => {
|
|
804
|
+
_customer = customer === null ? null : _cleanCustomer(customer);
|
|
268
805
|
});
|
|
269
806
|
},
|
|
270
807
|
/**
|
|
271
|
-
*
|
|
272
|
-
* Useful
|
|
808
|
+
* Send every queued event now and wait for the requests to finish.
|
|
809
|
+
* Useful at the end of a serverless handler or a test.
|
|
810
|
+
*/
|
|
811
|
+
flush(timeoutMs = WAIT_TIMEOUT_MS) {
|
|
812
|
+
try {
|
|
813
|
+
_checkExit();
|
|
814
|
+
_drainAll(false);
|
|
815
|
+
return _waitForPending(timeoutMs, false);
|
|
816
|
+
} catch (e) {
|
|
817
|
+
return Promise.resolve();
|
|
818
|
+
}
|
|
819
|
+
},
|
|
820
|
+
/**
|
|
821
|
+
* Send every queued event and stop the client. Call it, and await it, from
|
|
822
|
+
* your SDK's close() or before process.exit(): explicit exits and signals
|
|
823
|
+
* skip the automatic send that runs when Node exits on its own.
|
|
273
824
|
*/
|
|
274
|
-
|
|
825
|
+
shutdown(timeoutMs = WAIT_TIMEOUT_MS) {
|
|
826
|
+
try {
|
|
827
|
+
if (timeoutMs > 0) _drainAll(typeof window !== "undefined", true);
|
|
828
|
+
_teardown();
|
|
829
|
+
return _waitForPending(timeoutMs, true);
|
|
830
|
+
} catch (e) {
|
|
831
|
+
_safely(_teardown);
|
|
832
|
+
return Promise.resolve();
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
_flush() {
|
|
836
|
+
void SdkGarden.flush();
|
|
837
|
+
},
|
|
275
838
|
/**
|
|
276
839
|
* Reset all internal state.
|
|
277
840
|
* FOR UNIT TESTS ONLY — not documented in README.
|
|
278
|
-
* Clears queue, config, session ID,
|
|
841
|
+
* Clears queue, config, session ID, flush timer, listeners, registered
|
|
842
|
+
* method names and the record of requests in flight, without sending or cancelling anything.
|
|
279
843
|
*/
|
|
280
844
|
_reset() {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (typeof window !== "undefined" && _unloadHandler) {
|
|
286
|
-
window.removeEventListener("beforeunload", _unloadHandler);
|
|
287
|
-
_unloadHandler = null;
|
|
288
|
-
}
|
|
289
|
-
_config = null;
|
|
290
|
-
_queue = [];
|
|
291
|
-
_sessionId = "";
|
|
845
|
+
_teardown();
|
|
846
|
+
_pending.clear();
|
|
847
|
+
_registered.clear();
|
|
848
|
+
_undeclared = [];
|
|
292
849
|
}
|
|
293
850
|
};
|
|
294
851
|
var index_default = SdkGarden;
|
|
852
|
+
module.exports = Object.defineProperties(module.exports.default, { default: { value: module.exports.default }, __esModule: { value: true } });
|