@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.
Files changed (69) hide show
  1. package/dist/event-tracker.cjs +4252 -879
  2. package/dist/event-tracker.cjs.map +1 -0
  3. package/dist/event-tracker.js +4252 -879
  4. package/dist/event-tracker.js.map +1 -0
  5. package/dist/event-tracker.min.js +2 -1
  6. package/dist/event-tracker.min.js.map +1 -0
  7. package/dist/event-tracker.mjs +4212 -880
  8. package/dist/event-tracker.mjs.map +1 -0
  9. package/dist/plugin/debug-sender.cjs +53 -2
  10. package/dist/plugin/debug-sender.mjs +53 -2
  11. package/dist/plugin/experiment.cjs +181 -0
  12. package/dist/plugin/experiment.cjs.map +1 -0
  13. package/dist/plugin/experiment.mjs +178 -0
  14. package/dist/plugin/experiment.mjs.map +1 -0
  15. package/dist/plugin/indexeddb-sender.cjs +51 -2
  16. package/dist/plugin/indexeddb-sender.mjs +51 -2
  17. package/dist/plugin/otel-bridge.cjs +164 -0
  18. package/dist/plugin/otel-bridge.cjs.map +1 -0
  19. package/dist/plugin/otel-bridge.mjs +162 -0
  20. package/dist/plugin/otel-bridge.mjs.map +1 -0
  21. package/dist/plugin/predictive-batcher.cjs +61 -0
  22. package/dist/plugin/predictive-batcher.cjs.map +1 -0
  23. package/dist/plugin/predictive-batcher.mjs +58 -0
  24. package/dist/plugin/predictive-batcher.mjs.map +1 -0
  25. package/dist/plugin/webview-bridge.cjs +83 -31
  26. package/dist/plugin/webview-bridge.mjs +83 -31
  27. package/dist/stats.cjs +148 -0
  28. package/dist/stats.cjs.map +1 -0
  29. package/dist/stats.mjs +145 -0
  30. package/dist/stats.mjs.map +1 -0
  31. package/dist/types/core/env.d.ts +2 -0
  32. package/dist/types/core/failed-queue.d.ts +19 -2
  33. package/dist/types/core/idle.d.ts +23 -0
  34. package/dist/types/core/payload-signer.d.ts +31 -0
  35. package/dist/types/core/pii.d.ts +46 -0
  36. package/dist/types/core/platform.d.ts +23 -0
  37. package/dist/types/core/privacy.d.ts +42 -0
  38. package/dist/types/core/replay.d.ts +41 -0
  39. package/dist/types/core/retry-policy.d.ts +11 -8
  40. package/dist/types/core/send-pipeline.d.ts +5 -1
  41. package/dist/types/core/stats.d.ts +77 -0
  42. package/dist/types/core/tracker.d.ts +7 -1
  43. package/dist/types/core/wasm-crypto.d.ts +28 -0
  44. package/dist/types/edge/index.d.ts +41 -0
  45. package/dist/types/federation.d.ts +34 -0
  46. package/dist/types/index.d.ts +42 -1
  47. package/dist/types/plugins/audience-sync/index.d.ts +67 -0
  48. package/dist/types/plugins/cross-domain/index.d.ts +20 -0
  49. package/dist/types/plugins/csp-compliant/index.d.ts +17 -0
  50. package/dist/types/plugins/experiment/index.d.ts +43 -0
  51. package/dist/types/plugins/otel-bridge/index.d.ts +22 -0
  52. package/dist/types/plugins/otel-exporter/index.d.ts +50 -0
  53. package/dist/types/plugins/pii-detector/index.d.ts +8 -0
  54. package/dist/types/plugins/predictive-batcher/index.d.ts +29 -0
  55. package/dist/types/plugins/privacy/index.d.ts +19 -0
  56. package/dist/types/plugins/rate-limiter/index.d.ts +41 -0
  57. package/dist/types/plugins/schema-registry/index.d.ts +41 -0
  58. package/dist/types/plugins/webview-bridge/index.d.ts +33 -9
  59. package/dist/types/send/ajax-sender.d.ts +6 -1
  60. package/dist/types/send/batch-sender.d.ts +12 -1
  61. package/dist/types/send/encode.d.ts +13 -1
  62. package/dist/types/send/offscreen-sender.d.ts +25 -0
  63. package/dist/types/send/sender.d.ts +20 -3
  64. package/dist/types/send/ws-sender.d.ts +38 -0
  65. package/dist/types/types/config.d.ts +17 -1
  66. package/dist/types/types/index.d.ts +1 -1
  67. package/package.json +1 -1
  68. package/dist/types/types.test-d.d.ts +0 -5
  69. 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 桥(vapph5 协议)
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
- * 1. 探测 WebView 标识
50
- * 2. SDK 启动时调用 vapph5define.call('getAppInfo'),把 app_version/app_id/...
51
- * 注入到 config 与公共属性
52
- * 3. 暴露 helper:bridge.call(name, args) 与 bridge.on(name, fn)
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
- // 暴露 SDK 内部调用的便捷方法
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
- try {
84
- var protocolName = opts.protocolName || 'getAppInfo';
85
- var result = define.call(protocolName);
86
- if (result && typeof result === 'object') {
87
- var fm = opts.fieldMap || {};
88
- for (var _i = 0, _b = Object.entries(fm); _i < _b.length; _i++) {
89
- var _c = _b[_i], sdkKey = _c[0], resultKey = _c[1];
90
- var v = result[resultKey];
91
- if (v !== undefined && v !== null) {
92
- config[sdkKey] = v;
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
- catch (_d) {
104
- /* ignore */
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 桥(vapph5 协议)
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
- * 1. 探测 WebView 标识
48
- * 2. SDK 启动时调用 vapph5define.call('getAppInfo'),把 app_version/app_id/...
49
- * 注入到 config 与公共属性
50
- * 3. 暴露 helper:bridge.call(name, args) 与 bridge.on(name, fn)
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
- // 暴露 SDK 内部调用的便捷方法
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
- try {
82
- var protocolName = opts.protocolName || 'getAppInfo';
83
- var result = define.call(protocolName);
84
- if (result && typeof result === 'object') {
85
- var fm = opts.fieldMap || {};
86
- for (var _i = 0, _b = Object.entries(fm); _i < _b.length; _i++) {
87
- var _c = _b[_i], sdkKey = _c[0], resultKey = _c[1];
88
- var v = result[resultKey];
89
- if (v !== undefined && v !== null) {
90
- config[sdkKey] = v;
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
- catch (_d) {
102
- /* ignore */
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