@newrelic/browser-agent 1.276.0 → 1.278.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 (166) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cjs/common/aggregate/event-aggregator.js +1 -1
  3. package/dist/cjs/common/config/init.js +1 -10
  4. package/dist/cjs/common/config/runtime.js +2 -1
  5. package/dist/cjs/common/constants/env.cdn.js +1 -1
  6. package/dist/cjs/common/constants/env.npm.js +1 -1
  7. package/dist/cjs/common/harvest/harvester.js +255 -0
  8. package/dist/cjs/common/harvest/types.js +5 -21
  9. package/dist/cjs/features/ajax/aggregate/index.js +2 -11
  10. package/dist/cjs/features/generic_events/aggregate/index.js +17 -13
  11. package/dist/cjs/features/generic_events/constants.js +2 -1
  12. package/dist/cjs/features/jserrors/aggregate/index.js +3 -14
  13. package/dist/cjs/features/logging/aggregate/index.js +4 -12
  14. package/dist/cjs/features/metrics/aggregate/index.js +7 -15
  15. package/dist/cjs/features/page_view_event/aggregate/index.js +46 -48
  16. package/dist/cjs/features/page_view_timing/aggregate/index.js +0 -9
  17. package/dist/cjs/features/session_replay/aggregate/index.js +21 -43
  18. package/dist/cjs/features/session_replay/instrument/index.js +2 -1
  19. package/dist/cjs/features/session_replay/shared/recorder.js +6 -6
  20. package/dist/cjs/features/session_trace/aggregate/index.js +9 -24
  21. package/dist/cjs/features/session_trace/aggregate/trace/storage.js +8 -2
  22. package/dist/cjs/features/soft_navigations/aggregate/index.js +31 -21
  23. package/dist/cjs/features/soft_navigations/aggregate/initial-page-load-interaction.js +2 -1
  24. package/dist/cjs/features/soft_navigations/aggregate/interaction.js +12 -12
  25. package/dist/cjs/features/soft_navigations/constants.js +5 -2
  26. package/dist/cjs/features/spa/aggregate/index.js +7 -10
  27. package/dist/cjs/features/utils/aggregate-base.js +66 -27
  28. package/dist/cjs/features/utils/event-buffer.js +0 -1
  29. package/dist/cjs/features/utils/event-store-manager.js +109 -0
  30. package/dist/cjs/features/utils/instrument-base.js +1 -10
  31. package/dist/cjs/loaders/api/api-methods.js +1 -1
  32. package/dist/cjs/loaders/api/api.js +2 -1
  33. package/dist/cjs/loaders/features/features.js +16 -10
  34. package/dist/cjs/loaders/micro-agent-base.js +10 -0
  35. package/dist/cjs/loaders/micro-agent.js +1 -0
  36. package/dist/esm/common/aggregate/event-aggregator.js +1 -1
  37. package/dist/esm/common/config/init.js +1 -10
  38. package/dist/esm/common/config/runtime.js +2 -1
  39. package/dist/esm/common/constants/env.cdn.js +1 -1
  40. package/dist/esm/common/constants/env.npm.js +1 -1
  41. package/dist/esm/common/harvest/harvester.js +249 -0
  42. package/dist/esm/common/harvest/types.js +5 -21
  43. package/dist/esm/features/ajax/aggregate/index.js +3 -12
  44. package/dist/esm/features/generic_events/aggregate/index.js +18 -14
  45. package/dist/esm/features/generic_events/constants.js +1 -0
  46. package/dist/esm/features/jserrors/aggregate/index.js +4 -15
  47. package/dist/esm/features/logging/aggregate/index.js +4 -12
  48. package/dist/esm/features/metrics/aggregate/index.js +7 -15
  49. package/dist/esm/features/page_view_event/aggregate/index.js +46 -48
  50. package/dist/esm/features/page_view_timing/aggregate/index.js +1 -10
  51. package/dist/esm/features/session_replay/aggregate/index.js +22 -44
  52. package/dist/esm/features/session_replay/instrument/index.js +2 -1
  53. package/dist/esm/features/session_replay/shared/recorder.js +6 -6
  54. package/dist/esm/features/session_trace/aggregate/index.js +9 -24
  55. package/dist/esm/features/session_trace/aggregate/trace/storage.js +8 -2
  56. package/dist/esm/features/soft_navigations/aggregate/index.js +33 -23
  57. package/dist/esm/features/soft_navigations/aggregate/initial-page-load-interaction.js +2 -1
  58. package/dist/esm/features/soft_navigations/aggregate/interaction.js +13 -13
  59. package/dist/esm/features/soft_navigations/constants.js +4 -1
  60. package/dist/esm/features/spa/aggregate/index.js +8 -11
  61. package/dist/esm/features/utils/aggregate-base.js +66 -27
  62. package/dist/esm/features/utils/event-buffer.js +0 -1
  63. package/dist/esm/features/utils/event-store-manager.js +103 -0
  64. package/dist/esm/features/utils/instrument-base.js +1 -10
  65. package/dist/esm/loaders/api/api-methods.js +1 -1
  66. package/dist/esm/loaders/api/api.js +2 -1
  67. package/dist/esm/loaders/features/features.js +15 -9
  68. package/dist/esm/loaders/micro-agent-base.js +10 -0
  69. package/dist/esm/loaders/micro-agent.js +1 -0
  70. package/dist/types/common/aggregate/event-aggregator.d.ts +1 -1
  71. package/dist/types/common/aggregate/event-aggregator.d.ts.map +1 -1
  72. package/dist/types/common/config/init.d.ts.map +1 -1
  73. package/dist/types/common/config/runtime.d.ts.map +1 -1
  74. package/dist/types/common/harvest/harvester.d.ts +16 -0
  75. package/dist/types/common/harvest/harvester.d.ts.map +1 -0
  76. package/dist/types/common/harvest/types.d.ts +8 -45
  77. package/dist/types/common/harvest/types.d.ts.map +1 -1
  78. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  79. package/dist/types/features/generic_events/aggregate/index.d.ts +1 -3
  80. package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
  81. package/dist/types/features/generic_events/constants.d.ts +1 -0
  82. package/dist/types/features/generic_events/constants.d.ts.map +1 -1
  83. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  84. package/dist/types/features/logging/aggregate/index.d.ts +0 -3
  85. package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
  86. package/dist/types/features/metrics/aggregate/index.d.ts +1 -1
  87. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  88. package/dist/types/features/page_view_event/aggregate/index.d.ts +6 -2
  89. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  90. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  91. package/dist/types/features/session_replay/aggregate/index.d.ts +12 -15
  92. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  93. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  94. package/dist/types/features/session_trace/aggregate/index.d.ts +0 -5
  95. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  96. package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +8 -5
  97. package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -1
  98. package/dist/types/features/soft_navigations/aggregate/index.d.ts +1 -0
  99. package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
  100. package/dist/types/features/soft_navigations/aggregate/initial-page-load-interaction.d.ts.map +1 -1
  101. package/dist/types/features/soft_navigations/aggregate/interaction.d.ts +3 -3
  102. package/dist/types/features/soft_navigations/aggregate/interaction.d.ts.map +1 -1
  103. package/dist/types/features/soft_navigations/constants.d.ts +1 -0
  104. package/dist/types/features/soft_navigations/constants.d.ts.map +1 -1
  105. package/dist/types/features/spa/aggregate/index.d.ts +0 -1
  106. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  107. package/dist/types/features/utils/aggregate-base.d.ts +12 -7
  108. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  109. package/dist/types/features/utils/event-buffer.d.ts +1 -2
  110. package/dist/types/features/utils/event-buffer.d.ts.map +1 -1
  111. package/dist/types/features/utils/event-store-manager.d.ts +43 -0
  112. package/dist/types/features/utils/event-store-manager.d.ts.map +1 -0
  113. package/dist/types/features/utils/instrument-base.d.ts +0 -1
  114. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  115. package/dist/types/loaders/api/api.d.ts +1 -0
  116. package/dist/types/loaders/api/api.d.ts.map +1 -1
  117. package/dist/types/loaders/features/features.d.ts +15 -12
  118. package/dist/types/loaders/features/features.d.ts.map +1 -1
  119. package/dist/types/loaders/micro-agent-base.d.ts +7 -0
  120. package/dist/types/loaders/micro-agent-base.d.ts.map +1 -1
  121. package/dist/types/loaders/micro-agent.d.ts.map +1 -1
  122. package/package.json +6 -6
  123. package/src/common/aggregate/event-aggregator.js +1 -1
  124. package/src/common/config/init.js +9 -10
  125. package/src/common/config/runtime.js +2 -1
  126. package/src/common/harvest/__mocks__/harvester.js +6 -0
  127. package/src/common/harvest/harvester.js +230 -0
  128. package/src/common/harvest/types.js +5 -21
  129. package/src/features/ajax/aggregate/index.js +3 -14
  130. package/src/features/generic_events/aggregate/index.js +20 -17
  131. package/src/features/generic_events/constants.js +2 -0
  132. package/src/features/jserrors/aggregate/index.js +4 -11
  133. package/src/features/logging/aggregate/index.js +4 -12
  134. package/src/features/metrics/aggregate/index.js +5 -12
  135. package/src/features/page_view_event/aggregate/index.js +38 -38
  136. package/src/features/page_view_timing/aggregate/index.js +1 -12
  137. package/src/features/session_replay/aggregate/index.js +19 -42
  138. package/src/features/session_replay/instrument/index.js +1 -1
  139. package/src/features/session_replay/shared/recorder.js +6 -6
  140. package/src/features/session_trace/aggregate/index.js +8 -25
  141. package/src/features/session_trace/aggregate/trace/storage.js +5 -2
  142. package/src/features/soft_navigations/aggregate/index.js +26 -23
  143. package/src/features/soft_navigations/aggregate/initial-page-load-interaction.js +2 -1
  144. package/src/features/soft_navigations/aggregate/interaction.js +13 -12
  145. package/src/features/soft_navigations/constants.js +3 -1
  146. package/src/features/spa/aggregate/index.js +8 -11
  147. package/src/features/utils/aggregate-base.js +59 -27
  148. package/src/features/utils/event-buffer.js +0 -1
  149. package/src/features/utils/event-store-manager.js +101 -0
  150. package/src/features/utils/instrument-base.js +2 -8
  151. package/src/loaders/api/api-methods.js +1 -1
  152. package/src/loaders/api/api.js +3 -1
  153. package/src/loaders/features/features.js +16 -9
  154. package/src/loaders/micro-agent-base.js +10 -0
  155. package/src/loaders/micro-agent.js +1 -0
  156. package/dist/cjs/common/harvest/harvest-scheduler.js +0 -168
  157. package/dist/cjs/common/harvest/harvest.js +0 -295
  158. package/dist/esm/common/harvest/harvest-scheduler.js +0 -160
  159. package/dist/esm/common/harvest/harvest.js +0 -286
  160. package/dist/types/common/harvest/harvest-scheduler.d.ts +0 -50
  161. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +0 -1
  162. package/dist/types/common/harvest/harvest.d.ts +0 -65
  163. package/dist/types/common/harvest/harvest.d.ts.map +0 -1
  164. package/src/common/harvest/__mocks__/harvest.js +0 -13
  165. package/src/common/harvest/harvest-scheduler.js +0 -166
  166. package/src/common/harvest/harvest.js +0 -282
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/index.js"],"names":[],"mappings":"AAaA;IACE,2BAAiC;IACjC;;OAkDC;IA9CC,2BAAwC;IACxC,iBAA8B;IAE9B,uDAA0F;IAW1F,yBAA+B;IAC/B,0CAAiC;IAiCnC,qCAUC;IAED,0EAeC;IAED,2BAiBC;IAED;;;;;;;OAOG;IACH,6BAHW,mBAAmB,OAqB7B;;CA2FF;8BAjO6B,4BAA4B;2CAGf,iCAAiC;4BAChD,eAAe"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/index.js"],"names":[],"mappings":"AAYA;IACE,2BAAiC;IACjC;;OAkDC;IA/CC,2BAAwC;IACxC,iBAA8B;IAE9B,uDAA0F;IAa1F,yBAA+B;IAC/B,0CAAiC;IACjC,sBAA4B;IA+B9B,qCAUC;IAED,0EAiBC;IAED,2BAiBC;IAED;;;;;;;OAOG;IACH,6BAHW,mBAAmB,OAqB7B;;CA6FF;8BArO6B,4BAA4B;2CAGf,iCAAiC;4BAChD,eAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"initial-page-load-interaction.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/initial-page-load-interaction.js"],"names":[],"mappings":"AAOA;IACE,kCAKC;IAED,sBAAqD;IACrD,gCAAyE;IAEzE;;;OAGG;IACH,oCA6BC;CACF;4BAnD2B,eAAe"}
1
+ {"version":3,"file":"initial-page-load-interaction.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/initial-page-load-interaction.js"],"names":[],"mappings":"AAQA;IACE,kCAKC;IAED,sBAAqD;IACrD,gCAAyE;IAEzE;;;OAGG;IACH,oCA6BC;CACF;4BApD2B,eAAe"}
@@ -2,11 +2,9 @@
2
2
  * link https://github.com/newrelic/nr-querypack/blob/main/schemas/bel/7.qpschema
