@macroui/event-tracker 1.3.0 → 1.3.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/event-tracker.cjs +4252 -879
- package/dist/event-tracker.cjs.map +1 -0
- package/dist/event-tracker.js +4252 -879
- package/dist/event-tracker.js.map +1 -0
- package/dist/event-tracker.min.js +2 -1
- package/dist/event-tracker.min.js.map +1 -0
- package/dist/event-tracker.mjs +4212 -880
- package/dist/event-tracker.mjs.map +1 -0
- package/dist/plugin/debug-sender.cjs +53 -2
- package/dist/plugin/debug-sender.mjs +53 -2
- package/dist/plugin/experiment.cjs +181 -0
- package/dist/plugin/experiment.cjs.map +1 -0
- package/dist/plugin/experiment.mjs +178 -0
- package/dist/plugin/experiment.mjs.map +1 -0
- package/dist/plugin/indexeddb-sender.cjs +51 -2
- package/dist/plugin/indexeddb-sender.mjs +51 -2
- package/dist/plugin/otel-bridge.cjs +164 -0
- package/dist/plugin/otel-bridge.cjs.map +1 -0
- package/dist/plugin/otel-bridge.mjs +162 -0
- package/dist/plugin/otel-bridge.mjs.map +1 -0
- package/dist/plugin/predictive-batcher.cjs +61 -0
- package/dist/plugin/predictive-batcher.cjs.map +1 -0
- package/dist/plugin/predictive-batcher.mjs +58 -0
- package/dist/plugin/predictive-batcher.mjs.map +1 -0
- package/dist/plugin/webview-bridge.cjs +83 -31
- package/dist/plugin/webview-bridge.mjs +83 -31
- package/dist/stats.cjs +148 -0
- package/dist/stats.cjs.map +1 -0
- package/dist/stats.mjs +145 -0
- package/dist/stats.mjs.map +1 -0
- package/dist/types/core/env.d.ts +2 -0
- package/dist/types/core/failed-queue.d.ts +19 -2
- package/dist/types/core/idle.d.ts +23 -0
- package/dist/types/core/payload-signer.d.ts +31 -0
- package/dist/types/core/pii.d.ts +46 -0
- package/dist/types/core/platform.d.ts +23 -0
- package/dist/types/core/privacy.d.ts +42 -0
- package/dist/types/core/replay.d.ts +41 -0
- package/dist/types/core/retry-policy.d.ts +11 -8
- package/dist/types/core/send-pipeline.d.ts +5 -1
- package/dist/types/core/stats.d.ts +77 -0
- package/dist/types/core/tracker.d.ts +7 -1
- package/dist/types/core/wasm-crypto.d.ts +28 -0
- package/dist/types/edge/index.d.ts +41 -0
- package/dist/types/federation.d.ts +34 -0
- package/dist/types/index.d.ts +42 -1
- package/dist/types/plugins/audience-sync/index.d.ts +67 -0
- package/dist/types/plugins/cross-domain/index.d.ts +20 -0
- package/dist/types/plugins/csp-compliant/index.d.ts +17 -0
- package/dist/types/plugins/experiment/index.d.ts +43 -0
- package/dist/types/plugins/otel-bridge/index.d.ts +22 -0
- package/dist/types/plugins/otel-exporter/index.d.ts +50 -0
- package/dist/types/plugins/pii-detector/index.d.ts +8 -0
- package/dist/types/plugins/predictive-batcher/index.d.ts +29 -0
- package/dist/types/plugins/privacy/index.d.ts +19 -0
- package/dist/types/plugins/rate-limiter/index.d.ts +41 -0
- package/dist/types/plugins/schema-registry/index.d.ts +41 -0
- package/dist/types/plugins/webview-bridge/index.d.ts +33 -9
- package/dist/types/send/ajax-sender.d.ts +6 -1
- package/dist/types/send/batch-sender.d.ts +12 -1
- package/dist/types/send/encode.d.ts +13 -1
- package/dist/types/send/offscreen-sender.d.ts +25 -0
- package/dist/types/send/sender.d.ts +20 -3
- package/dist/types/send/ws-sender.d.ts +38 -0
- package/dist/types/types/config.d.ts +17 -1
- package/dist/types/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/types/types.test-d.d.ts +0 -5
- package/dist/types.test-d.ts +0 -103
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Predictive Batching(v1.2.0)
|
|
5
|
+
*
|
|
6
|
+
* - 监听 user activity(click/scroll/keypress/mousemove 节流)
|
|
7
|
+
* - 高活动期:缩短 batch flush 间隔
|
|
8
|
+
* - 低活动期:拉长间隔,省电 / 省流量
|
|
9
|
+
* - 通过 SDK config.batch_send.dynamic_interval 启用
|
|
10
|
+
*
|
|
11
|
+
* 不属于 SDK 强耦合:作为可选插件
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* 不修改 SDK 内部,而是提供一个工具函数 getInterval(opts)
|
|
15
|
+
* 业务侧在 BatchSender.flush interval 决策时调用
|
|
16
|
+
*/
|
|
17
|
+
function makeIntervalPredictor(opts) {
|
|
18
|
+
var _a, _b, _c, _d, _e;
|
|
19
|
+
if (opts === void 0) { opts = {}; }
|
|
20
|
+
var min = (_a = opts.minInterval) !== null && _a !== void 0 ? _a : 1000;
|
|
21
|
+
var max = (_b = opts.maxInterval) !== null && _b !== void 0 ? _b : 30000;
|
|
22
|
+
var winMs = (_c = opts.windowMs) !== null && _c !== void 0 ? _c : 5000;
|
|
23
|
+
var threshold = (_d = opts.activityThreshold) !== null && _d !== void 0 ? _d : 5;
|
|
24
|
+
var events = (_e = opts.events) !== null && _e !== void 0 ? _e : ['click', 'scroll', 'keypress'];
|
|
25
|
+
var counts = [];
|
|
26
|
+
if (typeof window !== 'undefined') {
|
|
27
|
+
var handler = function () {
|
|
28
|
+
var now = Date.now();
|
|
29
|
+
counts.push(now);
|
|
30
|
+
while (counts.length && now - counts[0] > winMs)
|
|
31
|
+
counts.shift();
|
|
32
|
+
};
|
|
33
|
+
for (var _i = 0, events_1 = events; _i < events_1.length; _i++) {
|
|
34
|
+
var e = events_1[_i];
|
|
35
|
+
window.addEventListener(e, handler, { passive: true });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return function () {
|
|
39
|
+
if (counts.length > threshold)
|
|
40
|
+
return min;
|
|
41
|
+
if (counts.length > 0)
|
|
42
|
+
return Math.round(min + (max - min) * (1 - counts.length / threshold));
|
|
43
|
+
return max;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function predictiveBatcher(opts) {
|
|
47
|
+
if (opts === void 0) { opts = {}; }
|
|
48
|
+
var predict = makeIntervalPredictor(opts);
|
|
49
|
+
return {
|
|
50
|
+
name: 'predictive-batcher',
|
|
51
|
+
install: function (_a) {
|
|
52
|
+
var config = _a.config;
|
|
53
|
+
// 把 dynamic_interval 计算器挂到 config(BatchSender 可选读取)
|
|
54
|
+
config.batch_send_predict = predict;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
exports.makeIntervalPredictor = makeIntervalPredictor;
|
|
60
|
+
exports.predictiveBatcher = predictiveBatcher;
|
|
61
|
+
//# sourceMappingURL=predictive-batcher.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predictive-batcher.cjs","sources":["../../src/plugins/predictive-batcher/index.ts"],"sourcesContent":["/**\n * Predictive Batching(v1.2.0)\n *\n * - 监听 user activity(click/scroll/keypress/mousemove 节流)\n * - 高活动期:缩短 batch flush 间隔\n * - 低活动期:拉长间隔,省电 / 省流量\n * - 通过 SDK config.batch_send.dynamic_interval 启用\n *\n * 不属于 SDK 强耦合:作为可选插件\n */\n\nimport type { Plugin } from '../../core/plugin.js';\n\nexport interface PredictiveBatchOptions {\n /** 最小间隔(活动期) */\n minInterval?: number;\n /** 最大间隔(静默期) */\n maxInterval?: number;\n /** 活动统计窗口(ms) */\n windowMs?: number;\n /** 活动阈值(窗口内事件 > 此数视为活动期) */\n activityThreshold?: number;\n /** 是否监听这些事件类型 */\n events?: ('click' | 'scroll' | 'keypress' | 'mousemove' | 'touchstart')[];\n}\n\n/**\n * 不修改 SDK 内部,而是提供一个工具函数 getInterval(opts)\n * 业务侧在 BatchSender.flush interval 决策时调用\n */\nexport function makeIntervalPredictor(opts: PredictiveBatchOptions = {}): () => number {\n const min = opts.minInterval ?? 1000;\n const max = opts.maxInterval ?? 30000;\n const winMs = opts.windowMs ?? 5000;\n const threshold = opts.activityThreshold ?? 5;\n const events = opts.events ?? ['click', 'scroll', 'keypress'];\n const counts: number[] = [];\n\n if (typeof window !== 'undefined') {\n const handler = () => {\n const now = Date.now();\n counts.push(now);\n while (counts.length && now - counts[0] > winMs) counts.shift();\n };\n for (const e of events) window.addEventListener(e, handler, { passive: true });\n }\n\n return () => {\n if (counts.length > threshold) return min;\n if (counts.length > 0) return Math.round(min + (max - min) * (1 - counts.length / threshold));\n return max;\n };\n}\n\nexport function predictiveBatcher(opts: PredictiveBatchOptions = {}): Plugin {\n const predict = makeIntervalPredictor(opts);\n return {\n name: 'predictive-batcher',\n install({ config }) {\n // 把 dynamic_interval 计算器挂到 config(BatchSender 可选读取)\n (config as unknown as { batch_send_predict?: () => number }).batch_send_predict = predict;\n },\n };\n}"],"names":[],"mappings":";;AAAA;;;;;;;;;AASG;AAiBH;;;AAGG;AACG,SAAU,qBAAqB,CAAC,IAAiC,EAAA;;AAAjC,IAAA,IAAA,IAAA,KAAA,MAAA,EAAA,EAAA,IAAA,GAAA,EAAiC,CAAA,CAAA;IACrE,IAAM,GAAG,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,IAAI;IACpC,IAAM,GAAG,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,KAAK;IACrC,IAAM,KAAK,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,QAAQ,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,IAAI;IACnC,IAAM,SAAS,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,iBAAiB,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,CAAC;AAC7C,IAAA,IAAM,MAAM,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,MAAM,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC7D,IAAM,MAAM,GAAa,EAAE;AAE3B,IAAA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;AACjC,QAAA,IAAM,OAAO,GAAG,YAAA;AACd,YAAA,IAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AACtB,YAAA,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;YAChB,OAAO,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK;gBAAE,MAAM,CAAC,KAAK,EAAE;AACjE,QAAA,CAAC;AACD,QAAA,KAAgB,UAAM,EAAN,QAAA,GAAA,MAAM,EAAN,EAAA,GAAA,QAAA,CAAA,MAAM,EAAN,EAAA,EAAM,EAAA;AAAjB,YAAA,IAAM,CAAC,GAAA,QAAA,CAAA,EAAA,CAAA;AAAY,YAAA,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAAC,QAAA;IACjF;IAEA,OAAO,YAAA;AACL,QAAA,IAAI,MAAM,CAAC,MAAM,GAAG,SAAS;AAAE,YAAA,OAAO,GAAG;AACzC,QAAA,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;AAC7F,QAAA,OAAO,GAAG;AACZ,IAAA,CAAC;AACH;AAEM,SAAU,iBAAiB,CAAC,IAAiC,EAAA;AAAjC,IAAA,IAAA,IAAA,KAAA,MAAA,EAAA,EAAA,IAAA,GAAA,EAAiC,CAAA,CAAA;AACjE,IAAA,IAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC;IAC3C,OAAO;AACL,QAAA,IAAI,EAAE,oBAAoB;AAC1B,QAAA,OAAO,YAAC,EAAU,EAAA;AAAR,YAAA,IAAA,MAAM,GAAA,EAAA,CAAA,MAAA;;AAEb,YAAA,MAA2D,CAAC,kBAAkB,GAAG,OAAO;QAC3F,CAAC;KACF;AACH;;;;;"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predictive Batching(v1.2.0)
|
|
3
|
+
*
|
|
4
|
+
* - 监听 user activity(click/scroll/keypress/mousemove 节流)
|
|
5
|
+
* - 高活动期:缩短 batch flush 间隔
|
|
6
|
+
* - 低活动期:拉长间隔,省电 / 省流量
|
|
7
|
+
* - 通过 SDK config.batch_send.dynamic_interval 启用
|
|
8
|
+
*
|
|
9
|
+
* 不属于 SDK 强耦合:作为可选插件
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* 不修改 SDK 内部,而是提供一个工具函数 getInterval(opts)
|
|
13
|
+
* 业务侧在 BatchSender.flush interval 决策时调用
|
|
14
|
+
*/
|
|
15
|
+
function makeIntervalPredictor(opts) {
|
|
16
|
+
var _a, _b, _c, _d, _e;
|
|
17
|
+
if (opts === void 0) { opts = {}; }
|
|
18
|
+
var min = (_a = opts.minInterval) !== null && _a !== void 0 ? _a : 1000;
|
|
19
|
+
var max = (_b = opts.maxInterval) !== null && _b !== void 0 ? _b : 30000;
|
|
20
|
+
var winMs = (_c = opts.windowMs) !== null && _c !== void 0 ? _c : 5000;
|
|
21
|
+
var threshold = (_d = opts.activityThreshold) !== null && _d !== void 0 ? _d : 5;
|
|
22
|
+
var events = (_e = opts.events) !== null && _e !== void 0 ? _e : ['click', 'scroll', 'keypress'];
|
|
23
|
+
var counts = [];
|
|
24
|
+
if (typeof window !== 'undefined') {
|
|
25
|
+
var handler = function () {
|
|
26
|
+
var now = Date.now();
|
|
27
|
+
counts.push(now);
|
|
28
|
+
while (counts.length && now - counts[0] > winMs)
|
|
29
|
+
counts.shift();
|
|
30
|
+
};
|
|
31
|
+
for (var _i = 0, events_1 = events; _i < events_1.length; _i++) {
|
|
32
|
+
var e = events_1[_i];
|
|
33
|
+
window.addEventListener(e, handler, { passive: true });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return function () {
|
|
37
|
+
if (counts.length > threshold)
|
|
38
|
+
return min;
|
|
39
|
+
if (counts.length > 0)
|
|
40
|
+
return Math.round(min + (max - min) * (1 - counts.length / threshold));
|
|
41
|
+
return max;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function predictiveBatcher(opts) {
|
|
45
|
+
if (opts === void 0) { opts = {}; }
|
|
46
|
+
var predict = makeIntervalPredictor(opts);
|
|
47
|
+
return {
|
|
48
|
+
name: 'predictive-batcher',
|
|
49
|
+
install: function (_a) {
|
|
50
|
+
var config = _a.config;
|
|
51
|
+
// 把 dynamic_interval 计算器挂到 config(BatchSender 可选读取)
|
|
52
|
+
config.batch_send_predict = predict;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { makeIntervalPredictor, predictiveBatcher };
|
|
58
|
+
//# sourceMappingURL=predictive-batcher.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predictive-batcher.mjs","sources":["../../src/plugins/predictive-batcher/index.ts"],"sourcesContent":["/**\n * Predictive Batching(v1.2.0)\n *\n * - 监听 user activity(click/scroll/keypress/mousemove 节流)\n * - 高活动期:缩短 batch flush 间隔\n * - 低活动期:拉长间隔,省电 / 省流量\n * - 通过 SDK config.batch_send.dynamic_interval 启用\n *\n * 不属于 SDK 强耦合:作为可选插件\n */\n\nimport type { Plugin } from '../../core/plugin.js';\n\nexport interface PredictiveBatchOptions {\n /** 最小间隔(活动期) */\n minInterval?: number;\n /** 最大间隔(静默期) */\n maxInterval?: number;\n /** 活动统计窗口(ms) */\n windowMs?: number;\n /** 活动阈值(窗口内事件 > 此数视为活动期) */\n activityThreshold?: number;\n /** 是否监听这些事件类型 */\n events?: ('click' | 'scroll' | 'keypress' | 'mousemove' | 'touchstart')[];\n}\n\n/**\n * 不修改 SDK 内部,而是提供一个工具函数 getInterval(opts)\n * 业务侧在 BatchSender.flush interval 决策时调用\n */\nexport function makeIntervalPredictor(opts: PredictiveBatchOptions = {}): () => number {\n const min = opts.minInterval ?? 1000;\n const max = opts.maxInterval ?? 30000;\n const winMs = opts.windowMs ?? 5000;\n const threshold = opts.activityThreshold ?? 5;\n const events = opts.events ?? ['click', 'scroll', 'keypress'];\n const counts: number[] = [];\n\n if (typeof window !== 'undefined') {\n const handler = () => {\n const now = Date.now();\n counts.push(now);\n while (counts.length && now - counts[0] > winMs) counts.shift();\n };\n for (const e of events) window.addEventListener(e, handler, { passive: true });\n }\n\n return () => {\n if (counts.length > threshold) return min;\n if (counts.length > 0) return Math.round(min + (max - min) * (1 - counts.length / threshold));\n return max;\n };\n}\n\nexport function predictiveBatcher(opts: PredictiveBatchOptions = {}): Plugin {\n const predict = makeIntervalPredictor(opts);\n return {\n name: 'predictive-batcher',\n install({ config }) {\n // 把 dynamic_interval 计算器挂到 config(BatchSender 可选读取)\n (config as unknown as { batch_send_predict?: () => number }).batch_send_predict = predict;\n },\n };\n}"],"names":[],"mappings":"AAAA;;;;;;;;;AASG;AAiBH;;;AAGG;AACG,SAAU,qBAAqB,CAAC,IAAiC,EAAA;;AAAjC,IAAA,IAAA,IAAA,KAAA,MAAA,EAAA,EAAA,IAAA,GAAA,EAAiC,CAAA,CAAA;IACrE,IAAM,GAAG,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,IAAI;IACpC,IAAM,GAAG,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,KAAK;IACrC,IAAM,KAAK,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,QAAQ,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,IAAI;IACnC,IAAM,SAAS,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,iBAAiB,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,CAAC;AAC7C,IAAA,IAAM,MAAM,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,MAAM,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC7D,IAAM,MAAM,GAAa,EAAE;AAE3B,IAAA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;AACjC,QAAA,IAAM,OAAO,GAAG,YAAA;AACd,YAAA,IAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AACtB,YAAA,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;YAChB,OAAO,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK;gBAAE,MAAM,CAAC,KAAK,EAAE;AACjE,QAAA,CAAC;AACD,QAAA,KAAgB,UAAM,EAAN,QAAA,GAAA,MAAM,EAAN,EAAA,GAAA,QAAA,CAAA,MAAM,EAAN,EAAA,EAAM,EAAA;AAAjB,YAAA,IAAM,CAAC,GAAA,QAAA,CAAA,EAAA,CAAA;AAAY,YAAA,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAAC,QAAA;IACjF;IAEA,OAAO,YAAA;AACL,QAAA,IAAI,MAAM,CAAC,MAAM,GAAG,SAAS;AAAE,YAAA,OAAO,GAAG;AACzC,QAAA,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;AAC7F,QAAA,OAAO,GAAG;AACZ,IAAA,CAAC;AACH;AAEM,SAAU,iBAAiB,CAAC,IAAiC,EAAA;AAAjC,IAAA,IAAA,IAAA,KAAA,MAAA,EAAA,EAAA,IAAA,GAAA,EAAiC,CAAA,CAAA;AACjE,IAAA,IAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC;IAC3C,OAAO;AACL,QAAA,IAAI,EAAE,oBAAoB;AAC1B,QAAA,OAAO,YAAC,EAAU,EAAA;AAAR,YAAA,IAAA,MAAM,GAAA,EAAA,CAAA,MAAA;;AAEb,YAAA,MAA2D,CAAC,kBAAkB,GAAG,OAAO;QAC3F,CAAC;KACF;AACH;;;;"}
|
|
@@ -40,22 +40,29 @@ function isBrowser() {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* WebView 桥(
|
|
44
|
-
* - 客户端(iOS/Android)注入 window.vapph5define 对象
|
|
45
|
-
* - H5 通过 vapph5define.call(name, args) 调用客户端方法
|
|
46
|
-
* - 客户端通过 vapph5define.handle(name, fn) 监听 H5 调用
|
|
43
|
+
* WebView 桥(v2 RPC)
|
|
47
44
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
45
|
+
* v1: vapph5define.call(name, args) 同步返回,缺点:
|
|
46
|
+
* - 没法 timeout
|
|
47
|
+
* - 没法传 callback-style
|
|
48
|
+
* - 没法识别 native async
|
|
49
|
+
*
|
|
50
|
+
* v2:
|
|
51
|
+
* - RPC 协议:call(name, args, cbId) → native 通过 vapph5define.rpc.response(cbId, result)
|
|
52
|
+
* - 自动超时(默认 5s)→ reject
|
|
53
|
+
* - 自动探测:window.vapph5define.rpc / window.vapph5define.call 任一可用
|
|
54
|
+
* - SDK 暴露 sdk.bridge.callAsync(name, args) 返回 Promise
|
|
55
|
+
* - 兼容旧 sdk.bridge.call(name, args)
|
|
56
|
+
* - install 时 fetch app info 可 await
|
|
53
57
|
*/
|
|
54
58
|
function webviewBridge(opts) {
|
|
55
59
|
if (opts === void 0) { opts = {}; }
|
|
60
|
+
var rpcCbSeq = 0;
|
|
61
|
+
var rpcPending = new Map();
|
|
56
62
|
return {
|
|
57
63
|
name: 'webview-bridge',
|
|
58
64
|
install: function (_a) {
|
|
65
|
+
var _b;
|
|
59
66
|
var sdk = _a.sdk, config = _a.config;
|
|
60
67
|
if (!isBrowser())
|
|
61
68
|
return;
|
|
@@ -65,7 +72,54 @@ function webviewBridge(opts) {
|
|
|
65
72
|
if (!define || typeof define.call !== 'function') {
|
|
66
73
|
return; // 不在 WebView 中
|
|
67
74
|
}
|
|
68
|
-
|
|
75
|
+
var timeout = (_b = opts.timeout) !== null && _b !== void 0 ? _b : 5000;
|
|
76
|
+
var callAsync = function (name, args, timeoutMs) {
|
|
77
|
+
return new Promise(function (resolve, reject) {
|
|
78
|
+
// 优先用 v2 rpc
|
|
79
|
+
if (define.rpc && typeof define.rpc.call === 'function') {
|
|
80
|
+
var cbId_1 = "rpc_".concat(++rpcCbSeq, "_").concat(Date.now());
|
|
81
|
+
var t = setTimeout(function () {
|
|
82
|
+
rpcPending.delete(cbId_1);
|
|
83
|
+
reject(new Error("[WebViewBridge] RPC '".concat(name, "' timeout after ").concat(timeoutMs !== null && timeoutMs !== void 0 ? timeoutMs : timeout, "ms")));
|
|
84
|
+
}, timeoutMs !== null && timeoutMs !== void 0 ? timeoutMs : timeout);
|
|
85
|
+
rpcPending.set(cbId_1, { resolve: resolve, reject: reject, timer: t });
|
|
86
|
+
try {
|
|
87
|
+
define.rpc.call(name, cbId_1, args);
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
clearTimeout(t);
|
|
91
|
+
rpcPending.delete(cbId_1);
|
|
92
|
+
reject(e);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// fallback v1:同步转异步
|
|
97
|
+
try {
|
|
98
|
+
var r = define.call(name, args);
|
|
99
|
+
resolve(r);
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
reject(e);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
// 注册 v2 rpc response 监听
|
|
108
|
+
if (define.rpc && typeof define.rpc.response === 'function') {
|
|
109
|
+
define.handle('rpc.response', function (cbId, result, err) {
|
|
110
|
+
if (typeof cbId !== 'string')
|
|
111
|
+
return;
|
|
112
|
+
var p = rpcPending.get(cbId);
|
|
113
|
+
if (!p)
|
|
114
|
+
return;
|
|
115
|
+
rpcPending.delete(cbId);
|
|
116
|
+
clearTimeout(p.timer);
|
|
117
|
+
if (err)
|
|
118
|
+
p.reject(new Error(String(err)));
|
|
119
|
+
else
|
|
120
|
+
p.resolve(result);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
69
123
|
var bridge = {
|
|
70
124
|
call: function (name) {
|
|
71
125
|
var args = [];
|
|
@@ -74,35 +128,33 @@ function webviewBridge(opts) {
|
|
|
74
128
|
}
|
|
75
129
|
return define.call.apply(define, __spreadArray([name], args, false));
|
|
76
130
|
},
|
|
131
|
+
callAsync: callAsync,
|
|
77
132
|
on: function (name, fn) { return define.handle(name, fn); },
|
|
78
133
|
isInApp: function () { return define.isInApp === true || define.call('isInApp') === true; },
|
|
79
134
|
};
|
|
80
135
|
sdk.bridge = bridge;
|
|
81
136
|
config.is_webview = true;
|
|
82
137
|
if (opts.fetchOnInit !== false) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (result
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
138
|
+
// 用 callAsync(支持 v2 rpc + v1 同步),避免阻塞 install
|
|
139
|
+
var protocolName = opts.protocolName || 'getAppInfo';
|
|
140
|
+
void callAsync(protocolName).then(function (result) {
|
|
141
|
+
if (!result || typeof result !== 'object')
|
|
142
|
+
return;
|
|
143
|
+
var fm = opts.fieldMap || {};
|
|
144
|
+
for (var _i = 0, _a = Object.entries(fm); _i < _a.length; _i++) {
|
|
145
|
+
var _b = _a[_i], sdkKey = _b[0], resultKey = _b[1];
|
|
146
|
+
var v = result[resultKey];
|
|
147
|
+
if (v !== undefined && v !== null) {
|
|
148
|
+
config[sdkKey] = v;
|
|
94
149
|
}
|
|
95
|
-
sdk.register({
|
|
96
|
-
$app_version: result.app_version || result.appVersion,
|
|
97
|
-
$app_id: result.app_id || result.appId,
|
|
98
|
-
$channel: result.channel,
|
|
99
|
-
$lib: result.lib || result.lib_name || result.libName,
|
|
100
|
-
});
|
|
101
150
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
151
|
+
sdk.register({
|
|
152
|
+
$app_version: result.app_version || result.appVersion,
|
|
153
|
+
$app_id: result.app_id || result.appId,
|
|
154
|
+
$channel: result.channel,
|
|
155
|
+
$lib: result.lib || result.lib_name || result.libName,
|
|
156
|
+
});
|
|
157
|
+
}).catch(function () { });
|
|
106
158
|
}
|
|
107
159
|
},
|
|
108
160
|
};
|
|
@@ -38,22 +38,29 @@ function isBrowser() {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* WebView 桥(
|
|
42
|
-
* - 客户端(iOS/Android)注入 window.vapph5define 对象
|
|
43
|
-
* - H5 通过 vapph5define.call(name, args) 调用客户端方法
|
|
44
|
-
* - 客户端通过 vapph5define.handle(name, fn) 监听 H5 调用
|
|
41
|
+
* WebView 桥(v2 RPC)
|
|
45
42
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
43
|
+
* v1: vapph5define.call(name, args) 同步返回,缺点:
|
|
44
|
+
* - 没法 timeout
|
|
45
|
+
* - 没法传 callback-style
|
|
46
|
+
* - 没法识别 native async
|
|
47
|
+
*
|
|
48
|
+
* v2:
|
|
49
|
+
* - RPC 协议:call(name, args, cbId) → native 通过 vapph5define.rpc.response(cbId, result)
|
|
50
|
+
* - 自动超时(默认 5s)→ reject
|
|
51
|
+
* - 自动探测:window.vapph5define.rpc / window.vapph5define.call 任一可用
|
|
52
|
+
* - SDK 暴露 sdk.bridge.callAsync(name, args) 返回 Promise
|
|
53
|
+
* - 兼容旧 sdk.bridge.call(name, args)
|
|
54
|
+
* - install 时 fetch app info 可 await
|
|
51
55
|
*/
|
|
52
56
|
function webviewBridge(opts) {
|
|
53
57
|
if (opts === void 0) { opts = {}; }
|
|
58
|
+
var rpcCbSeq = 0;
|
|
59
|
+
var rpcPending = new Map();
|
|
54
60
|
return {
|
|
55
61
|
name: 'webview-bridge',
|
|
56
62
|
install: function (_a) {
|
|
63
|
+
var _b;
|
|
57
64
|
var sdk = _a.sdk, config = _a.config;
|
|
58
65
|
if (!isBrowser())
|
|
59
66
|
return;
|
|
@@ -63,7 +70,54 @@ function webviewBridge(opts) {
|
|
|
63
70
|
if (!define || typeof define.call !== 'function') {
|
|
64
71
|
return; // 不在 WebView 中
|
|
65
72
|
}
|
|
66
|
-
|
|
73
|
+
var timeout = (_b = opts.timeout) !== null && _b !== void 0 ? _b : 5000;
|
|
74
|
+
var callAsync = function (name, args, timeoutMs) {
|
|
75
|
+
return new Promise(function (resolve, reject) {
|
|
76
|
+
// 优先用 v2 rpc
|
|
77
|
+
if (define.rpc && typeof define.rpc.call === 'function') {
|
|
78
|
+
var cbId_1 = "rpc_".concat(++rpcCbSeq, "_").concat(Date.now());
|
|
79
|
+
var t = setTimeout(function () {
|
|
80
|
+
rpcPending.delete(cbId_1);
|
|
81
|
+
reject(new Error("[WebViewBridge] RPC '".concat(name, "' timeout after ").concat(timeoutMs !== null && timeoutMs !== void 0 ? timeoutMs : timeout, "ms")));
|
|
82
|
+
}, timeoutMs !== null && timeoutMs !== void 0 ? timeoutMs : timeout);
|
|
83
|
+
rpcPending.set(cbId_1, { resolve: resolve, reject: reject, timer: t });
|
|
84
|
+
try {
|
|
85
|
+
define.rpc.call(name, cbId_1, args);
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
clearTimeout(t);
|
|
89
|
+
rpcPending.delete(cbId_1);
|
|
90
|
+
reject(e);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// fallback v1:同步转异步
|
|
95
|
+
try {
|
|
96
|
+
var r = define.call(name, args);
|
|
97
|
+
resolve(r);
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
reject(e);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
// 注册 v2 rpc response 监听
|
|
106
|
+
if (define.rpc && typeof define.rpc.response === 'function') {
|
|
107
|
+
define.handle('rpc.response', function (cbId, result, err) {
|
|
108
|
+
if (typeof cbId !== 'string')
|
|
109
|
+
return;
|
|
110
|
+
var p = rpcPending.get(cbId);
|
|
111
|
+
if (!p)
|
|
112
|
+
return;
|
|
113
|
+
rpcPending.delete(cbId);
|
|
114
|
+
clearTimeout(p.timer);
|
|
115
|
+
if (err)
|
|
116
|
+
p.reject(new Error(String(err)));
|
|
117
|
+
else
|
|
118
|
+
p.resolve(result);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
67
121
|
var bridge = {
|
|
68
122
|
call: function (name) {
|
|
69
123
|
var args = [];
|
|
@@ -72,35 +126,33 @@ function webviewBridge(opts) {
|
|
|
72
126
|
}
|
|
73
127
|
return define.call.apply(define, __spreadArray([name], args, false));
|
|
74
128
|
},
|
|
129
|
+
callAsync: callAsync,
|
|
75
130
|
on: function (name, fn) { return define.handle(name, fn); },
|
|
76
131
|
isInApp: function () { return define.isInApp === true || define.call('isInApp') === true; },
|
|
77
132
|
};
|
|
78
133
|
sdk.bridge = bridge;
|
|
79
134
|
config.is_webview = true;
|
|
80
135
|
if (opts.fetchOnInit !== false) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (result
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
136
|
+
// 用 callAsync(支持 v2 rpc + v1 同步),避免阻塞 install
|
|
137
|
+
var protocolName = opts.protocolName || 'getAppInfo';
|
|
138
|
+
void callAsync(protocolName).then(function (result) {
|
|
139
|
+
if (!result || typeof result !== 'object')
|
|
140
|
+
return;
|
|
141
|
+
var fm = opts.fieldMap || {};
|
|
142
|
+
for (var _i = 0, _a = Object.entries(fm); _i < _a.length; _i++) {
|
|
143
|
+
var _b = _a[_i], sdkKey = _b[0], resultKey = _b[1];
|
|
144
|
+
var v = result[resultKey];
|
|
145
|
+
if (v !== undefined && v !== null) {
|
|
146
|
+
config[sdkKey] = v;
|
|
92
147
|
}
|
|
93
|
-
sdk.register({
|
|
94
|
-
$app_version: result.app_version || result.appVersion,
|
|
95
|
-
$app_id: result.app_id || result.appId,
|
|
96
|
-
$channel: result.channel,
|
|
97
|
-
$lib: result.lib || result.lib_name || result.libName,
|
|
98
|
-
});
|
|
99
148
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
149
|
+
sdk.register({
|
|
150
|
+
$app_version: result.app_version || result.appVersion,
|
|
151
|
+
$app_id: result.app_id || result.appId,
|
|
152
|
+
$channel: result.channel,
|
|
153
|
+
$lib: result.lib || result.lib_name || result.libName,
|
|
154
|
+
});
|
|
155
|
+
}).catch(function () { });
|
|
104
156
|
}
|
|
105
157
|
},
|
|
106
158
|
};
|
package/dist/stats.cjs
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/******************************************************************************
|
|
4
|
+
Copyright (c) Microsoft Corporation.
|
|
5
|
+
|
|
6
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
7
|
+
purpose with or without fee is hereby granted.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
***************************************************************************** */
|
|
17
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
var __assign = function() {
|
|
21
|
+
__assign = Object.assign || function __assign(t) {
|
|
22
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
23
|
+
s = arguments[i];
|
|
24
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
|
25
|
+
}
|
|
26
|
+
return t;
|
|
27
|
+
};
|
|
28
|
+
return __assign.apply(this, arguments);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
32
|
+
var e = new Error(message);
|
|
33
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Sender 失败统计(v1.2.0)
|
|
38
|
+
*
|
|
39
|
+
* - 每个 sender 维护 attempts / success / failure / total_duration
|
|
40
|
+
* - SDK 全局汇总
|
|
41
|
+
* - 用户可 sdk.getStats() 查
|
|
42
|
+
* - 自动每 60s 输出到 console(debug 模式)
|
|
43
|
+
*/
|
|
44
|
+
var StatsCollector = /** @class */ (function () {
|
|
45
|
+
function StatsCollector() {
|
|
46
|
+
this.total = 0;
|
|
47
|
+
this.success = 0;
|
|
48
|
+
this.failure = 0;
|
|
49
|
+
this.retry = 0;
|
|
50
|
+
this.in_flight = 0;
|
|
51
|
+
this.flushCount = 0;
|
|
52
|
+
this.bySender = new Map();
|
|
53
|
+
}
|
|
54
|
+
/** 记录一次发送开始 */
|
|
55
|
+
StatsCollector.prototype.recordStart = function (senderName) {
|
|
56
|
+
this.total++;
|
|
57
|
+
this.in_flight++;
|
|
58
|
+
var s = this.getOrCreate(senderName);
|
|
59
|
+
s.attempts++;
|
|
60
|
+
return Date.now();
|
|
61
|
+
};
|
|
62
|
+
/** 记录一次发送成功 */
|
|
63
|
+
StatsCollector.prototype.recordSuccess = function (senderName, startTs) {
|
|
64
|
+
this.success++;
|
|
65
|
+
this.in_flight = Math.max(0, this.in_flight - 1);
|
|
66
|
+
var s = this.getOrCreate(senderName);
|
|
67
|
+
var dur = Date.now() - startTs;
|
|
68
|
+
s.total_duration += dur;
|
|
69
|
+
s.avg_duration = s.total_duration / s.attempts;
|
|
70
|
+
if (dur > s.max_duration)
|
|
71
|
+
s.max_duration = dur;
|
|
72
|
+
};
|
|
73
|
+
/** 记录一次发送失败 */
|
|
74
|
+
StatsCollector.prototype.recordFailure = function (senderName, startTs, err) {
|
|
75
|
+
this.failure++;
|
|
76
|
+
this.in_flight = Math.max(0, this.in_flight - 1);
|
|
77
|
+
var s = this.getOrCreate(senderName);
|
|
78
|
+
s.failure++;
|
|
79
|
+
s.last_error = err.message;
|
|
80
|
+
s.last_error_at = Date.now();
|
|
81
|
+
};
|
|
82
|
+
/** 记录一次重试 */
|
|
83
|
+
StatsCollector.prototype.recordRetry = function () {
|
|
84
|
+
this.retry++;
|
|
85
|
+
};
|
|
86
|
+
/** 记录一次 flush */
|
|
87
|
+
StatsCollector.prototype.recordFlush = function () {
|
|
88
|
+
this.flushCount++;
|
|
89
|
+
this.lastFlushAt = Date.now();
|
|
90
|
+
};
|
|
91
|
+
/** 拍快照 */
|
|
92
|
+
StatsCollector.prototype.snapshot = function () {
|
|
93
|
+
var by_sender = {};
|
|
94
|
+
for (var _i = 0, _a = this.bySender; _i < _a.length; _i++) {
|
|
95
|
+
var _b = _a[_i], k = _b[0], v = _b[1];
|
|
96
|
+
by_sender[k] = __assign({}, v);
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
total: this.total,
|
|
100
|
+
success: this.success,
|
|
101
|
+
failure: this.failure,
|
|
102
|
+
retry: this.retry,
|
|
103
|
+
in_flight: this.in_flight,
|
|
104
|
+
flush_count: this.flushCount,
|
|
105
|
+
last_flush_at: this.lastFlushAt,
|
|
106
|
+
by_sender: by_sender,
|
|
107
|
+
taken_at: Date.now(),
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
/** 重置 */
|
|
111
|
+
StatsCollector.prototype.reset = function () {
|
|
112
|
+
this.total = 0;
|
|
113
|
+
this.success = 0;
|
|
114
|
+
this.failure = 0;
|
|
115
|
+
this.retry = 0;
|
|
116
|
+
this.in_flight = 0;
|
|
117
|
+
this.flushCount = 0;
|
|
118
|
+
this.lastFlushAt = undefined;
|
|
119
|
+
this.bySender.clear();
|
|
120
|
+
};
|
|
121
|
+
/** 列出所有 sender 名 */
|
|
122
|
+
StatsCollector.prototype.listSenders = function () {
|
|
123
|
+
return Array.from(this.bySender.keys());
|
|
124
|
+
};
|
|
125
|
+
StatsCollector.prototype.getOrCreate = function (name) {
|
|
126
|
+
var s = this.bySender.get(name);
|
|
127
|
+
if (!s) {
|
|
128
|
+
s = {
|
|
129
|
+
name: name,
|
|
130
|
+
attempts: 0,
|
|
131
|
+
success: 0,
|
|
132
|
+
failure: 0,
|
|
133
|
+
total_duration: 0,
|
|
134
|
+
avg_duration: 0,
|
|
135
|
+
max_duration: 0,
|
|
136
|
+
};
|
|
137
|
+
this.bySender.set(name, s);
|
|
138
|
+
}
|
|
139
|
+
return s;
|
|
140
|
+
};
|
|
141
|
+
return StatsCollector;
|
|
142
|
+
}());
|
|
143
|
+
/** 全局单例 */
|
|
144
|
+
var GLOBAL_STATS = new StatsCollector();
|
|
145
|
+
|
|
146
|
+
exports.GLOBAL_STATS = GLOBAL_STATS;
|
|
147
|
+
exports.StatsCollector = StatsCollector;
|
|
148
|
+
//# sourceMappingURL=stats.cjs.map
|