@newrelic/browser-agent 1.258.2 → 1.260.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.
Files changed (132) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/cdn/polyfills.js +3 -1
  3. package/dist/cjs/common/constants/env.cdn.js +1 -1
  4. package/dist/cjs/common/constants/env.npm.js +1 -1
  5. package/dist/cjs/common/drain/drain.js +1 -1
  6. package/dist/cjs/common/harvest/harvest-scheduler.js +4 -2
  7. package/dist/cjs/common/session/session-entity.js +8 -1
  8. package/dist/cjs/common/timing/time-keeper.js +9 -30
  9. package/dist/cjs/features/ajax/constants.js +3 -2
  10. package/dist/cjs/features/jserrors/instrument/index.js +3 -4
  11. package/dist/cjs/features/metrics/aggregate/index.js +0 -8
  12. package/dist/cjs/features/page_view_event/aggregate/index.js +8 -6
  13. package/dist/cjs/features/session_replay/aggregate/index.js +31 -36
  14. package/dist/cjs/features/session_replay/constants.js +5 -2
  15. package/dist/cjs/features/session_replay/instrument/index.js +53 -13
  16. package/dist/cjs/features/session_replay/shared/recorder.js +8 -1
  17. package/dist/cjs/features/session_replay/shared/utils.js +3 -5
  18. package/dist/cjs/features/session_trace/aggregate/index.js +181 -527
  19. package/dist/cjs/features/session_trace/aggregate/trace/node.js +19 -0
  20. package/dist/cjs/features/session_trace/aggregate/trace/storage.js +289 -0
  21. package/dist/cjs/features/session_trace/constants.js +3 -2
  22. package/dist/cjs/features/session_trace/instrument/index.js +7 -3
  23. package/dist/cjs/features/utils/aggregate-base.js +1 -0
  24. package/dist/cjs/features/utils/feature-gates.js +17 -0
  25. package/dist/cjs/features/utils/instrument-base.js +2 -1
  26. package/dist/cjs/loaders/agent-base.js +4 -0
  27. package/dist/cjs/loaders/api/api-methods.js +1 -1
  28. package/dist/cjs/loaders/api/api.js +2 -2
  29. package/dist/cjs/loaders/configure/configure.js +1 -0
  30. package/dist/esm/cdn/polyfills.js +3 -1
  31. package/dist/esm/common/constants/env.cdn.js +1 -1
  32. package/dist/esm/common/constants/env.npm.js +1 -1
  33. package/dist/esm/common/drain/drain.js +1 -1
  34. package/dist/esm/common/harvest/harvest-scheduler.js +4 -2
  35. package/dist/esm/common/session/session-entity.js +8 -1
  36. package/dist/esm/common/timing/time-keeper.js +9 -30
  37. package/dist/esm/features/ajax/constants.js +2 -1
  38. package/dist/esm/features/jserrors/instrument/index.js +3 -4
  39. package/dist/esm/features/metrics/aggregate/index.js +0 -8
  40. package/dist/esm/features/page_view_event/aggregate/index.js +8 -6
  41. package/dist/esm/features/session_replay/aggregate/index.js +32 -37
  42. package/dist/esm/features/session_replay/constants.js +4 -1
  43. package/dist/esm/features/session_replay/instrument/index.js +54 -14
  44. package/dist/esm/features/session_replay/shared/recorder.js +8 -1
  45. package/dist/esm/features/session_replay/shared/utils.js +4 -6
  46. package/dist/esm/features/session_trace/aggregate/index.js +182 -527
  47. package/dist/esm/features/session_trace/aggregate/trace/node.js +12 -0
  48. package/dist/esm/features/session_trace/aggregate/trace/storage.js +282 -0
  49. package/dist/esm/features/session_trace/constants.js +2 -1
  50. package/dist/esm/features/session_trace/instrument/index.js +7 -3
  51. package/dist/esm/features/utils/aggregate-base.js +1 -0
  52. package/dist/esm/features/utils/feature-gates.js +11 -0
  53. package/dist/esm/features/utils/instrument-base.js +3 -2
  54. package/dist/esm/loaders/agent-base.js +4 -0
  55. package/dist/esm/loaders/api/api-methods.js +1 -1
  56. package/dist/esm/loaders/api/api.js +2 -2
  57. package/dist/esm/loaders/configure/configure.js +1 -0
  58. package/dist/types/common/harvest/harvest-scheduler.d.ts +1 -0
  59. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  60. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  61. package/dist/types/common/timing/time-keeper.d.ts +2 -0
  62. package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
  63. package/dist/types/features/ajax/constants.d.ts +1 -0
  64. package/dist/types/features/ajax/constants.d.ts.map +1 -1
  65. package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
  66. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  67. package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -0
  68. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  69. package/dist/types/features/session_replay/aggregate/index.d.ts +1 -1
  70. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  71. package/dist/types/features/session_replay/constants.d.ts +3 -0
  72. package/dist/types/features/session_replay/instrument/index.d.ts +0 -1
  73. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
  74. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  75. package/dist/types/features/session_replay/shared/utils.d.ts +1 -1
  76. package/dist/types/features/session_replay/shared/utils.d.ts.map +1 -1
  77. package/dist/types/features/session_trace/aggregate/index.d.ts +39 -52
  78. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  79. package/dist/types/features/session_trace/aggregate/trace/node.d.ts +12 -0
  80. package/dist/types/features/session_trace/aggregate/trace/node.d.ts.map +1 -0
  81. package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +43 -0
  82. package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -0
  83. package/dist/types/features/session_trace/constants.d.ts +1 -0
  84. package/dist/types/features/session_trace/constants.d.ts.map +1 -1
  85. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  86. package/dist/types/features/utils/aggregate-base.d.ts +1 -0
  87. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  88. package/dist/types/features/utils/feature-gates.d.ts +2 -0
  89. package/dist/types/features/utils/feature-gates.d.ts.map +1 -0
  90. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  91. package/dist/types/loaders/agent-base.d.ts +1 -0
  92. package/dist/types/loaders/agent-base.d.ts.map +1 -1
  93. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  94. package/package.json +1 -1
  95. package/src/cdn/polyfills.js +2 -0
  96. package/src/common/drain/drain.js +1 -1
  97. package/src/common/harvest/harvest-scheduler.js +4 -2
  98. package/src/common/session/session-entity.js +3 -1
  99. package/src/common/timing/time-keeper.js +9 -30
  100. package/src/features/ajax/constants.js +2 -0
  101. package/src/features/jserrors/instrument/index.js +3 -4
  102. package/src/features/metrics/aggregate/index.js +0 -8
  103. package/src/features/page_view_event/aggregate/index.js +9 -5
  104. package/src/features/session_replay/aggregate/index.js +30 -39
  105. package/src/features/session_replay/constants.js +4 -0
  106. package/src/features/session_replay/instrument/index.js +48 -8
  107. package/src/features/session_replay/shared/__mocks__/utils.js +0 -1
  108. package/src/features/session_replay/shared/recorder.js +8 -1
  109. package/src/features/session_replay/shared/utils.js +4 -7
  110. package/src/features/session_trace/aggregate/index.js +157 -493
  111. package/src/features/session_trace/aggregate/trace/node.js +12 -0
  112. package/src/features/session_trace/aggregate/trace/storage.js +287 -0
  113. package/src/features/session_trace/constants.js +1 -0
  114. package/src/features/session_trace/instrument/index.js +7 -2
  115. package/src/features/utils/__mocks__/feature-gates.js +1 -0
  116. package/src/features/utils/aggregate-base.js +1 -0
  117. package/src/features/utils/feature-gates.js +11 -0
  118. package/src/features/utils/instrument-base.js +3 -2
  119. package/src/loaders/agent-base.js +4 -0
  120. package/src/loaders/api/api-methods.js +1 -1
  121. package/src/loaders/api/api.js +2 -2
  122. package/src/loaders/configure/configure.js +1 -0
  123. package/dist/cjs/features/session_replay/shared/replay-mode.js +0 -28
  124. package/dist/cjs/features/utils/handler-cache.js +0 -70
  125. package/dist/esm/features/session_replay/shared/replay-mode.js +0 -23
  126. package/dist/esm/features/utils/handler-cache.js +0 -63
  127. package/dist/types/features/session_replay/shared/replay-mode.d.ts +0 -9
  128. package/dist/types/features/session_replay/shared/replay-mode.d.ts.map +0 -1
  129. package/dist/types/features/utils/handler-cache.d.ts +0 -23
  130. package/dist/types/features/utils/handler-cache.d.ts.map +0 -1
  131. package/src/features/session_replay/shared/replay-mode.js +0 -23
  132. package/src/features/utils/handler-cache.js +0 -65
