@backtrack-js/browser 0.4.0
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/LICENSE +9 -0
- package/README.md +291 -0
- package/bin/cli.cjs +51 -0
- package/bin/cli.js +2 -0
- package/bin/symbolize.cjs +654 -0
- package/bin/viewer.cjs +143 -0
- package/dist/capturers/console.d.ts +18 -0
- package/dist/capturers/console.d.ts.map +1 -0
- package/dist/capturers/errors.d.ts +22 -0
- package/dist/capturers/errors.d.ts.map +1 -0
- package/dist/capturers/index.d.ts +8 -0
- package/dist/capturers/index.d.ts.map +1 -0
- package/dist/capturers/navigation.d.ts +20 -0
- package/dist/capturers/navigation.d.ts.map +1 -0
- package/dist/capturers/network.d.ts +30 -0
- package/dist/capturers/network.d.ts.map +1 -0
- package/dist/capturers/performance.d.ts +15 -0
- package/dist/capturers/performance.d.ts.map +1 -0
- package/dist/capturers/route-matcher.d.ts +10 -0
- package/dist/capturers/route-matcher.d.ts.map +1 -0
- package/dist/capturers/rrweb.d.ts +18 -0
- package/dist/capturers/rrweb.d.ts.map +1 -0
- package/dist/capturers/sanitizer.d.ts +37 -0
- package/dist/capturers/sanitizer.d.ts.map +1 -0
- package/dist/core/flight-recorder.d.ts +75 -0
- package/dist/core/flight-recorder.d.ts.map +1 -0
- package/dist/core/state-machine.d.ts +55 -0
- package/dist/core/state-machine.d.ts.map +1 -0
- package/dist/index.cjs +1803 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5763 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/batch-writer.d.ts +57 -0
- package/dist/storage/batch-writer.d.ts.map +1 -0
- package/dist/storage/db.d.ts +39 -0
- package/dist/storage/db.d.ts.map +1 -0
- package/dist/storage/incident-manager.d.ts +107 -0
- package/dist/storage/incident-manager.d.ts.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/retention.d.ts +41 -0
- package/dist/storage/retention.d.ts.map +1 -0
- package/dist/storage/session.d.ts +32 -0
- package/dist/storage/session.d.ts.map +1 -0
- package/dist/types/artifact.d.ts +72 -0
- package/dist/types/artifact.d.ts.map +1 -0
- package/dist/types/chunk.d.ts +32 -0
- package/dist/types/chunk.d.ts.map +1 -0
- package/dist/types/health.d.ts +16 -0
- package/dist/types/health.d.ts.map +1 -0
- package/dist/types/incident.d.ts +35 -0
- package/dist/types/incident.d.ts.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/options.d.ts +84 -0
- package/dist/types/options.d.ts.map +1 -0
- package/dist/types/timeline.d.ts +74 -0
- package/dist/types/timeline.d.ts.map +1 -0
- package/dist/types/transport.d.ts +6 -0
- package/dist/types/transport.d.ts.map +1 -0
- package/dist/utils/compression.d.ts +28 -0
- package/dist/utils/compression.d.ts.map +1 -0
- package/dist/utils/gist-uploader.d.ts +12 -0
- package/dist/utils/gist-uploader.d.ts.map +1 -0
- package/dist/utils/markdown.d.ts +12 -0
- package/dist/utils/markdown.d.ts.map +1 -0
- package/dist/validation/validate.d.ts +27 -0
- package/dist/validation/validate.d.ts.map +1 -0
- package/dist/viewer/assets/backtrack-favico-Ds-TMW85.png +0 -0
- package/dist/viewer/assets/index-D6J82Kcf.js +191 -0
- package/dist/viewer/assets/index-cVrM07fr.css +1 -0
- package/dist/viewer/index.html +19 -0
- package/dist/widget/annotator.d.ts +85 -0
- package/dist/widget/annotator.d.ts.map +1 -0
- package/dist/widget/styles.d.ts +2 -0
- package/dist/widget/styles.d.ts.map +1 -0
- package/dist/widget/widget.d.ts +78 -0
- package/dist/widget/widget.d.ts.map +1 -0
- package/package.json +82 -0
package/bin/viewer.cjs
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { exec } = require('child_process');
|
|
5
|
+
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
let port = 5173;
|
|
8
|
+
|
|
9
|
+
let isExplicitPort = false;
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < args.length; i++) {
|
|
12
|
+
if (args[i] === '--port' || args[i] === '-p') {
|
|
13
|
+
port = parseInt(args[i + 1], 10) || 5173;
|
|
14
|
+
isExplicitPort = true;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const viewerDir = path.resolve(__dirname, '../dist/viewer');
|
|
19
|
+
|
|
20
|
+
if (!fs.existsSync(viewerDir)) {
|
|
21
|
+
console.error('\x1b[31m[Backtrack]\x1b[0m Viewer build not found at dist/viewer.');
|
|
22
|
+
console.error('Please run "npm run build" in @backtrack-js/browser first.');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const MIME_TYPES = {
|
|
27
|
+
'.html': 'text/html; charset=utf-8',
|
|
28
|
+
'.js': 'application/javascript; charset=utf-8',
|
|
29
|
+
'.css': 'text/css; charset=utf-8',
|
|
30
|
+
'.json': 'application/json; charset=utf-8',
|
|
31
|
+
'.png': 'image/png',
|
|
32
|
+
'.jpg': 'image/jpeg',
|
|
33
|
+
'.svg': 'image/svg+xml',
|
|
34
|
+
'.ico': 'image/x-icon',
|
|
35
|
+
'.woff': 'font/woff',
|
|
36
|
+
'.woff2': 'font/woff2'
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function createServerInstance() {
|
|
40
|
+
return http.createServer((req, res) => {
|
|
41
|
+
// CORS permissivo para uso local e integração com ferramentas de desenvolvimento
|
|
42
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
43
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
44
|
+
res.setHeader('Access-Control-Allow-Headers', '*');
|
|
45
|
+
|
|
46
|
+
if (req.method === 'OPTIONS') {
|
|
47
|
+
res.writeHead(204);
|
|
48
|
+
res.end();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const reqUrl = req.url.split('?')[0];
|
|
53
|
+
let safePath = path.normalize(reqUrl).replace(/^(\.\.[\/\\])+/, '');
|
|
54
|
+
let filePath = path.join(viewerDir, safePath);
|
|
55
|
+
|
|
56
|
+
if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) {
|
|
57
|
+
filePath = path.join(filePath, 'index.html');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!fs.existsSync(filePath)) {
|
|
61
|
+
// SPA fallback
|
|
62
|
+
filePath = path.join(viewerDir, 'index.html');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
66
|
+
const contentType = MIME_TYPES[ext] || 'application/octet-stream';
|
|
67
|
+
|
|
68
|
+
fs.readFile(filePath, (err, content) => {
|
|
69
|
+
if (err) {
|
|
70
|
+
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
71
|
+
res.end('Internal Server Error');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
75
|
+
res.end(content);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const os = require('os');
|
|
81
|
+
|
|
82
|
+
function start(targetPort) {
|
|
83
|
+
const server = createServerInstance();
|
|
84
|
+
|
|
85
|
+
server.on('error', (err) => {
|
|
86
|
+
if (err.code === 'EADDRINUSE') {
|
|
87
|
+
if (!isExplicitPort && targetPort < 5190) {
|
|
88
|
+
console.log(`\x1b[33m[Backtrack]\x1b[0m Porta ${targetPort} ocupada, tentando porta ${targetPort + 1}...`);
|
|
89
|
+
start(targetPort + 1);
|
|
90
|
+
} else {
|
|
91
|
+
console.error(`\x1b[31m[Backtrack]\x1b[0m A porta ${targetPort} já está em uso.`);
|
|
92
|
+
console.error(`Tente passar outra porta com: npm run viewer -- --port <porta>`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
console.error('\x1b[31m[Backtrack]\x1b[0m Erro no servidor:', err.message || err);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
server.listen(targetPort, '0.0.0.0', () => {
|
|
102
|
+
const url = `http://localhost:${targetPort}`;
|
|
103
|
+
console.log('\n\x1b[36m[Backtrack Viewer]\x1b[0m');
|
|
104
|
+
console.log(` > Local: \x1b[32m${url}\x1b[0m`);
|
|
105
|
+
|
|
106
|
+
// Detecta o IP da máquina na rede local Wi-Fi / Ethernet
|
|
107
|
+
const nets = os.networkInterfaces();
|
|
108
|
+
for (const name of Object.keys(nets)) {
|
|
109
|
+
for (const net of nets[name] || []) {
|
|
110
|
+
if (net.family === 'IPv4' && !net.internal) {
|
|
111
|
+
console.log(` > Network: \x1b[32mhttp://${net.address}:${targetPort}\x1b[0m`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log(' > Ready to inspect incidents. Pressione Ctrl+C para encerrar.\n');
|
|
117
|
+
|
|
118
|
+
// Tenta abrir o navegador automaticamente
|
|
119
|
+
const startCmd =
|
|
120
|
+
process.platform === 'darwin'
|
|
121
|
+
? `open "${url}"`
|
|
122
|
+
: process.platform === 'win32'
|
|
123
|
+
? `start "" "${url}"`
|
|
124
|
+
: `xdg-open "${url}"`;
|
|
125
|
+
|
|
126
|
+
if (!process.env.BACKTRACK_NO_OPEN) {
|
|
127
|
+
exec(startCmd, () => {
|
|
128
|
+
// Ignora erros ao abrir automaticamente
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return server;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (typeof process.env.VITEST === 'undefined') {
|
|
137
|
+
start(port);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = {
|
|
141
|
+
createServerInstance,
|
|
142
|
+
start
|
|
143
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BatchWriter } from '../storage/batch-writer';
|
|
2
|
+
export declare class ConsoleCapturer {
|
|
3
|
+
private writer;
|
|
4
|
+
private isRecording;
|
|
5
|
+
private sequenceProvider;
|
|
6
|
+
private originalLog;
|
|
7
|
+
private originalWarn;
|
|
8
|
+
private originalError;
|
|
9
|
+
private wrappedLog;
|
|
10
|
+
private wrappedWarn;
|
|
11
|
+
private wrappedError;
|
|
12
|
+
private isInsideHook;
|
|
13
|
+
constructor(writer: BatchWriter, sequenceProvider: () => number);
|
|
14
|
+
start(): void;
|
|
15
|
+
private handleConsole;
|
|
16
|
+
stop(): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=console.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/capturers/console.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3D,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAe;IAEvC,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,aAAa,CAAqC;IAE1D,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,WAAW,CAAoC;IACvD,OAAO,CAAC,YAAY,CAAqC;IAEzD,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,MAAM;IAKxD,KAAK,IAAI,IAAI;IAuBpB,OAAO,CAAC,aAAa;IAkCd,IAAI,IAAI,IAAI;CAsBpB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BatchWriter } from '../storage/batch-writer';
|
|
2
|
+
import type { IncidentManager } from '../storage/incident-manager';
|
|
3
|
+
import type { ErrorContext } from '../types/options';
|
|
4
|
+
export declare class ErrorCapturer {
|
|
5
|
+
private writer;
|
|
6
|
+
private incidentManager;
|
|
7
|
+
private sequenceProvider;
|
|
8
|
+
private isRecording;
|
|
9
|
+
private errorHandler?;
|
|
10
|
+
private rejectionHandler?;
|
|
11
|
+
constructor(writer: BatchWriter, incidentManager: IncidentManager, sequenceProvider: () => number);
|
|
12
|
+
start(): void;
|
|
13
|
+
private handleGlobalError;
|
|
14
|
+
private handleUnhandledRejection;
|
|
15
|
+
/**
|
|
16
|
+
* API pública para capturar exceções explicitamente (ex: do SentryBoundary do uTicket).
|
|
17
|
+
*/
|
|
18
|
+
captureException(error: unknown, context?: ErrorContext): Promise<string | undefined> | void;
|
|
19
|
+
private recordAndTriggerError;
|
|
20
|
+
stop(): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/capturers/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,YAAY,CAAC,CAA8B;IACnD,OAAO,CAAC,gBAAgB,CAAC,CAAyC;gBAGhE,MAAM,EAAE,WAAW,EACnB,eAAe,EAAE,eAAe,EAChC,gBAAgB,EAAE,MAAM,MAAM;IAOzB,KAAK,IAAI,IAAI;IAmBpB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,wBAAwB;IA8BhC;;OAEG;IACI,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI;IAmCnG,OAAO,CAAC,qBAAqB;IAoDtB,IAAI,IAAI,IAAI;CAepB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capturers/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BatchWriter } from '../storage/batch-writer';
|
|
2
|
+
export interface NavigationCapturerConfig {
|
|
3
|
+
sanitizeUrlCallback?: (url: URL) => string;
|
|
4
|
+
}
|
|
5
|
+
export declare class NavigationCapturer {
|
|
6
|
+
private writer;
|
|
7
|
+
private sequenceProvider;
|
|
8
|
+
private config;
|
|
9
|
+
private isRecording;
|
|
10
|
+
private currentUrl;
|
|
11
|
+
private originalPushState;
|
|
12
|
+
private originalReplaceState;
|
|
13
|
+
private popstateHandler?;
|
|
14
|
+
private hashchangeHandler?;
|
|
15
|
+
constructor(writer: BatchWriter, sequenceProvider: () => number, config?: NavigationCapturerConfig);
|
|
16
|
+
start(): void;
|
|
17
|
+
private recordNavigation;
|
|
18
|
+
stop(): void;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/capturers/navigation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3D,MAAM,WAAW,wBAAwB;IACvC,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC;CAC5C;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,iBAAiB,CAAgD;IACzE,OAAO,CAAC,oBAAoB,CAAmD;IAE/E,OAAO,CAAC,eAAe,CAAC,CAAa;IACrC,OAAO,CAAC,iBAAiB,CAAC,CAAa;gBAGrC,MAAM,EAAE,WAAW,EACnB,gBAAgB,EAAE,MAAM,MAAM,EAC9B,MAAM,CAAC,EAAE,wBAAwB;IAO5B,KAAK,IAAI,IAAI;IAyCpB,OAAO,CAAC,gBAAgB;IAoBjB,IAAI,IAAI,IAAI;CAwBpB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { BatchWriter } from '../storage/batch-writer';
|
|
2
|
+
import type { IncidentManager } from '../storage/incident-manager';
|
|
3
|
+
export interface NetworkCapturerConfig {
|
|
4
|
+
captureHttpStatus: number[];
|
|
5
|
+
ignoredUrls?: (string | RegExp)[];
|
|
6
|
+
sanitizeUrlCallback?: (url: URL) => string;
|
|
7
|
+
capturePayloads?: boolean;
|
|
8
|
+
maxPayloadSize?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class NetworkCapturer {
|
|
11
|
+
private writer;
|
|
12
|
+
private incidentManager;
|
|
13
|
+
private sequenceProvider;
|
|
14
|
+
private config;
|
|
15
|
+
private isRecording;
|
|
16
|
+
private originalFetch;
|
|
17
|
+
private wrappedFetch;
|
|
18
|
+
private originalXHROpen;
|
|
19
|
+
private originalXHRSend;
|
|
20
|
+
private originalXHRSetHeader;
|
|
21
|
+
private xhrMetadata;
|
|
22
|
+
constructor(writer: BatchWriter, incidentManager: IncidentManager, sequenceProvider: () => number, config?: Partial<NetworkCapturerConfig>);
|
|
23
|
+
start(): void;
|
|
24
|
+
private shouldIgnoreUrl;
|
|
25
|
+
private instrumentFetch;
|
|
26
|
+
private instrumentXHR;
|
|
27
|
+
private recordNetworkEvent;
|
|
28
|
+
stop(): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/capturers/network.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAGnE,MAAM,WAAW,qBAAqB;IACpC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAClC,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC;IAC3C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAUD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,YAAY,CAAoC;IAExD,OAAO,CAAC,eAAe,CAAqD;IAC5E,OAAO,CAAC,eAAe,CAAqD;IAC5E,OAAO,CAAC,oBAAoB,CAAiE;IAC7F,OAAO,CAAC,WAAW,CAA8C;gBAG/D,MAAM,EAAE,WAAW,EACnB,eAAe,EAAE,eAAe,EAChC,gBAAgB,EAAE,MAAM,MAAM,EAC9B,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAclC,KAAK,IAAI,IAAI;IAQpB,OAAO,CAAC,eAAe;IAkCvB,OAAO,CAAC,eAAe;IAqHvB,OAAO,CAAC,aAAa;IA4HrB,OAAO,CAAC,kBAAkB;IAqDnB,IAAI,IAAI,IAAI;CA6BpB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { BatchWriter } from '../storage/batch-writer';
|
|
2
|
+
export interface PerformanceCapturerConfig {
|
|
3
|
+
longTaskThresholdMs?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class PerformanceCapturer {
|
|
6
|
+
private writer;
|
|
7
|
+
private sequenceProvider;
|
|
8
|
+
private observer;
|
|
9
|
+
private isRecording;
|
|
10
|
+
private thresholdMs;
|
|
11
|
+
constructor(writer: BatchWriter, sequenceProvider: () => number, config?: PerformanceCapturerConfig);
|
|
12
|
+
start(): void;
|
|
13
|
+
stop(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=performance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"performance.d.ts","sourceRoot":"","sources":["../../src/capturers/performance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3D,MAAM,WAAW,yBAAyB;IACxC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;gBAG1B,MAAM,EAAE,WAAW,EACnB,gBAAgB,EAAE,MAAM,MAAM,EAC9B,MAAM,CAAC,EAAE,yBAAyB;IAO7B,KAAK,IAAI,IAAI;IA0Cb,IAAI,IAAI,IAAI;CAWpB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RouteMatcher } from '../types/options';
|
|
2
|
+
/**
|
|
3
|
+
* Converte um padrão de rota com wildcard (ex: '/checkout/*', '/auth/**') em RegExp.
|
|
4
|
+
*/
|
|
5
|
+
export declare function globToRegex(pattern: string): RegExp;
|
|
6
|
+
/**
|
|
7
|
+
* Verifica se um pathname ou URL corresponde a alguma das regras de sensitiveRoutes configuradas.
|
|
8
|
+
*/
|
|
9
|
+
export declare function matchesSensitiveRoute(pathname: string, matchers?: RouteMatcher[]): boolean;
|
|
10
|
+
//# sourceMappingURL=route-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-matcher.d.ts","sourceRoot":"","sources":["../../src/capturers/route-matcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkBnD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,YAAY,EAAE,GACxB,OAAO,CAsCT"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BatchWriter } from '../storage/batch-writer';
|
|
2
|
+
import type { PrivacyOptions } from '../types/options';
|
|
3
|
+
export interface RrwebCapturerConfig {
|
|
4
|
+
privacy?: PrivacyOptions;
|
|
5
|
+
checkoutEveryNms?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class RrwebCapturer {
|
|
8
|
+
private writer;
|
|
9
|
+
private config;
|
|
10
|
+
private isRecording;
|
|
11
|
+
private stopRecordFn;
|
|
12
|
+
private droppedEventsCount;
|
|
13
|
+
constructor(writer: BatchWriter, config?: RrwebCapturerConfig);
|
|
14
|
+
getDroppedEventsCount(): number;
|
|
15
|
+
start(): void;
|
|
16
|
+
stop(): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=rrweb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rrweb.d.ts","sourceRoot":"","sources":["../../src/capturers/rrweb.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,kBAAkB,CAAK;gBAEnB,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,mBAAmB;IAKtD,qBAAqB,IAAI,MAAM;IAI/B,KAAK,IAAI,IAAI;IAkFb,IAAI,IAAI,IAAI;CAapB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface SanitizerConfig {
|
|
2
|
+
maxDepth?: number;
|
|
3
|
+
maxKeys?: number;
|
|
4
|
+
maxItems?: number;
|
|
5
|
+
maxStringLength?: number;
|
|
6
|
+
sanitizeUrlCallback?: (url: URL) => string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Sanitiza uma URL conforme a seção 12.4 do SPEC.md:
|
|
10
|
+
* - Remove fragment (#...)
|
|
11
|
+
* - Preserva origin e pathname
|
|
12
|
+
* - Preserva apenas os NOMES dos query parameters (ordenados, sem valores)
|
|
13
|
+
* - Substitui UUIDs e IDs numéricos longos por :id
|
|
14
|
+
*/
|
|
15
|
+
export declare function sanitizeUrl(rawUrl: string, customCallback?: (url: URL) => string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Redige padrões reconhecíveis de segredos em texto puro.
|
|
18
|
+
*/
|
|
19
|
+
export declare function redactSensitiveString(str: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Serializador e sanitizador universal à prova de falhas:
|
|
22
|
+
* - Detecta ciclos circulares
|
|
23
|
+
* - Limita profundidade, chaves e tamanho de strings
|
|
24
|
+
* - Redige propriedades e valores sensíveis
|
|
25
|
+
* - Suporta Error, BigInt, Function, DOM elements e primitivos
|
|
26
|
+
* - NUNCA lança exceção (operação total)
|
|
27
|
+
*/
|
|
28
|
+
export declare function sanitizeAndSerialize(input: unknown, config?: SanitizerConfig): unknown;
|
|
29
|
+
/**
|
|
30
|
+
* Sanitiza strings de request e response body com redação de PII e teto máximo de tamanho.
|
|
31
|
+
*/
|
|
32
|
+
export declare function sanitizePayloadString(payload: string, maxLength?: number): string;
|
|
33
|
+
/**
|
|
34
|
+
* Sanitiza headers HTTP redigindo Authorization, Cookies, Tokens e Chaves.
|
|
35
|
+
*/
|
|
36
|
+
export declare function sanitizeHeaders(headers: Record<string, string> | Headers | [string, string][] | undefined | null): Record<string, string> | undefined;
|
|
37
|
+
//# sourceMappingURL=sanitizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../../src/capturers/sanitizer.ts"],"names":[],"mappings":"AA0CA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC;CAC5C;AASD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,GAAG,MAAM,CA4BzF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAczD;AAUD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CA8HtF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAkB,GAAG,MAAM,CAgB5F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,SAAS,GAAG,IAAI,GAChF,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAgCpC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { FlightRecorderDB } from '../storage/db';
|
|
2
|
+
import type { FlightRecorder, FlightRecorderOptions, CaptureOptions, ErrorContext } from '../types/options';
|
|
3
|
+
import type { RecorderHealth } from '../types/health';
|
|
4
|
+
import type { IncidentSummary } from '../types/incident';
|
|
5
|
+
import type { FlightRecorderArtifact } from '../types/artifact';
|
|
6
|
+
export declare class FlightRecorderImpl implements FlightRecorder {
|
|
7
|
+
private static activeInstance;
|
|
8
|
+
private options;
|
|
9
|
+
private stateMachine;
|
|
10
|
+
private db;
|
|
11
|
+
private writer;
|
|
12
|
+
private retention;
|
|
13
|
+
private incidentManager;
|
|
14
|
+
private widget;
|
|
15
|
+
private consoleCapturer;
|
|
16
|
+
private errorCapturer;
|
|
17
|
+
private networkCapturer;
|
|
18
|
+
private navigationCapturer;
|
|
19
|
+
private rrwebCapturer;
|
|
20
|
+
private performanceCapturer;
|
|
21
|
+
private sequence;
|
|
22
|
+
private retentionIntervalTimer;
|
|
23
|
+
private retentionPromise;
|
|
24
|
+
private cachedStorageBytes;
|
|
25
|
+
private cachedIncidentCount;
|
|
26
|
+
private pageHideHandler?;
|
|
27
|
+
private beforeUnloadHandler?;
|
|
28
|
+
private visibilityChangeHandler?;
|
|
29
|
+
private cachedProtectedBytes;
|
|
30
|
+
private cachedBrowserEstimateBytes?;
|
|
31
|
+
private cachedBrowserQuotaBytes?;
|
|
32
|
+
constructor(options?: FlightRecorderOptions, customDb?: FlightRecorderDB);
|
|
33
|
+
static init(options?: FlightRecorderOptions, customDb?: FlightRecorderDB): Promise<FlightRecorderImpl>;
|
|
34
|
+
static hideWidget(): void;
|
|
35
|
+
static showWidget(): void;
|
|
36
|
+
static toggleWidget(): boolean;
|
|
37
|
+
static hide(): void;
|
|
38
|
+
static show(): void;
|
|
39
|
+
static toggle(): boolean;
|
|
40
|
+
static resetInstance(): Promise<void>;
|
|
41
|
+
static getInstance(): FlightRecorderImpl | null;
|
|
42
|
+
hideWidget(): void;
|
|
43
|
+
showWidget(): void;
|
|
44
|
+
toggleWidget(): boolean;
|
|
45
|
+
private nextSequence;
|
|
46
|
+
private getEnvironmentMetadata;
|
|
47
|
+
start(): Promise<void>;
|
|
48
|
+
private scheduleRetention;
|
|
49
|
+
private handleQuotaExceeded;
|
|
50
|
+
private updateStatsCache;
|
|
51
|
+
private sendIncident;
|
|
52
|
+
private stoppingPromise?;
|
|
53
|
+
private stopCapturers;
|
|
54
|
+
private clearRuntimeReferences;
|
|
55
|
+
stop(): Promise<void>;
|
|
56
|
+
capture(reason?: string, windowSeconds?: number, options?: CaptureOptions): Promise<string>;
|
|
57
|
+
captureException(error: unknown, context?: ErrorContext): Promise<string | undefined> | void;
|
|
58
|
+
listIncidents(): Promise<IncidentSummary[]>;
|
|
59
|
+
getArtifact(incidentId: string): Promise<FlightRecorderArtifact>;
|
|
60
|
+
exportIncident(incidentId: string, options?: {
|
|
61
|
+
compress?: boolean;
|
|
62
|
+
aiOptimized?: boolean;
|
|
63
|
+
}): Promise<FlightRecorderArtifact>;
|
|
64
|
+
deleteIncident(incidentId: string): Promise<void>;
|
|
65
|
+
clear(): Promise<void>;
|
|
66
|
+
getHealth(): RecorderHealth;
|
|
67
|
+
getSequence(): number;
|
|
68
|
+
flush(): Promise<void>;
|
|
69
|
+
destroy(): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Função factory pública para instanciar o Flight Recorder.
|
|
73
|
+
*/
|
|
74
|
+
export declare function createFlightRecorder(options?: FlightRecorderOptions): FlightRecorder;
|
|
75
|
+
//# sourceMappingURL=flight-recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flight-recorder.d.ts","sourceRoot":"","sources":["../../src/core/flight-recorder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { RecorderState } from '../types/health';
|
|
2
|
+
/**
|
|
3
|
+
* Eventos que causam transição de estado no Flight Recorder.
|
|
4
|
+
*/
|
|
5
|
+
export type RecorderTransitionEvent = {
|
|
6
|
+
type: 'START';
|
|
7
|
+
} | {
|
|
8
|
+
type: 'STOP';
|
|
9
|
+
} | {
|
|
10
|
+
type: 'TRIGGER_AUTO';
|
|
11
|
+
} | {
|
|
12
|
+
type: 'TRIGGER_MANUAL';
|
|
13
|
+
} | {
|
|
14
|
+
type: 'FINALIZE_INCIDENT';
|
|
15
|
+
} | {
|
|
16
|
+
type: 'DEGRADE';
|
|
17
|
+
reason: string;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'RECOVER';
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Representação da máquina de estados descrita na Seção 8 do SPEC.md:
|
|
23
|
+
*
|
|
24
|
+
* ```text
|
|
25
|
+
* stopped
|
|
26
|
+
* │ start
|
|
27
|
+
* ▼
|
|
28
|
+
* recording
|
|
29
|
+
* │ trigger
|
|
30
|
+
* ▼
|
|
31
|
+
* incident_pending
|
|
32
|
+
* │ prazo posterior ou captura manual
|
|
33
|
+
* ▼
|
|
34
|
+
* incident_finalized (lógico / transitório para persistência)
|
|
35
|
+
* │ gravação contínua
|
|
36
|
+
* └──────────────────────────────► recording
|
|
37
|
+
*
|
|
38
|
+
* qualquer estado operacional
|
|
39
|
+
* │ falha parcial
|
|
40
|
+
* ▼
|
|
41
|
+
* degraded
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare class RecorderStateMachine {
|
|
45
|
+
private currentState;
|
|
46
|
+
private degradedReasons;
|
|
47
|
+
private previousOperationalState;
|
|
48
|
+
constructor(initialState?: RecorderState);
|
|
49
|
+
getState(): RecorderState;
|
|
50
|
+
getDegradedReasons(): string[];
|
|
51
|
+
isDegraded(): boolean;
|
|
52
|
+
isRecording(): boolean;
|
|
53
|
+
transition(event: RecorderTransitionEvent): RecorderState;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=state-machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-machine.d.ts","sourceRoot":"","sources":["../../src/core/state-machine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,CAAC,wBAAwB,CAA4B;gBAEhD,YAAY,GAAE,aAAyB;IAI5C,QAAQ,IAAI,aAAa;IAIzB,kBAAkB,IAAI,MAAM,EAAE;IAI9B,UAAU,IAAI,OAAO;IAIrB,WAAW,IAAI,OAAO;IAUtB,UAAU,CAAC,KAAK,EAAE,uBAAuB,GAAG,aAAa;CAuDjE"}
|