@newrelic/browser-agent 1.255.0 → 1.256.1

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/cjs/common/constants/env.cdn.js +2 -2
  3. package/dist/cjs/common/constants/env.npm.js +2 -2
  4. package/dist/cjs/common/constants/runtime.js +1 -1
  5. package/dist/cjs/common/session/session-entity.js +2 -1
  6. package/dist/cjs/common/timer/interaction-timer.js +16 -2
  7. package/dist/cjs/common/timing/time-keeper.js +1 -2
  8. package/dist/cjs/features/jserrors/aggregate/index.js +16 -6
  9. package/dist/cjs/features/jserrors/instrument/index.js +8 -3
  10. package/dist/cjs/features/session_replay/aggregate/index.js +48 -29
  11. package/dist/cjs/features/session_replay/constants.js +2 -1
  12. package/dist/cjs/features/session_replay/instrument/index.js +9 -2
  13. package/dist/cjs/features/session_replay/shared/recorder-events.js +1 -9
  14. package/dist/cjs/features/session_replay/shared/recorder.js +22 -50
  15. package/dist/cjs/features/session_replay/shared/utils.js +12 -0
  16. package/dist/cjs/loaders/api/api.js +7 -1
  17. package/dist/esm/common/constants/env.cdn.js +2 -2
  18. package/dist/esm/common/constants/env.npm.js +2 -2
  19. package/dist/esm/common/constants/runtime.js +1 -1
  20. package/dist/esm/common/session/session-entity.js +2 -1
  21. package/dist/esm/common/timer/interaction-timer.js +16 -2
  22. package/dist/esm/common/timing/time-keeper.js +1 -3
  23. package/dist/esm/features/jserrors/aggregate/index.js +16 -6
  24. package/dist/esm/features/jserrors/instrument/index.js +8 -3
  25. package/dist/esm/features/session_replay/aggregate/index.js +48 -29
  26. package/dist/esm/features/session_replay/constants.js +2 -1
  27. package/dist/esm/features/session_replay/instrument/index.js +9 -2
  28. package/dist/esm/features/session_replay/shared/recorder-events.js +1 -9
  29. package/dist/esm/features/session_replay/shared/recorder.js +23 -51
  30. package/dist/esm/features/session_replay/shared/utils.js +11 -0
  31. package/dist/esm/loaders/api/api.js +7 -1
  32. package/dist/types/common/constants/runtime.d.ts.map +1 -1
  33. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  34. package/dist/types/common/timer/interaction-timer.d.ts +2 -0
  35. package/dist/types/common/timer/interaction-timer.d.ts.map +1 -1
  36. package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
  37. package/dist/types/features/jserrors/aggregate/index.d.ts +2 -1
  38. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  39. package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
  40. package/dist/types/features/session_replay/aggregate/index.d.ts +5 -2
  41. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  42. package/dist/types/features/session_replay/constants.d.ts +1 -0
  43. package/dist/types/features/session_replay/constants.d.ts.map +1 -1
  44. package/dist/types/features/session_replay/instrument/index.d.ts +1 -0
  45. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
  46. package/dist/types/features/session_replay/shared/recorder-events.d.ts +0 -8
  47. package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -1
  48. package/dist/types/features/session_replay/shared/recorder.d.ts +1 -17
  49. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  50. package/dist/types/features/session_replay/shared/utils.d.ts +8 -0
  51. package/dist/types/features/session_replay/shared/utils.d.ts.map +1 -1
  52. package/dist/types/loaders/api/api.d.ts.map +1 -1
  53. package/package.json +2 -2
  54. package/src/common/constants/runtime.js +1 -1
  55. package/src/common/session/session-entity.js +2 -1
  56. package/src/common/timer/interaction-timer.js +17 -2
  57. package/src/common/timing/time-keeper.js +1 -3
  58. package/src/features/jserrors/aggregate/index.js +15 -6
  59. package/src/features/jserrors/instrument/index.js +9 -4
  60. package/src/features/session_replay/aggregate/index.js +43 -25
  61. package/src/features/session_replay/constants.js +2 -1
  62. package/src/features/session_replay/instrument/index.js +7 -2
  63. package/src/features/session_replay/shared/recorder-events.js +1 -6
  64. package/src/features/session_replay/shared/recorder.js +21 -27
  65. package/src/features/session_replay/shared/utils.js +12 -0
  66. package/src/loaders/api/api.js +10 -1
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/runtime.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,qCAEqB;AAErB;;GAEG;AACH,oCAeK;AAEL,oDAUI;AAEJ,oDAA6F;AAE7F,sCAA2F;AAE3F,qCAAyD;AAEzD,4BAA8E;AAE9E;;;;;;GAMG;AACH,iCAAwE;AAExE,+BAOI;AAEJ,2BAA2E;AAE3E,yCAAqE;AAErE,4BAAyI"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/runtime.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,qCAEqB;AAErB;;GAEG;AACH,oCAeK;AAEL,oDAUI;AAEJ,oDAA6F;AAE7F,sCAA2F;AAE3F,qCAAyD;AAEzD,4BAA8E;AAE9E;;;;;;GAMG;AACH,iCAAwE;AAExE,+BAOI;AAEJ,2BAA2E;AAE3E,yCAAqE;AAErE,4BAAgE"}
@@ -1 +1 @@
1
- {"version":3,"file":"session-entity.d.ts","sourceRoot":"","sources":["../../../../src/common/session/session-entity.js"],"names":[],"mappings":"AA6BA;IACE;;;;;OAKG;IACH,uBA0BC;IApBC,qBAAsC;IACtC,aAAsB;IACtB,UAAe;IAGf,SAAc;IAEd,QAAiC;IAenC;;;;aAwEC;IAjEC,8BAA0B;IAC1B,+BAA4B;IAc1B,gCAOqC;IAUrC,4CAiBsC;IAexC,iCAAuB;IAIzB,wBAEC;IAED,sBAEC;IAED;;;OAGG;IACH,QAFa,MAAM,CA6BlB;IAED;;;;;;OAMG;IACH,YAHW,MAAM,GACJ,MAAM,CAkBlB;IAED,gBAuBC;IAED;;OAEG;IACH,gBAIC;IAED;;;OAGG;IACH,qBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,gBAHW,MAAM,GACJ,OAAO,CAKnB;IAED,yDAUC;IAED,6DAIC;IAED;;;OAGG;IACH,6BAHW,MAAM,GACJ,MAAM,CAIlB;IAED,gDAaC;IAHG,YAAuD;CAI5D;sBApSqB,gBAAgB;iCAGL,4BAA4B"}
1
+ {"version":3,"file":"session-entity.d.ts","sourceRoot":"","sources":["../../../../src/common/session/session-entity.js"],"names":[],"mappings":"AA6BA;IACE;;;;;OAKG;IACH,uBA0BC;IApBC,qBAAsC;IACtC,aAAsB;IACtB,UAAe;IAGf,SAAc;IAEd,QAAiC;IAenC;;;;aAyEC;IAlEC,8BAA0B;IAC1B,+BAA4B;IAc1B,gCAOqC;IAUrC,4CAkBsC;IAexC,iCAAuB;IAIzB,wBAEC;IAED,sBAEC;IAED;;;OAGG;IACH,QAFa,MAAM,CA6BlB;IAED;;;;;;OAMG;IACH,YAHW,MAAM,GACJ,MAAM,CAkBlB;IAED,gBAuBC;IAED;;OAEG;IACH,gBAIC;IAED;;;OAGG;IACH,qBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,gBAHW,MAAM,GACJ,OAAO,CAKnB;IAED,yDAUC;IAED,6DAIC;IAED;;;OAGG;IACH,6BAHW,MAAM,GACJ,MAAM,CAIlB;IAED,gDAaC;IAHG,YAAuD;CAI5D;sBArSqB,gBAAgB;iCAGL,4BAA4B"}
@@ -2,6 +2,8 @@ export class InteractionTimer extends Timer {
2
2
  onPause: any;
3
3
  onRefresh: any;
4
4
  onResume: any;
5
+ /** used to double-check LS state at resume time */
6
+ readStorage: any;
5
7
  remainingMs: number | undefined;
6
8
  abortController: AbortController | undefined;
7
9
  ee: any;
@@ -1 +1 @@
1
- {"version":3,"file":"interaction-timer.d.ts","sourceRoot":"","sources":["../../../../src/common/timer/interaction-timer.js"],"names":[],"mappings":"AAKA;IAGI,aAAuF;IACvF,eAA6F;IAC7F,cAA0F;IAG1F,gCAA4B;IAM1B,6CAA4C;IAO1C,QAAiB;IAEjB,kDAIC;IAoBP,cAQC;IAED,cAIC;IAED,eAGC;IAED,gCAMC;CACF;sBAhFqB,SAAS"}
1
+ {"version":3,"file":"interaction-timer.d.ts","sourceRoot":"","sources":["../../../../src/common/timer/interaction-timer.js"],"names":[],"mappings":"AAKA;IAGI,aAAuF;IACvF,eAA6F;IAC7F,cAA0F;IAE1F,mDAAmD;IACnD,iBAAmC;IAGnC,gCAA4B;IAM1B,6CAA4C;IAO1C,QAAiB;IAEjB,kDAIC;IAoBP,cAQC;IAED,cAIC;IAED,eAeC;IAED,gCAMC;CACF;sBA/FqB,SAAS"}
@@ -1 +1 @@
1
- {"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"AAEA;;;;GAIG;AACH;IA+BE,oBAEC;IAED,yBAEC;IAED,kCAEC;IAED;;;;;OAKG;IACH,8BAJsB,cAAc,aACf,MAAM,WACR,MAAM,QAoBxB;IAED;;;;;OAKG;IACH,uCAHwB,MAAM,GACjB,MAAM,CAIlB;IAED;;;;OAIG;IACH,oCAHqB,MAAM,GACf,MAAM,CAIjB;;CACF"}
1
+ {"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;IA+BE,oBAEC;IAED,yBAEC;IAED,kCAEC;IAED;;;;;OAKG;IACH,8BAJsB,cAAc,aACf,MAAM,WACR,MAAM,QAoBxB;IAED;;;;;OAKG;IACH,uCAHwB,MAAM,GACjB,MAAM,CAIlB;IAED;;;;OAIG;IACH,oCAHqB,MAAM,GACf,MAAM,CAIjB;;CACF"}
@@ -10,6 +10,7 @@ export class Aggregate extends AggregateBase {
10
10
  bufferedErrorsUnderSpa: {};
11
11
  currentBody: {} | null | undefined;
12
12
  errorOnPage: boolean;
13
+ replayAborted: boolean;
13
14
  onHarvestStarted(options: any): {
14
15
  body: {} | null;
15
16
  qs: {};
@@ -25,7 +26,7 @@ export class Aggregate extends AggregateBase {
25
26
  * @returns {string} A canonical stack string built from the URLs and function names in the given `stackInfo` object.
26
27
  */
27
28
  buildCanonicalStackString(stackInfo: StackInfo): string;
28
- storeError(err: any, time: any, internal: any, customAttributes: any): void;
29
+ storeError(err: any, time: any, internal: any, customAttributes: any, hasReplay: any): void;
29
30
  onInteractionDone(interaction: any, wasSaved: any): void;
30
31
  onSoftNavNotification(interactionId: any, wasFinished: any, softNavAttrs: any): void;
31
32
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"AAyBA;;GAEG;AAEH;IACE,2BAAiC;IACjC,mDAgCC;IA7BC,kBAAuB;IACvB,eAAoB;IACpB,qBAA0B;IAC1B,2BAAgC;IAChC,mCAA4B;IAC5B,qBAAwB;IA0B1B;;;MAoBC;IAED,qCAWC;IAED,8BAEC;IAED,oEAMC;IAED;;;;;;OAMG;IACH,qCAHW,SAAS,GACP,MAAM,CAgBlB;IAED,4EAuFC;IA4BD,yDA6BC;IAED,qFAOC;;CACF;wBAvQY,OAAO,0BAA0B,EAAE,SAAS;8BAN3B,4BAA4B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"AAyBA;;GAEG;AAEH;IACE,2BAAiC;IACjC,mDAmCC;IAhCC,kBAAuB;IACvB,eAAoB;IACpB,qBAA0B;IAC1B,2BAAgC;IAChC,mCAA4B;IAC5B,qBAAwB;IACxB,uBAA0B;IA4B5B;;;MA2BC;IAED,qCAWC;IAED,8BAEC;IAED,oEAMC;IAED;;;;;;OAMG;IACH,qCAHW,SAAS,GACP,MAAM,CAgBlB;IAED,4FAsFC;IA4BD,yDA6BC;IAED,qFAOC;;CACF;wBAhRY,OAAO,0BAA0B,EAAE,SAAS;8BAN3B,4BAA4B"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/instrument/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IAIjC,mEA4CC;IAvCG,2CAA0C;IAqC5C,yBAA+B;;CAoFlC;+BA5I8B,6BAA6B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/instrument/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAAiC;IAKjC,mEA+CC;IA1CG,2CAA0C;IAwC5C,yBAA+B;;CAoFlC;+BAjJ8B,6BAA6B"}
@@ -1,6 +1,7 @@
1
1
  export class Aggregate extends AggregateBase {
2
2
  static featureName: string;
3
3
  constructor(agentIdentifier: any, aggregator: any, args: any);
4
+ mode: number;
4
5
  /** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
5
6
  harvestTimeSeconds: any;
6
7
  /** Set once the recorder has fully initialized after flag checks and sampling */
@@ -9,14 +10,15 @@ export class Aggregate extends AggregateBase {
9
10
  gzipper: typeof import("fflate").gzipSync | undefined;
10
11
  /** populated with the u8 string lib async */
11
12
  u8: typeof import("fflate").strToU8 | undefined;
12
- mode: any;
13
13
  /** set by BCS response */
14
14
  entitled: boolean;
15
15
  /** set at BCS response, stored in runtime */
16
16
  timeKeeper: any;
17
17
  recorder: any;
18
+ preloaded: boolean;
19
+ errorNoticed: any;
18
20
  scheduler: HarvestScheduler;
19
- errorNoticed: boolean;
21
+ handleError(e: any): void;
20
22
  switchToFull(): void;
21
23
  /**
22
24
  * Evaluate entitlements and sampling before starting feature mechanics, importing and configuring recording library, and setting storage state
@@ -41,6 +43,7 @@ export class Aggregate extends AggregateBase {
41
43
  };
42
44
  body: any;
43
45
  }[] | undefined;
46
+ getCorrectedTimestamp(node: any): any;
44
47
  getHarvestContents(recorderEvents: any): {
45
48
  qs: {
46
49
  browser_monitoring_key: any;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AA+BA;IACE,2BAAiC;IAEjC,8DAoHC;IAlHC,8GAA8G;IAC9G,wBAAgH;IAChH,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IAGnB,UAAuD;IAEvD,0BAA0B;IAC1B,kBAAqB;IACrB,6CAA6C;IAC7C,gBAA2B;IAE3B,cAA8B;IA8B9B,4BAKQ;IAmBN,sBAAwB;IA2C5B,qBAWC;IAED;;;;;;;OAOG;IACH,iCALW,OAAO,cACP,OAAO,iBACP,OAAO,GACL,IAAI,CA6DhB;IAED,2BASC;IAED;;;;;;;;;;;;oBAoCC;IAED;;;;;;;;;;MAmEC;IAED,qCAOC;IAED;;;;OAIG;IACH,mCAKC;IAED,yDAAyD;IACzD,yBAUC;IAED,yCAGC;CACF;8BAtX6B,4BAA4B;iCAHzB,2CAA2C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AAgCA;IACE,2BAAiC;IAIjC,8DAsGC;IAzGD,aAAe;IAKb,8GAA8G;IAC9G,wBAAgH;IAChH,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IAEnB,0BAA0B;IAC1B,kBAAqB;IACrB,6CAA6C;IAC7C,gBAA2B;IAE3B,cAA8B;IAC9B,mBAAgC;IAChC,kBAA+C;IA4B/C,4BAKQ;IAmDV,0BAMC;IAED,qBAWC;IAED;;;;;;;OAOG;IACH,iCALW,OAAO,cACP,OAAO,iBACP,OAAO,GACL,IAAI,CA8DhB;IAED,2BASC;IAED;;;;;;;;;;;;oBAiDC;IAED,sCAIC;IAED;;;;;;;;;;MAoEC;IAED,qCAOC;IAED;;;;OAIG;IACH,mCAKC;IAED,yDAAyD;IACzD,yBAUC;IAED,yCAGC;CACF;8BAxY6B,4BAA4B;iCAHzB,2CAA2C"}
@@ -2,6 +2,7 @@ export const FEATURE_NAME: string;
2
2
  export namespace SR_EVENT_EMITTER_TYPES {
3
3
  let RECORD: string;
4
4
  let PAUSE: string;
5
+ let REPLAY_RUNNING: string;
5
6
  }
6
7
  export const AVG_COMPRESSION: 0.12;
7
8
  export namespace RRWEB_EVENT_TYPES {
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/session_replay/constants.js"],"names":[],"mappings":"AAGA,kCAAuD;;;;;AAOvD,mCAAmC;;;;;;;;;AASnC,uCAAuC;AACvC,uCAAuC;AACvC,iCAAiC;AACjC,uCAAuC;AACvC,2GAA2G;AAC3G;;EAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BtF,0CAA0C;AAC1C,uCAAuC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/session_replay/constants.js"],"names":[],"mappings":"AAGA,kCAAuD;;;;;;AAQvD,mCAAmC;;;;;;;;;AASnC,uCAAuC;AACvC,uCAAuC;AACvC,iCAAiC;AACjC,uCAAuC;AACvC,2GAA2G;AAC3G;;EAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BtF,0CAA0C;AAC1C,uCAAuC"}
@@ -1,6 +1,7 @@
1
1
  export class Instrument extends InstrumentBase {
2
2
  static featureName: string;
3
3
  constructor(agentIdentifier: any, aggregator: any, auto?: boolean);
4
+ errorNoticed: boolean;
4
5
  recorder: import("../shared/recorder").Recorder | undefined;
5
6
  #private;
6
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/instrument/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAAiC;IACjC,mEAYC;IAiBC,4DAA6E;;CAKhF;+BAxC8B,6BAA6B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/instrument/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAAiC;IACjC,mEAiBC;IAPK,sBAAwB;IAwB5B,4DAA0F;;CAK7F;+BA7C8B,6BAA6B"}
@@ -1,18 +1,10 @@
1
1
  export class RecorderEvents {
2
- constructor({ canCorrectTimestamps }: {
3
- canCorrectTimestamps: any;
4
- });
5
2
  /** The buffer to hold recorder event nodes */
6
3
  events: any[];
7
4
  /** Payload metadata -- Should indicate when a replay blob started recording. Resets each time a harvest occurs.
8
5
  * cycle timestamps are used as fallbacks if event timestamps cannot be used
9
6
  */
10
7
  cycleTimestamp: number;
11
- /** Payload metadata -- Whether timestamps can be corrected, defaults as false, can be set to true if timekeeper is present at init time. Used to determine
12
- * if harvest needs to re-loop through nodes and correct them before sending. Ideal behavior is to correct them as they flow into the recorder
13
- * to prevent re-looping, but is not always possible since the timekeeper is not set until after page load and the recorder can be preloaded.
14
- */
15
- canCorrectTimestamps: boolean;
16
8
  /** A value which increments with every new mutation node reported. Resets after a harvest is sent */
17
9
  payloadBytesEstimation: number;
18
10
  /** Payload metadata -- Should indicate that the payload being sent has a full DOM snapshot. This can happen
@@ -1 +1 @@
1
- {"version":3,"file":"recorder-events.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder-events.js"],"names":[],"mappings":"AAAA;IACE;;OAyBC;IAxBC,8CAA8C;IAC9C,cAAgB;IAChB;;OAEG;IACH,uBAAgC;IAChC;;;MAGE;IACF,8BAAkD;IAClD,qGAAqG;IACrG,+BAA+B;IAC/B;;;MAGE;IACF,qBAAwB;IACxB,4IAA4I;IAC5I,iBAAoB;IACpB,+HAA+H;IAC/H,kBAAqB;IACrB,0FAA0F;IAC1F,+BAAiC;IAGnC,sBAEC;CACF"}
1
+ {"version":3,"file":"recorder-events.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder-events.js"],"names":[],"mappings":"AAAA;IAEI,8CAA8C;IAC9C,cAAgB;IAChB;;OAEG;IACH,uBAAgC;IAChC,qGAAqG;IACrG,+BAA+B;IAC/B;;;MAGE;IACF,qBAAwB;IACxB,4IAA4I;IAC5I,iBAAoB;IACpB,+HAA+H;IAC/H,kBAAqB;IACrB,0FAA0F;IAC1F,+BAAiC;IAGnC,sBAEC;CACF"}
@@ -15,31 +15,15 @@ export class Recorder {
15
15
  /** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
16
16
  stopRecording: () => void;
17
17
  getEvents(): {
18
- events: CorrectedSessionReplayEvent[];
19
18
  type: string;
19
+ events: any[];
20
20
  cycleTimestamp: number;
21
- canCorrectTimestamps: boolean;
22
21
  payloadBytesEstimation: number;
23
22
  hasSnapshot: boolean;
24
23
  hasMeta: boolean;
25
24
  hasError: boolean;
26
25
  inlinedAllStylesheets: boolean;
27
- } | {
28
- events: any[];
29
- type: string;
30
- cycleTimestamp: number;
31
- payloadBytesEstimation: number;
32
- hasError: boolean;
33
- hasMeta: boolean;
34
- hasSnapshot: boolean;
35
- inlinedAllStylesheets: boolean;
36
26
  };
37
- /**
38
- * Returns time-corrected events. If the events were correctable from the beginning, this correction will have already been applied.
39
- * @param {SessionReplayEvent[]} events The array of buffered SR nodes
40
- * @returns {CorrectedSessionReplayEvent[]}
41
- */
42
- returnCorrectTimestamps(events: SessionReplayEvent[]): CorrectedSessionReplayEvent[];
43
27
  /** Clears the buffer (this.#events), and resets all payload metadata properties */
44
28
  clearBuffer(): void;
45
29
  /** Begin recording using configured recording lib */
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"AAWA;IAUE,yBAkBC;IAdC,iEAAiE;IACjE,mBAAsB;IACtB,6DAA6D;IAC7D,oCAAuC;IACvC,kIAAkI;IAClI,kBAAqB;IACrB,sDAAsD;IACtD,YAAoB;IACpB,oEAAoE;IACpE,6BAAqH;IACrH,0FAA0F;IAC1F,eAA6C;IAC7C,uIAAuI;IACvI,0BAAyE;IAG3E;;;;;;;;;;;;;;;;;;;MAiBC;IAED;;;;OAIG;IACH,gCAHW,oBAAoB,GAClB,6BAA6B,CAOzC;IAED,mFAAmF;IACnF,oBAKC;IAED,qDAAqD;IACrD,uBAwBC;IAED;;;;;OAKG;IACH,yCA0BC;IAED,0HAA0H;IAC1H,yCA+CC;IAED,0HAA0H;IAC1H,yBAOC;IAED,wBAEC;IAED,gCAAgC;IAChC,uCAGC;IAED;;;SAGK;IACL,oCAGC;;CACF;+BAvN8B,mBAAmB"}
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"AAYA;IAUE,yBAkBC;IAdC,iEAAiE;IACjE,mBAAsB;IACtB,6DAA6D;IAC7D,oCAAuC;IACvC,kIAAkI;IAClI,kBAAqB;IACrB,sDAAsD;IACtD,YAAoB;IACpB,oEAAoE;IACpE,6BAAqH;IACrH,0FAA0F;IAC1F,eAA6C;IAC7C,uIAAuI;IACvI,0BAAyE;IAG3E;;;;;;;;;MAYC;IAED,mFAAmF;IACnF,oBAKC;IAED,qDAAqD;IACrD,uBAiCC;IAED;;;;;OAKG;IACH,yCA0BC;IAED,0HAA0H;IAC1H,yCAgDC;IAED,0HAA0H;IAC1H,yBAOC;IAED,wBAEC;IAED,gCAAgC;IAChC,uCAGC;IAED;;;SAGK;IACL,oCAGC;;CACF;+BAjN8B,mBAAmB"}
@@ -1,4 +1,12 @@
1
1
  export function isPreloadAllowed(agentId: any): any;
2
2
  export function canImportReplayAgg(agentId: any, sessionMgr: any): boolean;
3
+ export function buildNRMetaNode(timestamp: any, timeKeeper: any): {
4
+ originalTimestamp: any;
5
+ correctedTimestamp: any;
6
+ timestampDiff: number;
7
+ timeKeeperOriginTime: any;
8
+ timeKeeperCorrectedOriginTime: any;
9
+ timeKeeperDiff: number;
10
+ };
3
11
  export function enableSessionTracking(agentId: any): boolean;
4
12
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/utils.js"],"names":[],"mappings":"AAWA,oDAEC;AAED,2EAGC;AAfM,6DAA+H"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/utils.js"],"names":[],"mappings":"AAWA,oDAEC;AAED,2EAGC;AAED;;;;;;;EAUC;AA3BM,6DAA+H"}
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"AAkBA,2CAeC;AAED;;;;IAiDE;;;;OAIG;qBAFQ,MAAM;IAWjB;;;;OAIG;iCAFQ,MAAM,GAAC,IAAI;;;;;EA0GvB"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"AAmBA,2CAeC;AAID;;;;IAuDE;;;;OAIG;qBAFQ,MAAM;IAWjB;;;;OAIG;iCAFQ,MAAM,GAAC,IAAI;;;;;EA0GvB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.255.0",
3
+ "version": "1.256.1",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -168,7 +168,7 @@
168
168
  "dependencies": {
169
169
  "core-js": "^3.26.0",
170
170
  "fflate": "^0.7.4",
171
- "rrweb": "2.0.0-alpha.11",
171
+ "rrweb": "2.0.0-alpha.12",
172
172
  "web-vitals": "^3.1.0"
173
173
  },
174
174
  "devDependencies": {
@@ -74,4 +74,4 @@ export const isIE = Boolean(isBrowserScope && window.document.documentMode) // d
74
74
 
75
75
  export const supportsSendBeacon = !!globalScope.navigator?.sendBeacon
76
76
 
77
- export const offset = Math.floor(globalScope?.performance?.timeOrigin || globalScope?.performance?.timing?.navigationStart || Date.now())
77
+ export const offset = Math.floor(Date.now() - performance.now())
@@ -117,7 +117,8 @@ export class SessionEntity {
117
117
  this.write(getModeledObject(this.state, model))
118
118
  },
119
119
  ee: this.ee,
120
- refreshEvents: ['click', 'keydown', 'scroll']
120
+ refreshEvents: ['click', 'keydown', 'scroll'],
121
+ readStorage: () => this.storage.get(this.lookupKey)
121
122
  }, this.state.inactiveAt - Date.now())
122
123
  } else {
123
124
  this.state.inactiveAt = Infinity
@@ -10,6 +10,9 @@ export class InteractionTimer extends Timer {
10
10
  this.onRefresh = typeof opts.onRefresh === 'function' ? opts.onRefresh : () => { /* noop */ }
11
11
  this.onResume = typeof opts.onResume === 'function' ? opts.onResume : () => { /* noop */ }
12
12
 
13
+ /** used to double-check LS state at resume time */
14
+ this.readStorage = opts.readStorage
15
+
13
16
  // used by pause/resume
14
17
  this.remainingMs = undefined
15
18
 
@@ -67,8 +70,20 @@ export class InteractionTimer extends Timer {
67
70
  }
68
71
 
69
72
  resume () {
70
- this.refresh()
71
- this.onResume() // emit resume event after state updated
73
+ try {
74
+ const lsData = this.readStorage()
75
+ const obj = typeof lsData === 'string' ? JSON.parse(lsData) : lsData
76
+ if (isExpired(obj.expiresAt) || isExpired(obj.inactiveAt)) this.end()
77
+ else {
78
+ this.refresh()
79
+ this.onResume() // emit resume event after state updated
80
+ }
81
+ } catch (err) {
82
+ this.end()
83
+ }
84
+ function isExpired (timestamp) {
85
+ return Date.now() > timestamp
86
+ }
72
87
  }
73
88
 
74
89
  refresh (cb, ms) {
@@ -1,5 +1,3 @@
1
- import { globalScope } from '../constants/runtime'
2
-
3
1
  /**
4
2
  * Class used to adjust the timestamp of harvested data to New Relic server time. This
5
3
  * is done by tracking the performance timings of the RUM call and applying a calculation
@@ -33,7 +31,7 @@ export class TimeKeeper {
33
31
  #ready = false
34
32
 
35
33
  constructor () {
36
- this.#originTime = globalScope.performance.timeOrigin || globalScope.performance.timing.navigationStart
34
+ this.#originTime = Date.now() - performance.now()
37
35
  }
38
36
 
39
37
  get ready () {
@@ -38,10 +38,13 @@ export class Aggregate extends AggregateBase {
38
38
  this.bufferedErrorsUnderSpa = {}
39
39
  this.currentBody = undefined
40
40
  this.errorOnPage = false
41
+ this.replayAborted = false
41
42
 
42
43
  // this will need to change to match whatever ee we use in the instrument
43
44
  this.ee.on('interactionDone', (interaction, wasSaved) => this.onInteractionDone(interaction, wasSaved))
44
45
 
46
+ this.ee.on('REPLAY_ABORTED', () => { this.replayAborted = true })
47
+
45
48
  register('err', (...args) => this.storeError(...args), this.featureName, this.ee)
46
49
  register('ierr', (...args) => this.storeError(...args), this.featureName, this.ee)
47
50
  register('softNavFlush', (interactionId, wasFinished, softNavAttrs) =>
@@ -78,9 +81,16 @@ export class Aggregate extends AggregateBase {
78
81
  payload.qs.ri = releaseIds
79
82
  }
80
83
 
81
- if (body && body.err && body.err.length && !this.errorOnPage) {
82
- payload.qs.pve = '1'
83
- this.errorOnPage = true
84
+ if (body && body.err && body.err.length) {
85
+ if (this.replayAborted) {
86
+ body.err.forEach((e) => {
87
+ delete e.params?.hasReplay
88
+ })
89
+ }
90
+ if (!this.errorOnPage) {
91
+ payload.qs.pve = '1'
92
+ this.errorOnPage = true
93
+ }
84
94
  }
85
95
  return payload
86
96
  }
@@ -133,7 +143,7 @@ export class Aggregate extends AggregateBase {
133
143
  return canonicalStackString
134
144
  }
135
145
 
136
- storeError (err, time, internal, customAttributes) {
146
+ storeError (err, time, internal, customAttributes, hasReplay) {
137
147
  // are we in an interaction
138
148
  time = time || now()
139
149
  const agentRuntime = getRuntime(this.agentIdentifier)
@@ -189,7 +199,7 @@ export class Aggregate extends AggregateBase {
189
199
  this.pageviewReported[bucketHash] = true
190
200
  }
191
201
 
192
- if (agentRuntime?.session?.state?.sessionReplayMode) params.hasReplay = true
202
+ if (hasReplay && !this.replayAborted) params.hasReplay = hasReplay
193
203
  params.firstOccurrenceTimestamp = this.observedAt[bucketHash]
194
204
  params.timestamp = this.observedAt[bucketHash]
195
205
 
@@ -199,7 +209,6 @@ export class Aggregate extends AggregateBase {
199
209
  // Trace sends the error in its payload, and both trace & replay simply listens for any error to occur.
200
210
  const jsErrorEvent = [type, bucketHash, params, newMetrics, customAttributes]
201
211
  handle('errorAgg', jsErrorEvent, undefined, FEATURE_NAMES.sessionTrace, this.ee)
202
- handle('errorAgg', jsErrorEvent, undefined, FEATURE_NAMES.sessionReplay, this.ee)
203
212
  // still send EE events for other features such as above, but stop this one from aggregating internal data
204
213
  if (this.blocked) return
205
214
 
@@ -12,11 +12,13 @@ import { eventListenerOpts } from '../../../common/event-listener/event-listener
12
12
  import { stringify } from '../../../common/util/stringify'
13
13
  import { UncaughtError } from './uncaught-error'
14
14
  import { now } from '../../../common/timing/now'
15
+ import { SR_EVENT_EMITTER_TYPES } from '../../session_replay/constants'
15
16
 
16
17
  export class Instrument extends InstrumentBase {
17
18
  static featureName = FEATURE_NAME
18
19
 
19
20
  #seenErrors = new Set()
21
+ #replayRunning = false
20
22
 
21
23
  constructor (agentIdentifier, aggregator, auto = true) {
22
24
  super(agentIdentifier, aggregator, FEATURE_NAME, auto)
@@ -36,13 +38,16 @@ export class Instrument extends InstrumentBase {
36
38
 
37
39
  this.ee.on('internal-error', (error) => {
38
40
  if (!this.abortHandler) return
39
- handle('ierr', [this.#castError(error), now(), true], undefined, FEATURE_NAMES.jserrors, this.ee)
41
+ handle('ierr', [this.#castError(error), now(), true, {}, this.#replayRunning], undefined, FEATURE_NAMES.jserrors, this.ee)
42
+ })
43
+
44
+ this.ee.on(SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, (isRunning) => {
45
+ this.#replayRunning = isRunning
40
46
  })
41
47
 
42
48
  globalScope.addEventListener('unhandledrejection', (promiseRejectionEvent) => {
43
49
  if (!this.abortHandler) return
44
-
45
- handle('err', [this.#castPromiseRejectionEvent(promiseRejectionEvent), now(), false, { unhandledPromiseRejection: 1 }], undefined, FEATURE_NAMES.jserrors, this.ee)
50
+ handle('err', [this.#castPromiseRejectionEvent(promiseRejectionEvent), now(), false, { unhandledPromiseRejection: 1 }, this.#replayRunning], undefined, FEATURE_NAMES.jserrors, this.ee)
46
51
  }, eventListenerOpts(false, this.removeOnAbort?.signal))
47
52
 
48
53
  globalScope.addEventListener('error', (errorEvent) => {
@@ -57,7 +62,7 @@ export class Instrument extends InstrumentBase {
57
62
  return
58
63
  }
59
64
 
60
- handle('err', [this.#castErrorEvent(errorEvent), now()], undefined, FEATURE_NAMES.jserrors, this.ee)
65
+ handle('err', [this.#castErrorEvent(errorEvent), now(), false, {}, this.#replayRunning], undefined, FEATURE_NAMES.jserrors, this.ee)
61
66
  }, eventListenerOpts(false, this.removeOnAbort?.signal))
62
67
 
63
68
  this.abortHandler = this.#abort // we also use this as a flag to denote that the feature is active or on and handling errors
@@ -28,9 +28,12 @@ import { stringify } from '../../../common/util/stringify'
28
28
  import { stylesheetEvaluator } from '../shared/stylesheet-evaluator'
29
29
  import { deregisterDrain } from '../../../common/drain/drain'
30
30
  import { now } from '../../../common/timing/now'
31
+ import { buildNRMetaNode } from '../shared/utils'
31
32
 
32
33
  export class Aggregate extends AggregateBase {
33
34
  static featureName = FEATURE_NAME
35
+ mode = MODE.OFF
36
+
34
37
  // pass the recorder into the aggregator
35
38
  constructor (agentIdentifier, aggregator, args) {
36
39
  super(agentIdentifier, aggregator, FEATURE_NAME)
@@ -44,9 +47,6 @@ export class Aggregate extends AggregateBase {
44
47
  this.gzipper = undefined
45
48
  /** populated with the u8 string lib async */
46
49
  this.u8 = undefined
47
- /** the mode to start in. Defaults to off */
48
- const { session } = getRuntime(this.agentIdentifier)
49
- this.mode = session.state.sessionReplayMode || MODE.OFF
50
50
 
51
51
  /** set by BCS response */
52
52
  this.entitled = false
@@ -54,13 +54,13 @@ export class Aggregate extends AggregateBase {
54
54
  this.timeKeeper = undefined
55
55
 
56
56
  this.recorder = args?.recorder
57
- if (this.recorder) this.recorder.parent = this
57
+ this.preloaded = !!this.recorder
58
+ this.errorNoticed = args?.errorNoticed || false
58
59
 
59
60
  handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/Enabled'], undefined, FEATURE_NAMES.metrics, this.ee)
60
61
 
61
62
  // The SessionEntity class can emit a message indicating the session was cleared and reset (expiry, inactivity). This feature must abort and never resume if that occurs.
62
63
  this.ee.on(SESSION_EVENTS.RESET, () => {
63
- this.scheduler.runHarvest()
64
64
  this.abort(ABORT_REASONS.RESET)
65
65
  })
66
66
 
@@ -104,17 +104,6 @@ export class Aggregate extends AggregateBase {
104
104
  this.forceStop(this.mode !== MODE.ERROR)
105
105
  }, this.featureName, this.ee)
106
106
 
107
- // Wait for an error to be reported. This currently is wrapped around the "Error" feature. This is a feature-feature dependency.
108
- // This was to ensure that all errors, including those on the page before load and those handled with "noticeError" are accounted for. Needs evalulation
109
- registerHandler('errorAgg', (e) => {
110
- this.errorNoticed = true
111
- if (this.recorder) this.recorder.currentBufferTarget.hasError = true
112
- // run once
113
- if (this.mode === MODE.ERROR && globalScope?.document.visibilityState === 'visible') {
114
- this.switchToFull()
115
- }
116
- }, this.featureName, this.ee)
117
-
118
107
  const { error_sampling_rate, sampling_rate, autoStart, block_selector, mask_text_selector, mask_all_inputs, inline_stylesheet, inline_images, collect_fonts } = getConfigurationValue(this.agentIdentifier, 'session_replay')
119
108
 
120
109
  this.waitForFlags(['sr']).then(([flagOn]) => {
@@ -150,6 +139,14 @@ export class Aggregate extends AggregateBase {
150
139
  handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/ErrorSamplingRate/Value', error_sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee)
151
140
  }
152
141
 
142
+ handleError (e) {
143
+ if (this.recorder) this.recorder.currentBufferTarget.hasError = true
144
+ // run once
145
+ if (this.mode === MODE.ERROR && globalScope?.document.visibilityState === 'visible') {
146
+ this.switchToFull()
147
+ }
148
+ }
149
+
153
150
  switchToFull () {
154
151
  this.mode = MODE.FULL
155
152
  // if the error was noticed AFTER the recorder was already imported....
@@ -210,12 +207,13 @@ export class Aggregate extends AggregateBase {
210
207
  } catch (err) {
211
208
  return this.abort(ABORT_REASONS.IMPORT)
212
209
  }
210
+ } else {
211
+ this.recorder.parent = this
213
212
  }
214
213
 
215
214
  // If an error was noticed before the mode could be set (like in the early lifecycle of the page), immediately set to FULL mode
216
- if (this.mode === MODE.ERROR && this.errorNoticed) {
217
- this.mode = MODE.FULL
218
- }
215
+ if (this.mode === MODE.ERROR && this.errorNoticed) this.mode = MODE.FULL
216
+ if (!this.preloaded) this.ee.on('err', e => this.handleError(e))
219
217
 
220
218
  // FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
221
219
  // ERROR mode will do this until an error is thrown, and then switch into FULL mode.
@@ -255,16 +253,29 @@ export class Aggregate extends AggregateBase {
255
253
  return
256
254
  }
257
255
 
256
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Harvest/Attempts'], undefined, FEATURE_NAMES.metrics, this.ee)
257
+
258
258
  let len = 0
259
259
  if (!!this.gzipper && !!this.u8) {
260
- payload.body = this.gzipper(this.u8(`[${payload.body.map(e => {
261
- if (e.__serialized) return e.__serialized
262
- return stringify(e)
260
+ payload.body = this.gzipper(this.u8(`[${payload.body.map(({ __serialized, ...e }) => {
261
+ if (e.__newrelic && __serialized) return __serialized
262
+ const output = { ...e }
263
+ if (!output.__newrelic) {
264
+ output.__newrelic = buildNRMetaNode(e.timestamp, this.timeKeeper)
265
+ output.timestamp = this.timeKeeper.correctAbsoluteTimestamp(e.timestamp)
266
+ }
267
+ return stringify(output)
263
268
  }).join(',')}]`))
264
269
  len = payload.body.length
265
270
  this.scheduler.opts.gzip = true
266
271
  } else {
267
- payload.body = payload.body.map(({ __serialized, ...node }) => node)
272
+ payload.body = payload.body.map(({ __serialized, ...node }) => {
273
+ if (node.__newrelic) return node
274
+ const output = { ...node }
275
+ output.__newrelic = buildNRMetaNode(node.timestamp, this.timeKeeper)
276
+ output.timestamp = this.timeKeeper.correctAbsoluteTimestamp(node.timestamp)
277
+ return output
278
+ })
268
279
  len = stringify(payload.body).length
269
280
  this.scheduler.opts.gzip = false
270
281
  }
@@ -281,6 +292,12 @@ export class Aggregate extends AggregateBase {
281
292
  return [payload]
282
293
  }
283
294
 
295
+ getCorrectedTimestamp (node) {
296
+ if (!node.timestamp) return
297
+ if (node.__newrelic) return node.timestamp
298
+ return this.timeKeeper.correctAbsoluteTimestamp(node.timestamp)
299
+ }
300
+
284
301
  getHarvestContents (recorderEvents) {
285
302
  recorderEvents ??= this.recorder.getEvents()
286
303
  let events = recorderEvents.events
@@ -308,8 +325,8 @@ export class Aggregate extends AggregateBase {
308
325
 
309
326
  const relativeNow = now()
310
327
 
311
- const firstEventTimestamp = events[0]?.timestamp // from rrweb node
312
- const lastEventTimestamp = events[events.length - 1]?.timestamp // from rrweb node
328
+ const firstEventTimestamp = this.getCorrectedTimestamp(events[0]) // from rrweb node
329
+ const lastEventTimestamp = this.getCorrectedTimestamp(events[events.length - 1]) // from rrweb node
313
330
  const firstTimestamp = firstEventTimestamp || this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp) // from rrweb node || from when the harvest cycle started
314
331
  const lastTimestamp = lastEventTimestamp || this.timeKeeper.convertRelativeTimestamp(relativeNow)
315
332
 
@@ -341,6 +358,7 @@ export class Aggregate extends AggregateBase {
341
358
  invalidStylesheetsDetected: stylesheetEvaluator.invalidStylesheetsDetected,
342
359
  inlinedAllStylesheets: recorderEvents.inlinedAllStylesheets,
343
360
  'rrweb.version': RRWEB_VERSION,
361
+ 'payload.type': recorderEvents.type,
344
362
  // customer-defined data should go last so that if it exceeds the query param padding limit it will be truncated instead of important attrs
345
363
  ...(endUserId && { 'enduser.id': endUserId })
346
364
  // The Query Param is being arbitrarily limited in length here. It is also applied when estimating the size of the payload in getPayloadSize()
@@ -5,7 +5,8 @@ export const FEATURE_NAME = FEATURE_NAMES.sessionReplay
5
5
 
6
6
  export const SR_EVENT_EMITTER_TYPES = {
7
7
  RECORD: 'recordReplay',
8
- PAUSE: 'pauseReplay'
8
+ PAUSE: 'pauseReplay',
9
+ REPLAY_RUNNING: 'replayRunning'
9
10
  }
10
11
 
11
12
  export const AVG_COMPRESSION = 0.12
@@ -24,6 +24,11 @@ export class Instrument extends InstrumentBase {
24
24
  } catch (err) { }
25
25
 
26
26
  if (this.#canPreloadRecorder(session)) {
27
+ /** If this is preloaded, set up a buffer, if not, later when sampling we will set up a .on for live events */
28
+ this.ee.on('err', (e) => {
29
+ this.errorNoticed = true
30
+ if (this.featAggregate) this.featAggregate.handleError()
31
+ })
27
32
  this.#startRecording(session?.sessionReplayMode)
28
33
  } else {
29
34
  this.importAggregator()
@@ -45,9 +50,9 @@ export class Instrument extends InstrumentBase {
45
50
 
46
51
  async #startRecording (mode) {
47
52
  const { Recorder } = (await import(/* webpackChunkName: "recorder" */'../shared/recorder'))
48
- this.recorder = new Recorder({ mode, agentIdentifier: this.agentIdentifier })
53
+ this.recorder = new Recorder({ mode, agentIdentifier: this.agentIdentifier, ee: this.ee })
49
54
  this.recorder.startRecording()
50
55
  this.abortHandler = this.recorder.stopRecording
51
- this.importAggregator({ recorder: this.recorder })
56
+ this.importAggregator({ recorder: this.recorder, errorNoticed: this.errorNoticed })
52
57
  }
53
58
  }
@@ -1,16 +1,11 @@
1
1
  export class RecorderEvents {
2
- constructor ({ canCorrectTimestamps }) {
2
+ constructor () {
3
3
  /** The buffer to hold recorder event nodes */
4
4
  this.events = []
5
5
  /** Payload metadata -- Should indicate when a replay blob started recording. Resets each time a harvest occurs.
6
6
  * cycle timestamps are used as fallbacks if event timestamps cannot be used
7
7
  */
8
8
  this.cycleTimestamp = Date.now()
9
- /** Payload metadata -- Whether timestamps can be corrected, defaults as false, can be set to true if timekeeper is present at init time. Used to determine
10
- * if harvest needs to re-loop through nodes and correct them before sending. Ideal behavior is to correct them as they flow into the recorder
11
- * to prevent re-looping, but is not always possible since the timekeeper is not set until after page load and the recorder can be preloaded.
12
- */
13
- this.canCorrectTimestamps = !!canCorrectTimestamps
14
9
  /** A value which increments with every new mutation node reported. Resets after a harvest is sent */
15
10
  this.payloadBytesEstimation = 0
16
11
  /** Payload metadata -- Should indicate that the payload being sent has a full DOM snapshot. This can happen