@@ -1,61 +1,48 @@
1
1
  export class Aggregate extends AggregateBase {
2
2
  static featureName: string;
3
- constructor(agentIdentifier: any, aggregator: any, argsObj: any);
3
+ constructor(agentIdentifier: any, aggregator: any);
4
4
  agentRuntime: any;
5
- resourceObserver: any;
6
- ptid: string;
7
- trace: {};
8
- nodeCount: number;
9
- sentTrace: {} | null;
10
- prevStoredEvents: Set<any>;
5
+ agentInfo: any;
6
+ /** A buffer to hold on to harvested traces in the case that a retry must be made later */
7
+ sentTrace: any[] | null | undefined;
11
8
  harvestTimeSeconds: any;
12
- maxNodesPerHarvest: any;
13
- /**
14
- * Standalone (mode) refers to the legacy version of ST before the idea of 'session' or the Replay feature existed.
15
- * It has some different behavior vs when used in tandem with replay. */
16
- isStandalone: boolean;
17
- operationalGate: HandlerCache;
18
- startTracing(startupBuffer: any, dontStartHarvestYet?: boolean): void;
19
- processPVT(name: any, value: any, attrs: any): void;
20
- storeTiming(timingEntry: any): void;
21
- storeEvent(currentEvent: any, target: any, start: any, end: any): void;
22
- shouldIgnoreEvent(event: any, target: any): boolean;
23
- evtName(type: any): any;
24
- evtOrigin(t: any, target: any): string;
25
- storeHist(path: any, old: any, time: any): void;
26
- storeResources(resources: any): void;
27
- storeErrorAgg(type: any, name: any, params: any, metrics: any): void;
28
- storeXhrAgg(type: any, name: any, params: any, metrics: any): void;
29
- storeSTN(stn: any): void;
30
- /**
31
- * Trim the collection of nodes awaiting harvest such that those seen outside a certain span of time are discarded.
32
- * @param {number} lookbackDuration Past length of time until now for which we care about nodes, in milliseconds
33
- * @returns {number} However many nodes were discarded after trimming.
34
- */
35
- trimSTNs(lookbackDuration: number): number;
36
- takeSTNs(retry: any): {
37
- qs?: undefined;
38
- body?: undefined;
39
- } | {
9
+ /** Tied to the entitlement flag response from BCS. Will short circuit operations of the agg if false */
10
+ entitled: any;
11
+ /** A flag used to decide if the 30 node threshold should be ignored on the first harvest to ensure sending on the first payload */
12
+ everHarvested: boolean;
13
+ /** If the harvest module is harvesting */
14
+ harvesting: boolean;
15
+ /** TraceStorage is the mechanism that holds, normalizes and aggregates ST nodes. It will be accessed and purged when harvests occur */
16
+ traceStorage: TraceStorage;
17
+ /** Sets up event listeners, and initializes this module to run in the correct "mode". Can be triggered from a few places, but makes an effort to only set up listeners once */
18
+ initialize(stMode: any, stEntitled: any, ignoreSession: any): void;
19
+ mode: any;
20
+ initialized: boolean | undefined;
21
+ scheduler: HarvestScheduler | undefined;
22
+ /** This module does not auto harvest by default -- it needs to be kicked off. Once this method is called, it will then harvest on an interval */
23
+ startHarvesting(): void;
24
+ /** Called by the harvest scheduler at harvest time to retrieve the payload. This will only actually return a payload if running in full mode */
25
+ prepareHarvest(options?: {}): {
40
26
  qs: {
41
- fsh?: number | undefined;
42
- st: number;
43
- /** hr === "hasReplay" in NR1, standalone is always checked and processed before harvesting
44
- * so a race condition between ST and SR states should not be a concern if implemented here */
45
- hr: number;
46
- /** fts === "firstTimestamp" in NR1, indicates what the earliest NODE timestamp was
47
- * so that blob parsing doesn't need to happen to support UI/API functions */
48
- fts: number;
49
- /** n === "nodeCount" in NR1, a count of nodes in the ST payload, so that blob parsing doesn't need to happen to support UI/API functions */
50
- n: number;
51
- };
52
- body: {
53
- res: any[];
27
+ browser_monitoring_key: any;
28
+ type: string;
29
+ app_id: any;
30
+ protocol_version: string;
31
+ timestamp: any;
32
+ attributes: string;
54
33
  };
55
- };
56
- smearEvtsByOrigin(name: any): (byOrigin: any, evtNode: any) => any;
57
- #private;
34
+ body: any[] | undefined;
35
+ } | undefined;
36
+ /** When the harvest scheduler finishes, this callback is executed. It's main purpose is to determine if the payload needs to be retried
37
+ * and if so, it will take all data from the temporary buffer and place it back into the traceStorage module
38
+ */
39
+ onHarvestFinished(result: any): void;
40
+ /** Switch from "off" or "error" to full mode (if entitled) */
41
+ switchToFull(): void;
42
+ /** Stop running for the remainder of the page lifecycle */
43
+ abort(): void;
58
44
  }
