@cedarai/session-replay-sdk 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/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  interface SDKConfig {
2
2
  serverUrl: string;
3
3
  cedarSessionId: string;
4
+ environment: string;
5
+ developer?: string;
4
6
  batchIntervalMs?: number;
5
7
  batchMaxSize?: number;
6
8
  console?: ConsoleConfig;
@@ -23,6 +25,8 @@ interface RecorderConfig {
23
25
  interface InitConfig {
24
26
  serverUrl: string;
25
27
  cedarSessionId: string;
28
+ environment: string;
29
+ developer?: string;
26
30
  batchIntervalMs?: number;
27
31
  batchMaxSize?: number;
28
32
  console?: SDKConfig['console'];
package/dist/index.js CHANGED
@@ -165,7 +165,11 @@ var Transport = class {
165
165
  viewportWidth: typeof window !== "undefined" ? window.innerWidth : 0,
166
166
  viewportHeight: typeof window !== "undefined" ? window.innerHeight : 0,
167
167
  url: typeof window !== "undefined" ? window.location.href : "",
168
- events
168
+ events,
169
+ metadata: {
170
+ environment: this.config.environment,
171
+ ...this.config.developer ? { developer: this.config.developer } : {}
172
+ }
169
173
  };
170
174
  }
171
175
  estimateQueueSize() {
@@ -299,10 +303,36 @@ var ErrorCapture = class {
299
303
  // src/network.ts
300
304
  var nextId = 0;
301
305
  var RESPONSE_BODY_MAX_SIZE = 100 * 1024;
306
+ function extractHeaders(headers) {
307
+ if (!headers) return void 0;
308
+ const result = {};
309
+ if (headers instanceof Headers) {
310
+ headers.forEach((v, k) => {
311
+ result[k] = v;
312
+ });
313
+ } else if (Array.isArray(headers)) {
314
+ for (const [k, v] of headers) {
315
+ result[k] = v;
316
+ }
317
+ } else {
318
+ Object.assign(result, headers);
319
+ }
320
+ return Object.keys(result).length > 0 ? result : void 0;
321
+ }
322
+ function headersToRecord(headers) {
323
+ const result = {};
324
+ headers.forEach((v, k) => {
325
+ result[k] = v;
326
+ });
327
+ return Object.keys(result).length > 0 ? result : void 0;
328
+ }
302
329
  var NetworkCapture = class {
303
330
  onEvent;
304
331
  serverUrl;
305
332
  originalFetch = null;
333
+ originalXHROpen = null;
334
+ originalXHRSend = null;
335
+ originalXHRSetHeader = null;
306
336
  started = false;
307
337
  constructor(onEvent2, serverUrl) {
308
338
  this.onEvent = onEvent2;
@@ -311,6 +341,31 @@ var NetworkCapture = class {
311
341
  start() {
312
342
  if (this.started) return;
313
343
  this.started = true;
344
+ this.interceptFetch();
345
+ this.interceptXHR();
346
+ }
347
+ stop() {
348
+ if (!this.started) return;
349
+ this.started = false;
350
+ if (this.originalFetch) {
351
+ globalThis.fetch = this.originalFetch;
352
+ this.originalFetch = null;
353
+ }
354
+ if (this.originalXHROpen) {
355
+ XMLHttpRequest.prototype.open = this.originalXHROpen;
356
+ this.originalXHROpen = null;
357
+ }
358
+ if (this.originalXHRSend) {
359
+ XMLHttpRequest.prototype.send = this.originalXHRSend;
360
+ this.originalXHRSend = null;
361
+ }
362
+ if (this.originalXHRSetHeader) {
363
+ XMLHttpRequest.prototype.setRequestHeader = this.originalXHRSetHeader;
364
+ this.originalXHRSetHeader = null;
365
+ }
366
+ }
367
+ // ── Fetch interception ────────────────────────────────────────
368
+ interceptFetch() {
314
369
  this.originalFetch = globalThis.fetch;
315
370
  globalThis.fetch = async (input, init) => {
316
371
  const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
@@ -319,6 +374,7 @@ var NetworkCapture = class {
319
374
  }
320
375
  const method = init?.method?.toUpperCase() ?? "GET";
321
376
  const requestBody = init?.body ? String(init.body) : void 0;
377
+ const requestHeaders = extractHeaders(init?.headers);
322
378
  const startTime = performance.now();
323
379
  const id = String(++nextId);
324
380
  let graphqlOperationName;
@@ -354,8 +410,10 @@ var NetworkCapture = class {
354
410
  method,
355
411
  url,
356
412
  graphqlOperationName,
413
+ requestHeaders,
357
414
  requestBody,
358
415
  status: response.status,
416
+ responseHeaders: headersToRecord(response.headers),
359
417
  responseBody,
360
418
  startTime,
361
419
  endTime,
@@ -373,6 +431,7 @@ var NetworkCapture = class {
373
431
  method,
374
432
  url,
375
433
  graphqlOperationName,
434
+ requestHeaders,
376
435
  requestBody,
377
436
  startTime,
378
437
  endTime,
@@ -384,13 +443,72 @@ var NetworkCapture = class {
384
443
  }
385
444
  };
386
445
  }
387
- stop() {
388
- if (!this.started) return;
389
- this.started = false;
390
- if (this.originalFetch) {
391
- globalThis.fetch = this.originalFetch;
392
- this.originalFetch = null;
393
- }
446
+ // ── XMLHttpRequest interception ───────────────────────────────
447
+ interceptXHR() {
448
+ const self = this;
449
+ const xhrData = /* @__PURE__ */ new WeakMap();
450
+ this.originalXHROpen = XMLHttpRequest.prototype.open;
451
+ this.originalXHRSend = XMLHttpRequest.prototype.send;
452
+ this.originalXHRSetHeader = XMLHttpRequest.prototype.setRequestHeader;
453
+ XMLHttpRequest.prototype.open = function(method, url, ...rest) {
454
+ const urlStr = typeof url === "string" ? url : url.href;
455
+ xhrData.set(this, { method: method.toUpperCase(), url: urlStr, headers: {}, startTime: 0 });
456
+ return self.originalXHROpen.apply(this, [method, url, ...rest]);
457
+ };
458
+ XMLHttpRequest.prototype.setRequestHeader = function(name, value) {
459
+ const data = xhrData.get(this);
460
+ if (data) data.headers[name] = value;
461
+ return self.originalXHRSetHeader.apply(this, [name, value]);
462
+ };
463
+ XMLHttpRequest.prototype.send = function(body) {
464
+ const data = xhrData.get(this);
465
+ if (data && data.url.startsWith(self.serverUrl)) {
466
+ return self.originalXHRSend.apply(this, [body]);
467
+ }
468
+ if (data) {
469
+ data.startTime = performance.now();
470
+ }
471
+ const requestBody = body != null ? String(body) : void 0;
472
+ this.addEventListener("loadend", function() {
473
+ if (!data) return;
474
+ const endTime = performance.now();
475
+ const rawHeaders = this.getAllResponseHeaders();
476
+ const responseHeaders = {};
477
+ if (rawHeaders) {
478
+ rawHeaders.trim().split(/[\r\n]+/).forEach((line) => {
479
+ const idx = line.indexOf(": ");
480
+ if (idx > 0) responseHeaders[line.substring(0, idx)] = line.substring(idx + 2);
481
+ });
482
+ }
483
+ let responseBody;
484
+ if (this.responseType === "" || this.responseType === "text") {
485
+ try {
486
+ const text = this.responseText;
487
+ if (text.length <= RESPONSE_BODY_MAX_SIZE) responseBody = text;
488
+ } catch {
489
+ }
490
+ }
491
+ self.onEvent({
492
+ type: "network",
493
+ timestamp: Date.now(),
494
+ data: {
495
+ id: String(++nextId),
496
+ method: data.method,
497
+ url: data.url,
498
+ requestHeaders: Object.keys(data.headers).length > 0 ? data.headers : void 0,
499
+ requestBody,
500
+ status: this.status,
501
+ responseHeaders: Object.keys(responseHeaders).length > 0 ? responseHeaders : void 0,
502
+ responseBody,
503
+ startTime: data.startTime,
504
+ endTime,
505
+ duration: endTime - data.startTime,
506
+ error: this.status === 0 ? "Network error" : void 0
507
+ }
508
+ });
509
+ });
510
+ return self.originalXHRSend.apply(this, [body]);
511
+ };
394
512
  }
395
513
  };
396
514
 
@@ -552,6 +670,8 @@ var CedarReplay = {
552
670
  {
553
671
  serverUrl: config.serverUrl,
554
672
  cedarSessionId: config.cedarSessionId,
673
+ environment: config.environment,
674
+ developer: config.developer,
555
675
  batchIntervalMs: config.batchIntervalMs,
556
676
  batchMaxSize: config.batchMaxSize
557
677
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarai/session-replay-sdk",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",