3
3
  **/
4
4
  export class Interaction extends BelNode {
5
- constructor(agentIdentifier: any, uiEvent: any, uiEventTimestamp: any, currentRouteKnown: any);
5
+ constructor(agentIdentifier: any, uiEvent: any, uiEventTimestamp: any, currentRouteKnown: any, currentUrl: any);
6
6
  id: string;
7
7
  initialPageURL: string;
8
- oldURL: string;
9
- newURL: string;
10
8
  customName: any;
11
9
  customAttributes: {};
12
10
  customDataByApi: {};
@@ -27,6 +25,8 @@ export class Interaction extends BelNode {
27
25
  eventSubscription: Map<string, never[]>;
28
26
  forceSave: boolean;
29
27
  forceIgnore: boolean;
28
+ newURL: any;
29
+ oldURL: any;
30
30
  updateDom(timestamp: any): void;
31
31
  updateHistory(timestamp: any, newUrl: any): void;
32
32
  seenHistoryAndDomChange(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/interaction.js"],"names":[],"mappings":"AASA;;IAEI;AACJ;IAoBE,+FAYC;IA/BD,WAAmB;IACnB,uBAAgC;IAChC,eAAmC;IACnC,eAAmC;IACnC,gBAAU;IACV,qBAAqB;IACrB,oBAAoB;IACpB,eAAS;IACT,aAAO;IACP,cAAQ;IACR,+EAA+E;IAC/E,eAA8B;IAC9B,qBAAgB;IAChB,yBAAoB;IACpB,sBAAoB;IACpB,6BAA2B;IAC3B,cAAW;IACX,uBAAiB;IAIf,gBAAoC;IACpC,aAAsB;IAEtB,cAAiC;IACjC,wCAGE;IACF,mBAAyC;IAAxB,qBAAwB;IAI3C,gCAEC;IAED,iDAGC;IAED,mCAEC;IAED,8BAIC;IAED,kCAUC;IAwBD;;;;;OAKG;IACH,0BAHW,mBAAmB,WAM7B;IAGD,uBAAoB;IACpB,iCAA8B;IAC9B,sBAAmB;IAEnB,gDA2CC;;CACF;wBAxJuB,YAAY"}
1
+ {"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/interaction.js"],"names":[],"mappings":"AASA;;IAEI;AACJ;IAkBE,gHAaC;IA9BD,WAAmB;IACnB,uBAAgC;IAChC,gBAAU;IACV,qBAAqB;IACrB,oBAAoB;IACpB,eAAS;IACT,aAAO;IACP,cAAQ;IACR,+EAA+E;IAC/E,eAA8B;IAC9B,qBAAgB;IAChB,yBAAoB;IACpB,sBAAoB;IACpB,6BAA2B;IAC3B,cAAW;IACX,uBAAiB;IAIf,gBAAoC;IACpC,aAAsB;IAEtB,cAAiC;IACjC,wCAGE;IACF,mBAAyC;IAAxB,qBAAwB;IAEzC,YAAsE;IAAxD,YAAwD;IAGxE,gCAEC;IAED,iDAGC;IAED,mCAEC;IAED,8BAIC;IAED,kCAaC;IAsBD;;;;;OAKG;IACH,0BAHW,mBAAmB,WAM7B;IAGD,uBAAoB;IACpB,iCAA8B;IAC9B,sBAAmB;IAEnB,gDA4CC;;CACF;wBAzJuB,YAAY"}
@@ -1,5 +1,6 @@
1
1
  export const INTERACTION_TRIGGERS: string[];
2
2
  export const API_TRIGGER_NAME: "api";
3
+ export const IPL_TRIGGER_NAME: "initialPageLoad";
3
4
  export const FEATURE_NAME: string;
4
5
  export namespace INTERACTION_TYPE {
5
6
  let INITIAL_PAGE_LOAD: string;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/soft_navigations/constants.js"],"names":[],"mappings":"AAEA,4CAIC;AACD,qCAAqC;AAErC,kCAAiD"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/soft_navigations/constants.js"],"names":[],"mappings":"AAEA,4CAKC;AACD,qCAAqC;AACrC,iDAAiD;AAEjD,kCAAiD"}
@@ -14,7 +14,6 @@ export class Aggregate extends AggregateBase {
14
14
  pageLoaded: boolean;
15
15
  childTime: number;
16
16
  depth: number;
17
- harvestTimeSeconds: any;
18
17
  disableSpaFix: boolean;
19
18
  };
20
19
  spaSerializerClass: Serializer;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/spa/aggregate/index.js"],"names":[],"mappings":"AA8BA;IACE,2BAAiC;IACjC,2BA0rBC;IAvrBe;;;;;;;;;;;;;;;MAgBb;IACD,+BAA8C;IAwqBhD,qCAEC;CACF;8BA9sB6B,4BAA4B;2BAJ/B,cAAc"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/spa/aggregate/index.js"],"names":[],"mappings":"AA6BA;IACE,2BAAiC;IACjC,2BAwrBC;IArrBe;;;;;;;;;;;;;;MAeb;IACD,+BAA8C;IAuqBhD,qCAEC;CACF;8BA5sB6B,4BAA4B;2BAJ/B,cAAc"}
