rusty-replay 1.0.11 โ 1.0.13
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 +1 -4
- package/dist/index.cjs +68 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +72 -1
- package/dist/index.js.map +1 -1
- package/package.json +38 -4
package/README.md
CHANGED
package/dist/index.cjs
CHANGED
@@ -51,6 +51,7 @@ __export(index_exports, {
|
|
51
51
|
getEnvironment: () => getEnvironment,
|
52
52
|
getRecordedEvents: () => getRecordedEvents,
|
53
53
|
init: () => init,
|
54
|
+
initOtel: () => initOtel,
|
54
55
|
setupGlobalErrorHandler: () => setupGlobalErrorHandler,
|
55
56
|
startRecording: () => startRecording
|
56
57
|
});
|
@@ -76,7 +77,7 @@ function getBrowserInfo() {
|
|
76
77
|
return { browser, os, userAgent: ua };
|
77
78
|
}
|
78
79
|
function getEnvironment() {
|
79
|
-
if (
|
80
|
+
if (true) return "development";
|
80
81
|
return "production";
|
81
82
|
}
|
82
83
|
|
@@ -288,16 +289,70 @@ function setupGlobalErrorHandler() {
|
|
288
289
|
};
|
289
290
|
window.__errorHandlerSetup = true;
|
290
291
|
}
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
292
|
+
|
293
|
+
// src/front-end-tracer.ts
|
294
|
+
var import_core = require("@opentelemetry/core");
|
295
|
+
var import_sdk_trace_web = require("@opentelemetry/sdk-trace-web");
|
296
|
+
var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
|
297
|
+
var import_resources = require("@opentelemetry/resources");
|
298
|
+
var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
299
|
+
var import_exporter_trace_otlp_proto = require("@opentelemetry/exporter-trace-otlp-proto");
|
300
|
+
var initOtel = async (config = {}) => {
|
301
|
+
var _a, _b, _c, _d;
|
302
|
+
const finalConfig = {
|
303
|
+
serviceName: (_a = config.serviceName) != null ? _a : "replay",
|
304
|
+
endpoint: (_b = config.endpoint) != null ? _b : "http://localhost:8081/traces",
|
305
|
+
isSyntheticRequest: (_c = config.isSyntheticRequest) != null ? _c : false,
|
306
|
+
scheduledDelayMillis: (_d = config.scheduledDelayMillis) != null ? _d : 500,
|
307
|
+
customHeaders: __spreadValues({
|
308
|
+
"Content-Type": "application/x-protobuf"
|
309
|
+
}, config.customHeaders)
|
310
|
+
};
|
311
|
+
const { ZoneContextManager } = await import("@opentelemetry/context-zone");
|
312
|
+
let resource = (0, import_resources.resourceFromAttributes)({
|
313
|
+
[import_semantic_conventions.ATTR_SERVICE_NAME]: finalConfig.serviceName
|
314
|
+
});
|
315
|
+
if (finalConfig.isSyntheticRequest) {
|
316
|
+
resource = resource.merge(
|
317
|
+
(0, import_resources.resourceFromAttributes)({ "app.synthetic_request": "true" })
|
318
|
+
);
|
319
|
+
}
|
320
|
+
resource = resource.merge((0, import_resources.detectResources)({ detectors: [import_resources.osDetector] }));
|
321
|
+
const spanProcessor = new import_sdk_trace_base.BatchSpanProcessor(
|
322
|
+
new import_exporter_trace_otlp_proto.OTLPTraceExporter({
|
323
|
+
url: finalConfig.endpoint,
|
324
|
+
headers: finalConfig.customHeaders
|
325
|
+
}),
|
326
|
+
{ scheduledDelayMillis: finalConfig.scheduledDelayMillis }
|
327
|
+
);
|
328
|
+
const provider = new import_sdk_trace_web.WebTracerProvider({
|
329
|
+
resource,
|
330
|
+
spanProcessors: [spanProcessor]
|
331
|
+
});
|
332
|
+
provider.register({
|
333
|
+
contextManager: new ZoneContextManager(),
|
334
|
+
propagator: new import_core.W3CTraceContextPropagator()
|
335
|
+
});
|
336
|
+
if (typeof window !== "undefined") {
|
337
|
+
const backendOrigin = new URL(finalConfig.endpoint).origin;
|
338
|
+
const [{ FetchInstrumentation }, { XMLHttpRequestInstrumentation }] = await Promise.all([
|
339
|
+
import("@opentelemetry/instrumentation-fetch"),
|
340
|
+
import("@opentelemetry/instrumentation-xml-http-request")
|
341
|
+
]);
|
342
|
+
const fetchInst = new FetchInstrumentation({
|
343
|
+
propagateTraceHeaderCorsUrls: [backendOrigin],
|
344
|
+
clearTimingResources: true
|
345
|
+
});
|
346
|
+
const xhrInst = new XMLHttpRequestInstrumentation({
|
347
|
+
propagateTraceHeaderCorsUrls: [backendOrigin],
|
348
|
+
clearTimingResources: true
|
349
|
+
});
|
350
|
+
fetchInst.setTracerProvider(provider);
|
351
|
+
xhrInst.setTracerProvider(provider);
|
352
|
+
fetchInst.enable();
|
353
|
+
xhrInst.enable();
|
354
|
+
}
|
355
|
+
console.log("OpenTelemetry initialized successfully");
|
356
|
+
return provider;
|
357
|
+
};
|
303
358
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
@@ -1 +1 @@
|
|
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"]}
|
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","../src/front-end-tracer.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';\nexport { initOtel } from './front-end-tracer';\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","import { W3CTraceContextPropagator } from '@opentelemetry/core';\nimport { WebTracerProvider } from '@opentelemetry/sdk-trace-web';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport {\n resourceFromAttributes,\n osDetector,\n detectResources,\n} from '@opentelemetry/resources';\nimport { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';\n\nexport interface OtelConfig {\n serviceName?: string;\n endpoint?: string;\n isSyntheticRequest?: boolean;\n scheduledDelayMillis?: number;\n customHeaders?: Record<string, string>;\n}\n\nexport const initOtel = async (config: OtelConfig = {}) => {\n const finalConfig = {\n serviceName: config.serviceName ?? 'replay',\n endpoint: config.endpoint ?? 'http://localhost:8081/traces',\n isSyntheticRequest: config.isSyntheticRequest ?? false,\n scheduledDelayMillis: config.scheduledDelayMillis ?? 500,\n customHeaders: {\n 'Content-Type': 'application/x-protobuf',\n ...config.customHeaders,\n },\n };\n\n const { ZoneContextManager } = await import('@opentelemetry/context-zone');\n\n let resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: finalConfig.serviceName,\n });\n if (finalConfig.isSyntheticRequest) {\n resource = resource.merge(\n resourceFromAttributes({ 'app.synthetic_request': 'true' })\n );\n }\n resource = resource.merge(detectResources({ detectors: [osDetector] }));\n\n const spanProcessor = new BatchSpanProcessor(\n new OTLPTraceExporter({\n url: finalConfig.endpoint,\n headers: finalConfig.customHeaders,\n }),\n { scheduledDelayMillis: finalConfig.scheduledDelayMillis }\n );\n const provider = new WebTracerProvider({\n resource,\n spanProcessors: [spanProcessor],\n });\n provider.register({\n contextManager: new ZoneContextManager(),\n propagator: new W3CTraceContextPropagator(),\n });\n\n if (typeof window !== 'undefined') {\n const backendOrigin = new URL(finalConfig.endpoint).origin;\n\n const [{ FetchInstrumentation }, { XMLHttpRequestInstrumentation }] =\n await Promise.all([\n import('@opentelemetry/instrumentation-fetch'),\n import('@opentelemetry/instrumentation-xml-http-request'),\n ]);\n\n const fetchInst = new FetchInstrumentation({\n propagateTraceHeaderCorsUrls: [backendOrigin],\n clearTimingResources: true,\n });\n const xhrInst = new XMLHttpRequestInstrumentation({\n propagateTraceHeaderCorsUrls: [backendOrigin],\n clearTimingResources: true,\n });\n\n fetchInst.setTracerProvider(provider);\n xhrInst.setTracerProvider(provider);\n fetchInst.enable();\n xhrInst.enable();\n }\n\n console.log('OpenTelemetry initialized successfully');\n return provider;\n};\n"],"mappings":"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","names":["record","axios"]}
|
package/dist/index.d.cts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { eventWithTime } from '@rrweb/types';
|
2
|
+
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
|
2
3
|
|
3
4
|
interface AdditionalInfo {
|
4
5
|
pageUrl: string;
|
@@ -76,4 +77,13 @@ declare class ErrorBatcher {
|
|
76
77
|
|
77
78
|
declare function decompressFromBase64(base64: string): any[];
|
78
79
|
|
79
|
-
|
80
|
+
interface OtelConfig {
|
81
|
+
serviceName?: string;
|
82
|
+
endpoint?: string;
|
83
|
+
isSyntheticRequest?: boolean;
|
84
|
+
scheduledDelayMillis?: number;
|
85
|
+
customHeaders?: Record<string, string>;
|
86
|
+
}
|
87
|
+
declare const initOtel: (config?: OtelConfig) => Promise<WebTracerProvider>;
|
88
|
+
|
89
|
+
export { type AdditionalInfo, type BatchedEvent, type BatcherOptions, ErrorBatcher, type InitOptions, captureException, decompressFromBase64, getBrowserInfo, getEnvironment, getRecordedEvents, init, initOtel, setupGlobalErrorHandler, startRecording };
|
package/dist/index.d.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { eventWithTime } from '@rrweb/types';
|
2
|
+
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
|
2
3
|
|
3
4
|
interface AdditionalInfo {
|
4
5
|
pageUrl: string;
|
@@ -76,4 +77,13 @@ declare class ErrorBatcher {
|
|
76
77
|
|
77
78
|
declare function decompressFromBase64(base64: string): any[];
|
78
79
|
|
79
|
-
|
80
|
+
interface OtelConfig {
|
81
|
+
serviceName?: string;
|
82
|
+
endpoint?: string;
|
83
|
+
isSyntheticRequest?: boolean;
|
84
|
+
scheduledDelayMillis?: number;
|
85
|
+
customHeaders?: Record<string, string>;
|
86
|
+
}
|
87
|
+
declare const initOtel: (config?: OtelConfig) => Promise<WebTracerProvider>;
|
88
|
+
|
89
|
+
export { type AdditionalInfo, type BatchedEvent, type BatcherOptions, ErrorBatcher, type InitOptions, captureException, decompressFromBase64, getBrowserInfo, getEnvironment, getRecordedEvents, init, initOtel, setupGlobalErrorHandler, startRecording };
|
package/dist/index.js
CHANGED
@@ -35,7 +35,7 @@ function getBrowserInfo() {
|
|
35
35
|
return { browser, os, userAgent: ua };
|
36
36
|
}
|
37
37
|
function getEnvironment() {
|
38
|
-
if (
|
38
|
+
if (true) return "development";
|
39
39
|
return "production";
|
40
40
|
}
|
41
41
|
|
@@ -247,6 +247,76 @@ function setupGlobalErrorHandler() {
|
|
247
247
|
};
|
248
248
|
window.__errorHandlerSetup = true;
|
249
249
|
}
|
250
|
+
|
251
|
+
// src/front-end-tracer.ts
|
252
|
+
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
253
|
+
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
|
254
|
+
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
255
|
+
import {
|
256
|
+
resourceFromAttributes,
|
257
|
+
osDetector,
|
258
|
+
detectResources
|
259
|
+
} from "@opentelemetry/resources";
|
260
|
+
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
261
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
|
262
|
+
var initOtel = async (config = {}) => {
|
263
|
+
var _a, _b, _c, _d;
|
264
|
+
const finalConfig = {
|
265
|
+
serviceName: (_a = config.serviceName) != null ? _a : "replay",
|
266
|
+
endpoint: (_b = config.endpoint) != null ? _b : "http://localhost:8081/traces",
|
267
|
+
isSyntheticRequest: (_c = config.isSyntheticRequest) != null ? _c : false,
|
268
|
+
scheduledDelayMillis: (_d = config.scheduledDelayMillis) != null ? _d : 500,
|
269
|
+
customHeaders: __spreadValues({
|
270
|
+
"Content-Type": "application/x-protobuf"
|
271
|
+
}, config.customHeaders)
|
272
|
+
};
|
273
|
+
const { ZoneContextManager } = await import("@opentelemetry/context-zone");
|
274
|
+
let resource = resourceFromAttributes({
|
275
|
+
[ATTR_SERVICE_NAME]: finalConfig.serviceName
|
276
|
+
});
|
277
|
+
if (finalConfig.isSyntheticRequest) {
|
278
|
+
resource = resource.merge(
|
279
|
+
resourceFromAttributes({ "app.synthetic_request": "true" })
|
280
|
+
);
|
281
|
+
}
|
282
|
+
resource = resource.merge(detectResources({ detectors: [osDetector] }));
|
283
|
+
const spanProcessor = new BatchSpanProcessor(
|
284
|
+
new OTLPTraceExporter({
|
285
|
+
url: finalConfig.endpoint,
|
286
|
+
headers: finalConfig.customHeaders
|
287
|
+
}),
|
288
|
+
{ scheduledDelayMillis: finalConfig.scheduledDelayMillis }
|
289
|
+
);
|
290
|
+
const provider = new WebTracerProvider({
|
291
|
+
resource,
|
292
|
+
spanProcessors: [spanProcessor]
|
293
|
+
});
|
294
|
+
provider.register({
|
295
|
+
contextManager: new ZoneContextManager(),
|
296
|
+
propagator: new W3CTraceContextPropagator()
|
297
|
+
});
|
298
|
+
if (typeof window !== "undefined") {
|
299
|
+
const backendOrigin = new URL(finalConfig.endpoint).origin;
|
300
|
+
const [{ FetchInstrumentation }, { XMLHttpRequestInstrumentation }] = await Promise.all([
|
301
|
+
import("@opentelemetry/instrumentation-fetch"),
|
302
|
+
import("@opentelemetry/instrumentation-xml-http-request")
|
303
|
+
]);
|
304
|
+
const fetchInst = new FetchInstrumentation({
|
305
|
+
propagateTraceHeaderCorsUrls: [backendOrigin],
|
306
|
+
clearTimingResources: true
|
307
|
+
});
|
308
|
+
const xhrInst = new XMLHttpRequestInstrumentation({
|
309
|
+
propagateTraceHeaderCorsUrls: [backendOrigin],
|
310
|
+
clearTimingResources: true
|
311
|
+
});
|
312
|
+
fetchInst.setTracerProvider(provider);
|
313
|
+
xhrInst.setTracerProvider(provider);
|
314
|
+
fetchInst.enable();
|
315
|
+
xhrInst.enable();
|
316
|
+
}
|
317
|
+
console.log("OpenTelemetry initialized successfully");
|
318
|
+
return provider;
|
319
|
+
};
|
250
320
|
export {
|
251
321
|
ErrorBatcher,
|
252
322
|
captureException,
|
@@ -255,6 +325,7 @@ export {
|
|
255
325
|
getEnvironment,
|
256
326
|
getRecordedEvents,
|
257
327
|
init,
|
328
|
+
initOtel,
|
258
329
|
setupGlobalErrorHandler,
|
259
330
|
startRecording
|
260
331
|
};
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
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"]}
|
1
|
+
{"version":3,"sources":["../src/environment.ts","../src/error-batcher.ts","../src/recorder.ts","../src/utils.ts","../src/reporter.ts","../src/handler.ts","../src/front-end-tracer.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","import { W3CTraceContextPropagator } from '@opentelemetry/core';\nimport { WebTracerProvider } from '@opentelemetry/sdk-trace-web';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport {\n resourceFromAttributes,\n osDetector,\n detectResources,\n} from '@opentelemetry/resources';\nimport { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';\n\nexport interface OtelConfig {\n serviceName?: string;\n endpoint?: string;\n isSyntheticRequest?: boolean;\n scheduledDelayMillis?: number;\n customHeaders?: Record<string, string>;\n}\n\nexport const initOtel = async (config: OtelConfig = {}) => {\n const finalConfig = {\n serviceName: config.serviceName ?? 'replay',\n endpoint: config.endpoint ?? 'http://localhost:8081/traces',\n isSyntheticRequest: config.isSyntheticRequest ?? false,\n scheduledDelayMillis: config.scheduledDelayMillis ?? 500,\n customHeaders: {\n 'Content-Type': 'application/x-protobuf',\n ...config.customHeaders,\n },\n };\n\n const { ZoneContextManager } = await import('@opentelemetry/context-zone');\n\n let resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: finalConfig.serviceName,\n });\n if (finalConfig.isSyntheticRequest) {\n resource = resource.merge(\n resourceFromAttributes({ 'app.synthetic_request': 'true' })\n );\n }\n resource = resource.merge(detectResources({ detectors: [osDetector] }));\n\n const spanProcessor = new BatchSpanProcessor(\n new OTLPTraceExporter({\n url: finalConfig.endpoint,\n headers: finalConfig.customHeaders,\n }),\n { scheduledDelayMillis: finalConfig.scheduledDelayMillis }\n );\n const provider = new WebTracerProvider({\n resource,\n spanProcessors: [spanProcessor],\n });\n provider.register({\n contextManager: new ZoneContextManager(),\n propagator: new W3CTraceContextPropagator(),\n });\n\n if (typeof window !== 'undefined') {\n const backendOrigin = new URL(finalConfig.endpoint).origin;\n\n const [{ FetchInstrumentation }, { XMLHttpRequestInstrumentation }] =\n await Promise.all([\n import('@opentelemetry/instrumentation-fetch'),\n import('@opentelemetry/instrumentation-xml-http-request'),\n ]);\n\n const fetchInst = new FetchInstrumentation({\n propagateTraceHeaderCorsUrls: [backendOrigin],\n clearTimingResources: true,\n });\n const xhrInst = new XMLHttpRequestInstrumentation({\n propagateTraceHeaderCorsUrls: [backendOrigin],\n clearTimingResources: true,\n });\n\n fetchInst.setTracerProvider(provider);\n xhrInst.setTracerProvider(provider);\n fetchInst.enable();\n xhrInst.enable();\n }\n\n console.log('OpenTelemetry initialized successfully');\n return provider;\n};\n"],"mappings":"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","names":["record"]}
|
package/package.json
CHANGED
@@ -1,14 +1,36 @@
|
|
1
1
|
{
|
2
2
|
"name": "rusty-replay",
|
3
|
-
"version": "1.0.
|
4
|
-
"description": "",
|
3
|
+
"version": "1.0.13",
|
4
|
+
"description": "Lightweight error tracking and replay system for React apps using rrweb and Rust-powered backend integration.",
|
5
5
|
"main": "dist/index.cjs",
|
6
6
|
"module": "dist/index.js",
|
7
7
|
"type": "module",
|
8
8
|
"types": "dist/index.d.ts",
|
9
9
|
"files": [
|
10
|
-
"dist"
|
10
|
+
"dist",
|
11
|
+
"README.md"
|
11
12
|
],
|
13
|
+
"keywords": [
|
14
|
+
"rrweb",
|
15
|
+
"replay",
|
16
|
+
"error-tracking",
|
17
|
+
"frontend",
|
18
|
+
"typescript",
|
19
|
+
"react",
|
20
|
+
"cli",
|
21
|
+
"monitoring"
|
22
|
+
],
|
23
|
+
"browser": {
|
24
|
+
"require-in-the-middle": false,
|
25
|
+
"import-in-the-middle": false,
|
26
|
+
"@opentelemetry/instrumentation": false
|
27
|
+
},
|
28
|
+
"author": "Jaeha Lee <wogkdkrm112@gmail.com>",
|
29
|
+
"license": "MIT",
|
30
|
+
"repository": {
|
31
|
+
"type": "git",
|
32
|
+
"url": "https://github.com/rusty-replay/replay"
|
33
|
+
},
|
12
34
|
"scripts": {
|
13
35
|
"build": "tsup",
|
14
36
|
"prepublishOnly": "npm run build"
|
@@ -17,9 +39,21 @@
|
|
17
39
|
"@rrweb/types": "^2.0.0-alpha.4",
|
18
40
|
"react": "^16.8 || ^17 || ^18 || ^19",
|
19
41
|
"rrweb": "^2.0.0-alpha.4",
|
20
|
-
"rrweb-player": "^1.0.0-alpha.4"
|
42
|
+
"rrweb-player": "^1.0.0-alpha.4",
|
43
|
+
"import-in-the-middle": "^1.13.1",
|
44
|
+
"require-in-the-middle": "^7.5.2"
|
21
45
|
},
|
22
46
|
"dependencies": {
|
47
|
+
"@opentelemetry/context-zone": "^2.0.0",
|
48
|
+
"@opentelemetry/core": "^2.0.0",
|
49
|
+
"@opentelemetry/exporter-trace-otlp-proto": "^0.200.0",
|
50
|
+
"@opentelemetry/instrumentation": "^0.200.0",
|
51
|
+
"@opentelemetry/instrumentation-fetch": "^0.200.0",
|
52
|
+
"@opentelemetry/instrumentation-xml-http-request": "^0.200.0",
|
53
|
+
"@opentelemetry/resources": "^2.0.0",
|
54
|
+
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
55
|
+
"@opentelemetry/sdk-trace-web": "^2.0.0",
|
56
|
+
"@opentelemetry/semantic-conventions": "^1.32.0",
|
23
57
|
"@rrweb/packer": "2.0.0-alpha.18",
|
24
58
|
"axios": "^1.8.4",
|
25
59
|
"fflate": "^0.8.2",
|