rusty-replay 1.0.9 β 1.0.11
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 +164 -22
- package/dist/index.cjs +133 -166
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +118 -159
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
@@ -1,26 +1,168 @@
|
|
1
|
+
# π¦ rusty-replay
|
2
|
+
|
3
|
+
μΉ ν΄λΌμ΄μΈνΈμμ λ°μν μ€λ₯λ₯Ό μμ§νκ³ , μ§μ μ¬μ©μ νλμ 리νλ μ΄ ννλ‘ ν¨κ» μ μ‘νλ κ²½λ μ€λ₯ μΆμ λꡬμ
λλ€.
|
4
|
+
|
5
|
+
`rrweb` κΈ°λ°μ μ¬μ©μ νλ 리νλ μ΄ κΈ°λ₯κ³Ό `axios` μλ¬ μλ μ μ‘κΉμ§ μ§μν©λλ€.
|
6
|
+
|
7
|
+
## π¦ μ€μΉ
|
8
|
+
|
9
|
+
```bash
|
10
|
+
npm install rusty-replay
|
11
|
+
```
|
12
|
+
|
13
|
+
---
|
14
|
+
|
15
|
+
## βοΈ μ΄κΈ°ν
|
16
|
+
|
17
|
+
Next.jsμμ `rusty-replay`λ μΌλ°μ μΌλ‘ `app/providers.tsx` λλ `layout.tsx`μμ μ΄κΈ°νν©λλ€.
|
18
|
+
|
19
|
+
```ts
|
20
|
+
import { init } from 'rusty-replay';
|
21
|
+
|
22
|
+
init({
|
23
|
+
endpoint: 'https://your-api.com/batch-events',
|
24
|
+
apiKey: 'YOUR_PUBLIC_API_KEY',
|
25
|
+
flushIntervalMs: 10000, // λ²νΌκ° μ°° λκΉμ§ μ΅λ λκΈ° μκ° (ms)
|
26
|
+
maxBufferSize: 2000000, // μ μ‘ μ μ΅λ λ²νΌ μ¬μ΄μ¦ (bytes)
|
27
|
+
beforeErrorSec: 10, // μλ¬ λ°μ μ λͺ μ΄κ°μ μ΄λ²€νΈλ₯Ό 리νλ μ΄λ‘ λ¨κΈΈμ§
|
28
|
+
});
|
29
|
+
```
|
30
|
+
|
31
|
+
---
|
32
|
+
|
33
|
+
## π§ κΈλ‘λ² μλ¬ μλ μΊ‘μ²
|
34
|
+
|
35
|
+
```
|
36
|
+
ts
|
37
|
+
볡μ¬νΈμ§
|
38
|
+
import { setupGlobalErrorHandler } from 'rusty-replay';
|
39
|
+
|
40
|
+
setupGlobalErrorHandler();
|
41
|
+
|
42
|
+
```
|
43
|
+
|
44
|
+
- `window.onerror`
|
45
|
+
- `window.onunhandledrejection`
|
46
|
+
μ μλ κ°μ§νμ¬ μ€λ₯λ₯Ό μλ²λ‘ μ μ‘ν©λλ€.
|
47
|
+
|
48
|
+
---
|
49
|
+
|
50
|
+
## π§ Axios μλ¬ μλ μ μ‘
|
51
|
+
|
52
|
+
```ts
|
53
|
+
import axios from 'axios';
|
54
|
+
import { captureException, AdditionalInfo } from 'rusty-replay';
|
55
|
+
|
56
|
+
axios.interceptors.response.use(
|
57
|
+
(res) => res,
|
58
|
+
(error) => {
|
59
|
+
if (axios.isAxiosError(error)) {
|
60
|
+
const additionalInfo: Partial<AdditionalInfo> = {
|
61
|
+
pageUrl: window.location.href,
|
62
|
+
request: {
|
63
|
+
url: error.config?.url ?? '',
|
64
|
+
method: error.config?.method ?? '',
|
65
|
+
headers: error.config?.headers ?? {},
|
66
|
+
},
|
67
|
+
response: {
|
68
|
+
status: error.response?.status ?? 0,
|
69
|
+
statusText: error.response?.statusText ?? '',
|
70
|
+
data: {
|
71
|
+
message: error.response?.data?.message ?? '',
|
72
|
+
errorCode: error.response?.data?.errorCode ?? '',
|
73
|
+
},
|
74
|
+
},
|
75
|
+
};
|
76
|
+
|
77
|
+
captureException(
|
78
|
+
error instanceof Error ? error : new Error('API μμ² μ€ν¨'),
|
79
|
+
additionalInfo
|
80
|
+
);
|
81
|
+
}
|
82
|
+
|
83
|
+
return Promise.reject(error);
|
84
|
+
}
|
85
|
+
);
|
86
|
+
```
|
87
|
+
|
88
|
+
---
|
89
|
+
|
90
|
+
## π₯οΈ React Error Boundary ν΅ν©
|
91
|
+
|
1
92
|
```tsx
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
maxBufferSize: 200, // νμ μ΅λ 200건κΉμ§
|
9
|
-
beforeErrorSec: 30, // μλ¬ μ 30μ΄ λ¦¬νλ μ΄ μ΄λ²€νΈ ν¬ν¨
|
10
|
-
});
|
11
|
-
}, []);
|
12
|
-
|
13
|
-
<button
|
14
|
-
onClick={() => {
|
15
|
-
captureException(new Error('μλμ μΌλ‘ λ°μμν¨ μλ μλ¬'), {
|
16
|
-
additionalInfo: {
|
17
|
-
context: 'μλ μλ¬ λ¦¬ν¬ν
ν
μ€νΈ',
|
18
|
-
button: 'μλ μλ¬ λ²νΌ',
|
19
|
-
},
|
20
|
-
});
|
93
|
+
import { ErrorBoundary } from 'react-error-boundary';
|
94
|
+
import { captureException } from 'rusty-replay';
|
95
|
+
|
96
|
+
<ErrorBoundaryFallbackComponent={() => <div>μ€λ₯κ° λ°μνμ΅λλ€.</div>}
|
97
|
+
onError={(error, info) => {
|
98
|
+
captureException(error);
|
21
99
|
}}
|
22
|
-
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
23
100
|
>
|
24
|
-
|
25
|
-
</
|
101
|
+
<App />
|
102
|
+
</ErrorBoundary>
|
103
|
+
|
104
|
+
```
|
105
|
+
|
106
|
+
---
|
107
|
+
|
108
|
+
## π 리νλ μ΄ μ¬μ (rrweb-player)
|
109
|
+
|
110
|
+
```tsx
|
111
|
+
import { decompressFromBase64 } from 'rusty-replay';
|
112
|
+
import 'rrweb-player/dist/style.css';
|
113
|
+
|
114
|
+
const events = decompressFromBase64(error.replay);
|
115
|
+
|
116
|
+
new Player({
|
117
|
+
target: document.getElementById('player')!,
|
118
|
+
props: {
|
119
|
+
events,
|
120
|
+
width: 1000,
|
121
|
+
height: 600,
|
122
|
+
autoPlay: false,
|
123
|
+
showController: true,
|
124
|
+
skipInactive: true,
|
125
|
+
},
|
126
|
+
});
|
127
|
+
```
|
128
|
+
|
129
|
+
---
|
130
|
+
|
131
|
+
## π μλ²λ‘ μ μ‘λλ λ°μ΄ν° Payload
|
132
|
+
|
133
|
+
```ts
|
134
|
+
{
|
135
|
+
message: 'Uncaught TypeError: ...',
|
136
|
+
stacktrace: 'TypeError: ...',
|
137
|
+
replay: 'compressedBase64Data',
|
138
|
+
environment: 'production',
|
139
|
+
browser: 'Chrome 123.0',
|
140
|
+
os: 'macOS 14',
|
141
|
+
userAgent: '...',
|
142
|
+
appVersion: '1.0.0',
|
143
|
+
apiKey: 'YOUR_API_KEY',
|
144
|
+
additionalInfo: {
|
145
|
+
request: {...},
|
146
|
+
response: {...},
|
147
|
+
pageUrl: 'https://your.site/path'
|
148
|
+
},
|
149
|
+
userId: 123
|
150
|
+
}
|
151
|
+
|
26
152
|
```
|
153
|
+
|
154
|
+
---
|
155
|
+
|
156
|
+
## π API μ°Έκ³
|
157
|
+
|
158
|
+
### `init(options: InitOptions)`
|
159
|
+
|
160
|
+
μ΅μ
μ€λͺ
:
|
161
|
+
|
162
|
+
| μ΅μ
| νμ
| μ€λͺ
|
|
163
|
+
| ----------------- | ------ | -------------------------------------- |
|
164
|
+
| `endpoint` | string | μλ¬ μμ§ μλ²μ μλν¬μΈνΈ |
|
165
|
+
| `apiKey` | string | νλ‘μ νΈ μλ³μ© API Key |
|
166
|
+
| `flushIntervalMs` | number | μλ¬ μ μ‘ κ°κ²© (κΈ°λ³Έ: 10μ΄) |
|
167
|
+
| `maxBufferSize` | number | μ΅λ μ μ‘ λ²νΌ ν¬κΈ° |
|
168
|
+
| `beforeErrorSec` | number | 리νλ μ΄ μμ§ κ΅¬κ° (κΈ°λ³Έ: 10μ΄ μ κΉμ§) |
|
package/dist/index.cjs
CHANGED
@@ -19,9 +19,6 @@ var __spreadValues = (a, b) => {
|
|
19
19
|
}
|
20
20
|
return a;
|
21
21
|
};
|
22
|
-
var __esm = (fn, res) => function __init() {
|
23
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
24
|
-
};
|
25
22
|
var __export = (target, all) => {
|
26
23
|
for (var name in all)
|
27
24
|
__defProp(target, name, { get: all[name], enumerable: true });
|
@@ -44,12 +41,20 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
44
41
|
));
|
45
42
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
46
43
|
|
47
|
-
//
|
48
|
-
var
|
49
|
-
|
50
|
-
|
51
|
-
|
44
|
+
// src/index.ts
|
45
|
+
var index_exports = {};
|
46
|
+
__export(index_exports, {
|
47
|
+
ErrorBatcher: () => ErrorBatcher,
|
48
|
+
captureException: () => captureException,
|
49
|
+
decompressFromBase64: () => decompressFromBase64,
|
50
|
+
getBrowserInfo: () => getBrowserInfo,
|
51
|
+
getEnvironment: () => getEnvironment,
|
52
|
+
getRecordedEvents: () => getRecordedEvents,
|
53
|
+
init: () => init,
|
54
|
+
setupGlobalErrorHandler: () => setupGlobalErrorHandler,
|
55
|
+
startRecording: () => startRecording
|
52
56
|
});
|
57
|
+
module.exports = __toCommonJS(index_exports);
|
53
58
|
|
54
59
|
// src/environment.ts
|
55
60
|
function getBrowserInfo() {
|
@@ -72,94 +77,83 @@ function getBrowserInfo() {
|
|
72
77
|
}
|
73
78
|
function getEnvironment() {
|
74
79
|
if (process.env.NODE_ENV === "development") return "development";
|
75
|
-
if (process.env.NEXT_PUBLIC_VERCEL_ENV === "preview") return "staging";
|
76
80
|
return "production";
|
77
81
|
}
|
78
|
-
var init_environment = __esm({
|
79
|
-
"src/environment.ts"() {
|
80
|
-
"use strict";
|
81
|
-
init_cjs_shims();
|
82
|
-
}
|
83
|
-
});
|
84
82
|
|
85
83
|
// src/error-batcher.ts
|
86
|
-
var import_axios,
|
87
|
-
var
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
// 10MB
|
130
|
-
timeout: 3e4,
|
131
|
-
headers: {
|
132
|
-
"Content-Type": "application/json",
|
133
|
-
Authorization: `Bearer ${this.opts.apiKey}`
|
134
|
-
}
|
135
|
-
}
|
136
|
-
);
|
137
|
-
} catch (e) {
|
138
|
-
this.queue.unshift(...batch);
|
139
|
-
} finally {
|
140
|
-
this.isFlushing = false;
|
84
|
+
var import_axios = __toESM(require("axios"), 1);
|
85
|
+
var ErrorBatcher = class {
|
86
|
+
constructor(opts) {
|
87
|
+
this.opts = opts;
|
88
|
+
this.queue = [];
|
89
|
+
this.isFlushing = false;
|
90
|
+
var _a;
|
91
|
+
this.apiKey = opts.apiKey;
|
92
|
+
const interval = (_a = opts.flushIntervalMs) != null ? _a : 3e4;
|
93
|
+
this.flushTimer = window.setInterval(() => this.flush(), interval);
|
94
|
+
window.addEventListener("beforeunload", () => this.flushOnUnload());
|
95
|
+
}
|
96
|
+
getApiKey() {
|
97
|
+
return this.apiKey;
|
98
|
+
}
|
99
|
+
capture(evt) {
|
100
|
+
var _a;
|
101
|
+
const id = this.makeId();
|
102
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
103
|
+
const record2 = __spreadValues({ id, timestamp }, evt);
|
104
|
+
if (this.queue.length >= ((_a = this.opts.maxBufferSize) != null ? _a : 64)) {
|
105
|
+
this.queue.shift();
|
106
|
+
}
|
107
|
+
this.queue.push(record2);
|
108
|
+
return id;
|
109
|
+
}
|
110
|
+
async flush() {
|
111
|
+
if (this.isFlushing || this.queue.length === 0) return;
|
112
|
+
this.isFlushing = true;
|
113
|
+
const batch = this.queue.splice(0, this.queue.length);
|
114
|
+
try {
|
115
|
+
await import_axios.default.post(
|
116
|
+
this.opts.endpoint,
|
117
|
+
{ events: batch },
|
118
|
+
{
|
119
|
+
maxBodyLength: 1e3 * 1024 * 1024,
|
120
|
+
// 10MB
|
121
|
+
maxContentLength: 1e3 * 1024 * 1024,
|
122
|
+
// 10MB
|
123
|
+
timeout: 3e4,
|
124
|
+
headers: {
|
125
|
+
"Content-Type": "application/json"
|
126
|
+
}
|
141
127
|
}
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
makeId() {
|
149
|
-
return "xxxx-xxxx-4xxx-yxxx".replace(/[xy]/g, (c) => {
|
150
|
-
const r = Math.random() * 16 | 0;
|
151
|
-
const v = c === "x" ? r : r & 3 | 8;
|
152
|
-
return v.toString(16);
|
153
|
-
});
|
154
|
-
}
|
155
|
-
destroy() {
|
156
|
-
clearInterval(this.flushTimer);
|
157
|
-
}
|
158
|
-
};
|
128
|
+
);
|
129
|
+
} catch (e) {
|
130
|
+
this.queue.unshift(...batch);
|
131
|
+
} finally {
|
132
|
+
this.isFlushing = false;
|
133
|
+
}
|
159
134
|
}
|
160
|
-
|
135
|
+
flushOnUnload() {
|
136
|
+
if (!navigator.sendBeacon || this.queue.length === 0) return;
|
137
|
+
const payload = JSON.stringify({ events: this.queue });
|
138
|
+
navigator.sendBeacon(this.opts.endpoint, payload);
|
139
|
+
}
|
140
|
+
makeId() {
|
141
|
+
return "xxxx-xxxx-4xxx-yxxx".replace(/[xy]/g, (c) => {
|
142
|
+
const r = Math.random() * 16 | 0;
|
143
|
+
const v = c === "x" ? r : r & 3 | 8;
|
144
|
+
return v.toString(16);
|
145
|
+
});
|
146
|
+
}
|
147
|
+
destroy() {
|
148
|
+
clearInterval(this.flushTimer);
|
149
|
+
}
|
150
|
+
};
|
161
151
|
|
162
152
|
// src/recorder.ts
|
153
|
+
var import_rrweb = require("rrweb");
|
154
|
+
var events = [];
|
155
|
+
var MAX_EVENTS = 1e3;
|
156
|
+
var stopFn = void 0;
|
163
157
|
function startRecording() {
|
164
158
|
events = [];
|
165
159
|
stopFn == null ? void 0 : stopFn();
|
@@ -174,9 +168,22 @@ function startRecording() {
|
|
174
168
|
// checkoutEveryNms: 1000, // 1μ΄λ§λ€ 체ν¬μμ
|
175
169
|
checkoutEveryNms: 15e3,
|
176
170
|
// 15μ΄λ§λ€ ν λ²
|
177
|
-
checkoutEveryNth: 100
|
171
|
+
checkoutEveryNth: 100,
|
178
172
|
// 100κ° μ΄λ²€νΈλ§λ€ ν λ²
|
179
|
-
|
173
|
+
maskAllInputs: true,
|
174
|
+
sampling: {
|
175
|
+
mouseInteraction: {
|
176
|
+
MouseUp: false,
|
177
|
+
MouseDown: false,
|
178
|
+
Click: false,
|
179
|
+
ContextMenu: false,
|
180
|
+
DblClick: false,
|
181
|
+
Focus: false,
|
182
|
+
Blur: false,
|
183
|
+
TouchStart: false,
|
184
|
+
TouchEnd: false
|
185
|
+
}
|
186
|
+
}
|
180
187
|
});
|
181
188
|
}
|
182
189
|
function getRecordedEvents(beforeErrorSec = 10, errorTime = Date.now(), source = events) {
|
@@ -199,50 +206,23 @@ function clearEvents() {
|
|
199
206
|
function getCurrentEvents() {
|
200
207
|
return events.slice();
|
201
208
|
}
|
202
|
-
var import_rrweb, events, MAX_EVENTS, stopFn;
|
203
|
-
var init_recorder = __esm({
|
204
|
-
"src/recorder.ts"() {
|
205
|
-
"use strict";
|
206
|
-
init_cjs_shims();
|
207
|
-
import_rrweb = require("rrweb");
|
208
|
-
events = [];
|
209
|
-
MAX_EVENTS = 1e3;
|
210
|
-
stopFn = void 0;
|
211
|
-
}
|
212
|
-
});
|
213
209
|
|
214
|
-
// src/
|
215
|
-
var
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
error != null ? error : new Error(typeof message === "string" ? message : "Unknown error")
|
226
|
-
);
|
227
|
-
return false;
|
228
|
-
};
|
229
|
-
const origOnUnhandledRejection = window.onunhandledrejection;
|
230
|
-
window.onunhandledrejection = function thisWindowOnRejection(event) {
|
231
|
-
origOnUnhandledRejection == null ? void 0 : origOnUnhandledRejection.call(this, event);
|
232
|
-
const err = event.reason instanceof Error ? event.reason : new Error(JSON.stringify(event.reason));
|
233
|
-
captureException(err);
|
234
|
-
};
|
235
|
-
window.__errorHandlerSetup = true;
|
210
|
+
// src/utils.ts
|
211
|
+
var import_fflate = require("fflate");
|
212
|
+
function compressToBase64(obj) {
|
213
|
+
const json = JSON.stringify(obj);
|
214
|
+
const compressed = (0, import_fflate.zlibSync)(new TextEncoder().encode(json));
|
215
|
+
return btoa(String.fromCharCode(...compressed));
|
216
|
+
}
|
217
|
+
function decompressFromBase64(base64) {
|
218
|
+
const binary = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
|
219
|
+
const json = new TextDecoder().decode((0, import_fflate.unzlibSync)(binary));
|
220
|
+
return JSON.parse(json);
|
236
221
|
}
|
237
|
-
var init_handler = __esm({
|
238
|
-
"src/handler.ts"() {
|
239
|
-
"use strict";
|
240
|
-
init_cjs_shims();
|
241
|
-
init_reporter();
|
242
|
-
}
|
243
|
-
});
|
244
222
|
|
245
223
|
// src/reporter.ts
|
224
|
+
var batcher;
|
225
|
+
var globalOpts = { beforeErrorSec: 30 };
|
246
226
|
function init(options) {
|
247
227
|
var _a;
|
248
228
|
globalOpts.beforeErrorSec = (_a = options.beforeErrorSec) != null ? _a : 10;
|
@@ -253,10 +233,6 @@ function init(options) {
|
|
253
233
|
maxBufferSize: options.maxBufferSize
|
254
234
|
});
|
255
235
|
if (typeof window !== "undefined") {
|
256
|
-
const start = () => {
|
257
|
-
startRecording();
|
258
|
-
Promise.resolve().then(() => (init_handler(), handler_exports)).then((mod) => mod.setupGlobalErrorHandler());
|
259
|
-
};
|
260
236
|
if (document.readyState === "complete") {
|
261
237
|
requestAnimationFrame(() => startRecording());
|
262
238
|
} else {
|
@@ -270,17 +246,18 @@ function captureException(error, additionalInfo, userId) {
|
|
270
246
|
var _a, _b;
|
271
247
|
const errorTime = Date.now();
|
272
248
|
const eventsSnapshot = getCurrentEvents();
|
273
|
-
const
|
249
|
+
const rawReplay = getRecordedEvents(
|
274
250
|
globalOpts.beforeErrorSec,
|
275
251
|
errorTime,
|
276
252
|
eventsSnapshot
|
277
253
|
);
|
278
254
|
clearEvents();
|
279
255
|
const { browser, os, userAgent } = getBrowserInfo();
|
256
|
+
const compressedReplay = compressToBase64(rawReplay);
|
280
257
|
return batcher.capture({
|
281
258
|
message: (_a = error.message) != null ? _a : "",
|
282
259
|
stacktrace: (_b = error.stack) != null ? _b : "",
|
283
|
-
replay,
|
260
|
+
replay: compressedReplay,
|
284
261
|
environment: getEnvironment(),
|
285
262
|
browser,
|
286
263
|
os,
|
@@ -291,41 +268,31 @@ function captureException(error, additionalInfo, userId) {
|
|
291
268
|
apiKey: batcher.getApiKey()
|
292
269
|
});
|
293
270
|
}
|
294
|
-
var batcher, globalOpts;
|
295
|
-
var init_reporter = __esm({
|
296
|
-
"src/reporter.ts"() {
|
297
|
-
"use strict";
|
298
|
-
init_cjs_shims();
|
299
|
-
init_environment();
|
300
|
-
init_error_batcher();
|
301
|
-
init_recorder();
|
302
|
-
globalOpts = { beforeErrorSec: 30 };
|
303
|
-
}
|
304
|
-
});
|
305
271
|
|
306
|
-
// src/
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
272
|
+
// src/handler.ts
|
273
|
+
function setupGlobalErrorHandler() {
|
274
|
+
if (window.__errorHandlerSetup) return;
|
275
|
+
const origOnError = window.onerror;
|
276
|
+
window.onerror = function thisWindowOnError(message, source, lineno, colno, error) {
|
277
|
+
origOnError == null ? void 0 : origOnError.call(this, message, source, lineno, colno, error);
|
278
|
+
captureException(
|
279
|
+
error != null ? error : new Error(typeof message === "string" ? message : "Unknown error")
|
280
|
+
);
|
281
|
+
return false;
|
282
|
+
};
|
283
|
+
const origOnUnhandledRejection = window.onunhandledrejection;
|
284
|
+
window.onunhandledrejection = function thisWindowOnRejection(event) {
|
285
|
+
origOnUnhandledRejection == null ? void 0 : origOnUnhandledRejection.call(this, event);
|
286
|
+
const err = event.reason instanceof Error ? event.reason : new Error(JSON.stringify(event.reason));
|
287
|
+
captureException(err);
|
288
|
+
};
|
289
|
+
window.__errorHandlerSetup = true;
|
290
|
+
}
|
325
291
|
// Annotate the CommonJS export names for ESM import in node:
|
326
292
|
0 && (module.exports = {
|
327
293
|
ErrorBatcher,
|
328
294
|
captureException,
|
295
|
+
decompressFromBase64,
|
329
296
|
getBrowserInfo,
|
330
297
|
getEnvironment,
|
331
298
|
getRecordedEvents,
|
package/dist/index.cjs.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.4.0_jiti@2.4.2_postcss@8.5.3_typescript@5.8.3/node_modules/tsup/assets/cjs_shims.js","../src/environment.ts","../src/error-batcher.ts","../src/recorder.ts","../src/handler.ts","../src/reporter.ts","../src/index.ts"],"sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () =>\n typeof document === 'undefined'\n ? new URL(`file:${__filename}`).href\n : (document.currentScript && document.currentScript.src) ||\n new URL('main.js', document.baseURI).href\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","export function getBrowserInfo() {\n const ua = navigator.userAgent;\n let browser = 'unknown',\n os = 'unknown';\n\n if (ua.includes('Firefox')) browser = 'Firefox';\n else if (ua.includes('SamsungBrowser')) browser = 'Samsung Browser';\n else if (ua.includes('Opera') || ua.includes('OPR')) browser = 'Opera';\n else if (ua.includes('Trident')) browser = 'IE';\n else if (ua.includes('Edge')) browser = 'Edge (Legacy)';\n else if (ua.includes('Edg')) browser = 'Edge';\n else if (ua.includes('Chrome')) browser = 'Chrome';\n else if (ua.includes('Safari')) browser = 'Safari';\n\n if (ua.includes('Windows')) os = 'Windows';\n else if (ua.includes('Mac')) os = 'macOS';\n else if (ua.includes('Linux')) os = 'Linux';\n else if (ua.includes('Android')) os = 'Android';\n else if (ua.includes('like Mac')) os = 'iOS';\n\n return { browser, os, userAgent: ua };\n}\n\nexport function getEnvironment(): 'development' | 'staging' | 'production' {\n if (process.env.NODE_ENV === 'development') return 'development';\n if (process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') return 'staging';\n return 'production';\n}\n","import axios from 'axios';\nimport type { BatcherOptions, BatchedEvent } from './reporter';\n\nexport class ErrorBatcher {\n private queue: BatchedEvent[] = [];\n private isFlushing = false;\n private flushTimer: number;\n private readonly apiKey: string;\n\n constructor(private opts: BatcherOptions) {\n this.apiKey = opts.apiKey;\n const interval = opts.flushIntervalMs ?? 3000;\n this.flushTimer = window.setInterval(() => this.flush(), interval);\n window.addEventListener('beforeunload', () => this.flushOnUnload());\n }\n\n public getApiKey(): string {\n return this.apiKey;\n }\n\n public capture(evt: Omit<BatchedEvent, 'id' | 'timestamp'>): string {\n const id = this.makeId();\n const timestamp = new Date().toISOString();\n const record: BatchedEvent = { id, timestamp, ...evt };\n\n if (this.queue.length >= (this.opts.maxBufferSize ?? 64)) {\n this.queue.shift();\n }\n this.queue.push(record);\n return id;\n }\n\n private async flush() {\n if (this.isFlushing || this.queue.length === 0) return;\n this.isFlushing = true;\n\n const batch = this.queue.splice(0, this.queue.length);\n try {\n await axios.post(\n this.opts.endpoint,\n { events: batch },\n {\n maxBodyLength: 1000 * 1024 * 1024, // 10MB\n maxContentLength: 1000 * 1024 * 1024, // 10MB\n timeout: 30000,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.opts.apiKey}`,\n },\n }\n );\n } catch {\n this.queue.unshift(...batch);\n } finally {\n this.isFlushing = false;\n }\n }\n\n private flushOnUnload() {\n if (!navigator.sendBeacon || this.queue.length === 0) return;\n const payload = JSON.stringify({ events: this.queue });\n navigator.sendBeacon(this.opts.endpoint, payload);\n }\n\n private makeId() {\n return 'xxxx-xxxx-4xxx-yxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n public destroy() {\n clearInterval(this.flushTimer);\n }\n}\n","import type { eventWithTime, listenerHandler } from '@rrweb/types';\nimport { record } from 'rrweb';\nimport { pack } from '@rrweb/packer';\n\nlet events: eventWithTime[] = [];\nconst MAX_EVENTS = 1000;\nlet stopFn: listenerHandler | undefined = undefined;\n\nexport function startRecording() {\n events = [];\n stopFn?.();\n stopFn = record({\n emit(event) {\n if (event.type === 2) console.log('[rrweb] FullSnapshot κΈ°λ‘λ¨:', event);\n\n events.push(event);\n if (events.length > MAX_EVENTS) {\n events = events.slice(-MAX_EVENTS);\n }\n },\n // checkoutEveryNms: 1000, // 1μ΄λ§λ€ 체ν¬μμ\n checkoutEveryNms: 15000, // 15μ΄λ§λ€ ν λ²\n checkoutEveryNth: 100, // 100κ° μ΄λ²€νΈλ§λ€ ν λ²\n // packFn: pack,\n });\n}\n\nexport function getRecordedEvents(\n beforeErrorSec = 10,\n errorTime = Date.now(),\n source = events\n): eventWithTime[] {\n const sliced = source.filter(\n (e) => errorTime - e.timestamp < beforeErrorSec * 1000\n );\n\n const snapshotCandidates = source.filter((e) => e.type === 2);\n const lastSnapshot = [...snapshotCandidates]\n .reverse()\n .find((e) => e.timestamp <= errorTime);\n\n if (lastSnapshot && !sliced.includes(lastSnapshot)) {\n return [lastSnapshot, ...sliced];\n }\n\n if (!sliced.some((e) => e.type === 2)) {\n console.warn('β οΈ Snapshot μμ΄ μλ¦° replayμ
λλ€. 볡μ λΆκ°λ₯ν μ μμ.');\n }\n\n return sliced;\n}\n\n// export function getRecordedEvents(\n// beforeErrorSec = 10,\n// errorTime = Date.now(),\n// source = events\n// ): eventWithTime[] {\n// const sliced = source.filter(\n// (e) => errorTime - e.timestamp < beforeErrorSec * 1000\n// );\n\n// const fullSnapshots = source.filter((e) => e.type === 2);\n// const lastSnapshot = fullSnapshots.reverse().find(\n// (e) => e.timestamp <= sliced[0]?.timestamp\n// );\n// // const lastSnapshot = fullSnapshots\n// // .reverse()\n// // .find((e) => e.timestamp <= (sliced[0]?.timestamp ?? errorTime));\n\n// if (lastSnapshot && !sliced.includes(lastSnapshot)) {\n// return [lastSnapshot, ...sliced];\n// }\n\n// if (!sliced.some((e) => e.type === 2)) {\n// console.warn('β οΈ Snapshot μμ΄ μλ¦° replayμ
λλ€. 볡μ λΆκ°λ₯ν μ μμ.');\n// }\n\n// return sliced;\n// }\n\nexport function clearEvents() {\n events = [];\n}\n\nexport function getCurrentEvents(): eventWithTime[] {\n return events.slice();\n}\n","import { captureException } from './reporter';\n\nexport function setupGlobalErrorHandler() {\n if ((window as any).__errorHandlerSetup) return;\n\n const origOnError = window.onerror;\n window.onerror = function thisWindowOnError(\n this: Window & WindowEventHandlers,\n message: string | Event,\n source?: string,\n lineno?: number,\n colno?: number,\n error?: Error\n ): boolean {\n origOnError?.call(this, message, source, lineno, colno, error);\n captureException(\n error ??\n new Error(typeof message === 'string' ? message : 'Unknown error')\n );\n return false;\n };\n\n const origOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = function thisWindowOnRejection(\n this: Window & WindowEventHandlers,\n event: PromiseRejectionEvent\n ): any {\n origOnUnhandledRejection?.call(this, event);\n const err =\n event.reason instanceof Error\n ? event.reason\n : new Error(JSON.stringify(event.reason));\n captureException(err);\n } as typeof window.onunhandledrejection;\n\n (window as any).__errorHandlerSetup = true;\n}\n","import { getBrowserInfo, getEnvironment } from './environment';\nimport { ErrorBatcher } from './error-batcher';\nimport {\n startRecording,\n getRecordedEvents,\n getCurrentEvents,\n clearEvents,\n} from './recorder';\n\nexport interface AdditionalInfo {\n pageUrl: string;\n request: {\n url: string;\n method: string;\n headers: Record<string, string>;\n };\n response: {\n data: {\n message: string;\n errorCode: string;\n };\n status: number;\n statusText: string;\n };\n}\n\nexport interface BatchedEvent {\n id: string;\n timestamp: string;\n message: string;\n stacktrace: string;\n replay: any[];\n environment: string;\n browser: string;\n os: string;\n userAgent: string;\n userId?: number;\n additionalInfo?: AdditionalInfo;\n appVersion: string;\n apiKey: string;\n}\n\nexport interface BatcherOptions {\n endpoint: string;\n apiKey: string;\n flushIntervalMs?: number;\n maxBufferSize?: number;\n}\n\nexport interface InitOptions {\n endpoint: string;\n apiKey: string;\n flushIntervalMs?: number;\n maxBufferSize?: number;\n beforeErrorSec?: number;\n}\n\nlet batcher: ErrorBatcher;\nlet globalOpts: { beforeErrorSec: number } = { beforeErrorSec: 30 };\n\nexport function init(options: InitOptions) {\n globalOpts.beforeErrorSec = options.beforeErrorSec ?? 10;\n\n batcher = new ErrorBatcher({\n endpoint: options.endpoint,\n apiKey: options.apiKey,\n flushIntervalMs: options.flushIntervalMs,\n maxBufferSize: options.maxBufferSize,\n });\n\n if (typeof window !== 'undefined') {\n const start = () => {\n startRecording(); // DOM λ λλ§ νμ μμλλλ‘ μ§μ° μ€ν\n import('./handler.js').then((mod) => mod.setupGlobalErrorHandler());\n };\n\n if (document.readyState === 'complete') {\n requestAnimationFrame(() => startRecording());\n } else {\n window.addEventListener('load', () => {\n requestAnimationFrame(() => startRecording());\n });\n }\n\n // if ('requestIdleCallback' in window) {\n // window.requestIdleCallback(start);\n // } else {\n // setTimeout(start, 100);\n // }\n }\n}\n\nexport function captureException(\n error: Error,\n additionalInfo?: AdditionalInfo,\n userId?: number\n): string {\n const errorTime = Date.now();\n const eventsSnapshot = getCurrentEvents();\n const replay = getRecordedEvents(\n globalOpts.beforeErrorSec,\n errorTime,\n eventsSnapshot\n );\n\n clearEvents(); // λ€μ μλ¬ κΈ°λ‘μ μν΄ μ΄κΈ°ν\n\n const { browser, os, userAgent } = getBrowserInfo();\n\n return batcher.capture({\n message: error.message ?? '',\n stacktrace: error.stack ?? '',\n replay,\n environment: getEnvironment(),\n browser,\n os,\n userAgent,\n userId,\n additionalInfo,\n appVersion: '1.0.0',\n apiKey: batcher.getApiKey(),\n });\n}\n","export * from './reporter';\nexport { setupGlobalErrorHandler } from './handler';\nexport { startRecording, getRecordedEvents } from './recorder';\nexport { getBrowserInfo, getEnvironment } from './environment';\nexport { ErrorBatcher } from './error-batcher';\nexport type { BatchedEvent, InitOptions, AdditionalInfo } from './reporter';\n"],"mappings":"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","names":["record","axios"]}
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/error-batcher.ts","../src/recorder.ts","../src/utils.ts","../src/reporter.ts","../src/handler.ts"],"sourcesContent":["export * from './reporter';\nexport { setupGlobalErrorHandler } from './handler';\nexport { startRecording, getRecordedEvents } from './recorder';\nexport { getBrowserInfo, getEnvironment } from './environment';\nexport { ErrorBatcher } from './error-batcher';\nexport type { BatchedEvent, InitOptions, AdditionalInfo } from './reporter';\nexport { decompressFromBase64 } from './utils';\n","export function getBrowserInfo() {\n const ua = navigator.userAgent;\n let browser = 'unknown',\n os = 'unknown';\n\n if (ua.includes('Firefox')) browser = 'Firefox';\n else if (ua.includes('SamsungBrowser')) browser = 'Samsung Browser';\n else if (ua.includes('Opera') || ua.includes('OPR')) browser = 'Opera';\n else if (ua.includes('Trident')) browser = 'IE';\n else if (ua.includes('Edge')) browser = 'Edge (Legacy)';\n else if (ua.includes('Edg')) browser = 'Edge';\n else if (ua.includes('Chrome')) browser = 'Chrome';\n else if (ua.includes('Safari')) browser = 'Safari';\n\n if (ua.includes('Windows')) os = 'Windows';\n else if (ua.includes('Mac')) os = 'macOS';\n else if (ua.includes('Linux')) os = 'Linux';\n else if (ua.includes('Android')) os = 'Android';\n else if (ua.includes('like Mac')) os = 'iOS';\n\n return { browser, os, userAgent: ua };\n}\n\nexport function getEnvironment(): 'development' | 'staging' | 'production' {\n if (process.env.NODE_ENV === 'development') return 'development';\n return 'production';\n}\n","import axios from 'axios';\nimport type { BatcherOptions, BatchedEvent } from './reporter';\n\nexport class ErrorBatcher {\n private queue: BatchedEvent[] = [];\n private isFlushing = false;\n private flushTimer: number;\n private readonly apiKey: string;\n\n constructor(private opts: BatcherOptions) {\n this.apiKey = opts.apiKey;\n const interval = opts.flushIntervalMs ?? 30000;\n this.flushTimer = window.setInterval(() => this.flush(), interval);\n window.addEventListener('beforeunload', () => this.flushOnUnload());\n }\n\n public getApiKey(): string {\n return this.apiKey;\n }\n\n public capture(evt: Omit<BatchedEvent, 'id' | 'timestamp'>): string {\n const id = this.makeId();\n const timestamp = new Date().toISOString();\n const record: BatchedEvent = { id, timestamp, ...evt };\n\n if (this.queue.length >= (this.opts.maxBufferSize ?? 64)) {\n this.queue.shift();\n }\n this.queue.push(record);\n return id;\n }\n\n private async flush() {\n if (this.isFlushing || this.queue.length === 0) return;\n this.isFlushing = true;\n\n const batch = this.queue.splice(0, this.queue.length);\n try {\n await axios.post(\n this.opts.endpoint,\n { events: batch },\n {\n maxBodyLength: 1000 * 1024 * 1024, // 10MB\n maxContentLength: 1000 * 1024 * 1024, // 10MB\n timeout: 30000,\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n );\n } catch {\n this.queue.unshift(...batch);\n } finally {\n this.isFlushing = false;\n }\n }\n\n private flushOnUnload() {\n if (!navigator.sendBeacon || this.queue.length === 0) return;\n const payload = JSON.stringify({ events: this.queue });\n navigator.sendBeacon(this.opts.endpoint, payload);\n }\n\n private makeId() {\n return 'xxxx-xxxx-4xxx-yxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n public destroy() {\n clearInterval(this.flushTimer);\n }\n}\n","import type { eventWithTime, listenerHandler } from '@rrweb/types';\nimport { record } from 'rrweb';\n\nlet events: eventWithTime[] = [];\nconst MAX_EVENTS = 1000;\nlet stopFn: listenerHandler | undefined = undefined;\n\nexport function startRecording() {\n events = [];\n stopFn?.();\n stopFn = record({\n emit(event) {\n if (event.type === 2) console.log('[rrweb] FullSnapshot κΈ°λ‘λ¨:', event);\n\n events.push(event);\n if (events.length > MAX_EVENTS) {\n events = events.slice(-MAX_EVENTS);\n }\n },\n // checkoutEveryNms: 1000, // 1μ΄λ§λ€ 체ν¬μμ\n checkoutEveryNms: 15000, // 15μ΄λ§λ€ ν λ²\n checkoutEveryNth: 100, // 100κ° μ΄λ²€νΈλ§λ€ ν λ²\n maskAllInputs: true,\n sampling: {\n mouseInteraction: {\n MouseUp: false,\n MouseDown: false,\n Click: false,\n ContextMenu: false,\n DblClick: false,\n Focus: false,\n Blur: false,\n TouchStart: false,\n TouchEnd: false,\n },\n },\n });\n}\n\nexport function getRecordedEvents(\n beforeErrorSec = 10,\n errorTime = Date.now(),\n source = events\n): eventWithTime[] {\n const sliced = source.filter(\n (e) => errorTime - e.timestamp < beforeErrorSec * 1000\n );\n\n const snapshotCandidates = source.filter((e) => e.type === 2);\n const lastSnapshot = [...snapshotCandidates]\n .reverse()\n .find((e) => e.timestamp <= errorTime);\n\n if (lastSnapshot && !sliced.includes(lastSnapshot)) {\n return [lastSnapshot, ...sliced];\n }\n\n if (!sliced.some((e) => e.type === 2)) {\n console.warn('β οΈ Snapshot μμ΄ μλ¦° replayμ
λλ€. 볡μ λΆκ°λ₯ν μ μμ.');\n }\n\n return sliced;\n}\n\nexport function clearEvents() {\n events = [];\n}\n\nexport function getCurrentEvents(): eventWithTime[] {\n return events.slice();\n}\n","import { zlibSync, unzlibSync } from 'fflate';\n\nexport function compressToBase64(obj: any): string {\n const json = JSON.stringify(obj);\n const compressed = zlibSync(new TextEncoder().encode(json));\n return btoa(String.fromCharCode(...compressed));\n}\n\nexport function decompressFromBase64(base64: string): any[] {\n const binary = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));\n const json = new TextDecoder().decode(unzlibSync(binary));\n return JSON.parse(json);\n}\n","import { getBrowserInfo, getEnvironment } from './environment';\nimport { ErrorBatcher } from './error-batcher';\nimport {\n startRecording,\n getRecordedEvents,\n getCurrentEvents,\n clearEvents,\n} from './recorder';\nimport { compressToBase64 } from './utils';\n\nexport interface AdditionalInfo {\n pageUrl: string;\n request: {\n url: string;\n method: string;\n headers: Record<string, string>;\n };\n response: {\n data: {\n message: string;\n errorCode: string;\n };\n status: number;\n statusText: string;\n };\n}\n\nexport interface BatchedEvent {\n id: string;\n timestamp: string;\n message: string;\n stacktrace: string;\n replay: string | null;\n environment: string;\n browser: string;\n os: string;\n userAgent: string;\n userId?: number;\n additionalInfo?: Partial<AdditionalInfo>;\n appVersion: string;\n apiKey: string;\n}\n\nexport interface BatcherOptions {\n endpoint: string;\n apiKey: string;\n flushIntervalMs?: number;\n maxBufferSize?: number;\n}\n\nexport interface InitOptions {\n endpoint: string;\n apiKey: string;\n flushIntervalMs?: number;\n maxBufferSize?: number;\n beforeErrorSec?: number;\n}\n\nlet batcher: ErrorBatcher;\nlet globalOpts: { beforeErrorSec: number } = { beforeErrorSec: 30 };\n\nexport function init(options: InitOptions) {\n globalOpts.beforeErrorSec = options.beforeErrorSec ?? 10;\n\n batcher = new ErrorBatcher({\n endpoint: options.endpoint,\n apiKey: options.apiKey,\n flushIntervalMs: options.flushIntervalMs,\n maxBufferSize: options.maxBufferSize,\n });\n\n if (typeof window !== 'undefined') {\n if (document.readyState === 'complete') {\n requestAnimationFrame(() => startRecording());\n } else {\n window.addEventListener('load', () => {\n requestAnimationFrame(() => startRecording());\n });\n }\n }\n}\n\nexport function captureException(\n error: Error,\n additionalInfo?: Partial<AdditionalInfo>,\n userId?: number\n): string {\n const errorTime = Date.now();\n const eventsSnapshot = getCurrentEvents();\n const rawReplay = getRecordedEvents(\n globalOpts.beforeErrorSec,\n errorTime,\n eventsSnapshot\n );\n\n clearEvents();\n\n const { browser, os, userAgent } = getBrowserInfo();\n\n const compressedReplay = compressToBase64(rawReplay);\n\n return batcher.capture({\n message: error.message ?? '',\n stacktrace: error.stack ?? '',\n replay: compressedReplay as any,\n environment: getEnvironment(),\n browser,\n os,\n userAgent,\n userId,\n additionalInfo,\n appVersion: '1.0.0',\n apiKey: batcher.getApiKey(),\n });\n}\n","import { captureException } from './reporter';\n\nexport function setupGlobalErrorHandler() {\n if ((window as any).__errorHandlerSetup) return;\n\n const origOnError = window.onerror;\n window.onerror = function thisWindowOnError(\n this: Window & WindowEventHandlers,\n message: string | Event,\n source?: string,\n lineno?: number,\n colno?: number,\n error?: Error\n ): boolean {\n origOnError?.call(this, message, source, lineno, colno, error);\n captureException(\n error ??\n new Error(typeof message === 'string' ? message : 'Unknown error')\n );\n return false;\n };\n\n const origOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = function thisWindowOnRejection(\n this: Window & WindowEventHandlers,\n event: PromiseRejectionEvent\n ): any {\n origOnUnhandledRejection?.call(this, event);\n const err =\n event.reason instanceof Error\n ? event.reason\n : new Error(JSON.stringify(event.reason));\n captureException(err);\n } as typeof window.onunhandledrejection;\n\n (window as any).__errorHandlerSetup = true;\n}\n"],"mappings":"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","names":["record","axios"]}
|
package/dist/index.d.cts
CHANGED
@@ -21,13 +21,13 @@ interface BatchedEvent {
|
|
21
21
|
timestamp: string;
|
22
22
|
message: string;
|
23
23
|
stacktrace: string;
|
24
|
-
replay:
|
24
|
+
replay: string | null;
|
25
25
|
environment: string;
|
26
26
|
browser: string;
|
27
27
|
os: string;
|
28
28
|
userAgent: string;
|
29
29
|
userId?: number;
|
30
|
-
additionalInfo?: AdditionalInfo
|
30
|
+
additionalInfo?: Partial<AdditionalInfo>;
|
31
31
|
appVersion: string;
|
32
32
|
apiKey: string;
|
33
33
|
}
|
@@ -45,7 +45,7 @@ interface InitOptions {
|
|
45
45
|
beforeErrorSec?: number;
|
46
46
|
}
|
47
47
|
declare function init(options: InitOptions): void;
|
48
|
-
declare function captureException(error: Error, additionalInfo?: AdditionalInfo
|
48
|
+
declare function captureException(error: Error, additionalInfo?: Partial<AdditionalInfo>, userId?: number): string;
|
49
49
|
|
50
50
|
declare function setupGlobalErrorHandler(): void;
|
51
51
|
|
@@ -74,4 +74,6 @@ declare class ErrorBatcher {
|
|
74
74
|
destroy(): void;
|
75
75
|
}
|
76
76
|
|
77
|
-
|
77
|
+
declare function decompressFromBase64(base64: string): any[];
|
78
|
+
|
79
|
+
export { type AdditionalInfo, type BatchedEvent, type BatcherOptions, ErrorBatcher, type InitOptions, captureException, decompressFromBase64, getBrowserInfo, getEnvironment, getRecordedEvents, init, setupGlobalErrorHandler, startRecording };
|
package/dist/index.d.ts
CHANGED
@@ -21,13 +21,13 @@ interface BatchedEvent {
|
|
21
21
|
timestamp: string;
|
22
22
|
message: string;
|
23
23
|
stacktrace: string;
|
24
|
-
replay:
|
24
|
+
replay: string | null;
|
25
25
|
environment: string;
|
26
26
|
browser: string;
|
27
27
|
os: string;
|
28
28
|
userAgent: string;
|
29
29
|
userId?: number;
|
30
|
-
additionalInfo?: AdditionalInfo
|
30
|
+
additionalInfo?: Partial<AdditionalInfo>;
|
31
31
|
appVersion: string;
|
32
32
|
apiKey: string;
|
33
33
|
}
|
@@ -45,7 +45,7 @@ interface InitOptions {
|
|
45
45
|
beforeErrorSec?: number;
|
46
46
|
}
|
47
47
|
declare function init(options: InitOptions): void;
|
48
|
-
declare function captureException(error: Error, additionalInfo?: AdditionalInfo
|
48
|
+
declare function captureException(error: Error, additionalInfo?: Partial<AdditionalInfo>, userId?: number): string;
|
49
49
|
|
50
50
|
declare function setupGlobalErrorHandler(): void;
|
51
51
|
|
@@ -74,4 +74,6 @@ declare class ErrorBatcher {
|
|
74
74
|
destroy(): void;
|
75
75
|
}
|
76
76
|
|
77
|
-
|
77
|
+
declare function decompressFromBase64(base64: string): any[];
|
78
|
+
|
79
|
+
export { type AdditionalInfo, type BatchedEvent, type BatcherOptions, ErrorBatcher, type InitOptions, captureException, decompressFromBase64, getBrowserInfo, getEnvironment, getRecordedEvents, init, setupGlobalErrorHandler, startRecording };
|
package/dist/index.js
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
var __defProp = Object.defineProperty;
|
2
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
3
2
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
4
3
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
5
4
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
@@ -15,20 +14,6 @@ var __spreadValues = (a, b) => {
|
|
15
14
|
}
|
16
15
|
return a;
|
17
16
|
};
|
18
|
-
var __esm = (fn, res) => function __init() {
|
19
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
20
|
-
};
|
21
|
-
var __export = (target, all) => {
|
22
|
-
for (var name in all)
|
23
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
24
|
-
};
|
25
|
-
|
26
|
-
// ../../node_modules/.pnpm/tsup@8.4.0_jiti@2.4.2_postcss@8.5.3_typescript@5.8.3/node_modules/tsup/assets/esm_shims.js
|
27
|
-
var init_esm_shims = __esm({
|
28
|
-
"../../node_modules/.pnpm/tsup@8.4.0_jiti@2.4.2_postcss@8.5.3_typescript@5.8.3/node_modules/tsup/assets/esm_shims.js"() {
|
29
|
-
"use strict";
|
30
|
-
}
|
31
|
-
});
|
32
17
|
|
33
18
|
// src/environment.ts
|
34
19
|
function getBrowserInfo() {
|
@@ -51,95 +36,83 @@ function getBrowserInfo() {
|
|
51
36
|
}
|
52
37
|
function getEnvironment() {
|
53
38
|
if (process.env.NODE_ENV === "development") return "development";
|
54
|
-
if (process.env.NEXT_PUBLIC_VERCEL_ENV === "preview") return "staging";
|
55
39
|
return "production";
|
56
40
|
}
|
57
|
-
var init_environment = __esm({
|
58
|
-
"src/environment.ts"() {
|
59
|
-
"use strict";
|
60
|
-
init_esm_shims();
|
61
|
-
}
|
62
|
-
});
|
63
41
|
|
64
42
|
// src/error-batcher.ts
|
65
43
|
import axios from "axios";
|
66
|
-
var ErrorBatcher
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
// 10MB
|
109
|
-
timeout: 3e4,
|
110
|
-
headers: {
|
111
|
-
"Content-Type": "application/json",
|
112
|
-
Authorization: `Bearer ${this.opts.apiKey}`
|
113
|
-
}
|
114
|
-
}
|
115
|
-
);
|
116
|
-
} catch (e) {
|
117
|
-
this.queue.unshift(...batch);
|
118
|
-
} finally {
|
119
|
-
this.isFlushing = false;
|
44
|
+
var ErrorBatcher = class {
|
45
|
+
constructor(opts) {
|
46
|
+
this.opts = opts;
|
47
|
+
this.queue = [];
|
48
|
+
this.isFlushing = false;
|
49
|
+
var _a;
|
50
|
+
this.apiKey = opts.apiKey;
|
51
|
+
const interval = (_a = opts.flushIntervalMs) != null ? _a : 3e4;
|
52
|
+
this.flushTimer = window.setInterval(() => this.flush(), interval);
|
53
|
+
window.addEventListener("beforeunload", () => this.flushOnUnload());
|
54
|
+
}
|
55
|
+
getApiKey() {
|
56
|
+
return this.apiKey;
|
57
|
+
}
|
58
|
+
capture(evt) {
|
59
|
+
var _a;
|
60
|
+
const id = this.makeId();
|
61
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
62
|
+
const record2 = __spreadValues({ id, timestamp }, evt);
|
63
|
+
if (this.queue.length >= ((_a = this.opts.maxBufferSize) != null ? _a : 64)) {
|
64
|
+
this.queue.shift();
|
65
|
+
}
|
66
|
+
this.queue.push(record2);
|
67
|
+
return id;
|
68
|
+
}
|
69
|
+
async flush() {
|
70
|
+
if (this.isFlushing || this.queue.length === 0) return;
|
71
|
+
this.isFlushing = true;
|
72
|
+
const batch = this.queue.splice(0, this.queue.length);
|
73
|
+
try {
|
74
|
+
await axios.post(
|
75
|
+
this.opts.endpoint,
|
76
|
+
{ events: batch },
|
77
|
+
{
|
78
|
+
maxBodyLength: 1e3 * 1024 * 1024,
|
79
|
+
// 10MB
|
80
|
+
maxContentLength: 1e3 * 1024 * 1024,
|
81
|
+
// 10MB
|
82
|
+
timeout: 3e4,
|
83
|
+
headers: {
|
84
|
+
"Content-Type": "application/json"
|
85
|
+
}
|
120
86
|
}
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
87
|
+
);
|
88
|
+
} catch (e) {
|
89
|
+
this.queue.unshift(...batch);
|
90
|
+
} finally {
|
91
|
+
this.isFlushing = false;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
flushOnUnload() {
|
95
|
+
if (!navigator.sendBeacon || this.queue.length === 0) return;
|
96
|
+
const payload = JSON.stringify({ events: this.queue });
|
97
|
+
navigator.sendBeacon(this.opts.endpoint, payload);
|
98
|
+
}
|
99
|
+
makeId() {
|
100
|
+
return "xxxx-xxxx-4xxx-yxxx".replace(/[xy]/g, (c) => {
|
101
|
+
const r = Math.random() * 16 | 0;
|
102
|
+
const v = c === "x" ? r : r & 3 | 8;
|
103
|
+
return v.toString(16);
|
104
|
+
});
|
105
|
+
}
|
106
|
+
destroy() {
|
107
|
+
clearInterval(this.flushTimer);
|
138
108
|
}
|
139
|
-
}
|
109
|
+
};
|
140
110
|
|
141
111
|
// src/recorder.ts
|
142
112
|
import { record } from "rrweb";
|
113
|
+
var events = [];
|
114
|
+
var MAX_EVENTS = 1e3;
|
115
|
+
var stopFn = void 0;
|
143
116
|
function startRecording() {
|
144
117
|
events = [];
|
145
118
|
stopFn == null ? void 0 : stopFn();
|
@@ -154,9 +127,22 @@ function startRecording() {
|
|
154
127
|
// checkoutEveryNms: 1000, // 1μ΄λ§λ€ 체ν¬μμ
|
155
128
|
checkoutEveryNms: 15e3,
|
156
129
|
// 15μ΄λ§λ€ ν λ²
|
157
|
-
checkoutEveryNth: 100
|
130
|
+
checkoutEveryNth: 100,
|
158
131
|
// 100κ° μ΄λ²€νΈλ§λ€ ν λ²
|
159
|
-
|
132
|
+
maskAllInputs: true,
|
133
|
+
sampling: {
|
134
|
+
mouseInteraction: {
|
135
|
+
MouseUp: false,
|
136
|
+
MouseDown: false,
|
137
|
+
Click: false,
|
138
|
+
ContextMenu: false,
|
139
|
+
DblClick: false,
|
140
|
+
Focus: false,
|
141
|
+
Blur: false,
|
142
|
+
TouchStart: false,
|
143
|
+
TouchEnd: false
|
144
|
+
}
|
145
|
+
}
|
160
146
|
});
|
161
147
|
}
|
162
148
|
function getRecordedEvents(beforeErrorSec = 10, errorTime = Date.now(), source = events) {
|
@@ -179,49 +165,23 @@ function clearEvents() {
|
|
179
165
|
function getCurrentEvents() {
|
180
166
|
return events.slice();
|
181
167
|
}
|
182
|
-
var events, MAX_EVENTS, stopFn;
|
183
|
-
var init_recorder = __esm({
|
184
|
-
"src/recorder.ts"() {
|
185
|
-
"use strict";
|
186
|
-
init_esm_shims();
|
187
|
-
events = [];
|
188
|
-
MAX_EVENTS = 1e3;
|
189
|
-
stopFn = void 0;
|
190
|
-
}
|
191
|
-
});
|
192
168
|
|
193
|
-
// src/
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
error != null ? error : new Error(typeof message === "string" ? message : "Unknown error")
|
205
|
-
);
|
206
|
-
return false;
|
207
|
-
};
|
208
|
-
const origOnUnhandledRejection = window.onunhandledrejection;
|
209
|
-
window.onunhandledrejection = function thisWindowOnRejection(event) {
|
210
|
-
origOnUnhandledRejection == null ? void 0 : origOnUnhandledRejection.call(this, event);
|
211
|
-
const err = event.reason instanceof Error ? event.reason : new Error(JSON.stringify(event.reason));
|
212
|
-
captureException(err);
|
213
|
-
};
|
214
|
-
window.__errorHandlerSetup = true;
|
169
|
+
// src/utils.ts
|
170
|
+
import { zlibSync, unzlibSync } from "fflate";
|
171
|
+
function compressToBase64(obj) {
|
172
|
+
const json = JSON.stringify(obj);
|
173
|
+
const compressed = zlibSync(new TextEncoder().encode(json));
|
174
|
+
return btoa(String.fromCharCode(...compressed));
|
175
|
+
}
|
176
|
+
function decompressFromBase64(base64) {
|
177
|
+
const binary = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
|
178
|
+
const json = new TextDecoder().decode(unzlibSync(binary));
|
179
|
+
return JSON.parse(json);
|
215
180
|
}
|
216
|
-
var init_handler = __esm({
|
217
|
-
"src/handler.ts"() {
|
218
|
-
"use strict";
|
219
|
-
init_esm_shims();
|
220
|
-
init_reporter();
|
221
|
-
}
|
222
|
-
});
|
223
181
|
|
224
182
|
// src/reporter.ts
|
183
|
+
var batcher;
|
184
|
+
var globalOpts = { beforeErrorSec: 30 };
|
225
185
|
function init(options) {
|
226
186
|
var _a;
|
227
187
|
globalOpts.beforeErrorSec = (_a = options.beforeErrorSec) != null ? _a : 10;
|
@@ -232,10 +192,6 @@ function init(options) {
|
|
232
192
|
maxBufferSize: options.maxBufferSize
|
233
193
|
});
|
234
194
|
if (typeof window !== "undefined") {
|
235
|
-
const start = () => {
|
236
|
-
startRecording();
|
237
|
-
Promise.resolve().then(() => (init_handler(), handler_exports)).then((mod) => mod.setupGlobalErrorHandler());
|
238
|
-
};
|
239
195
|
if (document.readyState === "complete") {
|
240
196
|
requestAnimationFrame(() => startRecording());
|
241
197
|
} else {
|
@@ -249,17 +205,18 @@ function captureException(error, additionalInfo, userId) {
|
|
249
205
|
var _a, _b;
|
250
206
|
const errorTime = Date.now();
|
251
207
|
const eventsSnapshot = getCurrentEvents();
|
252
|
-
const
|
208
|
+
const rawReplay = getRecordedEvents(
|
253
209
|
globalOpts.beforeErrorSec,
|
254
210
|
errorTime,
|
255
211
|
eventsSnapshot
|
256
212
|
);
|
257
213
|
clearEvents();
|
258
214
|
const { browser, os, userAgent } = getBrowserInfo();
|
215
|
+
const compressedReplay = compressToBase64(rawReplay);
|
259
216
|
return batcher.capture({
|
260
217
|
message: (_a = error.message) != null ? _a : "",
|
261
218
|
stacktrace: (_b = error.stack) != null ? _b : "",
|
262
|
-
replay,
|
219
|
+
replay: compressedReplay,
|
263
220
|
environment: getEnvironment(),
|
264
221
|
browser,
|
265
222
|
os,
|
@@ -270,28 +227,30 @@ function captureException(error, additionalInfo, userId) {
|
|
270
227
|
apiKey: batcher.getApiKey()
|
271
228
|
});
|
272
229
|
}
|
273
|
-
var batcher, globalOpts;
|
274
|
-
var init_reporter = __esm({
|
275
|
-
"src/reporter.ts"() {
|
276
|
-
"use strict";
|
277
|
-
init_esm_shims();
|
278
|
-
init_environment();
|
279
|
-
init_error_batcher();
|
280
|
-
init_recorder();
|
281
|
-
globalOpts = { beforeErrorSec: 30 };
|
282
|
-
}
|
283
|
-
});
|
284
230
|
|
285
|
-
// src/
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
231
|
+
// src/handler.ts
|
232
|
+
function setupGlobalErrorHandler() {
|
233
|
+
if (window.__errorHandlerSetup) return;
|
234
|
+
const origOnError = window.onerror;
|
235
|
+
window.onerror = function thisWindowOnError(message, source, lineno, colno, error) {
|
236
|
+
origOnError == null ? void 0 : origOnError.call(this, message, source, lineno, colno, error);
|
237
|
+
captureException(
|
238
|
+
error != null ? error : new Error(typeof message === "string" ? message : "Unknown error")
|
239
|
+
);
|
240
|
+
return false;
|
241
|
+
};
|
242
|
+
const origOnUnhandledRejection = window.onunhandledrejection;
|
243
|
+
window.onunhandledrejection = function thisWindowOnRejection(event) {
|
244
|
+
origOnUnhandledRejection == null ? void 0 : origOnUnhandledRejection.call(this, event);
|
245
|
+
const err = event.reason instanceof Error ? event.reason : new Error(JSON.stringify(event.reason));
|
246
|
+
captureException(err);
|
247
|
+
};
|
248
|
+
window.__errorHandlerSetup = true;
|
249
|
+
}
|
292
250
|
export {
|
293
251
|
ErrorBatcher,
|
294
252
|
captureException,
|
253
|
+
decompressFromBase64,
|
295
254
|
getBrowserInfo,
|
296
255
|
getEnvironment,
|
297
256
|
getRecordedEvents,
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.4.0_jiti@2.4.2_postcss@8.5.3_typescript@5.8.3/node_modules/tsup/assets/esm_shims.js","../src/environment.ts","../src/error-batcher.ts","../src/recorder.ts","../src/handler.ts","../src/reporter.ts","../src/index.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport { fileURLToPath } from 'url'\nimport path from 'path'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","export function getBrowserInfo() {\n const ua = navigator.userAgent;\n let browser = 'unknown',\n os = 'unknown';\n\n if (ua.includes('Firefox')) browser = 'Firefox';\n else if (ua.includes('SamsungBrowser')) browser = 'Samsung Browser';\n else if (ua.includes('Opera') || ua.includes('OPR')) browser = 'Opera';\n else if (ua.includes('Trident')) browser = 'IE';\n else if (ua.includes('Edge')) browser = 'Edge (Legacy)';\n else if (ua.includes('Edg')) browser = 'Edge';\n else if (ua.includes('Chrome')) browser = 'Chrome';\n else if (ua.includes('Safari')) browser = 'Safari';\n\n if (ua.includes('Windows')) os = 'Windows';\n else if (ua.includes('Mac')) os = 'macOS';\n else if (ua.includes('Linux')) os = 'Linux';\n else if (ua.includes('Android')) os = 'Android';\n else if (ua.includes('like Mac')) os = 'iOS';\n\n return { browser, os, userAgent: ua };\n}\n\nexport function getEnvironment(): 'development' | 'staging' | 'production' {\n if (process.env.NODE_ENV === 'development') return 'development';\n if (process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') return 'staging';\n return 'production';\n}\n","import axios from 'axios';\nimport type { BatcherOptions, BatchedEvent } from './reporter';\n\nexport class ErrorBatcher {\n private queue: BatchedEvent[] = [];\n private isFlushing = false;\n private flushTimer: number;\n private readonly apiKey: string;\n\n constructor(private opts: BatcherOptions) {\n this.apiKey = opts.apiKey;\n const interval = opts.flushIntervalMs ?? 3000;\n this.flushTimer = window.setInterval(() => this.flush(), interval);\n window.addEventListener('beforeunload', () => this.flushOnUnload());\n }\n\n public getApiKey(): string {\n return this.apiKey;\n }\n\n public capture(evt: Omit<BatchedEvent, 'id' | 'timestamp'>): string {\n const id = this.makeId();\n const timestamp = new Date().toISOString();\n const record: BatchedEvent = { id, timestamp, ...evt };\n\n if (this.queue.length >= (this.opts.maxBufferSize ?? 64)) {\n this.queue.shift();\n }\n this.queue.push(record);\n return id;\n }\n\n private async flush() {\n if (this.isFlushing || this.queue.length === 0) return;\n this.isFlushing = true;\n\n const batch = this.queue.splice(0, this.queue.length);\n try {\n await axios.post(\n this.opts.endpoint,\n { events: batch },\n {\n maxBodyLength: 1000 * 1024 * 1024, // 10MB\n maxContentLength: 1000 * 1024 * 1024, // 10MB\n timeout: 30000,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.opts.apiKey}`,\n },\n }\n );\n } catch {\n this.queue.unshift(...batch);\n } finally {\n this.isFlushing = false;\n }\n }\n\n private flushOnUnload() {\n if (!navigator.sendBeacon || this.queue.length === 0) return;\n const payload = JSON.stringify({ events: this.queue });\n navigator.sendBeacon(this.opts.endpoint, payload);\n }\n\n private makeId() {\n return 'xxxx-xxxx-4xxx-yxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n public destroy() {\n clearInterval(this.flushTimer);\n }\n}\n","import type { eventWithTime, listenerHandler } from '@rrweb/types';\nimport { record } from 'rrweb';\nimport { pack } from '@rrweb/packer';\n\nlet events: eventWithTime[] = [];\nconst MAX_EVENTS = 1000;\nlet stopFn: listenerHandler | undefined = undefined;\n\nexport function startRecording() {\n events = [];\n stopFn?.();\n stopFn = record({\n emit(event) {\n if (event.type === 2) console.log('[rrweb] FullSnapshot κΈ°λ‘λ¨:', event);\n\n events.push(event);\n if (events.length > MAX_EVENTS) {\n events = events.slice(-MAX_EVENTS);\n }\n },\n // checkoutEveryNms: 1000, // 1μ΄λ§λ€ 체ν¬μμ\n checkoutEveryNms: 15000, // 15μ΄λ§λ€ ν λ²\n checkoutEveryNth: 100, // 100κ° μ΄λ²€νΈλ§λ€ ν λ²\n // packFn: pack,\n });\n}\n\nexport function getRecordedEvents(\n beforeErrorSec = 10,\n errorTime = Date.now(),\n source = events\n): eventWithTime[] {\n const sliced = source.filter(\n (e) => errorTime - e.timestamp < beforeErrorSec * 1000\n );\n\n const snapshotCandidates = source.filter((e) => e.type === 2);\n const lastSnapshot = [...snapshotCandidates]\n .reverse()\n .find((e) => e.timestamp <= errorTime);\n\n if (lastSnapshot && !sliced.includes(lastSnapshot)) {\n return [lastSnapshot, ...sliced];\n }\n\n if (!sliced.some((e) => e.type === 2)) {\n console.warn('β οΈ Snapshot μμ΄ μλ¦° replayμ
λλ€. 볡μ λΆκ°λ₯ν μ μμ.');\n }\n\n return sliced;\n}\n\n// export function getRecordedEvents(\n// beforeErrorSec = 10,\n// errorTime = Date.now(),\n// source = events\n// ): eventWithTime[] {\n// const sliced = source.filter(\n// (e) => errorTime - e.timestamp < beforeErrorSec * 1000\n// );\n\n// const fullSnapshots = source.filter((e) => e.type === 2);\n// const lastSnapshot = fullSnapshots.reverse().find(\n// (e) => e.timestamp <= sliced[0]?.timestamp\n// );\n// // const lastSnapshot = fullSnapshots\n// // .reverse()\n// // .find((e) => e.timestamp <= (sliced[0]?.timestamp ?? errorTime));\n\n// if (lastSnapshot && !sliced.includes(lastSnapshot)) {\n// return [lastSnapshot, ...sliced];\n// }\n\n// if (!sliced.some((e) => e.type === 2)) {\n// console.warn('β οΈ Snapshot μμ΄ μλ¦° replayμ
λλ€. 볡μ λΆκ°λ₯ν μ μμ.');\n// }\n\n// return sliced;\n// }\n\nexport function clearEvents() {\n events = [];\n}\n\nexport function getCurrentEvents(): eventWithTime[] {\n return events.slice();\n}\n","import { captureException } from './reporter';\n\nexport function setupGlobalErrorHandler() {\n if ((window as any).__errorHandlerSetup) return;\n\n const origOnError = window.onerror;\n window.onerror = function thisWindowOnError(\n this: Window & WindowEventHandlers,\n message: string | Event,\n source?: string,\n lineno?: number,\n colno?: number,\n error?: Error\n ): boolean {\n origOnError?.call(this, message, source, lineno, colno, error);\n captureException(\n error ??\n new Error(typeof message === 'string' ? message : 'Unknown error')\n );\n return false;\n };\n\n const origOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = function thisWindowOnRejection(\n this: Window & WindowEventHandlers,\n event: PromiseRejectionEvent\n ): any {\n origOnUnhandledRejection?.call(this, event);\n const err =\n event.reason instanceof Error\n ? event.reason\n : new Error(JSON.stringify(event.reason));\n captureException(err);\n } as typeof window.onunhandledrejection;\n\n (window as any).__errorHandlerSetup = true;\n}\n","import { getBrowserInfo, getEnvironment } from './environment';\nimport { ErrorBatcher } from './error-batcher';\nimport {\n startRecording,\n getRecordedEvents,\n getCurrentEvents,\n clearEvents,\n} from './recorder';\n\nexport interface AdditionalInfo {\n pageUrl: string;\n request: {\n url: string;\n method: string;\n headers: Record<string, string>;\n };\n response: {\n data: {\n message: string;\n errorCode: string;\n };\n status: number;\n statusText: string;\n };\n}\n\nexport interface BatchedEvent {\n id: string;\n timestamp: string;\n message: string;\n stacktrace: string;\n replay: any[];\n environment: string;\n browser: string;\n os: string;\n userAgent: string;\n userId?: number;\n additionalInfo?: AdditionalInfo;\n appVersion: string;\n apiKey: string;\n}\n\nexport interface BatcherOptions {\n endpoint: string;\n apiKey: string;\n flushIntervalMs?: number;\n maxBufferSize?: number;\n}\n\nexport interface InitOptions {\n endpoint: string;\n apiKey: string;\n flushIntervalMs?: number;\n maxBufferSize?: number;\n beforeErrorSec?: number;\n}\n\nlet batcher: ErrorBatcher;\nlet globalOpts: { beforeErrorSec: number } = { beforeErrorSec: 30 };\n\nexport function init(options: InitOptions) {\n globalOpts.beforeErrorSec = options.beforeErrorSec ?? 10;\n\n batcher = new ErrorBatcher({\n endpoint: options.endpoint,\n apiKey: options.apiKey,\n flushIntervalMs: options.flushIntervalMs,\n maxBufferSize: options.maxBufferSize,\n });\n\n if (typeof window !== 'undefined') {\n const start = () => {\n startRecording(); // DOM λ λλ§ νμ μμλλλ‘ μ§μ° μ€ν\n import('./handler.js').then((mod) => mod.setupGlobalErrorHandler());\n };\n\n if (document.readyState === 'complete') {\n requestAnimationFrame(() => startRecording());\n } else {\n window.addEventListener('load', () => {\n requestAnimationFrame(() => startRecording());\n });\n }\n\n // if ('requestIdleCallback' in window) {\n // window.requestIdleCallback(start);\n // } else {\n // setTimeout(start, 100);\n // }\n }\n}\n\nexport function captureException(\n error: Error,\n additionalInfo?: AdditionalInfo,\n userId?: number\n): string {\n const errorTime = Date.now();\n const eventsSnapshot = getCurrentEvents();\n const replay = getRecordedEvents(\n globalOpts.beforeErrorSec,\n errorTime,\n eventsSnapshot\n );\n\n clearEvents(); // λ€μ μλ¬ κΈ°λ‘μ μν΄ μ΄κΈ°ν\n\n const { browser, os, userAgent } = getBrowserInfo();\n\n return batcher.capture({\n message: error.message ?? '',\n stacktrace: error.stack ?? '',\n replay,\n environment: getEnvironment(),\n browser,\n os,\n userAgent,\n userId,\n additionalInfo,\n appVersion: '1.0.0',\n apiKey: batcher.getApiKey(),\n });\n}\n","export * from './reporter';\nexport { setupGlobalErrorHandler } from './handler';\nexport { startRecording, getRecordedEvents } from './recorder';\nexport { getBrowserInfo, getEnvironment } from './environment';\nexport { ErrorBatcher } from './error-batcher';\nexport type { BatchedEvent, InitOptions, AdditionalInfo } from './reporter';\n"],"mappings":"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","names":["record"]}
|
1
|
+
{"version":3,"sources":["../src/environment.ts","../src/error-batcher.ts","../src/recorder.ts","../src/utils.ts","../src/reporter.ts","../src/handler.ts"],"sourcesContent":["export function getBrowserInfo() {\n const ua = navigator.userAgent;\n let browser = 'unknown',\n os = 'unknown';\n\n if (ua.includes('Firefox')) browser = 'Firefox';\n else if (ua.includes('SamsungBrowser')) browser = 'Samsung Browser';\n else if (ua.includes('Opera') || ua.includes('OPR')) browser = 'Opera';\n else if (ua.includes('Trident')) browser = 'IE';\n else if (ua.includes('Edge')) browser = 'Edge (Legacy)';\n else if (ua.includes('Edg')) browser = 'Edge';\n else if (ua.includes('Chrome')) browser = 'Chrome';\n else if (ua.includes('Safari')) browser = 'Safari';\n\n if (ua.includes('Windows')) os = 'Windows';\n else if (ua.includes('Mac')) os = 'macOS';\n else if (ua.includes('Linux')) os = 'Linux';\n else if (ua.includes('Android')) os = 'Android';\n else if (ua.includes('like Mac')) os = 'iOS';\n\n return { browser, os, userAgent: ua };\n}\n\nexport function getEnvironment(): 'development' | 'staging' | 'production' {\n if (process.env.NODE_ENV === 'development') return 'development';\n return 'production';\n}\n","import axios from 'axios';\nimport type { BatcherOptions, BatchedEvent } from './reporter';\n\nexport class ErrorBatcher {\n private queue: BatchedEvent[] = [];\n private isFlushing = false;\n private flushTimer: number;\n private readonly apiKey: string;\n\n constructor(private opts: BatcherOptions) {\n this.apiKey = opts.apiKey;\n const interval = opts.flushIntervalMs ?? 30000;\n this.flushTimer = window.setInterval(() => this.flush(), interval);\n window.addEventListener('beforeunload', () => this.flushOnUnload());\n }\n\n public getApiKey(): string {\n return this.apiKey;\n }\n\n public capture(evt: Omit<BatchedEvent, 'id' | 'timestamp'>): string {\n const id = this.makeId();\n const timestamp = new Date().toISOString();\n const record: BatchedEvent = { id, timestamp, ...evt };\n\n if (this.queue.length >= (this.opts.maxBufferSize ?? 64)) {\n this.queue.shift();\n }\n this.queue.push(record);\n return id;\n }\n\n private async flush() {\n if (this.isFlushing || this.queue.length === 0) return;\n this.isFlushing = true;\n\n const batch = this.queue.splice(0, this.queue.length);\n try {\n await axios.post(\n this.opts.endpoint,\n { events: batch },\n {\n maxBodyLength: 1000 * 1024 * 1024, // 10MB\n maxContentLength: 1000 * 1024 * 1024, // 10MB\n timeout: 30000,\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n );\n } catch {\n this.queue.unshift(...batch);\n } finally {\n this.isFlushing = false;\n }\n }\n\n private flushOnUnload() {\n if (!navigator.sendBeacon || this.queue.length === 0) return;\n const payload = JSON.stringify({ events: this.queue });\n navigator.sendBeacon(this.opts.endpoint, payload);\n }\n\n private makeId() {\n return 'xxxx-xxxx-4xxx-yxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n public destroy() {\n clearInterval(this.flushTimer);\n }\n}\n","import type { eventWithTime, listenerHandler } from '@rrweb/types';\nimport { record } from 'rrweb';\n\nlet events: eventWithTime[] = [];\nconst MAX_EVENTS = 1000;\nlet stopFn: listenerHandler | undefined = undefined;\n\nexport function startRecording() {\n events = [];\n stopFn?.();\n stopFn = record({\n emit(event) {\n if (event.type === 2) console.log('[rrweb] FullSnapshot κΈ°λ‘λ¨:', event);\n\n events.push(event);\n if (events.length > MAX_EVENTS) {\n events = events.slice(-MAX_EVENTS);\n }\n },\n // checkoutEveryNms: 1000, // 1μ΄λ§λ€ 체ν¬μμ\n checkoutEveryNms: 15000, // 15μ΄λ§λ€ ν λ²\n checkoutEveryNth: 100, // 100κ° μ΄λ²€νΈλ§λ€ ν λ²\n maskAllInputs: true,\n sampling: {\n mouseInteraction: {\n MouseUp: false,\n MouseDown: false,\n Click: false,\n ContextMenu: false,\n DblClick: false,\n Focus: false,\n Blur: false,\n TouchStart: false,\n TouchEnd: false,\n },\n },\n });\n}\n\nexport function getRecordedEvents(\n beforeErrorSec = 10,\n errorTime = Date.now(),\n source = events\n): eventWithTime[] {\n const sliced = source.filter(\n (e) => errorTime - e.timestamp < beforeErrorSec * 1000\n );\n\n const snapshotCandidates = source.filter((e) => e.type === 2);\n const lastSnapshot = [...snapshotCandidates]\n .reverse()\n .find((e) => e.timestamp <= errorTime);\n\n if (lastSnapshot && !sliced.includes(lastSnapshot)) {\n return [lastSnapshot, ...sliced];\n }\n\n if (!sliced.some((e) => e.type === 2)) {\n console.warn('β οΈ Snapshot μμ΄ μλ¦° replayμ
λλ€. 볡μ λΆκ°λ₯ν μ μμ.');\n }\n\n return sliced;\n}\n\nexport function clearEvents() {\n events = [];\n}\n\nexport function getCurrentEvents(): eventWithTime[] {\n return events.slice();\n}\n","import { zlibSync, unzlibSync } from 'fflate';\n\nexport function compressToBase64(obj: any): string {\n const json = JSON.stringify(obj);\n const compressed = zlibSync(new TextEncoder().encode(json));\n return btoa(String.fromCharCode(...compressed));\n}\n\nexport function decompressFromBase64(base64: string): any[] {\n const binary = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));\n const json = new TextDecoder().decode(unzlibSync(binary));\n return JSON.parse(json);\n}\n","import { getBrowserInfo, getEnvironment } from './environment';\nimport { ErrorBatcher } from './error-batcher';\nimport {\n startRecording,\n getRecordedEvents,\n getCurrentEvents,\n clearEvents,\n} from './recorder';\nimport { compressToBase64 } from './utils';\n\nexport interface AdditionalInfo {\n pageUrl: string;\n request: {\n url: string;\n method: string;\n headers: Record<string, string>;\n };\n response: {\n data: {\n message: string;\n errorCode: string;\n };\n status: number;\n statusText: string;\n };\n}\n\nexport interface BatchedEvent {\n id: string;\n timestamp: string;\n message: string;\n stacktrace: string;\n replay: string | null;\n environment: string;\n browser: string;\n os: string;\n userAgent: string;\n userId?: number;\n additionalInfo?: Partial<AdditionalInfo>;\n appVersion: string;\n apiKey: string;\n}\n\nexport interface BatcherOptions {\n endpoint: string;\n apiKey: string;\n flushIntervalMs?: number;\n maxBufferSize?: number;\n}\n\nexport interface InitOptions {\n endpoint: string;\n apiKey: string;\n flushIntervalMs?: number;\n maxBufferSize?: number;\n beforeErrorSec?: number;\n}\n\nlet batcher: ErrorBatcher;\nlet globalOpts: { beforeErrorSec: number } = { beforeErrorSec: 30 };\n\nexport function init(options: InitOptions) {\n globalOpts.beforeErrorSec = options.beforeErrorSec ?? 10;\n\n batcher = new ErrorBatcher({\n endpoint: options.endpoint,\n apiKey: options.apiKey,\n flushIntervalMs: options.flushIntervalMs,\n maxBufferSize: options.maxBufferSize,\n });\n\n if (typeof window !== 'undefined') {\n if (document.readyState === 'complete') {\n requestAnimationFrame(() => startRecording());\n } else {\n window.addEventListener('load', () => {\n requestAnimationFrame(() => startRecording());\n });\n }\n }\n}\n\nexport function captureException(\n error: Error,\n additionalInfo?: Partial<AdditionalInfo>,\n userId?: number\n): string {\n const errorTime = Date.now();\n const eventsSnapshot = getCurrentEvents();\n const rawReplay = getRecordedEvents(\n globalOpts.beforeErrorSec,\n errorTime,\n eventsSnapshot\n );\n\n clearEvents();\n\n const { browser, os, userAgent } = getBrowserInfo();\n\n const compressedReplay = compressToBase64(rawReplay);\n\n return batcher.capture({\n message: error.message ?? '',\n stacktrace: error.stack ?? '',\n replay: compressedReplay as any,\n environment: getEnvironment(),\n browser,\n os,\n userAgent,\n userId,\n additionalInfo,\n appVersion: '1.0.0',\n apiKey: batcher.getApiKey(),\n });\n}\n","import { captureException } from './reporter';\n\nexport function setupGlobalErrorHandler() {\n if ((window as any).__errorHandlerSetup) return;\n\n const origOnError = window.onerror;\n window.onerror = function thisWindowOnError(\n this: Window & WindowEventHandlers,\n message: string | Event,\n source?: string,\n lineno?: number,\n colno?: number,\n error?: Error\n ): boolean {\n origOnError?.call(this, message, source, lineno, colno, error);\n captureException(\n error ??\n new Error(typeof message === 'string' ? message : 'Unknown error')\n );\n return false;\n };\n\n const origOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = function thisWindowOnRejection(\n this: Window & WindowEventHandlers,\n event: PromiseRejectionEvent\n ): any {\n origOnUnhandledRejection?.call(this, event);\n const err =\n event.reason instanceof Error\n ? event.reason\n : new Error(JSON.stringify(event.reason));\n captureException(err);\n } as typeof window.onunhandledrejection;\n\n (window as any).__errorHandlerSetup = true;\n}\n"],"mappings":"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","names":["record"]}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "rusty-replay",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.11",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/index.cjs",
|
6
6
|
"module": "dist/index.js",
|
@@ -22,6 +22,7 @@
|
|
22
22
|
"dependencies": {
|
23
23
|
"@rrweb/packer": "2.0.0-alpha.18",
|
24
24
|
"axios": "^1.8.4",
|
25
|
+
"fflate": "^0.8.2",
|
25
26
|
"rrweb-snapshot": "2.0.0-alpha.4"
|
26
27
|
},
|
27
28
|
"devDependencies": {
|