@@ -1,7 +1,7 @@
1
1
  export class AggregateBase extends FeatureBase {
2
2
  agentRef: any;
3
3
  events: any;
4
- obfuscator: any;
4
+ harvestOpts: {};
5
5
  /**
6
6
  * New handler for waiting for multiple flags. Useful when expecting multiple flags simultaneously (ex. stn vs sr)
7
7
  * @param {string[]} flagNames
@@ -13,21 +13,26 @@ export class AggregateBase extends FeatureBase {
13
13
  /**
14
14
  * Return harvest payload. A "serializer" function can be defined on a derived class to format the payload.
15
15
  * @param {Boolean} shouldRetryOnFail - harvester flag to backup payload for retry later if harvest request fails; this should be moved to harvester logic
16
- * @returns final payload, or undefined if there are no pending events
16
+ * @param {object|undefined} target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
17
+ * @returns {Array} Final payload tagged with their targeting browser app. The value of `payload` can be undefined if there are no pending events for an app. This should be a minimum length of 1.
17
18
  */
18
- makeHarvestPayload(shouldRetryOnFail?: boolean, opts?: {}): {
19
- body: any;
20
- } | undefined;
19
+ makeHarvestPayload(shouldRetryOnFail: boolean | undefined, target: object | undefined): any[];
21
20
  /**
22
21
  * Cleanup task after a harvest.
23
- * @param {Boolean} harvestFailed - harvester flag to restore events in main buffer for retry later if request failed
22
+ * @param {object} result - the cbResult object from the harvester's send method
24
23
  */
25
- postHarvestCleanup(harvestFailed?: boolean, opts?: {}): void;
24
+ postHarvestCleanup(result?: object): void;
26
25
  /**
27
26
  * Checks for additional `jsAttributes` items to support backward compatibility with implementations of the agent where
28
27
  * loader configurations may appear after the loader code is executed.
29
28
  */
30
29
  checkConfiguration(existingAgent: any): void;
30
+ /**
31
+ * These are actions related to shared resources that should be initialized once by whichever feature Aggregate subclass loads first.
32
+ * This method should run after checkConfiguration, which may reset the agent's info/runtime object that is used here.
33
+ */
34
+ doOnceForAllAggregate(agentRef: any): void;
35
+ obfuscator: any;
31
36
  }
