@arvoretech/bug-jar 0.4.0 → 0.6.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/README.md CHANGED
@@ -110,18 +110,44 @@ private S3 bucket via a presigned URL. No AWS credentials ever reach the browser
110
110
  Flow:
111
111
 
112
112
  1. Staff (admin) calls `POST /debug-sessions` with the target app URL and gets back
113
- a `debugLink` (`https://app.../?debug=<token>`), the presigned PUT URL, the
114
- server public key, and an expiry.
115
- 2. The user opens the link. Bug Jar detects `?debug=<token>`, fetches the session
116
- from `debugSessionEndpoint`, starts screen recording, and shows a top banner.
117
- 3. The user clicks **Finalizar e enviar**. Bug Jar builds the ZIP, encrypts it
118
- (libsodium sealed box + secretbox hybrid), and uploads the encrypted blob to S3.
119
- 4. Staff downloads the `.bin` via `GET /debug-sessions/:token/download` and
120
- decrypts it offline with the private key.
121
-
122
- The package leaves the browser already unreadable; only the holder of the X25519
123
- private key can open it. `libsodium-wrappers` is loaded dynamically, so it only
124
- ships when debug mode is actually used.
113
+ a `debugLink` (`https://app.../?debug=<token>`), the server public key, and an expiry.
114
+ 2. The user opens the link. Bug Jar detects `?debug=<token>`, persists the token in
115
+ a `.arvore.com.br` cookie, fetches the session, starts screen recording, and
116
+ shows an animated **session border** (no button, no banner).
117
+ 3. The user just uses the app. The session survives navigation across apps
118
+ (app-v2 → legacy → reader) by re-hydrating the token from the cookie on each
119
+ page. Each page streams **encrypted chunks** to S3 in real time:
120
+ - **data** (network/console/errors/actions/storage) every 5s as JSONL
121
+ - **video** chunks straight from `MediaRecorder` as they are produced
122
+ Chunks are uploaded to `debug/<token>/<pageId>/<stream>/<seq>.bin` via per-chunk
123
+ presigned PUT URLs (`POST /debug-sessions/:token/chunk-url`). Page metadata goes
124
+ to `debug/<token>/<pageId>/meta.json` (`POST /debug-sessions/:token/meta`).
125
+ 4. Staff reconstructs the session offline:
126
+ ```bash
127
+ BUG_JAR_API=https://api.arvore.com.br/debug-sessions \
128
+ BUG_JAR_API_TOKEN=<admin-jwt> \
129
+ node scripts/decrypt-session.cjs <token> ./out
130
+ ```
131
+ This reads the X25519 private key from Secrets Manager (`bug-jar/keypair`),
132
+ downloads all chunks via `GET /debug-sessions/:token/download`, decrypts each
133
+ per-page stream, and writes `<pageId>/data.jsonl`, `<pageId>/video.webm`,
134
+ `<pageId>/meta.json`.
135
+
136
+ ## Encryption
137
+
138
+ Each stream (data and video, per page) is encrypted with libsodium
139
+ `crypto_secretstream_xchacha20poly1305`: a random symmetric key drives the stream,
140
+ and that key is sealed with `crypto_box_seal` (X25519) to the server public key.
141
+ The first chunk of every stream is `[magic][version][sealedKeyLen][sealedKey][header]`;
142
+ subsequent chunks are the encrypted stream messages, the last carrying `TAG_FINAL`.
143
+ Chunks leave the browser already unreadable; only the holder of the X25519 private
144
+ key can open them. `libsodium-wrappers` is loaded dynamically, so it only ships
145
+ when debug mode is actually used.
146
+
147
+ > Cross-app continuity works because all apps live under `*.arvore.com.br` and
148
+ > share the session cookie. Screen recording restarts per app (the browser does
149
+ > not allow `getDisplayMedia` to persist across full page loads / origins), so the
150
+ > video is reconstructed per page rather than as one continuous file.
125
151
 
126
152
 
127
153
  ## Privacy & Security
package/dist/index.d.mts CHANGED
@@ -136,8 +136,6 @@ declare function exportAsZip(report: BugReport, videoBlob: Blob | null): Promise
136
136
  interface DebugSessionPayload {
137
137
  token: string;
138
138
  publicKey: string;
139
- presignedPut: string;
140
- reportId: string;
141
139
  expiresAt: number;
142
140
  }
143
141
 
@@ -153,8 +151,13 @@ declare class BugJar {
153
151
  private screenshot;
154
152
  private featureFlags;
155
153
  private screenRecorder;
156
- private debugBanner;
154
+ private sessionBorder;
157
155
  private debugSession;
156
+ private dataUploader;
157
+ private videoUploader;
158
+ private pageId;
159
+ private dataInterval;
160
+ private finalized;
158
161
  private started;
159
162
  constructor(config?: Partial<BugJarConfig>);
160
163
  start(): void;
@@ -165,7 +168,10 @@ declare class BugJar {
165
168
  captureAndExport(userDescription?: string): Promise<BugReport>;
166
169
  getReport(): Promise<BugReport>;
167
170
  private startDebugSession;
168
- private finishDebugSession;
171
+ private startDataStreaming;
172
+ private registerFlushHandlers;
173
+ private finalizePage;
174
+ endDebugSession(): void;
169
175
  }
170
176
  declare function init(config?: Partial<BugJarConfig>): BugJar;
171
177
 
package/dist/index.d.ts CHANGED
@@ -136,8 +136,6 @@ declare function exportAsZip(report: BugReport, videoBlob: Blob | null): Promise
136
136
  interface DebugSessionPayload {
137
137
  token: string;
138
138
  publicKey: string;
139
- presignedPut: string;
140
- reportId: string;
141
139
  expiresAt: number;
142
140
  }
143
141
 
@@ -153,8 +151,13 @@ declare class BugJar {
153
151
  private screenshot;
154
152
  private featureFlags;
155
153
  private screenRecorder;
156
- private debugBanner;
154
+ private sessionBorder;
157
155
  private debugSession;
156
+ private dataUploader;
157
+ private videoUploader;
158
+ private pageId;
159
+ private dataInterval;
160
+ private finalized;
158
161
  private started;
159
162
  constructor(config?: Partial<BugJarConfig>);
160
163
  start(): void;
@@ -165,7 +168,10 @@ declare class BugJar {
165
168
  captureAndExport(userDescription?: string): Promise<BugReport>;
166
169
  getReport(): Promise<BugReport>;
167
170
  private startDebugSession;
168
- private finishDebugSession;
171
+ private startDataStreaming;
172
+ private registerFlushHandlers;
173
+ private finalizePage;
174
+ endDebugSession(): void;
169
175
  }
170
176
  declare function init(config?: Partial<BugJarConfig>): BugJar;
171
177