@pluve/logger-sdk 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,6 +35,12 @@ sdk.track('error', 'TypeError: Cannot read property', {
35
35
  },
36
36
  });
37
37
 
38
+ // 记录带 traceId 的错误(用于关联多个日志)
39
+ sdk.track('error', 'Request failed', 'trace-abc-123', {
40
+ level: 'error',
41
+ tags: { api: '/api/user' },
42
+ });
43
+
38
44
  // 记录自定义事件
39
45
  sdk.track('custom', 'User clicked button', {
40
46
  level: 'info',
@@ -48,6 +54,8 @@ sdk.track('custom', 'User clicked button', {
48
54
 
49
55
  ```typescript
50
56
  {
57
+ "logId": "550e8400-e29b-41d4-a716-446655440000", // 日志 ID(UUID v4)
58
+ "traceId": "trace-123456", // 可选:追踪 ID(用于关联多个日志)
51
59
  "eventType": "error", // 固定:error/crash/pageview/custom
52
60
  "ts": 1690000000000, // 毫秒时间戳
53
61
  "appId": "web-shop", // 应用标识
@@ -84,14 +92,15 @@ interface SDKOptions {
84
92
  }
85
93
  ```
86
94
 
87
- ### `track(eventType, message, options?)`
95
+ ### `track(eventType, message, traceId?, options?)`
88
96
 
89
- 记录事件日志。
97
+ 记录事件日志。每条日志会自动生成唯一的 `logId`(UUID v4 格式)。
90
98
 
91
99
  **参数:**
92
100
 
93
101
  - `eventType`: 事件类型(`'error' | 'crash' | 'pageview' | 'custom'`)
94
102
  - `message`: 摘要信息
103
+ - `traceId`: (可选) 追踪 ID,用于关联多个相关日志
95
104
  - `options`: 可选配置
96
105
  - `level?`: 日志级别(`'info' | 'warn' | 'error' | 'fatal'`),默认 `'info'`
97
106
  - `stack?`: 堆栈信息
@@ -109,6 +118,12 @@ sdk.track('error', 'Failed to load resource', {
109
118
  tags: { resource: 'image.png' },
110
119
  });
111
120
 
121
+ // 记录带 traceId 的错误(用于关联多个日志)
122
+ sdk.track('error', 'API request failed', 'trace-xyz-789', {
123
+ level: 'error',
124
+ tags: { endpoint: '/api/users', statusCode: 500 },
125
+ });
126
+
112
127
  // 记录页面浏览
113
128
  sdk.track('pageview', 'User viewed product page', {
114
129
  level: 'info',
@@ -116,6 +131,29 @@ sdk.track('pageview', 'User viewed product page', {
116
131
  });
117
132
  ```
118
133
 
134
+ ### 日志 ID 和追踪 ID
135
+
136
+ - **logId**: 每条日志自动生成的唯一标识符(UUID v4 格式),用于全局唯一定位日志
137
+ - **traceId**: 可选的追踪 ID,用于关联同一请求链路上的多个日志(例如:前端请求、后端处理、数据库查询等)
138
+
139
+ ```typescript
140
+ // 在请求开始时生成 traceId
141
+ const traceId = `trace-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
142
+
143
+ // 在请求的不同阶段使用相同的 traceId
144
+ sdk.track('custom', 'Request started', traceId, {
145
+ level: 'info',
146
+ tags: { endpoint: '/api/checkout' },
147
+ });
148
+
149
+ // ... 请求处理 ...
150
+
151
+ sdk.track('error', 'Request failed', traceId, {
152
+ level: 'error',
153
+ tags: { endpoint: '/api/checkout', error: 'Network timeout' },
154
+ });
155
+ ```
156
+
119
157
  ### `identify(userId: string)`
120
158
 
121
159
  设置用户 ID(用于后续日志关联)。
package/dist/index.d.ts CHANGED
@@ -1 +1,6 @@
1
1
  export { LoggerSDK } from './loggerSDK';
2
+ export { defaultTransport, TransportAdapters } from './transportAdapter';
3
+ export type { TransportAdapter, TransportOptions } from './transportAdapter';
4
+ export type { SDKOptions, LogEvent, LogEventType, LogEventLevel, Env } from './types';
5
+ export type { PlatformType, EnvironmentInfo } from './utils';
6
+ export { getEnvironmentInfo, parseBrowserInfo, isWeChatMiniProgram, gzipCompress, isGzipSupported } from './utils';
package/dist/index.js CHANGED
@@ -6,4 +6,6 @@
6
6
  * @Description : 描述
7
7
  * Copyright (c) 2025 by 益丰大药房连锁股份有限公司, All Rights Reserved.
8
8
  */
9
- export { LoggerSDK } from "./loggerSDK";
9
+ export { LoggerSDK } from "./loggerSDK";
10
+ export { defaultTransport, TransportAdapters } from "./transportAdapter";
11
+ export { getEnvironmentInfo, parseBrowserInfo, isWeChatMiniProgram, gzipCompress, isGzipSupported } from "./utils";
@@ -14,7 +14,7 @@ export declare class LoggerSDK {
14
14
  /**
15
15
  * 记录事件
16
16
  */
17
- track(eventType: LogEventType, message: string, options?: {
17
+ track(eventType: LogEventType, message: string, traceId?: string, options?: {
18
18
  level?: LogEventLevel;
19
19
  stack?: string;
20
20
  userId?: string;
package/dist/loggerSDK.js CHANGED
@@ -11,7 +11,7 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
11
11
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
12
12
  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); }
13
13
  import { defaultTransport } from "./transportAdapter";
14
- import { isBrowser, isWeChatMiniProgram, now, getSessionId, getCurrentUrl, getEnvironmentInfo, parseBrowserInfo } from "./utils";
14
+ import { isBrowser, isWeChatMiniProgram, now, getSessionId, getCurrentUrl, getEnvironmentInfo, parseBrowserInfo, generateUUID } from "./utils";
15
15
  export var LoggerSDK = /*#__PURE__*/function () {
16
16
  function LoggerSDK(options) {
17
17
  _classCallCheck(this, LoggerSDK);
@@ -26,7 +26,8 @@ export var LoggerSDK = /*#__PURE__*/function () {
26
26
  env: options.env || 'dev',
27
27
  debug: !!options.debug,
28
28
  pixelParam: options.pixelParam || 'data',
29
- maxPixelUrlLen: options.maxPixelUrlLen || 1900
29
+ maxPixelUrlLen: options.maxPixelUrlLen || 1900,
30
+ enableGzip: !!options.enableGzip
30
31
  };
31
32
 
32
33
  // 初始化时收集环境信息
@@ -88,7 +89,7 @@ export var LoggerSDK = /*#__PURE__*/function () {
88
89
  }, {
89
90
  key: "track",
90
91
  value: (function () {
91
- var _track = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(eventType, message, options) {
92
+ var _track = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(eventType, message, traceId, options) {
92
93
  var logEvent;
93
94
  return _regeneratorRuntime().wrap(function _callee$(_context) {
94
95
  while (1) switch (_context.prev = _context.next) {
@@ -103,6 +104,9 @@ export var LoggerSDK = /*#__PURE__*/function () {
103
104
 
104
105
  // 构建标准化日志格式
105
106
  logEvent = {
107
+ logId: "".concat(this.opts.appId).concat(generateUUID()).concat(now()),
108
+ // UUID
109
+ traceId: traceId,
106
110
  eventType: eventType,
107
111
  ts: now(),
108
112
  appId: this.opts.appId || 'unknown',
@@ -134,7 +138,7 @@ export var LoggerSDK = /*#__PURE__*/function () {
134
138
  }
135
139
  }, _callee, this, [[5, 10]]);
136
140
  }));
137
- function track(_x, _x2, _x3) {
141
+ function track(_x, _x2, _x3, _x4) {
138
142
  return _track.apply(this, arguments);
139
143
  }
140
144
  return track;
@@ -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,13 @@ export interface SDKOptions {
18
18
  pixelParam?: string;
19
19
  /** 像素上报 URL 最大长度,默认 1900 */
20
20
  maxPixelUrlLen?: number;
21
+ /** 是否启用 gzip 压缩,默认 false */
22
+ enableGzip?: boolean;
21
23
  }
22
24
  /** 标准化日志上报格式 */
23
25
  export interface LogEvent {
26
+ logId: string;
27
+ traceId?: string;
24
28
  /** 事件类型:error/crash/pageview/custom */
25
29
  eventType: LogEventType;
26
30
  /** 毫秒时间戳 */
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
  /** 平台类型 */
package/dist/utils.js CHANGED
@@ -1,18 +1,46 @@
1
+ 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; }
2
+ 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); } }
3
+ 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); }); }; }
1
4
  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
5
  /*
3
6
  * @Author : 黄震 huangzhen@yfpharmacy.com
4
7
  * @Date : 2025-11-21 14:31:33
5
8
  * @LastEditors : 黄震 huangzhen@yfpharmacy.com
6
- * @LastEditTime : 2025-12-04 14:13:48
9
+ * @LastEditTime : 2025-12-08 13:46:02
7
10
  * @Description : utils 工具函数
8
11
  * Copyright (c) 2025 by 益丰大药房连锁股份有限公司, All Rights Reserved.
9
12
  */
10
13
 
11
- // 当前时间戳(毫秒)
14
+ // 当前时间戳(毫秒)
12
15
  export var now = function now() {
13
16
  return Date.now();
14
17
  };
15
18
 
19
+ /**
20
+ * 生成 UUID v4
21
+ * 符合 RFC 4122 标准
22
+ * 格式: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
23
+ * 其中 x 是 0-f 的十六进制数字,y 是 8/9/a/b 之一
24
+ */
25
+ export function generateUUID() {
26
+ // 使用 crypto.randomUUID() (现代浏览器支持)
27
+ if (isBrowser() && typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
28
+ try {
29
+ return crypto.randomUUID();
30
+ } catch (e) {
31
+ // fallback to manual generation
32
+ }
33
+ }
34
+
35
+ // 微信小程序环境 - 使用手动生成
36
+ // 浏览器环境降级方案 - 使用手动生成
37
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
38
+ var r = Math.floor(Math.random() * 16);
39
+ var v = c === 'x' ? r : Math.floor(r % 4 + 8);
40
+ return v.toString(16);
41
+ });
42
+ }
43
+
16
44
  // 判断是否在浏览器环境
17
45
  export function isBrowser() {
18
46
  try {
@@ -44,6 +72,110 @@ export function safeStringify(obj) {
44
72
  });
45
73
  }
46
74
 
75
+ /**
76
+ * 将字符串转换为 Uint8Array
77
+ */
78
+ function stringToUint8Array(str) {
79
+ var encoder = new TextEncoder();
80
+ return encoder.encode(str);
81
+ }
82
+
83
+ /**
84
+ * 将 Uint8Array 转换为 Base64
85
+ */
86
+ function uint8ArrayToBase64(bytes) {
87
+ var binary = '';
88
+ var len = bytes.byteLength;
89
+ for (var i = 0; i < len; i += 1) {
90
+ binary += String.fromCharCode(bytes[i]);
91
+ }
92
+ return btoa(binary);
93
+ }
94
+
95
+ /**
96
+ * gzip 压缩字符串
97
+ * @param data - 需要压缩的字符串
98
+ * @returns 压缩后的 Base64 字符串
99
+ */
100
+ export function gzipCompress(_x) {
101
+ return _gzipCompress.apply(this, arguments);
102
+ }
103
+
104
+ /**
105
+ * 检查是否支持 gzip 压缩
106
+ */
107
+ function _gzipCompress() {
108
+ _gzipCompress = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(data) {
109
+ var stream, writer, reader, bytes, chunks, result, totalLength, compressed, offset;
110
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
111
+ while (1) switch (_context.prev = _context.next) {
112
+ case 0:
113
+ if (!(isBrowser() && typeof CompressionStream !== 'undefined')) {
114
+ _context.next = 31;
115
+ break;
116
+ }
117
+ _context.prev = 1;
118
+ stream = new CompressionStream('gzip');
119
+ writer = stream.writable.getWriter();
120
+ reader = stream.readable.getReader(); // 将字符串转换为 Uint8Array
121
+ bytes = stringToUint8Array(data); // 写入数据
122
+ _context.next = 8;
123
+ return writer.write(bytes);
124
+ case 8:
125
+ _context.next = 10;
126
+ return writer.close();
127
+ case 10:
128
+ // 读取压缩后的数据
129
+ chunks = [];
130
+ _context.next = 13;
131
+ return reader.read();
132
+ case 13:
133
+ result = _context.sent;
134
+ case 14:
135
+ if (result.done) {
136
+ _context.next = 21;
137
+ break;
138
+ }
139
+ chunks.push(result.value);
140
+ // eslint-disable-next-line no-await-in-loop
141
+ _context.next = 18;
142
+ return reader.read();
143
+ case 18:
144
+ result = _context.sent;
145
+ _context.next = 14;
146
+ break;
147
+ case 21:
148
+ // 合并所有 chunks
149
+ totalLength = chunks.reduce(function (acc, chunk) {
150
+ return acc + chunk.length;
151
+ }, 0);
152
+ compressed = new Uint8Array(totalLength);
153
+ offset = 0;
154
+ chunks.forEach(function (chunk) {
155
+ compressed.set(chunk, offset);
156
+ offset += chunk.length;
157
+ });
158
+
159
+ // 转换为 Base64
160
+ return _context.abrupt("return", uint8ArrayToBase64(compressed));
161
+ case 28:
162
+ _context.prev = 28;
163
+ _context.t0 = _context["catch"](1);
164
+ return _context.abrupt("return", data);
165
+ case 31:
166
+ return _context.abrupt("return", data);
167
+ case 32:
168
+ case "end":
169
+ return _context.stop();
170
+ }
171
+ }, _callee, null, [[1, 28]]);
172
+ }));
173
+ return _gzipCompress.apply(this, arguments);
174
+ }
175
+ export function isGzipSupported() {
176
+ return isBrowser() && typeof CompressionStream !== 'undefined';
177
+ }
178
+
47
179
  // 生成随机 sessionId
48
180
  var cachedSessionId = null;
49
181
  export function getSessionId() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluve/logger-sdk",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "logger sdk",
5
5
  "keywords": [
6
6
  "logger"
@@ -8,14 +8,12 @@
8
8
  "author": "黄震 <huangzhen@yfpharmacy.com>",
9
9
  "homepage": "http://.",
10
10
  "license": "ISC",
11
- "main": "lib/index.js",
12
- "types": "lib/index.d.ts",
11
+ "main": "dist/index.js",
12
+ "types": "dist/index.d.ts",
13
13
  "directories": {
14
- "lib": "lib",
15
14
  "dist": "dist"
16
15
  },
17
16
  "files": [
18
- "lib/*",
19
17
  "dist/*"
20
18
  ],
21
19
  "publishConfig": {
package/lib/dbQueue.d.ts DELETED
@@ -1,10 +0,0 @@
1
- export default class IDBQueue {
2
- private dbName;
3
- private storeName;
4
- private db;
5
- constructor(dbName?: string, storeName?: string);
6
- open(): Promise<void>;
7
- add(item: any): Promise<void>;
8
- getAll(): Promise<any[]>;
9
- clear(): Promise<unknown>;
10
- }
package/lib/dbQueue.js DELETED
@@ -1,133 +0,0 @@
1
- /*
2
- * @Author : 黄震 huangzhen@yfpharmacy.com
3
- * @Date : 2025-11-21 14:32:51
4
- * @LastEditors : 黄震 huangzhen@yfpharmacy.com
5
- * @LastEditTime : 2025-11-21 14:38:50
6
- * @Description : 描述
7
- * Copyright (c) 2025 by 益丰大药房连锁股份有限公司, All Rights Reserved.
8
- */
9
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
10
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
11
- return new (P || (P = Promise))(function (resolve, reject) {
12
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
13
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
14
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
15
- step((generator = generator.apply(thisArg, _arguments || [])).next());
16
- });
17
- };
18
- var __generator = (this && this.__generator) || function (thisArg, body) {
19
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
20
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
21
- function verb(n) { return function (v) { return step([n, v]); }; }
22
- function step(op) {
23
- if (f) throw new TypeError("Generator is already executing.");
24
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
25
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
26
- if (y = 0, t) op = [op[0] & 2, t.value];
27
- switch (op[0]) {
28
- case 0: case 1: t = op; break;
29
- case 4: _.label++; return { value: op[1], done: false };
30
- case 5: _.label++; y = op[1]; op = [0]; continue;
31
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
32
- default:
33
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
34
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
35
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
36
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
37
- if (t[2]) _.ops.pop();
38
- _.trys.pop(); continue;
39
- }
40
- op = body.call(thisArg, _);
41
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
42
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
43
- }
44
- };
45
- import { isBrowser, isIndexedDBAvailable } from "./utils";
46
- // IndexedDB 轻量队列:作为 localStorage 的冗余通道
47
- var IDBQueue = /** @class */ (function () {
48
- function IDBQueue(dbName, storeName) {
49
- if (dbName === void 0) { dbName = 'logger_sdk_db'; }
50
- if (storeName === void 0) { storeName = 'queue'; }
51
- this.db = null;
52
- this.dbName = dbName;
53
- this.storeName = storeName;
54
- }
55
- // 打开数据库并初始化对象仓库
56
- IDBQueue.prototype.open = function () {
57
- return __awaiter(this, void 0, void 0, function () {
58
- var _this = this;
59
- return __generator(this, function (_a) {
60
- if (!isBrowser() || !isIndexedDBAvailable())
61
- return [2 /*return*/];
62
- if (this.db)
63
- return [2 /*return*/];
64
- return [2 /*return*/, new Promise(function (resolve, reject) {
65
- var req = indexedDB.open(_this.dbName, 1);
66
- req.onupgradeneeded = function () {
67
- var db = req.result;
68
- if (!db.objectStoreNames.contains(_this.storeName))
69
- db.createObjectStore(_this.storeName, { autoIncrement: true });
70
- };
71
- req.onsuccess = function () {
72
- _this.db = req.result;
73
- resolve();
74
- };
75
- req.onerror = function () { return reject(req.error); };
76
- })];
77
- });
78
- });
79
- };
80
- // 入队:追加一条记录
81
- IDBQueue.prototype.add = function (item) {
82
- return __awaiter(this, void 0, void 0, function () {
83
- var _this = this;
84
- return __generator(this, function (_a) {
85
- if (!this.db)
86
- return [2 /*return*/];
87
- return [2 /*return*/, new Promise(function (res, rej) {
88
- var tx = _this.db.transaction(_this.storeName, 'readwrite');
89
- var st = tx.objectStore(_this.storeName);
90
- var r = st.add(item);
91
- r.onsuccess = function () { return res(); };
92
- r.onerror = function () { return rej(r.error); };
93
- })];
94
- });
95
- });
96
- };
97
- // 读取全部记录(调试/回溯用)
98
- IDBQueue.prototype.getAll = function () {
99
- return __awaiter(this, void 0, void 0, function () {
100
- var _this = this;
101
- return __generator(this, function (_a) {
102
- if (!this.db)
103
- return [2 /*return*/, []];
104
- return [2 /*return*/, new Promise(function (res, rej) {
105
- var tx = _this.db.transaction(_this.storeName, 'readonly');
106
- var st = tx.objectStore(_this.storeName);
107
- var req = st.getAll();
108
- req.onsuccess = function () { return res(req.result || []); };
109
- req.onerror = function () { return rej(req.error); };
110
- })];
111
- });
112
- });
113
- };
114
- // 清空队列:发送成功后用于兜底清理
115
- IDBQueue.prototype.clear = function () {
116
- return __awaiter(this, void 0, void 0, function () {
117
- var _this = this;
118
- return __generator(this, function (_a) {
119
- if (!this.db)
120
- return [2 /*return*/];
121
- return [2 /*return*/, new Promise(function (res, rej) {
122
- var tx = _this.db.transaction(_this.storeName, 'readwrite');
123
- var st = tx.objectStore(_this.storeName);
124
- var req = st.clear();
125
- req.onsuccess = function () { return res(undefined); };
126
- req.onerror = function () { return rej(req.error); };
127
- })];
128
- });
129
- });
130
- };
131
- return IDBQueue;
132
- }());
133
- export default IDBQueue;
package/lib/index.d.ts DELETED
@@ -1 +0,0 @@
1
- export { LoggerSDK } from './loggerSDK';
package/lib/index.js DELETED
@@ -1,9 +0,0 @@
1
- /*
2
- * @Author : 黄震 huangzhen@yfpharmacy.com
3
- * @Date : 2025-11-21 14:25:26
4
- * @LastEditors : 黄震 huangzhen@yfpharmacy.com
5
- * @LastEditTime : 2025-12-02 15:09:28
6
- * @Description : 描述
7
- * Copyright (c) 2025 by 益丰大药房连锁股份有限公司, All Rights Reserved.
8
- */
9
- export { LoggerSDK } from './loggerSDK';