32
37
  import { FeatureBase } from './feature-base';
33
38
  //# sourceMappingURL=aggregate-base.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"AAUA;IAGI,cAAwB;IAEwD,YAAuC;IAIvH,gBAA6C;IAG/C;;;;OAIG;IACH,yBAHW,MAAM,EAAE,gBAwBlB;IAED,cAGC;IADC,6BAAmB;IAGrB;;;;OAIG;IACH;;kBAiBC;IAED;;;OAGG;IACH,6DAGC;IAED;;;OAGG;IACH,6CA0BC;CACF;4BAvH2B,gBAAgB"}
1
+ {"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"AAWA;IAGI,cAAwB;IAcpB,YAAuC;IAM3C,gBAAqB;IAGvB;;;;OAIG;IACH,yBAHW,MAAM,EAAE,gBAwBlB;IAED,cAGC;IADC,6BAAmB;IAGrB;;;;;OAKG;IACH,mEAHW,MAAM,GAAC,SAAS,SAwB1B;IAED;;;OAGG;IACH,4BAFW,MAAM,QAMhB;IAED;;;OAGG;IACH,6CAsBC;IAED;;;OAGG;IACH,2CASC;IAPC,gBAA6C;CAQhD;4BAvJ2B,gBAAgB"}
@@ -20,9 +20,8 @@ export class EventBuffer {
20
20
  clear(): void;
21
21
  /**
22
22
  * Backup the buffered data and clear the main buffer
23
- * @returns {Array} the events being backed up
24
23
  */
25
- save(): any[];
24
+ save(): void;
26
25
  /**
27
26
  * Wipes the backup buffer
28
27
  */
@@ -1 +1 @@
1
- {"version":3,"file":"event-buffer.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/event-buffer.js"],"names":[],"mappings":"AAGA;IAME;;OAEG;IACH,6BAFW,MAAM,EAIhB;IADC,uBAAoC;IAGtC,mBAEC;IAED,aAEC;IAED,mBAEC;IAED,+CAEC;IAED;;;;OAIG;IACH,WAHW,GAAG,WASb;IAED;;OAEG;IACH,cAGC;IAED;;;OAGG;IACH,cAGC;IAED;;OAEG;IACH,kBAGC;IAED;;OAEG;IACH,mBAKC;;CACF"}
1
+ {"version":3,"file":"event-buffer.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/event-buffer.js"],"names":[],"mappings":"AAGA;IAME;;OAEG;IACH,6BAFW,MAAM,EAIhB;IADC,uBAAoC;IAGtC,mBAEC;IAED,aAEC;IAED,mBAEC;IAED,+CAEC;IAED;;;;OAIG;IACH,WAHW,GAAG,WASb;IAED;;OAEG;IACH,cAGC;IAED;;OAEG;IACH,aAGC;IAED;;OAEG;IACH,kBAGC;IAED;;OAEG;IACH,mBAKC;;CACF"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * This layer allows multiple browser entity apps, or "target", to each have their own segregated storage instance.
3
+ * The purpose is so the harvester can send data to different apps within the same agent. Each feature should have a manager if it needs this capability.
4
+ */
5
+ export class EventStoreManager {
6
+ /**
7
+ * @param {object} defaultTarget - should contain licenseKey and appId of the main app from NREUM.info at startup
8
+ * @param {1|2} storageChoice - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
9
+ */
10
+ constructor(defaultTarget: object, storageChoice: 1 | 2);
11
+ mainApp: object;
12
+ StorageClass: typeof EventAggregator | typeof EventBuffer;
13
+ appStorageMap: Map<any, any>;
14
+ /**
15
+ * @param {object} optsIfPresent - exists if called during harvest interval, @see AggregateBase.makeHarvestPayload
16
+ * @param {object} target - specific app's storage to check; if not provided, this method takes into account all apps recorded by this manager
17
+ * @returns {boolean} True if the target's storage is empty, or target does not exist in map (defaults to all storages)
18
+ */
19
+ isEmpty(optsIfPresent: object, target: object): boolean;
20
+ /**
21
+ * @param {string} event - the event element to store
22
+ * @param {object} target - the app to store event under; if not provided, this method adds to the main app from NREUM.info
23
+ * @returns {boolean} True if the event was successfully added
24
+ */
25
+ add(event: string, target: object): boolean;
26
+ /** This is only used by the Metrics feature which has no need to add metric under a different app atm. */
27
+ addMetric(type: any, name: any, params: any, value: any): any;
28
+ /**
29
+ * @param {object} optsIfPresent - exists if called during harvest interval, @see AggregateBase.makeHarvestPayload
30
+ * @param {object} target - specific app to fetch; if not provided, this method fetches from all apps
31
+ * @returns {Array} Objects of `data` labeled with their respective `target` app to be sent to
32
+ */
33
+ get(optsIfPresent: object, target: object): any[];
34
+ byteSize(target: any): any;
35
+ wouldExceedMaxSize(incomingSize: any, target: any): any;
36
+ save(optsIfPresent: any, target: any): any;
37
+ clear(optsIfPresent: any, target: any): any;
38
+ reloadSave(optsIfPresent: any, target: any): any;
39
+ clearSave(optsIfPresent: any, target: any): any;
40
+ }
41
+ import { EventAggregator } from '../../common/aggregate/event-aggregator';
42
+ import { EventBuffer } from './event-buffer';
43
+ //# sourceMappingURL=event-store-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store-manager.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/event-store-manager.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH;IACE;;;OAGG;IACH,2BAHW,MAAM,iBACN,CAAC,GAAC,CAAC,EAOb;IAJC,gBAA4B;IAC5B,0DAAuE;IACvE,6BAA8B;IAMhC;;;;OAIG;IACH,uBAJW,MAAM,UACN,MAAM,GACJ,OAAO,CAWnB;IAED;;;;OAIG;IACH,WAJW,MAAM,UACN,MAAM,GACJ,OAAO,CAKnB;IAED,0GAA0G;IAC1G,8DAEC;IAED;;;;OAIG;IACH,mBAJW,MAAM,UACN,MAAM,SAUhB;IAED,2BAEC;IAED,wDAEC;IAED,2CAGC;IAED,4CAGC;IAGD,iDAMC;IAED,gDAMC;CACF;gCApG+B,yCAAyC;4BAC7C,gBAAgB"}
@@ -23,7 +23,6 @@ export class InstrumentBase extends FeatureBase {
23
23
  /**
24
24
  * @type {Promise} Assigned immediately after @see importAggregator runs. Serves as a signal for when the inner async fn finishes execution. Useful for features to await
25
25
  * one another if there are inter-features dependencies.
26
- * TODO: This is only used for the SPA feature component tests and should be refactored out.
27
26
  */
28
27
  onAggregateImported: Promise<any>;
29
28
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"instrument-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/instrument-base.js"],"names":[],"mappings":"AAgBA;;;GAGG;AACH;IACE;;;;;;;OAOG;IACH,wCALW,MAAM,8BAsChB;IA/BC,cAAgB;IAEhB,8IAA8I;IAC9I,cADW,WAAW,SAAS,CACF;IAE7B;;;MAGE;IACF,eAHU,OAAO,kBAAkB,EAAE,aAAa,CAGpB;IAE9B;;;;MAIE;IACF,kCAAoC;IAiBtC;;;;;;OAMG;IACH,kFAwDC;;CAkBF;4BA1I2B,gBAAgB"}
1
+ {"version":3,"file":"instrument-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/instrument-base.js"],"names":[],"mappings":"AAgBA;;;GAGG;AACH;IACE;;;;;;;OAOG;IACH,wCALW,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;;;;;;OAMG;IACH,kFAmDC;;CAkBF;4BApI2B,gBAAgB"}
@@ -9,6 +9,7 @@ export function setAPI(agentIdentifier: any, forceDrain: any, runSoftNavOverSpa?
9
9
  level?: string | undefined;
10
10
  }): void;
