@pluve/logger-sdk 0.0.3 → 0.0.5

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.
@@ -0,0 +1,201 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
4
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
5
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
7
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
8
+ /*
9
+ * @Author : 黄震 huangzhen@yfpharmacy.com
10
+ * @Date : 2025-12-18
11
+ * @LastEditors : 黄震 huangzhen@yfpharmacy.com
12
+ * @LastEditTime : 2025-12-18
13
+ * @Description : 队列管理器 - 支持内存队列和持久化存储
14
+ * Copyright (c) 2025 by 益丰大药房连锁股份有限公司, All Rights Reserved.
15
+ */
16
+
17
+ import { isBrowser, isWeChatMiniProgram, safeStringify } from "./utils";
18
+
19
+ /** 队列配置选项 */
20
+
21
+ /**
22
+ * 队列管理器
23
+ * - 内存队列:快速访问
24
+ * - 持久化存储:防止页面刷新/关闭时数据丢失
25
+ */
26
+ export var QueueManager = /*#__PURE__*/function () {
27
+ function QueueManager(options) {
28
+ _classCallCheck(this, QueueManager);
29
+ _defineProperty(this, "queue", []);
30
+ _defineProperty(this, "opts", void 0);
31
+ _defineProperty(this, "storageKey", void 0);
32
+ this.opts = options;
33
+ this.storageKey = "".concat(options.storagePrefix, "_queue");
34
+
35
+ // 从持久化存储恢复队列
36
+ if (this.opts.enableStorage) {
37
+ this.loadFromStorage();
38
+ }
39
+ }
40
+
41
+ /**
42
+ * 添加日志到队列
43
+ */
44
+ _createClass(QueueManager, [{
45
+ key: "enqueue",
46
+ value: function enqueue(event) {
47
+ // 队列已满,丢弃最旧的日志
48
+ if (this.queue.length >= this.opts.maxSize) {
49
+ this.queue.shift();
50
+ this.logDebug('Queue full, dropped oldest event');
51
+ }
52
+ this.queue.push(event);
53
+ this.logDebug('Enqueued event', event.logId);
54
+
55
+ // 持久化到存储
56
+ if (this.opts.enableStorage) {
57
+ this.saveToStorage();
58
+ }
59
+ return true;
60
+ }
61
+
62
+ /**
63
+ * 批量获取日志(不移除)
64
+ */
65
+ }, {
66
+ key: "peek",
67
+ value: function peek(count) {
68
+ return this.queue.slice(0, count);
69
+ }
70
+
71
+ /**
72
+ * 批量移除日志
73
+ */
74
+ }, {
75
+ key: "dequeue",
76
+ value: function dequeue(count) {
77
+ var items = this.queue.splice(0, count);
78
+ this.logDebug("Dequeued ".concat(items.length, " events"));
79
+
80
+ // 更新持久化存储
81
+ if (this.opts.enableStorage) {
82
+ this.saveToStorage();
83
+ }
84
+ return items;
85
+ }
86
+
87
+ /**
88
+ * 获取队列长度
89
+ */
90
+ }, {
91
+ key: "size",
92
+ value: function size() {
93
+ return this.queue.length;
94
+ }
95
+
96
+ /**
97
+ * 清空队列
98
+ */
99
+ }, {
100
+ key: "clear",
101
+ value: function clear() {
102
+ this.queue = [];
103
+ this.logDebug('Queue cleared');
104
+ if (this.opts.enableStorage) {
105
+ this.removeFromStorage();
106
+ }
107
+ }
108
+
109
+ /**
110
+ * 从持久化存储加载队列
111
+ */
112
+ }, {
113
+ key: "loadFromStorage",
114
+ value: function loadFromStorage() {
115
+ try {
116
+ var stored = null;
117
+
118
+ // 微信小程序环境
119
+ if (isWeChatMiniProgram()) {
120
+ // @ts-ignore
121
+ stored = wx.getStorageSync(this.storageKey);
122
+ }
123
+ // 浏览器环境
124
+ else if (isBrowser() && typeof localStorage !== 'undefined') {
125
+ stored = localStorage.getItem(this.storageKey);
126
+ }
127
+ if (stored) {
128
+ var parsed = JSON.parse(stored);
129
+ if (Array.isArray(parsed)) {
130
+ this.queue = parsed.slice(0, this.opts.maxSize);
131
+ this.logDebug("Loaded ".concat(this.queue.length, " events from storage"));
132
+ }
133
+ }
134
+ } catch (error) {
135
+ this.logDebug('Failed to load queue from storage', error);
136
+ // 加载失败不影响运行,使用空队列
137
+ }
138
+ }
139
+
140
+ /**
141
+ * 保存队列到持久化存储
142
+ */
143
+ }, {
144
+ key: "saveToStorage",
145
+ value: function saveToStorage() {
146
+ try {
147
+ var data = safeStringify(this.queue);
148
+
149
+ // 微信小程序环境
150
+ if (isWeChatMiniProgram()) {
151
+ // @ts-ignore
152
+ wx.setStorageSync(this.storageKey, data);
153
+ }
154
+ // 浏览器环境
155
+ else if (isBrowser() && typeof localStorage !== 'undefined') {
156
+ localStorage.setItem(this.storageKey, data);
157
+ }
158
+ } catch (error) {
159
+ this.logDebug('Failed to save queue to storage', error);
160
+ // 保存失败不影响运行
161
+ }
162
+ }
163
+
164
+ /**
165
+ * 从持久化存储移除队列
166
+ */
167
+ }, {
168
+ key: "removeFromStorage",
169
+ value: function removeFromStorage() {
170
+ try {
171
+ // 微信小程序环境
172
+ if (isWeChatMiniProgram()) {
173
+ // @ts-ignore
174
+ wx.removeStorageSync(this.storageKey);
175
+ }
176
+ // 浏览器环境
177
+ else if (isBrowser() && typeof localStorage !== 'undefined') {
178
+ localStorage.removeItem(this.storageKey);
179
+ }
180
+ } catch (error) {
181
+ this.logDebug('Failed to remove queue from storage', error);
182
+ }
183
+ }
184
+
185
+ /**
186
+ * 调试日志
187
+ */
188
+ }, {
189
+ key: "logDebug",
190
+ value: function logDebug() {
191
+ if (this.opts.debug) {
192
+ var _console;
193
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
194
+ args[_key] = arguments[_key];
195
+ }
196
+ (_console = console).debug.apply(_console, ['[QueueManager]'].concat(args));
197
+ }
198
+ }
199
+ }]);
200
+ return QueueManager;
201
+ }();
@@ -0,0 +1,57 @@
1
+ /** 重试配置选项 */
2
+ export interface RetryOptions {
3
+ /** 最大重试次数 */
4
+ maxRetries: number;
5
+ /** 基础延迟时间(毫秒) */
6
+ baseDelay: number;
7
+ /** 是否使用指数退避策略 */
8
+ useBackoff: boolean;
9
+ /** 调试模式 */
10
+ debug?: boolean;
11
+ }
12
+ /**
13
+ * 重试管理器
14
+ * - 支持自定义重试次数
15
+ * - 支持指数退避策略(exponential backoff)
16
+ * - 防止重复重试同一任务
17
+ */
18
+ export declare class RetryManager {
19
+ private opts;
20
+ private retryingTasks;
21
+ constructor(options: RetryOptions);
22
+ /**
23
+ * 执行带重试的任务
24
+ * @param taskId - 任务唯一标识
25
+ * @param fn - 要执行的异步函数
26
+ * @returns Promise
27
+ */
28
+ executeWithRetry<T>(taskId: string, fn: () => Promise<T>): Promise<T>;
29
+ /**
30
+ * 执行任务(带重试逻辑)
31
+ */
32
+ private executeTask;
33
+ /**
34
+ * 计算延迟时间
35
+ * @param attempt - 当前重试次数
36
+ * @param baseDelay - 基础延迟时间
37
+ * @param useBackoff - 是否使用指数退避
38
+ * @returns 延迟时间(毫秒)
39
+ */
40
+ private calculateDelay;
41
+ /**
42
+ * 睡眠函数
43
+ */
44
+ private sleep;
45
+ /**
46
+ * 获取正在重试的任务数量
47
+ */
48
+ getRetryingCount(): number;
49
+ /**
50
+ * 清空所有重试任务
51
+ */
52
+ clear(): void;
53
+ /**
54
+ * 调试日志
55
+ */
56
+ private logDebug;
57
+ }
@@ -0,0 +1,223 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw new Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw new Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, catch: function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
3
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
4
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
5
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
7
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
8
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
9
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
10
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
11
+ /*
12
+ * @Author : 黄震 huangzhen@yfpharmacy.com
13
+ * @Date : 2025-12-18
14
+ * @LastEditors : 黄震 huangzhen@yfpharmacy.com
15
+ * @LastEditTime : 2025-12-18
16
+ * @Description : 重试管理器 - 支持指数退避策略
17
+ * Copyright (c) 2025 by 益丰大药房连锁股份有限公司, All Rights Reserved.
18
+ */
19
+
20
+ /** 重试配置选项 */
21
+
22
+ /** 重试任务 */
23
+
24
+ /**
25
+ * 重试管理器
26
+ * - 支持自定义重试次数
27
+ * - 支持指数退避策略(exponential backoff)
28
+ * - 防止重复重试同一任务
29
+ */
30
+ export var RetryManager = /*#__PURE__*/function () {
31
+ function RetryManager(options) {
32
+ _classCallCheck(this, RetryManager);
33
+ _defineProperty(this, "opts", void 0);
34
+ _defineProperty(this, "retryingTasks", new Map());
35
+ this.opts = options;
36
+ }
37
+
38
+ /**
39
+ * 执行带重试的任务
40
+ * @param taskId - 任务唯一标识
41
+ * @param fn - 要执行的异步函数
42
+ * @returns Promise
43
+ */
44
+ _createClass(RetryManager, [{
45
+ key: "executeWithRetry",
46
+ value: (function () {
47
+ var _executeWithRetry = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(taskId, fn) {
48
+ var task, result;
49
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
50
+ while (1) switch (_context.prev = _context.next) {
51
+ case 0:
52
+ if (!this.retryingTasks.has(taskId)) {
53
+ _context.next = 3;
54
+ break;
55
+ }
56
+ this.logDebug("Task ".concat(taskId, " already retrying, skipped"));
57
+ throw new Error("Task ".concat(taskId, " already retrying"));
58
+ case 3:
59
+ task = {
60
+ id: taskId,
61
+ fn: fn,
62
+ retries: 0,
63
+ maxRetries: this.opts.maxRetries,
64
+ baseDelay: this.opts.baseDelay,
65
+ useBackoff: this.opts.useBackoff
66
+ };
67
+ this.retryingTasks.set(taskId, task);
68
+ _context.prev = 5;
69
+ _context.next = 8;
70
+ return this.executeTask(task);
71
+ case 8:
72
+ result = _context.sent;
73
+ this.retryingTasks.delete(taskId);
74
+ return _context.abrupt("return", result);
75
+ case 13:
76
+ _context.prev = 13;
77
+ _context.t0 = _context["catch"](5);
78
+ this.retryingTasks.delete(taskId);
79
+ throw _context.t0;
80
+ case 17:
81
+ case "end":
82
+ return _context.stop();
83
+ }
84
+ }, _callee, this, [[5, 13]]);
85
+ }));
86
+ function executeWithRetry(_x, _x2) {
87
+ return _executeWithRetry.apply(this, arguments);
88
+ }
89
+ return executeWithRetry;
90
+ }()
91
+ /**
92
+ * 执行任务(带重试逻辑)
93
+ */
94
+ )
95
+ }, {
96
+ key: "executeTask",
97
+ value: (function () {
98
+ var _executeTask = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(task) {
99
+ var result, delay;
100
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
101
+ while (1) switch (_context2.prev = _context2.next) {
102
+ case 0:
103
+ if (!(task.retries <= task.maxRetries)) {
104
+ _context2.next = 21;
105
+ break;
106
+ }
107
+ _context2.prev = 1;
108
+ _context2.next = 4;
109
+ return task.fn();
110
+ case 4:
111
+ result = _context2.sent;
112
+ if (task.retries > 0) {
113
+ this.logDebug("Task ".concat(task.id, " succeeded after ").concat(task.retries, " retries"));
114
+ }
115
+ return _context2.abrupt("return", result);
116
+ case 9:
117
+ _context2.prev = 9;
118
+ _context2.t0 = _context2["catch"](1);
119
+ task.retries += 1;
120
+
121
+ // 达到最大重试次数
122
+ if (!(task.retries > task.maxRetries)) {
123
+ _context2.next = 15;
124
+ break;
125
+ }
126
+ this.logDebug("Task ".concat(task.id, " failed after ").concat(task.maxRetries, " retries"));
127
+ throw _context2.t0;
128
+ case 15:
129
+ // 计算延迟时间
130
+ delay = this.calculateDelay(task.retries, task.baseDelay, task.useBackoff);
131
+ this.logDebug("Task ".concat(task.id, " failed (attempt ").concat(task.retries, "/").concat(task.maxRetries, "), retrying in ").concat(delay, "ms"));
132
+
133
+ // 等待后重试
134
+ _context2.next = 19;
135
+ return this.sleep(delay);
136
+ case 19:
137
+ _context2.next = 0;
138
+ break;
139
+ case 21:
140
+ throw new Error("Task ".concat(task.id, " exceeded max retries"));
141
+ case 22:
142
+ case "end":
143
+ return _context2.stop();
144
+ }
145
+ }, _callee2, this, [[1, 9]]);
146
+ }));
147
+ function executeTask(_x3) {
148
+ return _executeTask.apply(this, arguments);
149
+ }
150
+ return executeTask;
151
+ }()
152
+ /**
153
+ * 计算延迟时间
154
+ * @param attempt - 当前重试次数
155
+ * @param baseDelay - 基础延迟时间
156
+ * @param useBackoff - 是否使用指数退避
157
+ * @returns 延迟时间(毫秒)
158
+ */
159
+ )
160
+ }, {
161
+ key: "calculateDelay",
162
+ value: function calculateDelay(attempt, baseDelay, useBackoff) {
163
+ if (!useBackoff) {
164
+ return baseDelay;
165
+ }
166
+
167
+ // 指数退避策略:baseDelay * 2^(attempt-1)
168
+ // 第1次重试:baseDelay * 2^0 = baseDelay
169
+ // 第2次重试:baseDelay * 2^1 = baseDelay * 2
170
+ // 第3次重试:baseDelay * 2^2 = baseDelay * 4
171
+ var delay = baseDelay * Math.pow(2, attempt - 1);
172
+
173
+ // 添加随机抖动,避免惊群效应(thundering herd)
174
+ var jitter = Math.random() * 0.3 * delay; // 0-30% 的随机抖动
175
+ return Math.min(delay + jitter, 30000); // 最大不超过 30 秒
176
+ }
177
+
178
+ /**
179
+ * 睡眠函数
180
+ */
181
+ }, {
182
+ key: "sleep",
183
+ value: function sleep(ms) {
184
+ return new Promise(function (resolve) {
185
+ return setTimeout(resolve, ms);
186
+ });
187
+ }
188
+
189
+ /**
190
+ * 获取正在重试的任务数量
191
+ */
192
+ }, {
193
+ key: "getRetryingCount",
194
+ value: function getRetryingCount() {
195
+ return this.retryingTasks.size;
196
+ }
197
+
198
+ /**
199
+ * 清空所有重试任务
200
+ */
201
+ }, {
202
+ key: "clear",
203
+ value: function clear() {
204
+ this.retryingTasks.clear();
205
+ }
206
+
207
+ /**
208
+ * 调试日志
209
+ */
210
+ }, {
211
+ key: "logDebug",
212
+ value: function logDebug() {
213
+ if (this.opts.debug) {
214
+ var _console;
215
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
216
+ args[_key] = arguments[_key];
217
+ }
218
+ (_console = console).debug.apply(_console, ['[RetryManager]'].concat(args));
219
+ }
220
+ }
221
+ }]);
222
+ return RetryManager;
223
+ }();
@@ -6,12 +6,12 @@ function _asyncToGenerator(fn) { return function () { var self = this, args = ar
6
6
  * @Author : 黄震 huangzhen@yfpharmacy.com
7
7
  * @Date : 2025-11-21 14:35:48
8
8
  * @LastEditors : 黄震 huangzhen@yfpharmacy.com
9
- * @LastEditTime : 2025-12-04 14:30:00
9
+ * @LastEditTime : 2025-12-04 22:00:00
10
10
  * @Description : 传输适配器 - Beacon、像素图和微信小程序方式
11
11
  * Copyright (c) 2025 by 益丰大药房连锁股份有限公司, All Rights Reserved.
12
12
  */
13
13
 
14
- import { safeStringify, isBrowser, isWeChatMiniProgram, now } from "./utils";
14
+ import { safeStringify, isBrowser, isWeChatMiniProgram, now, gzipCompress } from "./utils";
15
15
 
16
16
  /** 传输选项接口 */
17
17
 
@@ -40,22 +40,34 @@ export var beaconTransport = {
40
40
  },
41
41
  send: function send(payload, opts) {
42
42
  return _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
43
- var body, endpoint, blob, success;
43
+ var body, endpoint, contentType, blob, success;
44
44
  return _regeneratorRuntime().wrap(function _callee$(_context) {
45
45
  while (1) switch (_context.prev = _context.next) {
46
46
  case 0:
47
47
  body = typeof payload === 'string' ? payload : safeStringify(payload);
48
- endpoint = getEndpoint(opts); // sendBeacon 使用 Blob 确保正确的 Content-Type
48
+ endpoint = getEndpoint(opts); // 如果启用 gzip 压缩
49
+ contentType = 'application/json';
50
+ if (!(opts !== null && opts !== void 0 && opts.enableGzip)) {
51
+ _context.next = 8;
52
+ break;
53
+ }
54
+ _context.next = 6;
55
+ return gzipCompress(body);
56
+ case 6:
57
+ body = _context.sent;
58
+ contentType = 'application/json; charset=utf-8';
59
+ case 8:
60
+ // sendBeacon 使用 Blob 确保正确的 Content-Type
49
61
  blob = new Blob([body], {
50
- type: 'application/json'
62
+ type: contentType
51
63
  });
52
64
  success = navigator.sendBeacon(endpoint, blob);
53
65
  if (success) {
54
- _context.next = 6;
66
+ _context.next = 12;
55
67
  break;
56
68
  }
57
69
  throw new Error('sendBeacon failed (queue full or other error)');
58
- case 6:
70
+ case 12:
59
71
  case "end":
60
72
  return _context.stop();
61
73
  }
@@ -79,13 +91,25 @@ export var wechatTransport = {
79
91
  },
80
92
  send: function send(payload, opts) {
81
93
  return _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
82
- var body, endpoint, timeout;
94
+ var body, endpoint, timeout, contentType;
83
95
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
84
96
  while (1) switch (_context2.prev = _context2.next) {
85
97
  case 0:
86
98
  body = typeof payload === 'string' ? payload : safeStringify(payload);
87
99
  endpoint = getEndpoint(opts);
88
100
  timeout = 10000; // 10秒超时
101
+ // 如果启用 gzip 压缩
102
+ contentType = 'application/json';
103
+ if (!(opts !== null && opts !== void 0 && opts.enableGzip)) {
104
+ _context2.next = 9;
105
+ break;
106
+ }
107
+ _context2.next = 7;
108
+ return gzipCompress(body);
109
+ case 7:
110
+ body = _context2.sent;
111
+ contentType = 'application/json; charset=utf-8';
112
+ case 9:
89
113
  return _context2.abrupt("return", new Promise(function (resolve, reject) {
90
114
  var timeoutId = null;
91
115
  var settled = false;
@@ -104,7 +128,7 @@ export var wechatTransport = {
104
128
  method: 'POST',
105
129
  data: body,
106
130
  header: {
107
- 'Content-Type': 'application/json'
131
+ 'Content-Type': contentType
108
132
  },
109
133
  success: function success(res) {
110
134
  if (timeoutId) clearTimeout(timeoutId);
@@ -126,7 +150,7 @@ export var wechatTransport = {
126
150
  }
127
151
  });
128
152
  }));
129
- case 4:
153
+ case 10:
130
154
  case "end":
131
155
  return _context2.stop();
132
156
  }
package/dist/types.d.ts CHANGED
@@ -9,7 +9,7 @@ export interface SDKOptions {
9
9
  /** 上报端点 URL */
10
10
  endpoint: string;
11
11
  /** 应用 ID */
12
- appId?: string;
12
+ appId: string;
13
13
  /** 环境标识 */
14
14
  env?: Env;
15
15
  /** 是否开启调试模式 */
@@ -18,9 +18,33 @@ export interface SDKOptions {
18
18
  pixelParam?: string;
19
19
  /** 像素上报 URL 最大长度,默认 1900 */
20
20
  maxPixelUrlLen?: number;
21
+ /** 是否启用 gzip 压缩,默认 false */
22
+ enableGzip?: boolean;
23
+ /** 是否启用批量上报,默认 true */
24
+ enableBatch?: boolean;
25
+ /** 批量上报最大数量,默认 10 */
26
+ batchSize?: number;
27
+ /** 批量上报时间间隔(毫秒),默认 5000 */
28
+ batchInterval?: number;
29
+ /** 队列最大长度,默认 100 */
30
+ maxQueueSize?: number;
31
+ /** 是否启用持久化存储,默认 true */
32
+ enableStorage?: boolean;
33
+ /** 持久化存储的 key 前缀,默认 'logger_sdk' */
34
+ storagePrefix?: string;
35
+ /** 是否启用重试,默认 true */
36
+ enableRetry?: boolean;
37
+ /** 最大重试次数,默认 3 */
38
+ maxRetries?: number;
39
+ /** 重试基础延迟时间(毫秒),默认 1000 */
40
+ retryDelay?: number;
41
+ /** 是否使用指数退避策略,默认 true */
42
+ retryBackoff?: boolean;
21
43
  }
22
44
  /** 标准化日志上报格式 */
23
45
  export interface LogEvent {
46
+ logId: string;
47
+ traceId?: string;
24
48
  /** 事件类型:error/crash/pageview/custom */
25
49
  eventType: LogEventType;
26
50
  /** 毫秒时间戳 */
package/dist/utils.d.ts CHANGED
@@ -1,7 +1,24 @@
1
1
  export declare const now: () => number;
2
+ /**
3
+ * 生成 UUID v4
4
+ * 符合 RFC 4122 标准
5
+ * 格式: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
6
+ * 其中 x 是 0-f 的十六进制数字,y 是 8/9/a/b 之一
7
+ */
8
+ export declare function generateUUID(): string;
2
9
  export declare function isBrowser(): boolean;
3
10
  export declare function isWeChatMiniProgram(): boolean;
4
11
  export declare function safeStringify(obj: any): string;
12
+ /**
13
+ * gzip 压缩字符串
14
+ * @param data - 需要压缩的字符串
15
+ * @returns 压缩后的 Base64 字符串
16
+ */
17
+ export declare function gzipCompress(data: string): Promise<string>;
18
+ /**
19
+ * 检查是否支持 gzip 压缩
20
+ */
21
+ export declare function isGzipSupported(): boolean;
5
22
  export declare function getSessionId(): string;
6
23
  export declare function getCurrentUrl(): string;
7
24
  /** 平台类型 */