rusty-replay 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +82 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -6
- package/dist/index.d.ts +2 -6
- package/dist/index.js +81 -68
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
@@ -51,49 +51,6 @@ var init_cjs_shims = __esm({
|
|
51
51
|
}
|
52
52
|
});
|
53
53
|
|
54
|
-
// src/recorder.ts
|
55
|
-
function startRecording() {
|
56
|
-
events = [];
|
57
|
-
(0, import_rrweb.record)({
|
58
|
-
emit(event) {
|
59
|
-
if (shouldCaptureEvent(event)) {
|
60
|
-
events.push(event);
|
61
|
-
if (events.length > MAX_EVENTS) {
|
62
|
-
events = events.slice(-MAX_EVENTS);
|
63
|
-
}
|
64
|
-
}
|
65
|
-
},
|
66
|
-
blockClass: "no-record",
|
67
|
-
ignoreClass: "ignore-recording",
|
68
|
-
maskTextClass: "mask-text",
|
69
|
-
maskAllInputs: true,
|
70
|
-
mousemoveWait: 100
|
71
|
-
});
|
72
|
-
}
|
73
|
-
function shouldCaptureEvent(event) {
|
74
|
-
if (event.type === 3) {
|
75
|
-
return Date.now() % 300 === 0;
|
76
|
-
}
|
77
|
-
if (event.type === 4) {
|
78
|
-
return Date.now() % 200 === 0;
|
79
|
-
}
|
80
|
-
return true;
|
81
|
-
}
|
82
|
-
function getRecordedEvents(beforeErrorSec = 30) {
|
83
|
-
const now = Date.now();
|
84
|
-
return events.filter((e) => now - e.timestamp < beforeErrorSec * 1e3);
|
85
|
-
}
|
86
|
-
var import_rrweb, events, MAX_EVENTS;
|
87
|
-
var init_recorder = __esm({
|
88
|
-
"src/recorder.ts"() {
|
89
|
-
"use strict";
|
90
|
-
init_cjs_shims();
|
91
|
-
import_rrweb = require("rrweb");
|
92
|
-
events = [];
|
93
|
-
MAX_EVENTS = 300;
|
94
|
-
}
|
95
|
-
});
|
96
|
-
|
97
54
|
// src/environment.ts
|
98
55
|
function getBrowserInfo() {
|
99
56
|
const ua = navigator.userAgent;
|
@@ -166,6 +123,11 @@ var init_error_batcher = __esm({
|
|
166
123
|
this.opts.endpoint,
|
167
124
|
{ events: batch },
|
168
125
|
{
|
126
|
+
maxBodyLength: 1e3 * 1024 * 1024,
|
127
|
+
// 10MB
|
128
|
+
maxContentLength: 1e3 * 1024 * 1024,
|
129
|
+
// 10MB
|
130
|
+
timeout: 3e4,
|
169
131
|
headers: {
|
170
132
|
"Content-Type": "application/json",
|
171
133
|
Authorization: `Bearer ${this.opts.apiKey}`
|
@@ -197,6 +159,58 @@ var init_error_batcher = __esm({
|
|
197
159
|
}
|
198
160
|
});
|
199
161
|
|
162
|
+
// src/recorder.ts
|
163
|
+
function startRecording() {
|
164
|
+
events = [];
|
165
|
+
stopFn == null ? void 0 : stopFn();
|
166
|
+
stopFn = (0, import_rrweb.record)({
|
167
|
+
emit(event) {
|
168
|
+
if (event.type === 2) console.log("[rrweb] FullSnapshot \uAE30\uB85D\uB428:", event);
|
169
|
+
events.push(event);
|
170
|
+
if (events.length > MAX_EVENTS) {
|
171
|
+
events = events.slice(-MAX_EVENTS);
|
172
|
+
}
|
173
|
+
},
|
174
|
+
// checkoutEveryNms: 1000, // 1초마다 체크아웃
|
175
|
+
checkoutEveryNms: 15e3,
|
176
|
+
// 15초마다 한 번
|
177
|
+
checkoutEveryNth: 100
|
178
|
+
// 100개 이벤트마다 한 번
|
179
|
+
// packFn: pack,
|
180
|
+
});
|
181
|
+
}
|
182
|
+
function getRecordedEvents(beforeErrorSec = 10, errorTime = Date.now(), source = events) {
|
183
|
+
const sliced = source.filter(
|
184
|
+
(e) => errorTime - e.timestamp < beforeErrorSec * 1e3
|
185
|
+
);
|
186
|
+
const snapshotCandidates = source.filter((e) => e.type === 2);
|
187
|
+
const lastSnapshot = [...snapshotCandidates].reverse().find((e) => e.timestamp <= errorTime);
|
188
|
+
if (lastSnapshot && !sliced.includes(lastSnapshot)) {
|
189
|
+
return [lastSnapshot, ...sliced];
|
190
|
+
}
|
191
|
+
if (!sliced.some((e) => e.type === 2)) {
|
192
|
+
console.warn("\u26A0\uFE0F Snapshot \uC5C6\uC774 \uC798\uB9B0 replay\uC785\uB2C8\uB2E4. \uBCF5\uC6D0 \uBD88\uAC00\uB2A5\uD560 \uC218 \uC788\uC74C.");
|
193
|
+
}
|
194
|
+
return sliced;
|
195
|
+
}
|
196
|
+
function clearEvents() {
|
197
|
+
events = [];
|
198
|
+
}
|
199
|
+
function getCurrentEvents() {
|
200
|
+
return events.slice();
|
201
|
+
}
|
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
|
+
|
200
214
|
// src/handler.ts
|
201
215
|
var handler_exports = {};
|
202
216
|
__export(handler_exports, {
|
@@ -231,20 +245,38 @@ var init_handler = __esm({
|
|
231
245
|
// src/reporter.ts
|
232
246
|
function init(options) {
|
233
247
|
var _a;
|
234
|
-
|
235
|
-
globalOpts.beforeErrorSec = (_a = options.beforeErrorSec) != null ? _a : 30;
|
248
|
+
globalOpts.beforeErrorSec = (_a = options.beforeErrorSec) != null ? _a : 10;
|
236
249
|
batcher = new ErrorBatcher({
|
237
250
|
endpoint: options.endpoint,
|
238
251
|
apiKey: options.apiKey,
|
239
252
|
flushIntervalMs: options.flushIntervalMs,
|
240
253
|
maxBufferSize: options.maxBufferSize
|
241
254
|
});
|
242
|
-
|
255
|
+
if (typeof window !== "undefined") {
|
256
|
+
const start = () => {
|
257
|
+
startRecording();
|
258
|
+
Promise.resolve().then(() => (init_handler(), handler_exports)).then((mod) => mod.setupGlobalErrorHandler());
|
259
|
+
};
|
260
|
+
if (document.readyState === "complete") {
|
261
|
+
requestAnimationFrame(() => startRecording());
|
262
|
+
} else {
|
263
|
+
window.addEventListener("load", () => {
|
264
|
+
requestAnimationFrame(() => startRecording());
|
265
|
+
});
|
266
|
+
}
|
267
|
+
}
|
243
268
|
}
|
244
269
|
function captureException(error, additionalInfo, userId) {
|
245
270
|
var _a, _b;
|
271
|
+
const errorTime = Date.now();
|
272
|
+
const eventsSnapshot = getCurrentEvents();
|
273
|
+
const replay = getRecordedEvents(
|
274
|
+
globalOpts.beforeErrorSec,
|
275
|
+
errorTime,
|
276
|
+
eventsSnapshot
|
277
|
+
);
|
278
|
+
clearEvents();
|
246
279
|
const { browser, os, userAgent } = getBrowserInfo();
|
247
|
-
const replay = getRecordedEvents(globalOpts.beforeErrorSec);
|
248
280
|
return batcher.capture({
|
249
281
|
message: (_a = error.message) != null ? _a : "",
|
250
282
|
stacktrace: (_b = error.stack) != null ? _b : "",
|
@@ -259,32 +291,14 @@ function captureException(error, additionalInfo, userId) {
|
|
259
291
|
apiKey: batcher.getApiKey()
|
260
292
|
});
|
261
293
|
}
|
262
|
-
function wrap(fn, info) {
|
263
|
-
return (...args) => {
|
264
|
-
try {
|
265
|
-
return fn(...args);
|
266
|
-
} catch (err) {
|
267
|
-
if (err instanceof Error) {
|
268
|
-
captureException(err, info == null ? void 0 : info.additionalInfo, info == null ? void 0 : info.userId);
|
269
|
-
} else {
|
270
|
-
captureException(
|
271
|
-
new Error(String(err)),
|
272
|
-
info == null ? void 0 : info.additionalInfo,
|
273
|
-
info == null ? void 0 : info.userId
|
274
|
-
);
|
275
|
-
}
|
276
|
-
throw err;
|
277
|
-
}
|
278
|
-
};
|
279
|
-
}
|
280
294
|
var batcher, globalOpts;
|
281
295
|
var init_reporter = __esm({
|
282
296
|
"src/reporter.ts"() {
|
283
297
|
"use strict";
|
284
298
|
init_cjs_shims();
|
285
|
-
init_recorder();
|
286
299
|
init_environment();
|
287
300
|
init_error_batcher();
|
301
|
+
init_recorder();
|
288
302
|
globalOpts = { beforeErrorSec: 30 };
|
289
303
|
}
|
290
304
|
});
|
@@ -299,8 +313,7 @@ __export(index_exports, {
|
|
299
313
|
getRecordedEvents: () => getRecordedEvents,
|
300
314
|
init: () => init,
|
301
315
|
setupGlobalErrorHandler: () => setupGlobalErrorHandler,
|
302
|
-
startRecording: () => startRecording
|
303
|
-
wrap: () => wrap
|
316
|
+
startRecording: () => startRecording
|
304
317
|
});
|
305
318
|
module.exports = __toCommonJS(index_exports);
|
306
319
|
init_cjs_shims();
|
@@ -318,7 +331,6 @@ init_error_batcher();
|
|
318
331
|
getRecordedEvents,
|
319
332
|
init,
|
320
333
|
setupGlobalErrorHandler,
|
321
|
-
startRecording
|
322
|
-
wrap
|
334
|
+
startRecording
|
323
335
|
});
|
324
336
|
//# sourceMappingURL=index.cjs.map
|
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/recorder.ts","../src/environment.ts","../src/error-batcher.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","import type { eventWithTime } from '@rrweb/types';\nimport { record } from 'rrweb';\n\nlet events: eventWithTime[] = [];\nconst MAX_EVENTS = 300;\n\nexport function startRecording(): void {\n events = [];\n record({\n emit(event) {\n if (shouldCaptureEvent(event)) {\n events.push(event);\n if (events.length > MAX_EVENTS) {\n events = events.slice(-MAX_EVENTS);\n }\n }\n },\n\n blockClass: 'no-record',\n ignoreClass: 'ignore-recording',\n maskTextClass: 'mask-text',\n maskAllInputs: true,\n mousemoveWait: 100,\n });\n}\n\nfunction shouldCaptureEvent(event: eventWithTime): boolean {\n // 마우스 움직임, 스크롤 등 빈번한 이벤트는 샘플링\n if (event.type === 3) {\n return Date.now() % 300 === 0;\n }\n\n // 스크롤 이벤트 샘플링\n if (event.type === 4) {\n return Date.now() % 200 === 0;\n }\n\n return true;\n}\n\nexport function getRecordedEvents(beforeErrorSec = 30): eventWithTime[] {\n const now = Date.now();\n return events.filter((e) => now - e.timestamp < beforeErrorSec * 1000);\n}\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 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 { 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 { startRecording, getRecordedEvents } from './recorder';\nimport { getBrowserInfo, getEnvironment } from './environment';\nimport { ErrorBatcher } from './error-batcher';\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?: Record<string, any>;\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 startRecording();\n globalOpts.beforeErrorSec = options.beforeErrorSec ?? 30;\n batcher = new ErrorBatcher({\n endpoint: options.endpoint,\n apiKey: options.apiKey,\n flushIntervalMs: options.flushIntervalMs,\n maxBufferSize: options.maxBufferSize,\n });\n import('./handler.js').then((mod) => mod.setupGlobalErrorHandler());\n}\n\nexport function captureException(\n error: Error,\n additionalInfo?: Record<string, any>,\n userId?: number\n): string {\n const { browser, os, userAgent } = getBrowserInfo();\n const replay = getRecordedEvents(globalOpts.beforeErrorSec);\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\nexport function wrap<T extends (...args: any[]) => any>(\n fn: T,\n info?: { additionalInfo?: Record<string, any>; userId?: number }\n): (...args: Parameters<T>) => ReturnType<T> {\n return (...args) => {\n try {\n return fn(...args);\n } catch (err) {\n if (err instanceof Error) {\n captureException(err, info?.additionalInfo, info?.userId);\n } else {\n captureException(\n new Error(String(err)),\n info?.additionalInfo,\n info?.userId\n );\n }\n throw err;\n }\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 } from './reporter';\n"],"mappings":"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","names":["record","axios"]}
|
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 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?: Record<string, any>;\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?: Record<string, any>,\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 } from './reporter';\n"],"mappings":"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","names":["record","axios"]}
|
package/dist/index.d.cts
CHANGED
@@ -30,15 +30,11 @@ interface InitOptions {
|
|
30
30
|
}
|
31
31
|
declare function init(options: InitOptions): void;
|
32
32
|
declare function captureException(error: Error, additionalInfo?: Record<string, any>, userId?: number): string;
|
33
|
-
declare function wrap<T extends (...args: any[]) => any>(fn: T, info?: {
|
34
|
-
additionalInfo?: Record<string, any>;
|
35
|
-
userId?: number;
|
36
|
-
}): (...args: Parameters<T>) => ReturnType<T>;
|
37
33
|
|
38
34
|
declare function setupGlobalErrorHandler(): void;
|
39
35
|
|
40
36
|
declare function startRecording(): void;
|
41
|
-
declare function getRecordedEvents(beforeErrorSec?: number): eventWithTime[];
|
37
|
+
declare function getRecordedEvents(beforeErrorSec?: number, errorTime?: number, source?: eventWithTime[]): eventWithTime[];
|
42
38
|
|
43
39
|
declare function getBrowserInfo(): {
|
44
40
|
browser: string;
|
@@ -62,4 +58,4 @@ declare class ErrorBatcher {
|
|
62
58
|
destroy(): void;
|
63
59
|
}
|
64
60
|
|
65
|
-
export { type BatchedEvent, type BatcherOptions, ErrorBatcher, type InitOptions, captureException, getBrowserInfo, getEnvironment, getRecordedEvents, init, setupGlobalErrorHandler, startRecording
|
61
|
+
export { type BatchedEvent, type BatcherOptions, ErrorBatcher, type InitOptions, captureException, getBrowserInfo, getEnvironment, getRecordedEvents, init, setupGlobalErrorHandler, startRecording };
|
package/dist/index.d.ts
CHANGED
@@ -30,15 +30,11 @@ interface InitOptions {
|
|
30
30
|
}
|
31
31
|
declare function init(options: InitOptions): void;
|
32
32
|
declare function captureException(error: Error, additionalInfo?: Record<string, any>, userId?: number): string;
|
33
|
-
declare function wrap<T extends (...args: any[]) => any>(fn: T, info?: {
|
34
|
-
additionalInfo?: Record<string, any>;
|
35
|
-
userId?: number;
|
36
|
-
}): (...args: Parameters<T>) => ReturnType<T>;
|
37
33
|
|
38
34
|
declare function setupGlobalErrorHandler(): void;
|
39
35
|
|
40
36
|
declare function startRecording(): void;
|
41
|
-
declare function getRecordedEvents(beforeErrorSec?: number): eventWithTime[];
|
37
|
+
declare function getRecordedEvents(beforeErrorSec?: number, errorTime?: number, source?: eventWithTime[]): eventWithTime[];
|
42
38
|
|
43
39
|
declare function getBrowserInfo(): {
|
44
40
|
browser: string;
|
@@ -62,4 +58,4 @@ declare class ErrorBatcher {
|
|
62
58
|
destroy(): void;
|
63
59
|
}
|
64
60
|
|
65
|
-
export { type BatchedEvent, type BatcherOptions, ErrorBatcher, type InitOptions, captureException, getBrowserInfo, getEnvironment, getRecordedEvents, init, setupGlobalErrorHandler, startRecording
|
61
|
+
export { type BatchedEvent, type BatcherOptions, ErrorBatcher, type InitOptions, captureException, getBrowserInfo, getEnvironment, getRecordedEvents, init, setupGlobalErrorHandler, startRecording };
|
package/dist/index.js
CHANGED
@@ -30,49 +30,6 @@ var init_esm_shims = __esm({
|
|
30
30
|
}
|
31
31
|
});
|
32
32
|
|
33
|
-
// src/recorder.ts
|
34
|
-
import { record } from "rrweb";
|
35
|
-
function startRecording() {
|
36
|
-
events = [];
|
37
|
-
record({
|
38
|
-
emit(event) {
|
39
|
-
if (shouldCaptureEvent(event)) {
|
40
|
-
events.push(event);
|
41
|
-
if (events.length > MAX_EVENTS) {
|
42
|
-
events = events.slice(-MAX_EVENTS);
|
43
|
-
}
|
44
|
-
}
|
45
|
-
},
|
46
|
-
blockClass: "no-record",
|
47
|
-
ignoreClass: "ignore-recording",
|
48
|
-
maskTextClass: "mask-text",
|
49
|
-
maskAllInputs: true,
|
50
|
-
mousemoveWait: 100
|
51
|
-
});
|
52
|
-
}
|
53
|
-
function shouldCaptureEvent(event) {
|
54
|
-
if (event.type === 3) {
|
55
|
-
return Date.now() % 300 === 0;
|
56
|
-
}
|
57
|
-
if (event.type === 4) {
|
58
|
-
return Date.now() % 200 === 0;
|
59
|
-
}
|
60
|
-
return true;
|
61
|
-
}
|
62
|
-
function getRecordedEvents(beforeErrorSec = 30) {
|
63
|
-
const now = Date.now();
|
64
|
-
return events.filter((e) => now - e.timestamp < beforeErrorSec * 1e3);
|
65
|
-
}
|
66
|
-
var events, MAX_EVENTS;
|
67
|
-
var init_recorder = __esm({
|
68
|
-
"src/recorder.ts"() {
|
69
|
-
"use strict";
|
70
|
-
init_esm_shims();
|
71
|
-
events = [];
|
72
|
-
MAX_EVENTS = 300;
|
73
|
-
}
|
74
|
-
});
|
75
|
-
|
76
33
|
// src/environment.ts
|
77
34
|
function getBrowserInfo() {
|
78
35
|
const ua = navigator.userAgent;
|
@@ -145,6 +102,11 @@ var init_error_batcher = __esm({
|
|
145
102
|
this.opts.endpoint,
|
146
103
|
{ events: batch },
|
147
104
|
{
|
105
|
+
maxBodyLength: 1e3 * 1024 * 1024,
|
106
|
+
// 10MB
|
107
|
+
maxContentLength: 1e3 * 1024 * 1024,
|
108
|
+
// 10MB
|
109
|
+
timeout: 3e4,
|
148
110
|
headers: {
|
149
111
|
"Content-Type": "application/json",
|
150
112
|
Authorization: `Bearer ${this.opts.apiKey}`
|
@@ -176,6 +138,58 @@ var init_error_batcher = __esm({
|
|
176
138
|
}
|
177
139
|
});
|
178
140
|
|
141
|
+
// src/recorder.ts
|
142
|
+
import { record } from "rrweb";
|
143
|
+
function startRecording() {
|
144
|
+
events = [];
|
145
|
+
stopFn == null ? void 0 : stopFn();
|
146
|
+
stopFn = record({
|
147
|
+
emit(event) {
|
148
|
+
if (event.type === 2) console.log("[rrweb] FullSnapshot \uAE30\uB85D\uB428:", event);
|
149
|
+
events.push(event);
|
150
|
+
if (events.length > MAX_EVENTS) {
|
151
|
+
events = events.slice(-MAX_EVENTS);
|
152
|
+
}
|
153
|
+
},
|
154
|
+
// checkoutEveryNms: 1000, // 1초마다 체크아웃
|
155
|
+
checkoutEveryNms: 15e3,
|
156
|
+
// 15초마다 한 번
|
157
|
+
checkoutEveryNth: 100
|
158
|
+
// 100개 이벤트마다 한 번
|
159
|
+
// packFn: pack,
|
160
|
+
});
|
161
|
+
}
|
162
|
+
function getRecordedEvents(beforeErrorSec = 10, errorTime = Date.now(), source = events) {
|
163
|
+
const sliced = source.filter(
|
164
|
+
(e) => errorTime - e.timestamp < beforeErrorSec * 1e3
|
165
|
+
);
|
166
|
+
const snapshotCandidates = source.filter((e) => e.type === 2);
|
167
|
+
const lastSnapshot = [...snapshotCandidates].reverse().find((e) => e.timestamp <= errorTime);
|
168
|
+
if (lastSnapshot && !sliced.includes(lastSnapshot)) {
|
169
|
+
return [lastSnapshot, ...sliced];
|
170
|
+
}
|
171
|
+
if (!sliced.some((e) => e.type === 2)) {
|
172
|
+
console.warn("\u26A0\uFE0F Snapshot \uC5C6\uC774 \uC798\uB9B0 replay\uC785\uB2C8\uB2E4. \uBCF5\uC6D0 \uBD88\uAC00\uB2A5\uD560 \uC218 \uC788\uC74C.");
|
173
|
+
}
|
174
|
+
return sliced;
|
175
|
+
}
|
176
|
+
function clearEvents() {
|
177
|
+
events = [];
|
178
|
+
}
|
179
|
+
function getCurrentEvents() {
|
180
|
+
return events.slice();
|
181
|
+
}
|
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
|
+
|
179
193
|
// src/handler.ts
|
180
194
|
var handler_exports = {};
|
181
195
|
__export(handler_exports, {
|
@@ -210,20 +224,38 @@ var init_handler = __esm({
|
|
210
224
|
// src/reporter.ts
|
211
225
|
function init(options) {
|
212
226
|
var _a;
|
213
|
-
|
214
|
-
globalOpts.beforeErrorSec = (_a = options.beforeErrorSec) != null ? _a : 30;
|
227
|
+
globalOpts.beforeErrorSec = (_a = options.beforeErrorSec) != null ? _a : 10;
|
215
228
|
batcher = new ErrorBatcher({
|
216
229
|
endpoint: options.endpoint,
|
217
230
|
apiKey: options.apiKey,
|
218
231
|
flushIntervalMs: options.flushIntervalMs,
|
219
232
|
maxBufferSize: options.maxBufferSize
|
220
233
|
});
|
221
|
-
|
234
|
+
if (typeof window !== "undefined") {
|
235
|
+
const start = () => {
|
236
|
+
startRecording();
|
237
|
+
Promise.resolve().then(() => (init_handler(), handler_exports)).then((mod) => mod.setupGlobalErrorHandler());
|
238
|
+
};
|
239
|
+
if (document.readyState === "complete") {
|
240
|
+
requestAnimationFrame(() => startRecording());
|
241
|
+
} else {
|
242
|
+
window.addEventListener("load", () => {
|
243
|
+
requestAnimationFrame(() => startRecording());
|
244
|
+
});
|
245
|
+
}
|
246
|
+
}
|
222
247
|
}
|
223
248
|
function captureException(error, additionalInfo, userId) {
|
224
249
|
var _a, _b;
|
250
|
+
const errorTime = Date.now();
|
251
|
+
const eventsSnapshot = getCurrentEvents();
|
252
|
+
const replay = getRecordedEvents(
|
253
|
+
globalOpts.beforeErrorSec,
|
254
|
+
errorTime,
|
255
|
+
eventsSnapshot
|
256
|
+
);
|
257
|
+
clearEvents();
|
225
258
|
const { browser, os, userAgent } = getBrowserInfo();
|
226
|
-
const replay = getRecordedEvents(globalOpts.beforeErrorSec);
|
227
259
|
return batcher.capture({
|
228
260
|
message: (_a = error.message) != null ? _a : "",
|
229
261
|
stacktrace: (_b = error.stack) != null ? _b : "",
|
@@ -238,32 +270,14 @@ function captureException(error, additionalInfo, userId) {
|
|
238
270
|
apiKey: batcher.getApiKey()
|
239
271
|
});
|
240
272
|
}
|
241
|
-
function wrap(fn, info) {
|
242
|
-
return (...args) => {
|
243
|
-
try {
|
244
|
-
return fn(...args);
|
245
|
-
} catch (err) {
|
246
|
-
if (err instanceof Error) {
|
247
|
-
captureException(err, info == null ? void 0 : info.additionalInfo, info == null ? void 0 : info.userId);
|
248
|
-
} else {
|
249
|
-
captureException(
|
250
|
-
new Error(String(err)),
|
251
|
-
info == null ? void 0 : info.additionalInfo,
|
252
|
-
info == null ? void 0 : info.userId
|
253
|
-
);
|
254
|
-
}
|
255
|
-
throw err;
|
256
|
-
}
|
257
|
-
};
|
258
|
-
}
|
259
273
|
var batcher, globalOpts;
|
260
274
|
var init_reporter = __esm({
|
261
275
|
"src/reporter.ts"() {
|
262
276
|
"use strict";
|
263
277
|
init_esm_shims();
|
264
|
-
init_recorder();
|
265
278
|
init_environment();
|
266
279
|
init_error_batcher();
|
280
|
+
init_recorder();
|
267
281
|
globalOpts = { beforeErrorSec: 30 };
|
268
282
|
}
|
269
283
|
});
|
@@ -283,7 +297,6 @@ export {
|
|
283
297
|
getRecordedEvents,
|
284
298
|
init,
|
285
299
|
setupGlobalErrorHandler,
|
286
|
-
startRecording
|
287
|
-
wrap
|
300
|
+
startRecording
|
288
301
|
};
|
289
302
|
//# sourceMappingURL=index.js.map
|
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/recorder.ts","../src/environment.ts","../src/error-batcher.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","import type { eventWithTime } from '@rrweb/types';\nimport { record } from 'rrweb';\n\nlet events: eventWithTime[] = [];\nconst MAX_EVENTS = 300;\n\nexport function startRecording(): void {\n events = [];\n record({\n emit(event) {\n if (shouldCaptureEvent(event)) {\n events.push(event);\n if (events.length > MAX_EVENTS) {\n events = events.slice(-MAX_EVENTS);\n }\n }\n },\n\n blockClass: 'no-record',\n ignoreClass: 'ignore-recording',\n maskTextClass: 'mask-text',\n maskAllInputs: true,\n mousemoveWait: 100,\n });\n}\n\nfunction shouldCaptureEvent(event: eventWithTime): boolean {\n // 마우스 움직임, 스크롤 등 빈번한 이벤트는 샘플링\n if (event.type === 3) {\n return Date.now() % 300 === 0;\n }\n\n // 스크롤 이벤트 샘플링\n if (event.type === 4) {\n return Date.now() % 200 === 0;\n }\n\n return true;\n}\n\nexport function getRecordedEvents(beforeErrorSec = 30): eventWithTime[] {\n const now = Date.now();\n return events.filter((e) => now - e.timestamp < beforeErrorSec * 1000);\n}\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 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 { 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 { startRecording, getRecordedEvents } from './recorder';\nimport { getBrowserInfo, getEnvironment } from './environment';\nimport { ErrorBatcher } from './error-batcher';\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?: Record<string, any>;\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 startRecording();\n globalOpts.beforeErrorSec = options.beforeErrorSec ?? 30;\n batcher = new ErrorBatcher({\n endpoint: options.endpoint,\n apiKey: options.apiKey,\n flushIntervalMs: options.flushIntervalMs,\n maxBufferSize: options.maxBufferSize,\n });\n import('./handler.js').then((mod) => mod.setupGlobalErrorHandler());\n}\n\nexport function captureException(\n error: Error,\n additionalInfo?: Record<string, any>,\n userId?: number\n): string {\n const { browser, os, userAgent } = getBrowserInfo();\n const replay = getRecordedEvents(globalOpts.beforeErrorSec);\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\nexport function wrap<T extends (...args: any[]) => any>(\n fn: T,\n info?: { additionalInfo?: Record<string, any>; userId?: number }\n): (...args: Parameters<T>) => ReturnType<T> {\n return (...args) => {\n try {\n return fn(...args);\n } catch (err) {\n if (err instanceof Error) {\n captureException(err, info?.additionalInfo, info?.userId);\n } else {\n captureException(\n new Error(String(err)),\n info?.additionalInfo,\n info?.userId\n );\n }\n throw err;\n }\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 } from './reporter';\n"],"mappings":"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","names":["record"]}
|
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 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?: Record<string, any>;\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?: Record<string, any>,\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 } from './reporter';\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.8",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/index.cjs",
|
6
6
|
"module": "dist/index.js",
|
@@ -20,7 +20,9 @@
|
|
20
20
|
"rrweb-player": "^1.0.0-alpha.4"
|
21
21
|
},
|
22
22
|
"dependencies": {
|
23
|
-
"
|
23
|
+
"@rrweb/packer": "2.0.0-alpha.18",
|
24
|
+
"axios": "^1.8.4",
|
25
|
+
"rrweb-snapshot": "2.0.0-alpha.4"
|
24
26
|
},
|
25
27
|
"devDependencies": {
|
26
28
|
"@types/node": "^20",
|