59
45
  import { AggregateBase } from '../../utils/aggregate-base';
60
- import { HandlerCache } from '../../utils/handler-cache';
46
+ import { TraceStorage } from './trace/storage';
47
+ import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
61
48
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_trace/aggregate/index.js"],"names":[],"mappings":"AAkCA;IACE,2BAAiC;IAGjC,iEAyIC;IAvIC,kBAA+C;IAC/C,sBAAiD;IACjD,aAAc;IACd,UAAe;IACf,kBAAkB;IAClB,qBAAqB;IACrB,2BAAiC;IACjC,wBAA0G;IAC1G,wBAA4G;IAC5G;;4EAEwE;IACxE,sBAAyB;IAGzB,8BAAsC;IA0HxC,sEAcC;IA8CD,oDAOC;IAGD,oCAwBC;IAGD,uEAoBC;IAED,oDAKC;IAED,wBAwBC;IAED,uCAuBC;IAGD,gDASC;IAID,qCAkBC;IAGD,qEAUC;IAGD,mEAUC;IAGD,yBAeC;IAED;;;;OAIG;IACH,2BAHW,MAAM,GACJ,MAAM,CAsBlB;IAGD;;;;;;;YAkCM;0GAC8F;;YAE9F;0FAC8E;;YAE9E,4IAA4I;;;;;;MAMjJ;IAED,mEA6BC;;CACF;8BA/gB6B,4BAA4B;6BAF7B,2BAA2B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_trace/aggregate/index.js"],"names":[],"mappings":"AAcA;IACE,2BAAiC;IAEjC,mDAmBC;IAjBC,kBAA+C;IAC/C,eAAyC;IAEzC,0FAA0F;IAC1F,oCAAqB;IACrB,wBAA0G;IAC1G,0GAA0G;IAC1G,cAAyB;IACzB,mIAAmI;IACnI,uBAA0B;IAC1B,0CAA0C;IAC1C,oBAAuB;IACvB,wIAAwI;IACxI,2BAA0C;IAM5C,gLAAgL;IAChL,mEA6DC;IA1CyD,UAA4D;IAGpH,iCAAuB;IAOvB,wCAKQ;IA6BV,kJAAkJ;IAClJ,wBAIC;IAED,iJAAiJ;IACjJ;;;;;;;;;;kBA4DC;IAED;;OAEG;IACH,qCAKC;IAED,8DAA8D;IAC9D,qBAUC;IAED,2DAA2D;IAC3D,cAKC;CACF;8BAtM6B,4BAA4B;6BAC7B,iBAAiB;iCAJb,2CAA2C"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * All nodes reported to the consumer must take this shape
3
+ */
4
+ export class TraceNode {
5
+ constructor(name: any, start: any, end: any, origin: any, type: any);
6
+ n: any;
7
+ s: any;
8
+ e: any;
9
+ o: any;
10
+ t: any;
11
+ }
12
+ //# sourceMappingURL=node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../../../../src/features/session_trace/aggregate/trace/node.js"],"names":[],"mappings":"AAAA;;GAEG;AACH;IACE,qEAMC;IALC,OAAa;IACb,OAAc;IACd,OAAY;IACZ,OAAe;IACf,OAAa;CAEhB"}
@@ -0,0 +1,43 @@
1
+ /** The purpose of this class is to manage, normalize, and retrieve ST nodes as needed without polluting the main ST modules */
2
+ export class TraceStorage {
3
+ constructor(parent: any);
4
+ nodeCount: number;
5
+ trace: {};
6
+ earliestTimeStamp: number;
7
+ latestTimeStamp: number;
8
+ tempStorage: any[];
9
+ prevStoredEvents: Set<any>;
10
+ parent: any;
11
+ /** Central function called by all the other store__ & addToTrace API to append a trace node. */
12
+ storeSTN(stn: any): void;
13
+ /**
14
+ * Trim the collection of nodes awaiting harvest such that those seen outside a certain span of time are discarded.
15
+ * @param {number} lookbackDuration Past length of time until now for which we care about nodes, in milliseconds
16
+ * @returns {number} However many nodes were discarded after trimming.
17
+ */
18
+ trimSTNs(lookbackDuration: number): number;
19
+ /** Used by session trace's harvester to create the payload body. */
20
+ takeSTNs(): {
21
+ stns?: undefined;
22
+ earliestTimeStamp?: undefined;
23
+ latestTimeStamp?: undefined;
24
+ } | {
25
+ stns: any[];
26
+ earliestTimeStamp: number;
27
+ latestTimeStamp: number;
28
+ };
29
+ smearEvtsByOrigin(name: any): (byOrigin: any, evtNode: any) => any;
30
+ processPVT(name: any, value: any, attrs: any): void;
31
+ storeTiming(timingEntry: any): void;
32
+ storeEvent(currentEvent: any, target: any, start: any, end: any): void;
33
+ shouldIgnoreEvent(event: any, target: any): boolean;
34
+ evtName(type: any): any;
35
+ evtOrigin(t: any, target: any): string;
36
+ storeHist(path: any, old: any, time: any): void;
37
+ storeResources(resources: any): void;
38
+ storeErrorAgg(type: any, name: any, params: any, metrics: any): void;
39
+ storeXhrAgg(type: any, name: any, params: any, metrics: any): void;
40
+ restoreNode(name: any, listOfSTNodes: any): void;
41
+ #private;
42
+ }
43
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../../../src/features/session_trace/aggregate/trace/storage.js"],"names":[],"mappings":"AAyBA,+HAA+H;AAC/H;IAQE,yBAEC;IATD,kBAAa;IACb,UAAU;IACV,0BAA4B;IAC5B,wBAAmB;IACnB,mBAAgB;IAChB,2BAA4B;IAG1B,YAAoB;IAGtB,gGAAgG;IAChG,yBAiBC;IAED;;;;OAIG;IACH,2BAHW,MAAM,GACJ,MAAM,CAsBlB;IAED,oEAAoE;IACpE;;;;;;;;MAsBC;IAED,mEA6BC;IAED,oDAOC;IAED,oCAkBC;IAGD,uEAcC;IAED,oDAKC;IAED,wBAwBC;IAED,uCAuBC;IAGD,gDAEC;IAID,qCAaC;IAGD,qEAGC;IAGD,mEAIC;IAED,iDAKC;;CACF"}
@@ -6,4 +6,5 @@ export const END: "-end";
6
6
  export const FN_START: string;