11
11
  addPageAction: (...args: any[]) => any;
12
+ recordCustomEvent: (...args: any[]) => any;
12
13
  setPageViewName(name: any, host: any): any;
13
14
  setCustomAttribute(name: any, value: any, persistAttribute?: boolean): any;
14
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"AAuBA,2CAiBC;AAID;;;;;;;;;;;;IAiEE;;;;OAIG;qBAFQ,MAAM;IAWjB;;;;OAIG;iCAFQ,MAAM,GAAC,IAAI;;;;;EAiGvB"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"AAuBA,2CAiBC;AAID;;;;;;;;;;;;;IAmEE;;;;OAIG;qBAFQ,MAAM;IAWjB;;;;OAIG;iCAFQ,MAAM,GAAC,IAAI;;;;;EAiGvB"}
@@ -1,16 +1,19 @@
1
+ export const EVENTS: "events";
2
+ export const JSERRORS: "jserrors";
3
+ export const RUM: "rum";
1
4
  export namespace FEATURE_NAMES {
2
- let ajax: string;
3
- let genericEvents: string;
4
- let jserrors: string;
5
- let logging: string;
6
- let metrics: string;
7
- let pageAction: string;
8
- let pageViewEvent: string;
9
- let pageViewTiming: string;
10
- let sessionReplay: string;
11
- let sessionTrace: string;
12
- let softNav: string;
13
- let spa: string;
5
+ export let ajax: string;
6
+ export let genericEvents: string;
7
+ export { JSERRORS as jserrors };
8
+ export let logging: string;
9
+ export let metrics: string;
10
+ export let pageAction: string;
11
+ export let pageViewEvent: string;
12
+ export let pageViewTiming: string;
13
+ export let sessionReplay: string;
14
+ export let sessionTrace: string;
15
+ export let softNav: string;
16
+ export let spa: string;
14
17
  }
15
18
  /**
16
19
  * The order in which features will be instrumented. This is the traditional order. It's unclear if the order of
@@ -1 +1 @@
1
- {"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../../../src/loaders/features/features.js"],"names":[],"mappings":";;;;;;;;;;;;;;AAkBA;;;GAGG;AACH;;EAYC;AAED;;EAWC"}
1
+ {"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../../../src/loaders/features/features.js"],"names":[],"mappings":"AACA,8BAA8B;AAC9B,kCAAkC;AAElC,wBAAwB;;;;;;;;;;;;;;;AAoBxB;;;GAGG;AACH;;EAYC;AAED;;EAYC"}
@@ -8,6 +8,13 @@ export class MicroAgentBase {
8
8
  * @param {object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}. The key is reported as its own PageAction attribute with the specified values.
9
9
  */
10
10
  addPageAction(name: string, attributes?: object | undefined): any;