7
7
  export const FN_END: string;
8
8
  export const PUSH_STATE: "pushState";
9
+ export const MAX_NODES_PER_HARVEST: 1000;
9
10
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/session_trace/constants.js"],"names":[],"mappings":"AAEA,kCAAsD;AACtD,yCAAyC;AACzC,kCAAkC;AAClC,6BAA6B;AAC7B,yBAAyB;AACzB,8BAAoC;AACpC,4BAAgC;AAChC,qCAAqC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/session_trace/constants.js"],"names":[],"mappings":"AAEA,kCAAsD;AACtD,yCAAyC;AACzC,kCAAkC;AAClC,6BAA6B;AAC7B,yBAAyB;AACzB,8BAAoC;AACpC,4BAAgC;AAChC,qCAAqC;AACrC,yCAAyC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_trace/instrument/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAAiC;IACjC,mEAsCC;IAhCC,6BAA4C;CAiC/C;+BAnD8B,6BAA6B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_trace/instrument/index.js"],"names":[],"mappings":"AAiBA;IACE,2BAAiC;IACjC,mEA0CC;IAhCC,6BAA4C;CAiC/C;+BAxD8B,6BAA6B"}
@@ -7,6 +7,7 @@ export class AggregateBase extends FeatureBase {
7
7
  */
8
8
  waitForFlags(flagNames?: string[]): Promise<any>;
9
9
  drain(): void;
10
+ drained: boolean | undefined;
10
11
  /**
11
12
  * Checks for additional `jsAttributes` items to support backward compatibility with implementations of the agent where
12
13
  * loader configurations may appear after the loader code is executed.
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"AAOA;IACE,4BAGC;IAED;;;;OAIG;IACH,yBAHW,MAAM,EAAE,gBAmBlB;IAED,cAEC;IAED;;;OAGG;IACH,2BAqBC;CACF;4BAlE2B,gBAAgB"}
1
+ {"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"AAOA;IACE,4BAGC;IAED;;;;OAIG;IACH,yBAHW,MAAM,EAAE,gBAmBlB;IAED,cAGC;IADC,6BAAmB;IAGrB;;;OAGG;IACH,2BAqBC;CACF;4BAnE2B,gBAAgB"}
@@ -0,0 +1,2 @@
1
+ export function canEnableSessionTracking(agentId: string): boolean;
2
+ //# sourceMappingURL=feature-gates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-gates.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/feature-gates.js"],"names":[],"mappings":"AAQO,kDAHI,MAAM,GACJ,OAAO,CAInB"}
@@ -1 +1 @@
1
- {"version":3,"file":"instrument-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/instrument-base.js"],"names":[],"mappings":"AAgBA;;;GAGG;AACH;IACE;;;;;;;;OAQG;IACH,6BAPW,MAAM,cACN,OAAO,mCAAmC,EAAE,UAAU,eACtD,MAAM,8BAqChB;IA9BC,cAAgB;IAEhB,8IAA8I;IAC9I,cADW,WAAW,SAAS,CACF;IAE7B;;;MAGE;IACF,eAHU,OAAO,kBAAkB,EAAE,aAAa,CAGpB;IAE9B;;;MAGE;IACF,kCAAoC;IAiBtC;;;;;OAKG;IACH,mEAgDC;;CAYF;4BA3H2B,gBAAgB"}
1
+ {"version":3,"file":"instrument-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/instrument-base.js"],"names":[],"mappings":"AAiBA;;;GAGG;AACH;IACE;;;;;;;;OAQG;IACH,6BAPW,MAAM,cACN,OAAO,mCAAmC,EAAE,UAAU,eACtD,MAAM,8BAqChB;IA9BC,cAAgB;IAEhB,8IAA8I;IAC9I,cADW,WAAW,SAAS,CACF;IAE7B;;;MAGE;IACF,eAHU,OAAO,kBAAkB,EAAE,aAAa,CAGpB;IAE9B;;;MAGE;IACF,kCAAoC;IAiBtC;;;;;OAKG;IACH,mEAgDC;;CAYF;4BA5H2B,gBAAgB"}
@@ -4,6 +4,7 @@
4
4
  export class AgentBase {
5
5
  constructor(agentIdentifier?: string);
6
6
  agentIdentifier: string;
7
+ ee: any;
7
8
  /**
8
9
  * Reports a browser PageAction event along with a name and optional attributes.
9
10
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addpageaction/}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/agent-base.js"],"names":[],"mappings":"AAMA;;GAEG;AAEH;IAGE,sCAEC;IAJD,wBAAe;IAgBf;;;;;OAKG;IACH,oBAHW,MAAM,wCAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,kCAKhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,IAAI,sCAK5B;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,8CAKtB;IAED;;;;OAIG;IACH,iBAFW,MAAM,GAAC,IAAI,OAIrB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,OAMrB;IAED;;;;OAIG;IACH,kCAFmB,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,OAI9D;IAED;;;;OAIG;IACH,8CAEC;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,OAIhB;IAED;;;;OAIG;IACH,yDAEC;IAED;;;;OAIG;IACH,oBAEC;IAED;;;;;OAKG;IACH,mBAEC;IAED;;;;;;;;;;OAUG;IACH,6BARW;QAAC,MAAM,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,OAUrF;IAED;;;;;OAKG;IACH,0BAHW,MAAM,OAKhB;IAED;;;;;MAKE;IACF,eAHa,mBAAmB,CAK/B;;CACF;kCA5KY,OAAO,yBAAyB,EAAE,mBAAmB"}
1
+ {"version":3,"file":"agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/agent-base.js"],"names":[],"mappings":"AAOA;;GAEG;AAEH;IAGE,sCAKC;IAPD,wBAAe;IAMb,QAAiC;IAanC;;;;;OAKG;IACH,oBAHW,MAAM,wCAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,kCAKhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,IAAI,sCAK5B;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,8CAKtB;IAED;;;;OAIG;IACH,iBAFW,MAAM,GAAC,IAAI,OAIrB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,OAMrB;IAED;;;;OAIG;IACH,kCAFmB,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,OAI9D;IAED;;;;OAIG;IACH,8CAEC;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,OAIhB;IAED;;;;OAIG;IACH,yDAEC;IAED;;;;OAIG;IACH,oBAEC;IAED;;;;;OAKG;IACH,mBAEC;IAED;;;;;;;;;;OAUG;IACH,6BARW;QAAC,MAAM,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,OAUrF;IAED;;;;;OAKG;IACH,0BAHW,MAAM,OAKhB;IAED;;;;;MAKE;IACF,eAHa,mBAAmB,CAK/B;;CACF;kCA/KY,OAAO,yBAAyB,EAAE,mBAAmB"}
@@ -1 +1 @@
1
- {"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../../../src/loaders/configure/configure.js"],"names":[],"mappings":"AASA;;GAEG;AACH,oGA+CC"}
1
+ {"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../../../src/loaders/configure/configure.js"],"names":[],"mappings":"AASA;;GAEG;AACH,oGAgDC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.258.2",
3
+ "version": "1.260.0",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -10,6 +10,7 @@ import 'core-js/stable/array/flat'
10
10
  import 'core-js/stable/array/flat-map'
11
11
  import 'core-js/stable/array/from'
12
12
  import 'core-js/stable/array/some'
13
+ import 'core-js/stable/array/find-index'
13
14
  import 'core-js/stable/object/assign'
14
15
  import 'core-js/stable/object/entries'
15
16
  import 'core-js/stable/object/values'
@@ -23,3 +24,4 @@ import 'core-js/stable/url'
23
24
  import 'core-js/stable/url-search-params'
24
25
  import 'core-js/stable/string/starts-with'
25
26
  import 'core-js/stable/number/is-nan'
27
+ import 'core-js/stable/string/includes'
@@ -71,7 +71,7 @@ export function drain (agentIdentifier = '', featureName = 'feature', force = fa
71
71
  function checkCanDrainAll (agentIdentifier) {
72
72
  // Only when the event-groups for all features are ready to drain (staged) do we execute the drain. This has the effect
73
73
  // that the last feature to call drain triggers drain for all features.
74
- const items = [...registry[agentIdentifier]]
74
+ const items = Array.from(registry[agentIdentifier])
75
75
  if (items.every(([key, values]) => values.staged)) {
76
76
  items.sort((a, b) => a[1].priority - b[1].priority)
77
77
  items.forEach(([group]) => {
@@ -31,7 +31,7 @@ export class HarvestScheduler extends SharedContext {
31
31
  this.started = false
32
32
  this.timeoutHandle = null
33
33
  this.aborted = false // this controls the per-interval and final harvests for the scheduler (currently per feature specific!)
34
-
34
+ this.harvesting = false
35
35
  this.harvest = new Harvest(this.sharedContext)
36
36
 
37
37
  // unload if EOL mechanism fires
@@ -82,12 +82,14 @@ export class HarvestScheduler extends SharedContext {
82
82
 
83
83
  runHarvest (opts) {
84
84
  if (this.aborted) return
85
+ this.harvesting = true
85
86
 
86
87
  /**
87
88
  * This is executed immediately after harvest sends the data via XHR, or if there's nothing to send. Note that this excludes on unloading / sendBeacon.
88
89
  * @param {Object} result
89
90
  */
90
91
  const cbRanAfterSend = (result) => {
92
+ this.harvesting = false
91
93
  if (opts?.forceNoRetry) result.retry = false // discard unsent data rather than re-queuing for next harvest attempt
92
94
  this.onHarvestFinished(opts, result)
93
95
  }
@@ -102,7 +104,7 @@ export class HarvestScheduler extends SharedContext {
102
104
  if (!submitMethod) return false
103
105
 
104
106
  const retry = !opts?.unload && submitMethod === submitData.xhr
105
- payload = this.opts.getPayload({ retry, opts })
107
+ payload = this.opts.getPayload({ retry, ...opts })
106
108
 
107
109
  if (!payload) {
108
110
  if (this.started) {
@@ -64,8 +64,10 @@ export class SessionEntity {
64
64
  }
65
65
 
66
66
  setup ({ value = generateRandomHexString(16), expiresMs = DEFAULT_EXPIRES_MS, inactiveMs = DEFAULT_INACTIVE_MS }) {
67
+ /** Ensure that certain properties are preserved across a reset if already set */
68
+ const persistentAttributes = { serverTimeDiff: this.state.serverTimeDiff || model.serverTimeDiff }
67
69
  this.state = {}
68
- this.sync(model)
70
+ this.sync({ ...model, ...persistentAttributes })
69
71
 
70
72
  // value is intended to act as the primary value of the k=v pair
71
73
  this.state.value = value
@@ -1,7 +1,5 @@
1
1
  import { originTime } from '../constants/runtime'
2
- import { ee as baseEE } from '../event-emitter/contextual-ee'
3
2
  import { getRuntime } from '../config/config'
4
- import { SESSION_EVENT_TYPES, SESSION_EVENTS } from '../session/constants'
5
3
 
6
4
  /**
7
5
  * Class used to adjust the timestamp of harvested data to New Relic server time. This
@@ -37,17 +35,7 @@ export class TimeKeeper {
37
35
 
38
36
  constructor (agentIdentifier) {
39
37
  this.#session = getRuntime(agentIdentifier)?.session
40
-
41
- if (this.#session) {
42
- const ee = baseEE.get(agentIdentifier)
43
- ee.on(SESSION_EVENTS.UPDATE, this.#processSessionUpdate.bind(this))
44
- ee.on(SESSION_EVENTS.STARTED, () => {
45
- if (this.#ready) {
46
- this.#session.write({ serverTimeDiff: this.#localTimeDiff })
47
- }
48
- })
49
- this.#processSessionUpdate(null, this.#session.read())
50
- }
38
+ this.processStoredDiff()
51
39
  }
52
40
 
53
41
  get ready () {
@@ -65,8 +53,8 @@ export class TimeKeeper {
65
53
  * @param endTime {number} The end time of the RUM request
66
54
  */
67
55
  processRumRequest (rumRequest, startTime, endTime) {
56
+ this.processStoredDiff()
68
57
  if (this.#ready) return // Server time calculated from session entity
69
-
70
58
  const responseDateHeader = rumRequest.getResponseHeader('Date')
71
59
  if (!responseDateHeader) {
72
60
  throw new Error('Missing date header on rum response.')
@@ -79,11 +67,11 @@ export class TimeKeeper {
79
67
  this.#correctedOriginTime = Math.floor(Date.parse(responseDateHeader) - serverOffset)
80
68
  this.#localTimeDiff = originTime - this.#correctedOriginTime
81
69
 
82
- if (Number.isNaN(this.#correctedOriginTime)) {
70
+ if (isNaN(this.#correctedOriginTime)) {
83
71
  throw new Error('Date header invalid format.')
84
72
  }
85
73
 
86
- if (this.#session) this.#session.write({ serverTimeDiff: this.#localTimeDiff })
74
+ this.#session?.write({ serverTimeDiff: this.#localTimeDiff })
87
75
  this.#ready = true
88
76
  }
89
77
 
@@ -106,20 +94,11 @@ export class TimeKeeper {
106
94
  return Math.floor(timestamp - this.#localTimeDiff)
107
95
  }
108
96
 
109
- /**
110
- * Processes a session entity update payload to extract the server time calculated.
111
- * @param {import('../session/constants').SESSION_EVENT_TYPES | null} type
112
- * @param {Object} data
113
- */
114
- #processSessionUpdate (type, data) {
115
- if (typeof data?.serverTimeDiff !== 'number') return
116
-
117
- if (
118
- (!type && !this.#ready) || // This captures the initial read from the session entity when the timekeeper first initializes
119
- type === SESSION_EVENT_TYPES.CROSS_TAB // This captures any cross-tab write of the session entity
120
- ) {
121
- // This captures the initial read from the session entity when the timekeeper first initializes
122
- this.#localTimeDiff = data.serverTimeDiff
97
+ /** Process the session entity and use the info to set the main time calculations if present */
98
+ processStoredDiff () {
99
+ const storedServerTimeDiff = this.#session?.read()?.serverTimeDiff
100
+ if (typeof storedServerTimeDiff === 'number' && !isNaN(storedServerTimeDiff)) {
101
+ this.#localTimeDiff = storedServerTimeDiff
123
102
  this.#correctedOriginTime = originTime - this.#localTimeDiff
124
103
  this.#ready = true
125
104
  }
@@ -1,3 +1,5 @@
1
1
  import { FEATURE_NAMES } from '../../loaders/features/features'
2
2
 
3
3
  export const FEATURE_NAME = FEATURE_NAMES.ajax
4
+
5
+ export const MAX_PAYLOAD_SIZE = 1000000
@@ -6,7 +6,6 @@
6
6
  import { handle } from '../../../common/event-emitter/handle'
7
7
  import { InstrumentBase } from '../../utils/instrument-base'
8
8
  import { FEATURE_NAME } from '../constants'
9
- import { FEATURE_NAMES } from '../../../loaders/features/features'
10
9
  import { globalScope } from '../../../common/constants/runtime'
11
10
  import { eventListenerOpts } from '../../../common/event-listener/event-listener-opts'
12
11
  import { now } from '../../../common/timing/now'
@@ -28,7 +27,7 @@ export class Instrument extends InstrumentBase {
28
27
 
29
28
  this.ee.on('internal-error', (error) => {
30
29
  if (!this.abortHandler) return
31
- handle('ierr', [castError(error), now(), true, {}, this.#replayRunning], undefined, FEATURE_NAMES.jserrors, this.ee)
30
+ handle('ierr', [castError(error), now(), true, {}, this.#replayRunning], undefined, this.featureName, this.ee)
32
31
  })
33
32
 
34
33
  this.ee.on(SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, (isRunning) => {
@@ -37,12 +36,12 @@ export class Instrument extends InstrumentBase {
37
36
 
38
37
  globalScope.addEventListener('unhandledrejection', (promiseRejectionEvent) => {
39
38
  if (!this.abortHandler) return
40
- handle('err', [castPromiseRejectionEvent(promiseRejectionEvent), now(), false, { unhandledPromiseRejection: 1 }, this.#replayRunning], undefined, FEATURE_NAMES.jserrors, this.ee)
39
+ handle('err', [castPromiseRejectionEvent(promiseRejectionEvent), now(), false, { unhandledPromiseRejection: 1 }, this.#replayRunning], undefined, this.featureName, this.ee)
41
40
  }, eventListenerOpts(false, this.removeOnAbort?.signal))
42
41
 
43
42
  globalScope.addEventListener('error', (errorEvent) => {
44
43
  if (!this.abortHandler) return
45
- handle('err', [castErrorEvent(errorEvent), now(), false, {}, this.#replayRunning], undefined, FEATURE_NAMES.jserrors, this.ee)
44
+ handle('err', [castErrorEvent(errorEvent), now(), false, {}, this.#replayRunning], undefined, this.featureName, this.ee)
46
45
  }, eventListenerOpts(false, this.removeOnAbort?.signal))
47
46
 
48
47
  this.abortHandler = this.#abort // we also use this as a flag to denote that the feature is active or on and handling errors
@@ -112,8 +112,6 @@ export class Aggregate extends AggregateBase {
112
112
  if (this.resourcesSent) return
113
113
  this.resourcesSent = true // make sure this only gets sent once
114
114
 
115
- const agentRuntime = getRuntime(this.agentIdentifier)
116
-
117
115
  // Capture SMs around network resources using the performance API to assess
118
116
  // work to split this out from the ST nodes
119
117
  // differentiate between internal+external and ajax+non-ajax
@@ -132,12 +130,6 @@ export class Aggregate extends AggregateBase {
132
130
  }
133
131
  })
134
132
 
135
- // Capture SMs for session trace if active (`ptid` is set when returned by replay ingest).
136
- // Retain these SMs while we are working through the session_replay feature
137
- if (agentRuntime.ptid) {
138
- this.storeSupportabilityMetrics('PageSession/Feature/SessionTrace/DurationMs', Math.round(performance.now()))
139
- }
140
-
141
133
  // Capture SMs for performance markers and measures to assess the usage and possible inclusion of this
142
134
  // data in the agent for use in NR
143
135
  if (typeof performance !== 'undefined') {
@@ -26,6 +26,7 @@ export class Aggregate extends AggregateBase {
26
26
  this.timeToFirstByte = 0
27
27
  this.firstByteToWindowLoad = 0 // our "frontend" duration
28
28
  this.firstByteToDomContent = 0 // our "dom processing" duration
29
+ this.timeKeeper = new TimeKeeper(this.agentIdentifier)
29
30
 
30
31
  if (isBrowserScope) {
31
32
  timeToFirstByte.subscribe(({ value, attrs }) => {
@@ -102,6 +103,10 @@ export class Aggregate extends AggregateBase {
102
103
  queryParameters.fp = firstPaint.current.value
103
104
  queryParameters.fcp = firstContentfulPaint.current.value
104
105
 
106
+ if (this.timeKeeper?.ready) {
107
+ queryParameters.timestamp = this.timeKeeper.convertRelativeTimestamp(now())
108
+ }
109
+
105
110
  const rumStartTime = now()
106
111
  harvester.send({
107
112
  endpoint: 'rum',
@@ -117,16 +122,15 @@ export class Aggregate extends AggregateBase {
117
122
  }
118
123
 
119
124
  try {
120
- const timeKeeper = new TimeKeeper(this.agentIdentifier)
121
- timeKeeper.processRumRequest(xhr, rumStartTime, rumEndTime)
122
- if (!timeKeeper.ready) throw new Error('TimeKeeper not ready')
125
+ this.timeKeeper.processRumRequest(xhr, rumStartTime, rumEndTime)
126
+ if (!this.timeKeeper.ready) throw new Error('TimeKeeper not ready')
123
127
 
124
- agentRuntime.timeKeeper = timeKeeper
128
+ agentRuntime.timeKeeper = this.timeKeeper
125
129
  } catch (error) {
126
130
  handle(SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/Failed'], undefined, FEATURE_NAMES.metrics, this.ee)
127
131
  drain(this.agentIdentifier, FEATURE_NAMES.metrics, true)
128
132
  this.ee.abort()
129
- warn('Could not calculate New Relic server time. Agent shutting down.')
133
+ warn('Could not calculate New Relic server time. Agent shutting down.', error)
130
134
  return
131
135
  }
132
136
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  import { registerHandler } from '../../../common/event-emitter/register-handler'
14
14
  import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
15
- import { ABORT_REASONS, FEATURE_NAME, MAX_PAYLOAD_SIZE, QUERY_PARAM_PADDING, RRWEB_EVENT_TYPES, SR_EVENT_EMITTER_TYPES } from '../constants'
15
+ import { ABORT_REASONS, FEATURE_NAME, MAX_PAYLOAD_SIZE, QUERY_PARAM_PADDING, RRWEB_EVENT_TYPES, SR_EVENT_EMITTER_TYPES, TRIGGERS } from '../constants'
16
16
  import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config'
17
17
  import { AggregateBase } from '../../utils/aggregate-base'
18
18
  import { sharedChannel } from '../../../common/constants/shared-channel'
@@ -97,16 +97,6 @@ export class Aggregate extends AggregateBase {
97
97
  raw: true
98
98
  }, this)
99
99
 
100
- registerHandler(SR_EVENT_EMITTER_TYPES.RECORD, () => {
101
- // if it has aborted or BCS returned bad entitlements, do not allow
102
- if (this.blocked || !this.entitled) return
103
- // if it isnt already (fully) initialized... initialize it
104
- if (!this.recorder) this.initializeRecording(false, true, true)
105
- // its been initialized and imported the recorder but its not recording (mode === off || error)
106
- else if (this.mode !== MODE.FULL) this.switchToFull()
107
- // if it gets all the way to here, that means a full session is already recording... do nothing
108
- }, this.featureName, this.ee)
109
-
110
100
  registerHandler(SR_EVENT_EMITTER_TYPES.PAUSE, () => {
111
101
  this.forceStop(this.mode !== MODE.ERROR)
112
102
  }, this.featureName, this.ee)
@@ -117,8 +107,8 @@ export class Aggregate extends AggregateBase {
117
107
 
118
108
  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
109
 
120
- this.waitForFlags(['sr']).then(([flagOn]) => {
121
- this.entitled = flagOn
110
+ this.waitForFlags(['srs', 'sr']).then(([srMode, entitled]) => {
111
+ this.entitled = !!entitled
122
112
  if (!this.entitled) {
123
113
  deregisterDrain(this.agentIdentifier, this.featureName)
124
114
  if (this.recorder?.recording) {
@@ -128,14 +118,14 @@ export class Aggregate extends AggregateBase {
128
118
  return
129
119
  }
130
120
  this.drain()
131
- this.initializeRecording(
132
- (Math.random() * 100) < error_sampling_rate,
133
- (Math.random() * 100) < sampling_rate
134
- )
121
+ this.initializeRecording(srMode)
135
122
  }).then(() => {
136
- if (this.mode === MODE.OFF) args?.recorder?.stopRecording() // stop any conservative preload recording launched by instrument
137
- sharedChannel.onReplayReady(this.mode) // notify watchers that replay started with the mode
138
- })
123
+ if (this.mode === MODE.OFF) {
124
+ this.recorder?.stopRecording() // stop any conservative preload recording launched by instrument
125
+ while (this.recorder?.getEvents().events.length) this.recorder?.clearBuffer?.()
126
+ }
127
+ sharedChannel.onReplayReady(this.mode)
128
+ }) // notify watchers that replay started with the mode
139
129
 
140
130
  /** Detect if the default configs have been altered and report a SM. This is useful to evaluate what the reasonable defaults are across a customer base over time */
141
131
  if (!autoStart) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/AutoStart/Modified'], undefined, FEATURE_NAMES.metrics, this.ee)
@@ -179,7 +169,7 @@ export class Aggregate extends AggregateBase {
179
169
  * @param {boolean} ignoreSession - whether to force the method to ignore the session state and use just the sample flags
180
170
  * @returns {void}
181
171
  */
182
- async initializeRecording (errorSample, fullSample, ignoreSession) {
172
+ async initializeRecording (srMode, ignoreSession) {
183
173
  this.initialized = true
184
174
  if (!this.entitled) return
185
175
 
@@ -191,23 +181,16 @@ export class Aggregate extends AggregateBase {
191
181
  // session replays can continue if already in progress
192
182
  const { session, timeKeeper } = getRuntime(this.agentIdentifier)
193
183
  this.timeKeeper = timeKeeper
194
- if (!session.isNew && !ignoreSession) { // inherit the mode of the existing session
184
+ if (this.recorder?.parent.trigger === TRIGGERS.API && this.recorder?.recording) {
185
+ this.mode = MODE.FULL
186
+ } else if (!session.isNew && !ignoreSession) { // inherit the mode of the existing session
195
187
  this.mode = session.state.sessionReplayMode
196
188
  } else {
197
189
  // The session is new... determine the mode the new session should start in
198
- if (fullSample) this.mode = MODE.FULL // full mode has precedence over error mode
199
- else if (errorSample) this.mode = MODE.ERROR
200
- // If neither are selected, then don't record (early return)
201
- else {
202
- return
203
- }
204
- }
205
-
206
- if (this.recorder?.getEvents().type === 'preloaded') {
207
- this.prepUtils().then(() => {
208
- this.scheduler.runHarvest()
209
- })
190
+ this.mode = srMode
210
191
  }
192
+ // If off, then don't record (early return)
193
+ if (this.mode === MODE.OFF) return
211
194
 
212
195
  if (!this.recorder) {
213
196
  try {
@@ -225,12 +208,20 @@ export class Aggregate extends AggregateBase {
225
208
  // If an error was noticed before the mode could be set (like in the early lifecycle of the page), immediately set to FULL mode
226
209
  if (this.mode === MODE.ERROR && this.errorNoticed) this.mode = MODE.FULL
227
210
 
228
- // FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
229
- // ERROR mode will do this until an error is thrown, and then switch into FULL mode.
230
- // If an error happened in ERROR mode before we've gotten to this stage, it will have already set the mode to FULL
231
- if (this.mode === MODE.FULL && !this.scheduler.started) {
211
+ if (this.mode === MODE.FULL) {
212
+ // If theres preloaded events and we are in full mode, just harvest immediately to clear up space and for consistency
213
+ if (this.recorder?.getEvents().type === 'preloaded') {
214
+ this.prepUtils().then(() => {
215
+ this.scheduler.runHarvest()
216
+ })
217
+ }
218
+ // FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
219
+ // ERROR mode will do this until an error is thrown, and then switch into FULL mode.
220
+ // If an error happened in ERROR mode before we've gotten to this stage, it will have already set the mode to FULL
221
+ if (!this.scheduler.started) {
232
222
  // We only report (harvest) in FULL mode
233
- this.scheduler.startTimer(this.harvestTimeSeconds)
223
+ this.scheduler.startTimer(this.harvestTimeSeconds)
224
+ }
234
225
  }
235
226
 
236
227
  await this.prepUtils()