11
+ /**
12
+ * Records a custom event with a specified eventType and attributes.
13
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/recordCustomEvent/}
14
+ * @param {string} eventType The eventType to store the event as.
15
+ * @param {object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}.
16
+ */
17
+ recordCustomEvent(eventType: string, attributes?: object | undefined): any;
11
18
  /**
12
19
  * Groups page views to help URL structure or to capture the URL's routing information.
13
20
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setpageviewname/}
@@ -1 +1 @@
1
- {"version":3,"file":"micro-agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent-base.js"],"names":[],"mappings":"AAGA;IAGE,sCAEC;IAJD,wBAAe;IAkBf;;;;;OAKG;IACH,oBAHW,MAAM,wCAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,kCAKhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,GAAC,IAAI,sCAKpC;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,0BAFW,CAAC,KAAK,EAAE,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,OAI9D;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,OAIhB;IAED;;;;;MAKE;IACF,aAHW,MAAM;2BACc,MAAM;gBAAU,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM;wBAInF;;CACF"}
1
+ {"version":3,"file":"micro-agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent-base.js"],"names":[],"mappings":"AAGA;IAGE,sCAEC;IAJD,wBAAe;IAkBf;;;;;OAKG;IACH,oBAHW,MAAM,wCAKhB;IAED;;;;;OAKG;IACH,6BAHW,MAAM,wCAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,kCAKhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,GAAC,IAAI,sCAKpC;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,0BAFW,CAAC,KAAK,EAAE,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,OAI9D;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,OAIhB;IAED;;;;;MAKE;IACF,aAHW,MAAM;2BACc,MAAM;gBAAU,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM;wBAInF;;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"micro-agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent.js"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH;IACE;;;OAGG;IACH,qBAHW,MAAM,oBACN,MAAM,YAAC,EAqDjB;IAhDC,aAAkB;IAMlB;;;;OAIG;IACH,iEAkCC;IAKH;;;;;MAOC;CACF;+BAhF8B,oBAAoB"}
1
+ {"version":3,"file":"micro-agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent.js"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH;IACE;;;OAGG;IACH,qBAHW,MAAM,oBACN,MAAM,YAAC,EAsDjB;IAjDC,aAAkB;IAMlB;;;;OAIG;IACH,iEAmCC;IAKH;;;;;MAOC;CACF;+BAjF8B,oBAAoB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.276.0",
3
+ "version": "1.278.0",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -228,9 +228,9 @@
228
228
  "@newrelic/nr-querypack": "https://git@github.com/newrelic/nr-querypack",
229
229
  "@wdio/cli": "^8.27.0",
230
230
  "@wdio/local-runner": "^8.27.0",
231
- "@wdio/logger": "^8.24.12",
231
+ "@wdio/logger": "^9.4.4",
232
232
  "@wdio/mocha-framework": "^8.27.0",
233
- "@wdio/spec-reporter": "^8.27.0",
233
+ "@wdio/spec-reporter": "^9.5.0",
234
234
  "babel-jest": "^29.7.0",
235
235
  "babel-loader": "^9.1.3",
236
236
  "babel-plugin-transform-inline-environment-variables": "^0.4.4",
@@ -243,7 +243,7 @@
243
243
  "eslint-plugin-promise": "^6.1.1",
244
244
  "eslint-plugin-sonarjs": "^0.23.0",
245
245
  "fastify": "^4.25.2",
246
- "fastify-plugin": "^4.5.1",
246
+ "fastify-plugin": "^5.0.1",
247
247
  "form-data": "^4.0.0",
248
248
  "fs-extra": "^11.2.0",
249
249
  "glob": "^11.0.0",
@@ -256,7 +256,7 @@
256
256
  "jest": "^29.7.0",
257
257
  "jest-environment-jsdom": "29.7.0",
258
258
  "jest-extended": "^4.0.2",
259
- "jsonpath-plus": "^9.0.0",
259
+ "jsonpath-plus": "^10.0.7",
260
260
  "jung": "^2.1.0",
261
261
  "node-fetch": "^3.3.2",
262
262
  "npm-run-all": "^4.1.5",
@@ -264,7 +264,7 @@
264
264
  "terser-webpack-plugin": "^5.3.10",
265
265
  "tsd": "^0.30.0",
266
266
  "typescript": "^5.3.3",
267
- "uuid": "^10.0.0",
267
+ "uuid": "^11.0.3",
268
268
  "wait-on": "^8.0.0",
269
269
  "wdio-lambdatest-service": "^3.0.1",
270
270
  "webpack": "^5.89.0",
@@ -13,7 +13,7 @@ export class EventAggregator {
13
13
  return aggregatorTypes.every(type => !this.#aggregator.aggregatedData[type]) // no bucket exist for any of the types we're looking for
14
14
  }
15
15
 
16
- add (type, name, params, newMetrics, customParams) {
16
+ add ([type, name, params, newMetrics, customParams]) {
17
17
  // Do we need to track byte size here like EventBuffer?
18
18
  this.#aggregator.store(type, name, params, newMetrics, customParams)
19
19
  return true
@@ -39,7 +39,7 @@ const model = () => {
39
39
  }
40
40
  }
41
41
  return {
42
- ajax: { deny_list: undefined, block_internal: true, enabled: true, harvestTimeSeconds: 10, autoStart: true },
42
+ ajax: { deny_list: undefined, block_internal: true, enabled: true, autoStart: true },
43
43
  distributed_tracing: {
44
44
  enabled: undefined,
45
45
  exclude_newrelic_header: undefined,
@@ -49,15 +49,15 @@ const model = () => {
49
49
  },
50
50
  get feature_flags () { return hiddenState.feature_flags },
51
51
  set feature_flags (val) { hiddenState.feature_flags = val },
52
- generic_events: { enabled: true, harvestTimeSeconds: 30, autoStart: true },
53
- harvest: { tooManyRequestsDelay: 60 },
54
- jserrors: { enabled: true, harvestTimeSeconds: 10, autoStart: true },
55
- logging: { enabled: true, harvestTimeSeconds: 10, autoStart: true, level: LOG_LEVELS.INFO },
52
+ generic_events: { enabled: true, autoStart: true },
53
+ harvest: { interval: 30 },
54
+ jserrors: { enabled: true, autoStart: true },
55
+ logging: { enabled: true, autoStart: true, level: LOG_LEVELS.INFO },
56
56
  metrics: { enabled: true, autoStart: true },
57
57
  obfuscate: undefined,
58
58
  page_action: { enabled: true },
59
59
  page_view_event: { enabled: true, autoStart: true },
60
- page_view_timing: { enabled: true, harvestTimeSeconds: 30, autoStart: true },
60
+ page_view_timing: { enabled: true, autoStart: true },
61
61
  performance: {
62
62
  get capture_marks () { return hiddenState.feature_flags.includes(FEATURE_FLAGS.MARKS) || hiddenState.experimental.marks },
63
63
  set capture_marks (val) { hiddenState.experimental.marks = val },
@@ -85,7 +85,6 @@ const model = () => {
85
85
  // feature settings
86
86
  autoStart: true,
87
87
  enabled: false,
88
- harvestTimeSeconds: 60,
89
88
  preload: false, // if true, enables the agent to load rrweb immediately instead of waiting to do so after the window.load event
90
89
  sampling_rate: 10, // float from 0 - 100
91
90
  error_sampling_rate: 100, // float from 0 - 100
@@ -123,9 +122,9 @@ const model = () => {
123
122
  else warn(7, val)
124
123
  }
125
124
  },
126
- session_trace: { enabled: true, harvestTimeSeconds: 10, autoStart: true },
127
- soft_navigations: { enabled: true, harvestTimeSeconds: 10, autoStart: true },
128
- spa: { enabled: true, harvestTimeSeconds: 10, autoStart: true },
125
+ session_trace: { enabled: true, autoStart: true },
126
+ soft_navigations: { enabled: true, autoStart: true },
127
+ spa: { enabled: true, autoStart: true },
129
128
  ssl: undefined,
130
129
  user_actions: { enabled: true }
131
130
  }
@@ -30,7 +30,8 @@ const model = {
30
30
  session: undefined,
31
31
  denyList: undefined,
32
32
  timeKeeper: undefined,
33
- obfuscator: undefined
33
+ obfuscator: undefined,
34
+ harvester: undefined
34
35
  }
35
36
 
36
37
  const _cache = {}
@@ -0,0 +1,6 @@
1
+ // create a jest mock of the Harvester class
2
+ export const Harvester = jest.fn().mockImplementation(() => ({
3
+ startTimer: jest.fn(),
4
+ triggerHarvestFor: jest.fn(),
5
+ initializedAggregates: []
6
+ }))
@@ -0,0 +1,230 @@
1
+ import { FEATURE_TO_ENDPOINT, JSERRORS, RUM, EVENTS } from '../../loaders/features/features'
2
+ import { VERSION } from '../constants/env'
3
+ import { globalScope, isWorkerScope } from '../constants/runtime'
4
+ import { eventListenerOpts } from '../event-listener/event-listener-opts'
5
+ import { SESSION_EVENTS } from '../session/constants'
6
+ import { now } from '../timing/now'
7
+ import { subscribeToEOL } from '../unload/eol'
8
+ import { cleanURL } from '../url/clean-url'
9
+ import { obj, param } from '../url/encode'
10
+ import { warn } from '../util/console'
11
+ import { stringify } from '../util/stringify'
12
+ import { getSubmitMethod, xhr as xhrMethod, xhrFetch as fetchMethod } from '../util/submit-data'
13
+
14
+ export class Harvester {
15
+ #started = false
16
+ initializedAggregates = []
17
+
18
+ constructor (agentRef) {
19
+ this.agentRef = agentRef
20
+
21
+ subscribeToEOL(() => { // do one last harvest round or check
22
+ this.initializedAggregates.forEach(aggregateInst => { // let all features wrap up things needed to do before ANY harvest in case there's last minute cross-feature data dependencies
23
+ if (typeof aggregateInst.harvestOpts.beforeUnload === 'function') aggregateInst.harvestOpts.beforeUnload()
24
+ })
25
+ this.initializedAggregates.forEach(aggregateInst => this.triggerHarvestFor(aggregateInst, { isFinalHarvest: true }))
26
+ /* This callback should run in bubble phase, so that that CWV api, like "onLCP", is called before the final harvest so that emitted timings are part of last outgoing. */
27
+ }, false)
28
+
29
+ /* Flush all buffered data if session resets and give up retries. This should be synchronous to ensure that the correct `session` value is sent.
30
+ Since session-reset generates a new session ID and the ID is grabbed at send-time, any delays or retries would cause the payload to be sent under the wrong session ID. */
31
+ agentRef.ee.on(SESSION_EVENTS.RESET, () => this.initializedAggregates.forEach(aggregateInst => this.triggerHarvestFor(aggregateInst, { forceNoRetry: true })))
32
+ }
33
+
34
+ startTimer (harvestInterval = this.agentRef.init.harvest.interval) {
35
+ if (this.#started) return
36
+ this.#started = true
37
+
38
+ const onHarvestInterval = () => {
39
+ this.initializedAggregates.forEach(aggregateInst => this.triggerHarvestFor(aggregateInst))
40
+ setTimeout(onHarvestInterval, harvestInterval * 1000) // repeat in X seconds
41
+ }
42
+ setTimeout(onHarvestInterval, harvestInterval * 1000)
43
+ }
44
+
45
+ /**
46
+ * Given a feature (aggregate), execute a harvest on-demand.
47
+ * @param {object} aggregateInst
48
+ * @param {object} localOpts
49
+ * @returns {boolean} True if 1+ network call was made. Note that this does not mean or guarantee that it was successful (or that all were in the case of more than 1).
50
+ */
51
+ triggerHarvestFor (aggregateInst, localOpts = {}) {
52
+ if (aggregateInst.blocked) return false
53
+
54
+ const submitMethod = getSubmitMethod(localOpts)
55
+ if (!submitMethod) return false
56
+
57
+ const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === xhrMethod // always retry all features harvests except for final
58
+ let dataToSendArr; let ranSend = false
59
+ if (!localOpts.directSend) { // primarily used by rum call to bypass makeHarvestPayload by providing payload directly
60
+ dataToSendArr = aggregateInst.makeHarvestPayload(shouldRetryOnFail) // be sure the 'this' of makeHarvestPayload is the aggregate w/ access to its harvestOpts
61
+ if (!dataToSendArr) return false // can be undefined if storage is empty or preharvest checks failed
62
+ } else dataToSendArr = [localOpts.directSend]
63
+
64
+ dataToSendArr.forEach(({ targetApp, payload }) => {
65
+ if (!payload) return
66
+
67
+ send(this.agentRef, {
68
+ endpoint: FEATURE_TO_ENDPOINT[aggregateInst.featureName],
69
+ targetApp,
70
+ payload,
71
+ localOpts,
72
+ submitMethod,
73
+ cbFinished,
74
+ raw: aggregateInst.harvestOpts.raw
75
+ })
76
+ ranSend = true
77
+ })
78
+ return ranSend
79
+
80
+ /**
81
+ * 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.
82
+ * @param {Object} result - information regarding the result of the harvest attempt
83
+ */
84
+ function cbFinished (result) {
85
+ if (localOpts.forceNoRetry) result.retry = false // discard unsent data rather than re-queuing for next harvest attempt
86
+ aggregateInst.postHarvestCleanup(result)
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * @typedef {import('./types.js').NetworkSendSpec} NetworkSendSpec
93
+ */
94
+
95
+ const warnings = {}
96
+ /**
97
+ * Initiate a harvest call.
98
+ * @param {NetworkSendSpec} param0 Specification for sending data
99
+ * @returns {boolean} True if a network call was made. Note that this does not mean or guarantee that it was successful.
100
+ */
101
+ function send (agentRef, { endpoint, targetApp, payload, localOpts = {}, submitMethod, cbFinished, raw }) {
102
+ if (!agentRef.info.errorBeacon) return false
103
+
104
+ let { body, qs } = cleanPayload(payload)
105
+
106
+ if (Object.keys(body).length === 0 && !localOpts.sendEmptyBody) { // if there's no body to send, just run onfinish stuff and return
107
+ if (cbFinished) cbFinished({ sent: false, targetApp })
108
+ return false
109
+ }
110
+
111
+ const protocol = agentRef.init.ssl === false ? 'http' : 'https'
112
+ const perceivedBeacon = agentRef.init.proxy.beacon || agentRef.info.errorBeacon
113
+ const url = raw
114
+ ? `${protocol}://${perceivedBeacon}/${endpoint}`
115
+ : `${protocol}://${perceivedBeacon}${endpoint !== RUM ? '/' + endpoint : ''}/1/${targetApp.licenseKey}`
116
+ const baseParams = !raw ? baseQueryString(agentRef, qs, endpoint, targetApp.appId) : ''
117
+ let payloadParams = obj(qs, agentRef.runtime.maxBytes)
118
+ if (baseParams === '' && payloadParams.startsWith('&')) {
119
+ payloadParams = payloadParams.substring(1)
120
+ }
121
+
122
+ const fullUrl = `${url}?${baseParams}${payloadParams}`
123
+ const gzip = !!qs?.attributes?.includes('gzip')
124
+ if (!gzip) {
125
+ if (endpoint !== EVENTS) body = stringify(body) // all features going to 'events' endpoint should already be serialized & stringified
126
+ // Warn--once per endpoint--if the agent tries to send large payloads
127
+ if (body.length > 750000 && (warnings[endpoint] = (warnings[endpoint] || 0) + 1) === 1) warn(28, endpoint)
128
+ }
129
+
130
+ // If body is null, undefined, or an empty object or array after stringifying, send an empty string instead.
131
+ if (!body || body.length === 0 || body === '{}' || body === '[]') body = ''
132
+
133
+ const headers = [{ key: 'content-type', value: 'text/plain' }]
134
+
135
+ /* Since workers don't support sendBeacon right now, they can only use XHR method.
136
+ Because they still do permit synch XHR, the idea is that at final harvest time (worker is closing),
137
+ we just make a BLOCKING request--trivial impact--with the remaining data as a temp fill-in for sendBeacon.
138
+ Following the removal of img-element method. */
139
+ let result = submitMethod({ url: fullUrl, body, sync: localOpts.isFinalHarvest && isWorkerScope, headers })
140
+
141
+ if (!localOpts.isFinalHarvest && cbFinished) { // final harvests don't hold onto buffer data (shouldRetryOnFail is false), so cleanup isn't needed
142
+ if (submitMethod === xhrMethod) {
143
+ result.addEventListener('loadend', function () {
144
+ // `this` here in block refers to the XHR object in this scope, do not change the anon function to an arrow function
145
+ // status 0 refers to a local error, such as CORS or network failure, or a blocked request by the browser (e.g. adblocker)
146
+ const cbResult = { sent: this.status !== 0, status: this.status, retry: shouldRetry(this.status), xhr: this, fullUrl, targetApp }
147
+ if (localOpts.needResponse) cbResult.responseText = this.responseText
148
+ cbFinished(cbResult)
149
+ }, eventListenerOpts(false))
150
+ } else if (submitMethod === fetchMethod) {
151
+ result.then(async function (response) {
152
+ const status = response.status
153
+ const cbResult = { sent: true, status, retry: shouldRetry(status), fullUrl, fetchResponse: response, targetApp }
154
+ if (localOpts.needResponse) cbResult.responseText = await response.text()
155
+ cbFinished(cbResult)
156
+ })
157
+ }
158
+ }
159
+ return true
160
+
161
+ function shouldRetry (status) {
162
+ switch (status) {
163
+ case 429:
164
+ case 408:
165
+ case 500:
166
+ case 503:
167
+ return true
168
+ default:
169
+ return false
170
+ }
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Cleans and returns a payload object containing a body and qs
176
+ * object with key/value pairs. KV pairs where the value is null,
177
+ * undefined, or an empty string are removed to save on transmission
178
+ * size.
179
+ * @param {HarvestPayload} payload Payload to be sent to the endpoint.
180
+ * @returns {HarvestPayload} Cleaned payload payload to be sent to the endpoint.
181
+ */
182
+ function cleanPayload (payload = {}) {
183
+ const clean = (input) => {
184
+ if ((typeof Uint8Array !== 'undefined' && input instanceof Uint8Array) || Array.isArray(input)) return input
185
+ if (typeof input === 'string') return input.length > 0 ? input : null
186
+ return Object.entries(input || {}).reduce((accumulator, [key, value]) => {
187
+ if ((typeof value === 'number') ||
188
+ (typeof value === 'string' && value.length > 0) ||
189
+ (typeof value === 'object' && Object.keys(value || {}).length > 0)
190
+ ) {
191
+ accumulator[key] = value
192
+ }
193
+ return accumulator
194
+ }, {})
195
+ }
196
+
197
+ return {
198
+ body: clean(payload.body),
199
+ qs: clean(payload.qs)
200
+ }
201
+ }
202
+
203
+ // The stuff that gets sent every time.
204
+ function baseQueryString (agentRef, qs, endpoint, applicationID) {
205
+ const ref = agentRef.runtime.obfuscator.obfuscateString(cleanURL('' + globalScope.location))
206
+ const hr = agentRef.runtime.session?.state.sessionReplayMode === 1 && endpoint !== JSERRORS
207
+
208
+ const qps = [
209
+ 'a=' + applicationID,
210
+ param('sa', (agentRef.info.sa ? '' + agentRef.info.sa : '')),
211
+ param('v', VERSION),
212
+ transactionNameParam(),
213
+ param('ct', agentRef.runtime.customTransaction),
214
+ '&rst=' + now(),
215
+ '&ck=0', // ck param DEPRECATED - still expected by backend
216
+ '&s=' + (agentRef.runtime.session?.state.value || '0'), // the 0 id encaps all untrackable and default traffic
217
+ param('ref', ref),
218
+ param('ptid', (agentRef.runtime.ptid ? '' + agentRef.runtime.ptid : ''))
219
+ ]
220
+ if (hr) qps.push(param('hr', '1', qs))
221
+ return qps.join('')
222
+
223
+ // Constructs the transaction name param for the beacon URL.
224
+ // Prefers the obfuscated transaction name over the plain text.
225
+ // Falls back to making up a name.
226
+ function transactionNameParam () {
227
+ if (agentRef.info.transactionName) return param('to', agentRef.info.transactionName)
228
+ return param('t', agentRef.info.tNamePlain || 'Unnamed Transaction')
229
+ }
230
+ }