@safaricom-mxl/web-sdk 0.0.7 → 0.0.9

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 (93) hide show
  1. package/dist/constants/attributes.cjs +2 -0
  2. package/dist/constants/attributes.cjs.map +1 -1
  3. package/dist/constants/attributes.d.cts +2 -1
  4. package/dist/constants/attributes.d.cts.map +1 -1
  5. package/dist/constants/attributes.d.ts +2 -1
  6. package/dist/constants/attributes.d.ts.map +1 -1
  7. package/dist/constants/attributes.js +2 -1
  8. package/dist/constants/attributes.js.map +1 -1
  9. package/dist/constants/index.cjs +1 -0
  10. package/dist/constants/index.d.cts +2 -2
  11. package/dist/constants/index.d.ts +2 -2
  12. package/dist/constants/index.js +2 -2
  13. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.cjs +12 -11
  14. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.cjs.map +1 -1
  15. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.d.cts.map +1 -1
  16. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.d.ts.map +1 -1
  17. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.js +12 -11
  18. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.js.map +1 -1
  19. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.cjs +2 -1
  20. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.cjs.map +1 -1
  21. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.d.cts.map +1 -1
  22. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.d.ts.map +1 -1
  23. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.js +2 -1
  24. package/dist/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.js.map +1 -1
  25. package/dist/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.cjs +1 -0
  26. package/dist/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.cjs.map +1 -1
  27. package/dist/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.d.cts.map +1 -1
  28. package/dist/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.d.ts.map +1 -1
  29. package/dist/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.js +2 -1
  30. package/dist/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.js.map +1 -1
  31. package/dist/mxl-web-sdk.js +1 -1
  32. package/dist/mxl-web-sdk.js.map +1 -1
  33. package/dist/processors/BrowserLogRecordProcessor/BrowserLogRecordProcessor.cjs +26 -0
  34. package/dist/processors/BrowserLogRecordProcessor/BrowserLogRecordProcessor.cjs.map +1 -0
  35. package/dist/processors/BrowserLogRecordProcessor/BrowserLogRecordProcessor.d.cts +19 -0
  36. package/dist/processors/BrowserLogRecordProcessor/BrowserLogRecordProcessor.d.cts.map +1 -0
  37. package/dist/processors/BrowserLogRecordProcessor/BrowserLogRecordProcessor.d.ts +19 -0
  38. package/dist/processors/BrowserLogRecordProcessor/BrowserLogRecordProcessor.d.ts.map +1 -0
  39. package/dist/processors/BrowserLogRecordProcessor/BrowserLogRecordProcessor.js +25 -0
  40. package/dist/processors/BrowserLogRecordProcessor/BrowserLogRecordProcessor.js.map +1 -0
  41. package/dist/processors/BrowserLogRecordProcessor/index.cjs +4 -0
  42. package/dist/processors/BrowserLogRecordProcessor/index.d.cts +2 -0
  43. package/dist/processors/BrowserLogRecordProcessor/index.d.ts +2 -0
  44. package/dist/processors/BrowserLogRecordProcessor/index.js +3 -0
  45. package/dist/processors/BrowserLogRecordProcessor/types.cjs +0 -0
  46. package/dist/processors/BrowserLogRecordProcessor/types.d.cts +9 -0
  47. package/dist/processors/BrowserLogRecordProcessor/types.d.cts.map +1 -0
  48. package/dist/processors/BrowserLogRecordProcessor/types.d.ts +9 -0
  49. package/dist/processors/BrowserLogRecordProcessor/types.d.ts.map +1 -0
  50. package/dist/processors/BrowserLogRecordProcessor/types.js +0 -0
  51. package/dist/processors/BrowserSpanProcessor/BrowserSpanProcessor.cjs +27 -0
  52. package/dist/processors/BrowserSpanProcessor/BrowserSpanProcessor.cjs.map +1 -0
  53. package/dist/processors/BrowserSpanProcessor/BrowserSpanProcessor.d.cts +20 -0
  54. package/dist/processors/BrowserSpanProcessor/BrowserSpanProcessor.d.cts.map +1 -0
  55. package/dist/processors/BrowserSpanProcessor/BrowserSpanProcessor.d.ts +20 -0
  56. package/dist/processors/BrowserSpanProcessor/BrowserSpanProcessor.d.ts.map +1 -0
  57. package/dist/processors/BrowserSpanProcessor/BrowserSpanProcessor.js +26 -0
  58. package/dist/processors/BrowserSpanProcessor/BrowserSpanProcessor.js.map +1 -0
  59. package/dist/processors/BrowserSpanProcessor/index.cjs +4 -0
  60. package/dist/processors/BrowserSpanProcessor/index.d.cts +2 -0
  61. package/dist/processors/BrowserSpanProcessor/index.d.ts +2 -0
  62. package/dist/processors/BrowserSpanProcessor/index.js +3 -0
  63. package/dist/processors/BrowserSpanProcessor/types.cjs +0 -0
  64. package/dist/processors/BrowserSpanProcessor/types.d.cts +9 -0
  65. package/dist/processors/BrowserSpanProcessor/types.d.cts.map +1 -0
  66. package/dist/processors/BrowserSpanProcessor/types.d.ts +9 -0
  67. package/dist/processors/BrowserSpanProcessor/types.d.ts.map +1 -0
  68. package/dist/processors/BrowserSpanProcessor/types.js +0 -0
  69. package/dist/processors/index.cjs +4 -0
  70. package/dist/processors/index.d.cts +3 -1
  71. package/dist/processors/index.d.ts +5 -1
  72. package/dist/processors/index.js +3 -1
  73. package/dist/resources/constants/index.cjs +1 -1
  74. package/dist/resources/constants/index.cjs.map +1 -1
  75. package/dist/resources/constants/index.d.cts +1 -1
  76. package/dist/resources/constants/index.d.ts +1 -1
  77. package/dist/resources/constants/index.js +1 -1
  78. package/dist/resources/constants/index.js.map +1 -1
  79. package/dist/sdk/initSDK.cjs +13 -55
  80. package/dist/sdk/initSDK.cjs.map +1 -1
  81. package/dist/sdk/initSDK.d.cts.map +1 -1
  82. package/dist/sdk/initSDK.d.ts.map +1 -1
  83. package/dist/sdk/initSDK.js +13 -55
  84. package/dist/sdk/initSDK.js.map +1 -1
  85. package/dist/transport/FetchTransport/FetchTransport.cjs +60 -10
  86. package/dist/transport/FetchTransport/FetchTransport.cjs.map +1 -1
  87. package/dist/transport/FetchTransport/FetchTransport.d.cts +3 -1
  88. package/dist/transport/FetchTransport/FetchTransport.d.cts.map +1 -1
  89. package/dist/transport/FetchTransport/FetchTransport.d.ts +3 -1
  90. package/dist/transport/FetchTransport/FetchTransport.d.ts.map +1 -1
  91. package/dist/transport/FetchTransport/FetchTransport.js +60 -11
  92. package/dist/transport/FetchTransport/FetchTransport.js.map +1 -1
  93. package/package.json +1 -1
@@ -26,6 +26,7 @@ const KEY_MXL_JS_FILE_BUNDLE_IDS = "mxl.js_file_bundle_ids";
26
26
  const KEY_MXL_W3C_TRACEPARENT = "mxl.w3c_traceparent";
27
27
  const KEY_MXL_NAVIGATION_SOURCE = "mxl.navigation_source";
28
28
  const KEY_MXL_REFERRER_URL = "mxl.referrer_url";
29
+ const KEY_BROWSER_URL_FULL = "browser.url.full";
29
30
  const KEY_MXL_MAX_PENDING_SPANS_REACHED = "mxl.max_pending_spans_reached";
30
31
  const KEY_MXL_PAGE_PATH = "app.surface.name";
31
32
  const KEY_MXL_PAGE_ID = "app.surface.id";
@@ -61,6 +62,7 @@ let MXL_ERROR_INSTRUMENTATIONS = /* @__PURE__ */ function(MXL_ERROR_INSTRUMENTAT
61
62
 
62
63
  //#endregion
63
64
  exports.KEY_APP_SURFACE_LABEL = KEY_APP_SURFACE_LABEL;
65
+ exports.KEY_BROWSER_URL_FULL = KEY_BROWSER_URL_FULL;
64
66
  exports.KEY_MXL_APP_INSTANCE_ID = KEY_MXL_APP_INSTANCE_ID;
65
67
  exports.KEY_MXL_COLD_START = KEY_MXL_COLD_START;
66
68
  exports.KEY_MXL_ERROR_CODE = KEY_MXL_ERROR_CODE;
@@ -1 +1 @@
1
- {"version":3,"file":"attributes.cjs","names":[],"sources":["../../src/constants/attributes.ts"],"sourcesContent":["export const KEY_MXL_TYPE = 'mxl.type';\nexport const KEY_MXL_STATE = 'mxl.state';\nexport const KEY_MXL_COLD_START = 'mxl.cold_start';\nexport const KEY_MXL_SESSION_NUMBER = 'mxl.session_number';\nexport const KEY_MXL_EXCEPTION_NUMBER = 'mxl.exception_number';\nexport const KEY_MXL_SDK_STARTUP_DURATION = 'mxl.sdk_startup_duration';\nexport const KEY_PREFIX_MXL_PROPERTIES = 'mxl.properties.';\nexport const KEY_MXL_SESSION_REASON_ENDED = 'mxl.session_end_type';\nexport const KEY_MXL_SESSION_REASON_STARTED = 'mxl.session_start_type';\nexport const KEY_MXL_JS_EXCEPTION_STACKTRACE = 'mxl.stacktrace.js';\nexport const KEY_MXL_EXCEPTION_HANDLING = 'mxl.exception_handling';\nexport const KEY_MXL_EXCEPTION_CAUSE = 'mxl.exception_cause';\nexport const KEY_MXL_ERROR_CODE = 'mxl.error_code';\nexport const KEY_MXL_APP_INSTANCE_ID = 'mxl.app_instance_id';\nexport const KEY_MXL_TAB_ID = 'mxl.tab_id';\nexport const KEY_MXL_SOURCE_TAB_ID = 'mxl.source_tab_id';\nexport const KEY_MXL_EXPERIENCE_ID = 'mxl.experience_id';\nexport const KEY_MXL_ERROR_LOG_COUNT = 'mxl.error_log_count';\nexport const KEY_MXL_INSTRUMENTATION = 'mxl.instrumentation';\nexport const KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT =\n 'mxl.unhandled_exceptions_count';\nexport const KEY_MXL_FROM_STORAGE = 'mxl.from_storage';\nexport const KEY_MXL_JS_FILE_BUNDLE_IDS = 'mxl.js_file_bundle_ids';\nexport const KEY_MXL_W3C_TRACEPARENT = 'mxl.w3c_traceparent';\nexport const KEY_MXL_NAVIGATION_SOURCE = 'mxl.navigation_source';\nexport const KEY_MXL_REFERRER_URL = 'mxl.referrer_url';\nexport const KEY_MXL_MAX_PENDING_SPANS_REACHED =\n 'mxl.max_pending_spans_reached';\n// In the backend we use 'app.surface.name' and 'app.surface.id' for the page name and id\n// to be consistent with mobile where we use 'app.surface.*' for screen names and ids\nexport const KEY_MXL_PAGE_PATH = 'app.surface.name';\nexport const KEY_MXL_PAGE_ID = 'app.surface.id';\nexport const KEY_APP_SURFACE_LABEL = 'app.surface.label';\n\nexport enum MXL_TYPES {\n Session = 'ux.session',\n Network = 'perf.network_request',\n Perf = 'perf',\n SystemLog = 'sys.log', // SystemLog is a log emb type that tells the MXL BE to treat this as an MXL Log to be shown in the dashboard.\n SystemException = 'sys.exception',\n WebVital = 'ux.web_vital',\n ResourceFetch = 'ux.resource_fetch',\n DocumentLoad = 'ux.document_load',\n Surface = 'ux.surface',\n}\n\nexport enum MXL_STATES {\n Foreground = 'foreground',\n Background = 'background',\n}\n\nexport enum MXL_NAVIGATION_INSTRUMENTATIONS {\n DeclarativeLegacy = 'react_router_declarative_legacy',\n Declarative = 'react_router_declarative',\n Data = 'react_router_data',\n Manual = 'manual',\n}\n\nexport enum MXL_ERROR_INSTRUMENTATIONS {\n ReactErrorBoundary = 'react_error_boundary',\n}\n\nexport type MXL_INSTRUMENTATIONS =\n | MXL_NAVIGATION_INSTRUMENTATIONS\n | MXL_ERROR_INSTRUMENTATIONS;\n"],"mappings":";;;AAAA,MAAa,eAAe;AAC5B,MAAa,gBAAgB;AAC7B,MAAa,qBAAqB;AAClC,MAAa,yBAAyB;AACtC,MAAa,2BAA2B;AACxC,MAAa,+BAA+B;AAC5C,MAAa,4BAA4B;AACzC,MAAa,+BAA+B;AAC5C,MAAa,iCAAiC;AAC9C,MAAa,kCAAkC;AAC/C,MAAa,6BAA6B;AAC1C,MAAa,0BAA0B;AACvC,MAAa,qBAAqB;AAClC,MAAa,0BAA0B;AACvC,MAAa,iBAAiB;AAC9B,MAAa,wBAAwB;AACrC,MAAa,wBAAwB;AACrC,MAAa,0BAA0B;AACvC,MAAa,0BAA0B;AACvC,MAAa,qCACX;AACF,MAAa,uBAAuB;AACpC,MAAa,6BAA6B;AAC1C,MAAa,0BAA0B;AACvC,MAAa,4BAA4B;AACzC,MAAa,uBAAuB;AACpC,MAAa,oCACX;AAGF,MAAa,oBAAoB;AACjC,MAAa,kBAAkB;AAC/B,MAAa,wBAAwB;AAErC,IAAY,gDAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGF,IAAY,kDAAL;AACL;AACA;;;AAGF,IAAY,4FAAL;AACL;AACA;AACA;AACA;;;AAGF,IAAY,kFAAL;AACL"}
1
+ {"version":3,"file":"attributes.cjs","names":[],"sources":["../../src/constants/attributes.ts"],"sourcesContent":["export const KEY_MXL_TYPE = 'mxl.type';\nexport const KEY_MXL_STATE = 'mxl.state';\nexport const KEY_MXL_COLD_START = 'mxl.cold_start';\nexport const KEY_MXL_SESSION_NUMBER = 'mxl.session_number';\nexport const KEY_MXL_EXCEPTION_NUMBER = 'mxl.exception_number';\nexport const KEY_MXL_SDK_STARTUP_DURATION = 'mxl.sdk_startup_duration';\nexport const KEY_PREFIX_MXL_PROPERTIES = 'mxl.properties.';\nexport const KEY_MXL_SESSION_REASON_ENDED = 'mxl.session_end_type';\nexport const KEY_MXL_SESSION_REASON_STARTED = 'mxl.session_start_type';\nexport const KEY_MXL_JS_EXCEPTION_STACKTRACE = 'mxl.stacktrace.js';\nexport const KEY_MXL_EXCEPTION_HANDLING = 'mxl.exception_handling';\nexport const KEY_MXL_EXCEPTION_CAUSE = 'mxl.exception_cause';\nexport const KEY_MXL_ERROR_CODE = 'mxl.error_code';\nexport const KEY_MXL_APP_INSTANCE_ID = 'mxl.app_instance_id';\nexport const KEY_MXL_TAB_ID = 'mxl.tab_id';\nexport const KEY_MXL_SOURCE_TAB_ID = 'mxl.source_tab_id';\nexport const KEY_MXL_EXPERIENCE_ID = 'mxl.experience_id';\nexport const KEY_MXL_ERROR_LOG_COUNT = 'mxl.error_log_count';\nexport const KEY_MXL_INSTRUMENTATION = 'mxl.instrumentation';\nexport const KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT =\n 'mxl.unhandled_exceptions_count';\nexport const KEY_MXL_FROM_STORAGE = 'mxl.from_storage';\nexport const KEY_MXL_JS_FILE_BUNDLE_IDS = 'mxl.js_file_bundle_ids';\nexport const KEY_MXL_W3C_TRACEPARENT = 'mxl.w3c_traceparent';\nexport const KEY_MXL_NAVIGATION_SOURCE = 'mxl.navigation_source';\nexport const KEY_MXL_REFERRER_URL = 'mxl.referrer_url';\nexport const KEY_BROWSER_URL_FULL = 'browser.url.full';\nexport const KEY_MXL_MAX_PENDING_SPANS_REACHED =\n 'mxl.max_pending_spans_reached';\n// In the backend we use 'app.surface.name' and 'app.surface.id' for the page name and id\n// to be consistent with mobile where we use 'app.surface.*' for screen names and ids\nexport const KEY_MXL_PAGE_PATH = 'app.surface.name';\nexport const KEY_MXL_PAGE_ID = 'app.surface.id';\nexport const KEY_APP_SURFACE_LABEL = 'app.surface.label';\n\nexport enum MXL_TYPES {\n Session = 'ux.session',\n Network = 'perf.network_request',\n Perf = 'perf',\n SystemLog = 'sys.log', // SystemLog is a log emb type that tells the MXL BE to treat this as an MXL Log to be shown in the dashboard.\n SystemException = 'sys.exception',\n WebVital = 'ux.web_vital',\n ResourceFetch = 'ux.resource_fetch',\n DocumentLoad = 'ux.document_load',\n Surface = 'ux.surface',\n}\n\nexport enum MXL_STATES {\n Foreground = 'foreground',\n Background = 'background',\n}\n\nexport enum MXL_NAVIGATION_INSTRUMENTATIONS {\n DeclarativeLegacy = 'react_router_declarative_legacy',\n Declarative = 'react_router_declarative',\n Data = 'react_router_data',\n Manual = 'manual',\n}\n\nexport enum MXL_ERROR_INSTRUMENTATIONS {\n ReactErrorBoundary = 'react_error_boundary',\n}\n\nexport type MXL_INSTRUMENTATIONS =\n | MXL_NAVIGATION_INSTRUMENTATIONS\n | MXL_ERROR_INSTRUMENTATIONS;\n"],"mappings":";;;AAAA,MAAa,eAAe;AAC5B,MAAa,gBAAgB;AAC7B,MAAa,qBAAqB;AAClC,MAAa,yBAAyB;AACtC,MAAa,2BAA2B;AACxC,MAAa,+BAA+B;AAC5C,MAAa,4BAA4B;AACzC,MAAa,+BAA+B;AAC5C,MAAa,iCAAiC;AAC9C,MAAa,kCAAkC;AAC/C,MAAa,6BAA6B;AAC1C,MAAa,0BAA0B;AACvC,MAAa,qBAAqB;AAClC,MAAa,0BAA0B;AACvC,MAAa,iBAAiB;AAC9B,MAAa,wBAAwB;AACrC,MAAa,wBAAwB;AACrC,MAAa,0BAA0B;AACvC,MAAa,0BAA0B;AACvC,MAAa,qCACX;AACF,MAAa,uBAAuB;AACpC,MAAa,6BAA6B;AAC1C,MAAa,0BAA0B;AACvC,MAAa,4BAA4B;AACzC,MAAa,uBAAuB;AACpC,MAAa,uBAAuB;AACpC,MAAa,oCACX;AAGF,MAAa,oBAAoB;AACjC,MAAa,kBAAkB;AAC/B,MAAa,wBAAwB;AAErC,IAAY,gDAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGF,IAAY,kDAAL;AACL;AACA;;;AAGF,IAAY,4FAAL;AACL;AACA;AACA;AACA;;;AAGF,IAAY,kFAAL;AACL"}
@@ -24,6 +24,7 @@ declare const KEY_MXL_JS_FILE_BUNDLE_IDS = "mxl.js_file_bundle_ids";
24
24
  declare const KEY_MXL_W3C_TRACEPARENT = "mxl.w3c_traceparent";
25
25
  declare const KEY_MXL_NAVIGATION_SOURCE = "mxl.navigation_source";
26
26
  declare const KEY_MXL_REFERRER_URL = "mxl.referrer_url";
27
+ declare const KEY_BROWSER_URL_FULL = "browser.url.full";
27
28
  declare const KEY_MXL_MAX_PENDING_SPANS_REACHED = "mxl.max_pending_spans_reached";
28
29
  declare const KEY_MXL_PAGE_PATH = "app.surface.name";
29
30
  declare const KEY_MXL_PAGE_ID = "app.surface.id";
@@ -55,5 +56,5 @@ declare enum MXL_ERROR_INSTRUMENTATIONS {
55
56
  }
56
57
  type MXL_INSTRUMENTATIONS = MXL_NAVIGATION_INSTRUMENTATIONS | MXL_ERROR_INSTRUMENTATIONS;
57
58
  //#endregion
58
- export { KEY_APP_SURFACE_LABEL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_ERROR_LOG_COUNT, KEY_MXL_EXCEPTION_CAUSE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_JS_FILE_BUNDLE_IDS, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
59
+ export { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_ERROR_LOG_COUNT, KEY_MXL_EXCEPTION_CAUSE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_JS_FILE_BUNDLE_IDS, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
59
60
  //# sourceMappingURL=attributes.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"attributes.d.cts","names":[],"sources":["../../src/constants/attributes.ts"],"mappings":";cAAa,YAAA;AAAA,cACA,aAAA;AAAA,cACA,kBAAA;AAAA,cACA,sBAAA;AAAA,cACA,wBAAA;AAAA,cACA,4BAAA;AAAA,cACA,yBAAA;AAAA,cACA,4BAAA;AAAA,cACA,8BAAA;AAAA,cACA,+BAAA;AAAA,cACA,0BAAA;AAAA,cACA,uBAAA;AAAA,cACA,kBAAA;AAAA,cACA,uBAAA;AAAA,cACA,cAAA;AAAA,cACA,qBAAA;AAAA,cACA,qBAAA;AAAA,cACA,uBAAA;AAAA,cACA,uBAAA;AAAA,cACA,kCAAA;AAAA,cAEA,oBAAA;AAAA,cACA,0BAAA;AAAA,cACA,uBAAA;AAAA,cACA,yBAAA;AAAA,cACA,oBAAA;AAAA,cACA,iCAAA;AAAA,cAIA,iBAAA;AAAA,cACA,eAAA;AAAA,cACA,qBAAA;AAAA,aAED,SAAA;EACV,OAAA;EACA,OAAA;EACA,IAAA;EACA,SAAA;EAAA;EACA,eAAA;EACA,QAAA;EACA,aAAA;EACA,YAAA;EACA,OAAA;AAAA;AAAA,aAGU,UAAA;EACV,UAAA;EACA,UAAA;AAAA;AAAA,aAGU,+BAAA;EACV,iBAAA;EACA,WAAA;EACA,IAAA;EACA,MAAA;AAAA;AAAA,aAGU,0BAAA;EACV,kBAAA;AAAA;AAAA,KAGU,oBAAA,GACR,+BAAA,GACA,0BAAA"}
1
+ {"version":3,"file":"attributes.d.cts","names":[],"sources":["../../src/constants/attributes.ts"],"mappings":";cAAa,YAAA;AAAA,cACA,aAAA;AAAA,cACA,kBAAA;AAAA,cACA,sBAAA;AAAA,cACA,wBAAA;AAAA,cACA,4BAAA;AAAA,cACA,yBAAA;AAAA,cACA,4BAAA;AAAA,cACA,8BAAA;AAAA,cACA,+BAAA;AAAA,cACA,0BAAA;AAAA,cACA,uBAAA;AAAA,cACA,kBAAA;AAAA,cACA,uBAAA;AAAA,cACA,cAAA;AAAA,cACA,qBAAA;AAAA,cACA,qBAAA;AAAA,cACA,uBAAA;AAAA,cACA,uBAAA;AAAA,cACA,kCAAA;AAAA,cAEA,oBAAA;AAAA,cACA,0BAAA;AAAA,cACA,uBAAA;AAAA,cACA,yBAAA;AAAA,cACA,oBAAA;AAAA,cACA,oBAAA;AAAA,cACA,iCAAA;AAAA,cAIA,iBAAA;AAAA,cACA,eAAA;AAAA,cACA,qBAAA;AAAA,aAED,SAAA;EACV,OAAA;EACA,OAAA;EACA,IAAA;EACA,SAAA;EAAA;EACA,eAAA;EACA,QAAA;EACA,aAAA;EACA,YAAA;EACA,OAAA;AAAA;AAAA,aAGU,UAAA;EACV,UAAA;EACA,UAAA;AAAA;AAAA,aAGU,+BAAA;EACV,iBAAA;EACA,WAAA;EACA,IAAA;EACA,MAAA;AAAA;AAAA,aAGU,0BAAA;EACV,kBAAA;AAAA;AAAA,KAGU,oBAAA,GACR,+BAAA,GACA,0BAAA"}
@@ -24,6 +24,7 @@ declare const KEY_MXL_JS_FILE_BUNDLE_IDS = "mxl.js_file_bundle_ids";
24
24
  declare const KEY_MXL_W3C_TRACEPARENT = "mxl.w3c_traceparent";
25
25
  declare const KEY_MXL_NAVIGATION_SOURCE = "mxl.navigation_source";
26
26
  declare const KEY_MXL_REFERRER_URL = "mxl.referrer_url";
27
+ declare const KEY_BROWSER_URL_FULL = "browser.url.full";
27
28
  declare const KEY_MXL_MAX_PENDING_SPANS_REACHED = "mxl.max_pending_spans_reached";
28
29
  declare const KEY_MXL_PAGE_PATH = "app.surface.name";
29
30
  declare const KEY_MXL_PAGE_ID = "app.surface.id";
@@ -55,5 +56,5 @@ declare enum MXL_ERROR_INSTRUMENTATIONS {
55
56
  }
56
57
  type MXL_INSTRUMENTATIONS = MXL_NAVIGATION_INSTRUMENTATIONS | MXL_ERROR_INSTRUMENTATIONS;
57
58
  //#endregion
58
- export { KEY_APP_SURFACE_LABEL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_ERROR_LOG_COUNT, KEY_MXL_EXCEPTION_CAUSE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_JS_FILE_BUNDLE_IDS, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
59
+ export { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_ERROR_LOG_COUNT, KEY_MXL_EXCEPTION_CAUSE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_JS_FILE_BUNDLE_IDS, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
59
60
  //# sourceMappingURL=attributes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"attributes.d.ts","names":[],"sources":["../../src/constants/attributes.ts"],"mappings":";cAAa,YAAA;AAAA,cACA,aAAA;AAAA,cACA,kBAAA;AAAA,cACA,sBAAA;AAAA,cACA,wBAAA;AAAA,cACA,4BAAA;AAAA,cACA,yBAAA;AAAA,cACA,4BAAA;AAAA,cACA,8BAAA;AAAA,cACA,+BAAA;AAAA,cACA,0BAAA;AAAA,cACA,uBAAA;AAAA,cACA,kBAAA;AAAA,cACA,uBAAA;AAAA,cACA,cAAA;AAAA,cACA,qBAAA;AAAA,cACA,qBAAA;AAAA,cACA,uBAAA;AAAA,cACA,uBAAA;AAAA,cACA,kCAAA;AAAA,cAEA,oBAAA;AAAA,cACA,0BAAA;AAAA,cACA,uBAAA;AAAA,cACA,yBAAA;AAAA,cACA,oBAAA;AAAA,cACA,iCAAA;AAAA,cAIA,iBAAA;AAAA,cACA,eAAA;AAAA,cACA,qBAAA;AAAA,aAED,SAAA;EACV,OAAA;EACA,OAAA;EACA,IAAA;EACA,SAAA;EAAA;EACA,eAAA;EACA,QAAA;EACA,aAAA;EACA,YAAA;EACA,OAAA;AAAA;AAAA,aAGU,UAAA;EACV,UAAA;EACA,UAAA;AAAA;AAAA,aAGU,+BAAA;EACV,iBAAA;EACA,WAAA;EACA,IAAA;EACA,MAAA;AAAA;AAAA,aAGU,0BAAA;EACV,kBAAA;AAAA;AAAA,KAGU,oBAAA,GACR,+BAAA,GACA,0BAAA"}
1
+ {"version":3,"file":"attributes.d.ts","names":[],"sources":["../../src/constants/attributes.ts"],"mappings":";cAAa,YAAA;AAAA,cACA,aAAA;AAAA,cACA,kBAAA;AAAA,cACA,sBAAA;AAAA,cACA,wBAAA;AAAA,cACA,4BAAA;AAAA,cACA,yBAAA;AAAA,cACA,4BAAA;AAAA,cACA,8BAAA;AAAA,cACA,+BAAA;AAAA,cACA,0BAAA;AAAA,cACA,uBAAA;AAAA,cACA,kBAAA;AAAA,cACA,uBAAA;AAAA,cACA,cAAA;AAAA,cACA,qBAAA;AAAA,cACA,qBAAA;AAAA,cACA,uBAAA;AAAA,cACA,uBAAA;AAAA,cACA,kCAAA;AAAA,cAEA,oBAAA;AAAA,cACA,0BAAA;AAAA,cACA,uBAAA;AAAA,cACA,yBAAA;AAAA,cACA,oBAAA;AAAA,cACA,oBAAA;AAAA,cACA,iCAAA;AAAA,cAIA,iBAAA;AAAA,cACA,eAAA;AAAA,cACA,qBAAA;AAAA,aAED,SAAA;EACV,OAAA;EACA,OAAA;EACA,IAAA;EACA,SAAA;EAAA;EACA,eAAA;EACA,QAAA;EACA,aAAA;EACA,YAAA;EACA,OAAA;AAAA;AAAA,aAGU,UAAA;EACV,UAAA;EACA,UAAA;AAAA;AAAA,aAGU,+BAAA;EACV,iBAAA;EACA,WAAA;EACA,IAAA;EACA,MAAA;AAAA;AAAA,aAGU,0BAAA;EACV,kBAAA;AAAA;AAAA,KAGU,oBAAA,GACR,+BAAA,GACA,0BAAA"}
@@ -24,6 +24,7 @@ const KEY_MXL_JS_FILE_BUNDLE_IDS = "mxl.js_file_bundle_ids";
24
24
  const KEY_MXL_W3C_TRACEPARENT = "mxl.w3c_traceparent";
25
25
  const KEY_MXL_NAVIGATION_SOURCE = "mxl.navigation_source";
26
26
  const KEY_MXL_REFERRER_URL = "mxl.referrer_url";
27
+ const KEY_BROWSER_URL_FULL = "browser.url.full";
27
28
  const KEY_MXL_MAX_PENDING_SPANS_REACHED = "mxl.max_pending_spans_reached";
28
29
  const KEY_MXL_PAGE_PATH = "app.surface.name";
29
30
  const KEY_MXL_PAGE_ID = "app.surface.id";
@@ -58,5 +59,5 @@ let MXL_ERROR_INSTRUMENTATIONS = /* @__PURE__ */ function(MXL_ERROR_INSTRUMENTAT
58
59
  }({});
59
60
 
60
61
  //#endregion
61
- export { KEY_APP_SURFACE_LABEL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_ERROR_LOG_COUNT, KEY_MXL_EXCEPTION_CAUSE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_JS_FILE_BUNDLE_IDS, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
62
+ export { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_ERROR_LOG_COUNT, KEY_MXL_EXCEPTION_CAUSE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_JS_FILE_BUNDLE_IDS, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
62
63
  //# sourceMappingURL=attributes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"attributes.js","names":[],"sources":["../../src/constants/attributes.ts"],"sourcesContent":["export const KEY_MXL_TYPE = 'mxl.type';\nexport const KEY_MXL_STATE = 'mxl.state';\nexport const KEY_MXL_COLD_START = 'mxl.cold_start';\nexport const KEY_MXL_SESSION_NUMBER = 'mxl.session_number';\nexport const KEY_MXL_EXCEPTION_NUMBER = 'mxl.exception_number';\nexport const KEY_MXL_SDK_STARTUP_DURATION = 'mxl.sdk_startup_duration';\nexport const KEY_PREFIX_MXL_PROPERTIES = 'mxl.properties.';\nexport const KEY_MXL_SESSION_REASON_ENDED = 'mxl.session_end_type';\nexport const KEY_MXL_SESSION_REASON_STARTED = 'mxl.session_start_type';\nexport const KEY_MXL_JS_EXCEPTION_STACKTRACE = 'mxl.stacktrace.js';\nexport const KEY_MXL_EXCEPTION_HANDLING = 'mxl.exception_handling';\nexport const KEY_MXL_EXCEPTION_CAUSE = 'mxl.exception_cause';\nexport const KEY_MXL_ERROR_CODE = 'mxl.error_code';\nexport const KEY_MXL_APP_INSTANCE_ID = 'mxl.app_instance_id';\nexport const KEY_MXL_TAB_ID = 'mxl.tab_id';\nexport const KEY_MXL_SOURCE_TAB_ID = 'mxl.source_tab_id';\nexport const KEY_MXL_EXPERIENCE_ID = 'mxl.experience_id';\nexport const KEY_MXL_ERROR_LOG_COUNT = 'mxl.error_log_count';\nexport const KEY_MXL_INSTRUMENTATION = 'mxl.instrumentation';\nexport const KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT =\n 'mxl.unhandled_exceptions_count';\nexport const KEY_MXL_FROM_STORAGE = 'mxl.from_storage';\nexport const KEY_MXL_JS_FILE_BUNDLE_IDS = 'mxl.js_file_bundle_ids';\nexport const KEY_MXL_W3C_TRACEPARENT = 'mxl.w3c_traceparent';\nexport const KEY_MXL_NAVIGATION_SOURCE = 'mxl.navigation_source';\nexport const KEY_MXL_REFERRER_URL = 'mxl.referrer_url';\nexport const KEY_MXL_MAX_PENDING_SPANS_REACHED =\n 'mxl.max_pending_spans_reached';\n// In the backend we use 'app.surface.name' and 'app.surface.id' for the page name and id\n// to be consistent with mobile where we use 'app.surface.*' for screen names and ids\nexport const KEY_MXL_PAGE_PATH = 'app.surface.name';\nexport const KEY_MXL_PAGE_ID = 'app.surface.id';\nexport const KEY_APP_SURFACE_LABEL = 'app.surface.label';\n\nexport enum MXL_TYPES {\n Session = 'ux.session',\n Network = 'perf.network_request',\n Perf = 'perf',\n SystemLog = 'sys.log', // SystemLog is a log emb type that tells the MXL BE to treat this as an MXL Log to be shown in the dashboard.\n SystemException = 'sys.exception',\n WebVital = 'ux.web_vital',\n ResourceFetch = 'ux.resource_fetch',\n DocumentLoad = 'ux.document_load',\n Surface = 'ux.surface',\n}\n\nexport enum MXL_STATES {\n Foreground = 'foreground',\n Background = 'background',\n}\n\nexport enum MXL_NAVIGATION_INSTRUMENTATIONS {\n DeclarativeLegacy = 'react_router_declarative_legacy',\n Declarative = 'react_router_declarative',\n Data = 'react_router_data',\n Manual = 'manual',\n}\n\nexport enum MXL_ERROR_INSTRUMENTATIONS {\n ReactErrorBoundary = 'react_error_boundary',\n}\n\nexport type MXL_INSTRUMENTATIONS =\n | MXL_NAVIGATION_INSTRUMENTATIONS\n | MXL_ERROR_INSTRUMENTATIONS;\n"],"mappings":";AAAA,MAAa,eAAe;AAC5B,MAAa,gBAAgB;AAC7B,MAAa,qBAAqB;AAClC,MAAa,yBAAyB;AACtC,MAAa,2BAA2B;AACxC,MAAa,+BAA+B;AAC5C,MAAa,4BAA4B;AACzC,MAAa,+BAA+B;AAC5C,MAAa,iCAAiC;AAC9C,MAAa,kCAAkC;AAC/C,MAAa,6BAA6B;AAC1C,MAAa,0BAA0B;AACvC,MAAa,qBAAqB;AAClC,MAAa,0BAA0B;AACvC,MAAa,iBAAiB;AAC9B,MAAa,wBAAwB;AACrC,MAAa,wBAAwB;AACrC,MAAa,0BAA0B;AACvC,MAAa,0BAA0B;AACvC,MAAa,qCACX;AACF,MAAa,uBAAuB;AACpC,MAAa,6BAA6B;AAC1C,MAAa,0BAA0B;AACvC,MAAa,4BAA4B;AACzC,MAAa,uBAAuB;AACpC,MAAa,oCACX;AAGF,MAAa,oBAAoB;AACjC,MAAa,kBAAkB;AAC/B,MAAa,wBAAwB;AAErC,IAAY,gDAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGF,IAAY,kDAAL;AACL;AACA;;;AAGF,IAAY,4FAAL;AACL;AACA;AACA;AACA;;;AAGF,IAAY,kFAAL;AACL"}
1
+ {"version":3,"file":"attributes.js","names":[],"sources":["../../src/constants/attributes.ts"],"sourcesContent":["export const KEY_MXL_TYPE = 'mxl.type';\nexport const KEY_MXL_STATE = 'mxl.state';\nexport const KEY_MXL_COLD_START = 'mxl.cold_start';\nexport const KEY_MXL_SESSION_NUMBER = 'mxl.session_number';\nexport const KEY_MXL_EXCEPTION_NUMBER = 'mxl.exception_number';\nexport const KEY_MXL_SDK_STARTUP_DURATION = 'mxl.sdk_startup_duration';\nexport const KEY_PREFIX_MXL_PROPERTIES = 'mxl.properties.';\nexport const KEY_MXL_SESSION_REASON_ENDED = 'mxl.session_end_type';\nexport const KEY_MXL_SESSION_REASON_STARTED = 'mxl.session_start_type';\nexport const KEY_MXL_JS_EXCEPTION_STACKTRACE = 'mxl.stacktrace.js';\nexport const KEY_MXL_EXCEPTION_HANDLING = 'mxl.exception_handling';\nexport const KEY_MXL_EXCEPTION_CAUSE = 'mxl.exception_cause';\nexport const KEY_MXL_ERROR_CODE = 'mxl.error_code';\nexport const KEY_MXL_APP_INSTANCE_ID = 'mxl.app_instance_id';\nexport const KEY_MXL_TAB_ID = 'mxl.tab_id';\nexport const KEY_MXL_SOURCE_TAB_ID = 'mxl.source_tab_id';\nexport const KEY_MXL_EXPERIENCE_ID = 'mxl.experience_id';\nexport const KEY_MXL_ERROR_LOG_COUNT = 'mxl.error_log_count';\nexport const KEY_MXL_INSTRUMENTATION = 'mxl.instrumentation';\nexport const KEY_MXL_UNHANDLED_EXCEPTIONS_COUNT =\n 'mxl.unhandled_exceptions_count';\nexport const KEY_MXL_FROM_STORAGE = 'mxl.from_storage';\nexport const KEY_MXL_JS_FILE_BUNDLE_IDS = 'mxl.js_file_bundle_ids';\nexport const KEY_MXL_W3C_TRACEPARENT = 'mxl.w3c_traceparent';\nexport const KEY_MXL_NAVIGATION_SOURCE = 'mxl.navigation_source';\nexport const KEY_MXL_REFERRER_URL = 'mxl.referrer_url';\nexport const KEY_BROWSER_URL_FULL = 'browser.url.full';\nexport const KEY_MXL_MAX_PENDING_SPANS_REACHED =\n 'mxl.max_pending_spans_reached';\n// In the backend we use 'app.surface.name' and 'app.surface.id' for the page name and id\n// to be consistent with mobile where we use 'app.surface.*' for screen names and ids\nexport const KEY_MXL_PAGE_PATH = 'app.surface.name';\nexport const KEY_MXL_PAGE_ID = 'app.surface.id';\nexport const KEY_APP_SURFACE_LABEL = 'app.surface.label';\n\nexport enum MXL_TYPES {\n Session = 'ux.session',\n Network = 'perf.network_request',\n Perf = 'perf',\n SystemLog = 'sys.log', // SystemLog is a log emb type that tells the MXL BE to treat this as an MXL Log to be shown in the dashboard.\n SystemException = 'sys.exception',\n WebVital = 'ux.web_vital',\n ResourceFetch = 'ux.resource_fetch',\n DocumentLoad = 'ux.document_load',\n Surface = 'ux.surface',\n}\n\nexport enum MXL_STATES {\n Foreground = 'foreground',\n Background = 'background',\n}\n\nexport enum MXL_NAVIGATION_INSTRUMENTATIONS {\n DeclarativeLegacy = 'react_router_declarative_legacy',\n Declarative = 'react_router_declarative',\n Data = 'react_router_data',\n Manual = 'manual',\n}\n\nexport enum MXL_ERROR_INSTRUMENTATIONS {\n ReactErrorBoundary = 'react_error_boundary',\n}\n\nexport type MXL_INSTRUMENTATIONS =\n | MXL_NAVIGATION_INSTRUMENTATIONS\n | MXL_ERROR_INSTRUMENTATIONS;\n"],"mappings":";AAAA,MAAa,eAAe;AAC5B,MAAa,gBAAgB;AAC7B,MAAa,qBAAqB;AAClC,MAAa,yBAAyB;AACtC,MAAa,2BAA2B;AACxC,MAAa,+BAA+B;AAC5C,MAAa,4BAA4B;AACzC,MAAa,+BAA+B;AAC5C,MAAa,iCAAiC;AAC9C,MAAa,kCAAkC;AAC/C,MAAa,6BAA6B;AAC1C,MAAa,0BAA0B;AACvC,MAAa,qBAAqB;AAClC,MAAa,0BAA0B;AACvC,MAAa,iBAAiB;AAC9B,MAAa,wBAAwB;AACrC,MAAa,wBAAwB;AACrC,MAAa,0BAA0B;AACvC,MAAa,0BAA0B;AACvC,MAAa,qCACX;AACF,MAAa,uBAAuB;AACpC,MAAa,6BAA6B;AAC1C,MAAa,0BAA0B;AACvC,MAAa,4BAA4B;AACzC,MAAa,uBAAuB;AACpC,MAAa,uBAAuB;AACpC,MAAa,oCACX;AAGF,MAAa,oBAAoB;AACjC,MAAa,kBAAkB;AAC/B,MAAa,wBAAwB;AAErC,IAAY,gDAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGF,IAAY,kDAAL;AACL;AACA;;;AAGF,IAAY,4FAAL;AACL;AACA;AACA;AACA;;;AAGF,IAAY,kFAAL;AACL"}
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_constants_attributes = require('./attributes.cjs');
3
3
 
4
4
  exports.KEY_APP_SURFACE_LABEL = require_constants_attributes.KEY_APP_SURFACE_LABEL;
5
+ exports.KEY_BROWSER_URL_FULL = require_constants_attributes.KEY_BROWSER_URL_FULL;
5
6
  exports.KEY_MXL_APP_INSTANCE_ID = require_constants_attributes.KEY_MXL_APP_INSTANCE_ID;
6
7
  exports.KEY_MXL_COLD_START = require_constants_attributes.KEY_MXL_COLD_START;
7
8
  exports.KEY_MXL_ERROR_CODE = require_constants_attributes.KEY_MXL_ERROR_CODE;
@@ -1,2 +1,2 @@
1
- import { KEY_APP_SURFACE_LABEL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES } from "./attributes.cjs";
2
- export { KEY_APP_SURFACE_LABEL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, type MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
1
+ import { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES } from "./attributes.cjs";
2
+ export { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, type MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
@@ -1,2 +1,2 @@
1
- import { KEY_APP_SURFACE_LABEL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES } from "./attributes.js";
2
- export { KEY_APP_SURFACE_LABEL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, type MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
1
+ import { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES } from "./attributes.js";
2
+ export { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, type MXL_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
@@ -1,3 +1,3 @@
1
- import { KEY_APP_SURFACE_LABEL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES } from "./attributes.js";
1
+ import { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES } from "./attributes.js";
2
2
 
3
- export { KEY_APP_SURFACE_LABEL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
3
+ export { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_APP_INSTANCE_ID, KEY_MXL_COLD_START, KEY_MXL_ERROR_CODE, KEY_MXL_EXCEPTION_HANDLING, KEY_MXL_EXCEPTION_NUMBER, KEY_MXL_EXPERIENCE_ID, KEY_MXL_FROM_STORAGE, KEY_MXL_INSTRUMENTATION, KEY_MXL_JS_EXCEPTION_STACKTRACE, KEY_MXL_MAX_PENDING_SPANS_REACHED, KEY_MXL_NAVIGATION_SOURCE, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_REFERRER_URL, KEY_MXL_SDK_STARTUP_DURATION, KEY_MXL_SESSION_NUMBER, KEY_MXL_SESSION_REASON_ENDED, KEY_MXL_SESSION_REASON_STARTED, KEY_MXL_SOURCE_TAB_ID, KEY_MXL_STATE, KEY_MXL_TAB_ID, KEY_MXL_TYPE, KEY_MXL_W3C_TRACEPARENT, KEY_PREFIX_MXL_PROPERTIES, MXL_ERROR_INSTRUMENTATIONS, MXL_NAVIGATION_INSTRUMENTATIONS, MXL_STATES, MXL_TYPES };
@@ -10,17 +10,18 @@ const require_instrumentations_navigation_NavigationInstrumentation_instance = r
10
10
  *
11
11
  * Filtering by currentPathname ensures that we only consider routes that are relevant to the current URL.
12
12
  */
13
- const getRouteFromMatches = (matches, currentPathname) => matches.filter((m) => currentPathname.includes(m.pathname)).reduce((route, match) => {
14
- if (!match.route.path) return route;
15
- if (route) return {
16
- url: match.pathname,
17
- path: `${route.path}/${match.route.path}`
18
- };
19
- return {
20
- url: match.pathname,
21
- path: match.route.path
22
- };
23
- }, null);
13
+ const getRouteFromMatches = (matches, currentPathname) => {
14
+ const currentMatchIndex = matches.findIndex((match) => match.pathname === currentPathname);
15
+ if (currentMatchIndex === -1 || !matches[currentMatchIndex].route.path) return null;
16
+ return matches.slice(0, currentMatchIndex + 1).reduce((acc, match) => {
17
+ const routePath = match.route.path;
18
+ if (!routePath) return acc;
19
+ return {
20
+ path: routePath.startsWith("/") ? routePath : `${acc?.path ?? ""}/${routePath}`,
21
+ url: matches[currentMatchIndex].pathname
22
+ };
23
+ }, null);
24
+ };
24
25
  const listenToRouterChanges = ({ router, routesMatcher, config: { pathnameDocument = window.location } = {} }) => {
25
26
  const navigationInstrumentation = require_instrumentations_navigation_NavigationInstrumentation_instance.getNavigationInstrumentation();
26
27
  navigationInstrumentation.setInstrumentationType(require_constants_attributes.MXL_NAVIGATION_INSTRUMENTATIONS.Data);
@@ -1 +1 @@
1
- {"version":3,"file":"listenToRouterChanges.cjs","names":["getNavigationInstrumentation","MXL_NAVIGATION_INSTRUMENTATIONS"],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.ts"],"sourcesContent":["import type { Route } from '../../../../../api-page/index.ts';\nimport { MXL_NAVIGATION_INSTRUMENTATIONS } from '../../../../../constants/index.ts';\nimport { getNavigationInstrumentation } from '../../index.ts';\nimport type { ListenToRouterChangesArgs, Match } from './types.ts';\n\n/**\n * getRouteFromMatches goes through all the matches routes to build the full path\n * nested routes contain only the partial match, so we need to go through all of them\n * in order to build the full path.\n *\n * Filtering by currentPathname ensures that we only consider routes that are relevant to the current URL.\n */\nconst getRouteFromMatches = (\n matches: Match[],\n currentPathname: string,\n): Route | null =>\n matches\n .filter((m) => currentPathname.includes(m.pathname))\n .reduce<null | Route>((route, match) => {\n if (!match.route.path) {\n return route;\n }\n\n if (route) {\n return {\n url: match.pathname,\n path: `${route.path}/${match.route.path}`,\n } as Route;\n }\n\n return {\n url: match.pathname,\n path: match.route.path,\n } as Route;\n }, null);\n\nexport const listenToRouterChanges = ({\n router,\n routesMatcher,\n config: { pathnameDocument = window.location } = {},\n}: ListenToRouterChangesArgs) => {\n const navigationInstrumentation = getNavigationInstrumentation();\n navigationInstrumentation.setInstrumentationType(\n MXL_NAVIGATION_INSTRUMENTATIONS.Data,\n );\n\n const initialMatches = routesMatcher(router.routes, {\n pathname: pathnameDocument.pathname,\n });\n\n const initialRoute = initialMatches\n ? getRouteFromMatches(initialMatches, pathnameDocument.pathname)\n : null;\n\n if (initialRoute) {\n navigationInstrumentation.setCurrentRoute(initialRoute);\n }\n\n return router.subscribe((state) => {\n // State has a list of already matched routes\n // https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts#L954\n const currentRoute = getRouteFromMatches(\n state.matches,\n state.location.pathname,\n );\n\n if (currentRoute) {\n navigationInstrumentation.setCurrentRoute(currentRoute);\n }\n });\n};\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,uBACJ,SACA,oBAEA,QACG,QAAQ,MAAM,gBAAgB,SAAS,EAAE,SAAS,CAAC,CACnD,QAAsB,OAAO,UAAU;AACtC,KAAI,CAAC,MAAM,MAAM,KACf,QAAO;AAGT,KAAI,MACF,QAAO;EACL,KAAK,MAAM;EACX,MAAM,GAAG,MAAM,KAAK,GAAG,MAAM,MAAM;EACpC;AAGH,QAAO;EACL,KAAK,MAAM;EACX,MAAM,MAAM,MAAM;EACnB;GACA,KAAK;AAEZ,MAAa,yBAAyB,EACpC,QACA,eACA,QAAQ,EAAE,mBAAmB,OAAO,aAAa,EAAE,OACpB;CAC/B,MAAM,4BAA4BA,qGAA8B;AAChE,2BAA0B,uBACxBC,6DAAgC,KACjC;CAED,MAAM,iBAAiB,cAAc,OAAO,QAAQ,EAClD,UAAU,iBAAiB,UAC5B,CAAC;CAEF,MAAM,eAAe,iBACjB,oBAAoB,gBAAgB,iBAAiB,SAAS,GAC9D;AAEJ,KAAI,aACF,2BAA0B,gBAAgB,aAAa;AAGzD,QAAO,OAAO,WAAW,UAAU;EAGjC,MAAM,eAAe,oBACnB,MAAM,SACN,MAAM,SAAS,SAChB;AAED,MAAI,aACF,2BAA0B,gBAAgB,aAAa;GAEzD"}
1
+ {"version":3,"file":"listenToRouterChanges.cjs","names":["getNavigationInstrumentation","MXL_NAVIGATION_INSTRUMENTATIONS"],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.ts"],"sourcesContent":["import type { Route } from '../../../../../api-page/index.ts';\nimport { MXL_NAVIGATION_INSTRUMENTATIONS } from '../../../../../constants/index.ts';\nimport { getNavigationInstrumentation } from '../../index.ts';\nimport type { ListenToRouterChangesArgs, Match } from './types.ts';\n\n/**\n * getRouteFromMatches goes through all the matches routes to build the full path\n * nested routes contain only the partial match, so we need to go through all of them\n * in order to build the full path.\n *\n * Filtering by currentPathname ensures that we only consider routes that are relevant to the current URL.\n */\nconst getRouteFromMatches = (\n matches: Match[],\n currentPathname: string,\n): Route | null => {\n const currentMatchIndex = matches.findIndex(\n (match) => match.pathname === currentPathname,\n );\n\n if (currentMatchIndex === -1 || !matches[currentMatchIndex].route.path) {\n return null;\n }\n\n // Build full absolute path by reducing all matches up to the current one.\n // Absolute child paths reset the accumulation; relative paths are appended.\n return matches\n .slice(0, currentMatchIndex + 1)\n .reduce<Route | null>((acc, match) => {\n const routePath = match.route.path;\n\n if (!routePath) {\n return acc;\n }\n\n // If the route path starts with '/', it's an absolute path and should reset the accumulated path.\n // Otherwise, it's a relative path and should be appended to the accumulated path.\n const path = routePath.startsWith('/')\n ? routePath\n : `${acc?.path ?? ''}/${routePath}`;\n\n return { path, url: matches[currentMatchIndex].pathname };\n }, null);\n};\n\nexport const listenToRouterChanges = ({\n router,\n routesMatcher,\n config: { pathnameDocument = window.location } = {},\n}: ListenToRouterChangesArgs) => {\n const navigationInstrumentation = getNavigationInstrumentation();\n navigationInstrumentation.setInstrumentationType(\n MXL_NAVIGATION_INSTRUMENTATIONS.Data,\n );\n\n const initialMatches = routesMatcher(router.routes, {\n pathname: pathnameDocument.pathname,\n });\n\n const initialRoute = initialMatches\n ? getRouteFromMatches(initialMatches, pathnameDocument.pathname)\n : null;\n\n if (initialRoute) {\n navigationInstrumentation.setCurrentRoute(initialRoute);\n }\n\n return router.subscribe((state) => {\n // State has a list of already matched routes\n // https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts#L954\n const currentRoute = getRouteFromMatches(\n state.matches,\n state.location.pathname,\n );\n\n if (currentRoute) {\n navigationInstrumentation.setCurrentRoute(currentRoute);\n }\n });\n};\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,uBACJ,SACA,oBACiB;CACjB,MAAM,oBAAoB,QAAQ,WAC/B,UAAU,MAAM,aAAa,gBAC/B;AAED,KAAI,sBAAsB,MAAM,CAAC,QAAQ,mBAAmB,MAAM,KAChE,QAAO;AAKT,QAAO,QACJ,MAAM,GAAG,oBAAoB,EAAE,CAC/B,QAAsB,KAAK,UAAU;EACpC,MAAM,YAAY,MAAM,MAAM;AAE9B,MAAI,CAAC,UACH,QAAO;AAST,SAAO;GAAE,MAJI,UAAU,WAAW,IAAI,GAClC,YACA,GAAG,KAAK,QAAQ,GAAG,GAAG;GAEX,KAAK,QAAQ,mBAAmB;GAAU;IACxD,KAAK;;AAGZ,MAAa,yBAAyB,EACpC,QACA,eACA,QAAQ,EAAE,mBAAmB,OAAO,aAAa,EAAE,OACpB;CAC/B,MAAM,4BAA4BA,qGAA8B;AAChE,2BAA0B,uBACxBC,6DAAgC,KACjC;CAED,MAAM,iBAAiB,cAAc,OAAO,QAAQ,EAClD,UAAU,iBAAiB,UAC5B,CAAC;CAEF,MAAM,eAAe,iBACjB,oBAAoB,gBAAgB,iBAAiB,SAAS,GAC9D;AAEJ,KAAI,aACF,2BAA0B,gBAAgB,aAAa;AAGzD,QAAO,OAAO,WAAW,UAAU;EAGjC,MAAM,eAAe,oBACnB,MAAM,SACN,MAAM,SAAS,SAChB;AAED,MAAI,aACF,2BAA0B,gBAAgB,aAAa;GAEzD"}
@@ -1 +1 @@
1
- {"version":3,"file":"listenToRouterChanges.d.cts","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.ts"],"mappings":";;;cAoCa,qBAAA;EAAyB,MAAA;EAAA,aAAA;EAAA,MAAA;IAAA;EAAA;AAAA,GAInC,yBAAA"}
1
+ {"version":3,"file":"listenToRouterChanges.d.cts","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.ts"],"mappings":";;;cA6Ca,qBAAA;EAAyB,MAAA;EAAA,aAAA;EAAA,MAAA;IAAA;EAAA;AAAA,GAInC,yBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"listenToRouterChanges.d.ts","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.ts"],"mappings":";;;cAoCa,qBAAA;EAAyB,MAAA;EAAA,aAAA;EAAA,MAAA;IAAA;EAAA;AAAA,GAInC,yBAAA"}
1
+ {"version":3,"file":"listenToRouterChanges.d.ts","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.ts"],"mappings":";;;cA6Ca,qBAAA;EAAyB,MAAA;EAAA,aAAA;EAAA,MAAA;IAAA;EAAA;AAAA,GAInC,yBAAA"}
@@ -9,17 +9,18 @@ import { getNavigationInstrumentation } from "../../instance.js";
9
9
  *
10
10
  * Filtering by currentPathname ensures that we only consider routes that are relevant to the current URL.
11
11
  */
12
- const getRouteFromMatches = (matches, currentPathname) => matches.filter((m) => currentPathname.includes(m.pathname)).reduce((route, match) => {
13
- if (!match.route.path) return route;
14
- if (route) return {
15
- url: match.pathname,
16
- path: `${route.path}/${match.route.path}`
17
- };
18
- return {
19
- url: match.pathname,
20
- path: match.route.path
21
- };
22
- }, null);
12
+ const getRouteFromMatches = (matches, currentPathname) => {
13
+ const currentMatchIndex = matches.findIndex((match) => match.pathname === currentPathname);
14
+ if (currentMatchIndex === -1 || !matches[currentMatchIndex].route.path) return null;
15
+ return matches.slice(0, currentMatchIndex + 1).reduce((acc, match) => {
16
+ const routePath = match.route.path;
17
+ if (!routePath) return acc;
18
+ return {
19
+ path: routePath.startsWith("/") ? routePath : `${acc?.path ?? ""}/${routePath}`,
20
+ url: matches[currentMatchIndex].pathname
21
+ };
22
+ }, null);
23
+ };
23
24
  const listenToRouterChanges = ({ router, routesMatcher, config: { pathnameDocument = window.location } = {} }) => {
24
25
  const navigationInstrumentation = getNavigationInstrumentation();
25
26
  navigationInstrumentation.setInstrumentationType(MXL_NAVIGATION_INSTRUMENTATIONS.Data);
@@ -1 +1 @@
1
- {"version":3,"file":"listenToRouterChanges.js","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.ts"],"sourcesContent":["import type { Route } from '../../../../../api-page/index.ts';\nimport { MXL_NAVIGATION_INSTRUMENTATIONS } from '../../../../../constants/index.ts';\nimport { getNavigationInstrumentation } from '../../index.ts';\nimport type { ListenToRouterChangesArgs, Match } from './types.ts';\n\n/**\n * getRouteFromMatches goes through all the matches routes to build the full path\n * nested routes contain only the partial match, so we need to go through all of them\n * in order to build the full path.\n *\n * Filtering by currentPathname ensures that we only consider routes that are relevant to the current URL.\n */\nconst getRouteFromMatches = (\n matches: Match[],\n currentPathname: string,\n): Route | null =>\n matches\n .filter((m) => currentPathname.includes(m.pathname))\n .reduce<null | Route>((route, match) => {\n if (!match.route.path) {\n return route;\n }\n\n if (route) {\n return {\n url: match.pathname,\n path: `${route.path}/${match.route.path}`,\n } as Route;\n }\n\n return {\n url: match.pathname,\n path: match.route.path,\n } as Route;\n }, null);\n\nexport const listenToRouterChanges = ({\n router,\n routesMatcher,\n config: { pathnameDocument = window.location } = {},\n}: ListenToRouterChangesArgs) => {\n const navigationInstrumentation = getNavigationInstrumentation();\n navigationInstrumentation.setInstrumentationType(\n MXL_NAVIGATION_INSTRUMENTATIONS.Data,\n );\n\n const initialMatches = routesMatcher(router.routes, {\n pathname: pathnameDocument.pathname,\n });\n\n const initialRoute = initialMatches\n ? getRouteFromMatches(initialMatches, pathnameDocument.pathname)\n : null;\n\n if (initialRoute) {\n navigationInstrumentation.setCurrentRoute(initialRoute);\n }\n\n return router.subscribe((state) => {\n // State has a list of already matched routes\n // https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts#L954\n const currentRoute = getRouteFromMatches(\n state.matches,\n state.location.pathname,\n );\n\n if (currentRoute) {\n navigationInstrumentation.setCurrentRoute(currentRoute);\n }\n });\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,uBACJ,SACA,oBAEA,QACG,QAAQ,MAAM,gBAAgB,SAAS,EAAE,SAAS,CAAC,CACnD,QAAsB,OAAO,UAAU;AACtC,KAAI,CAAC,MAAM,MAAM,KACf,QAAO;AAGT,KAAI,MACF,QAAO;EACL,KAAK,MAAM;EACX,MAAM,GAAG,MAAM,KAAK,GAAG,MAAM,MAAM;EACpC;AAGH,QAAO;EACL,KAAK,MAAM;EACX,MAAM,MAAM,MAAM;EACnB;GACA,KAAK;AAEZ,MAAa,yBAAyB,EACpC,QACA,eACA,QAAQ,EAAE,mBAAmB,OAAO,aAAa,EAAE,OACpB;CAC/B,MAAM,4BAA4B,8BAA8B;AAChE,2BAA0B,uBACxB,gCAAgC,KACjC;CAED,MAAM,iBAAiB,cAAc,OAAO,QAAQ,EAClD,UAAU,iBAAiB,UAC5B,CAAC;CAEF,MAAM,eAAe,iBACjB,oBAAoB,gBAAgB,iBAAiB,SAAS,GAC9D;AAEJ,KAAI,aACF,2BAA0B,gBAAgB,aAAa;AAGzD,QAAO,OAAO,WAAW,UAAU;EAGjC,MAAM,eAAe,oBACnB,MAAM,SACN,MAAM,SAAS,SAChB;AAED,MAAI,aACF,2BAA0B,gBAAgB,aAAa;GAEzD"}
1
+ {"version":3,"file":"listenToRouterChanges.js","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Data/listenToRouterChanges.ts"],"sourcesContent":["import type { Route } from '../../../../../api-page/index.ts';\nimport { MXL_NAVIGATION_INSTRUMENTATIONS } from '../../../../../constants/index.ts';\nimport { getNavigationInstrumentation } from '../../index.ts';\nimport type { ListenToRouterChangesArgs, Match } from './types.ts';\n\n/**\n * getRouteFromMatches goes through all the matches routes to build the full path\n * nested routes contain only the partial match, so we need to go through all of them\n * in order to build the full path.\n *\n * Filtering by currentPathname ensures that we only consider routes that are relevant to the current URL.\n */\nconst getRouteFromMatches = (\n matches: Match[],\n currentPathname: string,\n): Route | null => {\n const currentMatchIndex = matches.findIndex(\n (match) => match.pathname === currentPathname,\n );\n\n if (currentMatchIndex === -1 || !matches[currentMatchIndex].route.path) {\n return null;\n }\n\n // Build full absolute path by reducing all matches up to the current one.\n // Absolute child paths reset the accumulation; relative paths are appended.\n return matches\n .slice(0, currentMatchIndex + 1)\n .reduce<Route | null>((acc, match) => {\n const routePath = match.route.path;\n\n if (!routePath) {\n return acc;\n }\n\n // If the route path starts with '/', it's an absolute path and should reset the accumulated path.\n // Otherwise, it's a relative path and should be appended to the accumulated path.\n const path = routePath.startsWith('/')\n ? routePath\n : `${acc?.path ?? ''}/${routePath}`;\n\n return { path, url: matches[currentMatchIndex].pathname };\n }, null);\n};\n\nexport const listenToRouterChanges = ({\n router,\n routesMatcher,\n config: { pathnameDocument = window.location } = {},\n}: ListenToRouterChangesArgs) => {\n const navigationInstrumentation = getNavigationInstrumentation();\n navigationInstrumentation.setInstrumentationType(\n MXL_NAVIGATION_INSTRUMENTATIONS.Data,\n );\n\n const initialMatches = routesMatcher(router.routes, {\n pathname: pathnameDocument.pathname,\n });\n\n const initialRoute = initialMatches\n ? getRouteFromMatches(initialMatches, pathnameDocument.pathname)\n : null;\n\n if (initialRoute) {\n navigationInstrumentation.setCurrentRoute(initialRoute);\n }\n\n return router.subscribe((state) => {\n // State has a list of already matched routes\n // https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts#L954\n const currentRoute = getRouteFromMatches(\n state.matches,\n state.location.pathname,\n );\n\n if (currentRoute) {\n navigationInstrumentation.setCurrentRoute(currentRoute);\n }\n });\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,uBACJ,SACA,oBACiB;CACjB,MAAM,oBAAoB,QAAQ,WAC/B,UAAU,MAAM,aAAa,gBAC/B;AAED,KAAI,sBAAsB,MAAM,CAAC,QAAQ,mBAAmB,MAAM,KAChE,QAAO;AAKT,QAAO,QACJ,MAAM,GAAG,oBAAoB,EAAE,CAC/B,QAAsB,KAAK,UAAU;EACpC,MAAM,YAAY,MAAM,MAAM;AAE9B,MAAI,CAAC,UACH,QAAO;AAST,SAAO;GAAE,MAJI,UAAU,WAAW,IAAI,GAClC,YACA,GAAG,KAAK,QAAQ,GAAG,GAAG;GAEX,KAAK,QAAQ,mBAAmB;GAAU;IACxD,KAAK;;AAGZ,MAAa,yBAAyB,EACpC,QACA,eACA,QAAQ,EAAE,mBAAmB,OAAO,aAAa,EAAE,OACpB;CAC/B,MAAM,4BAA4B,8BAA8B;AAChE,2BAA0B,uBACxB,gCAAgC,KACjC;CAED,MAAM,iBAAiB,cAAc,OAAO,QAAQ,EAClD,UAAU,iBAAiB,UAC5B,CAAC;CAEF,MAAM,eAAe,iBACjB,oBAAoB,gBAAgB,iBAAiB,SAAS,GAC9D;AAEJ,KAAI,aACF,2BAA0B,gBAAgB,aAAa;AAGzD,QAAO,OAAO,WAAW,UAAU;EAGjC,MAAM,eAAe,oBACnB,MAAM,SACN,MAAM,SAAS,SAChB;AAED,MAAI,aACF,2BAA0B,gBAAgB,aAAa;GAEzD"}
@@ -9,7 +9,8 @@ hoist_non_react_statics = require_runtime.__toESM(hoist_non_react_statics);
9
9
  //#region src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts
10
10
  const getLastRoute = (matchedComponent, lastRoute) => {
11
11
  if (!matchedComponent.props.match || !matchedComponent.props.match.route) return null;
12
- const path = lastRoute ? `${lastRoute.path}/${matchedComponent.props.match.route.path}` : matchedComponent.props.match.route.path;
12
+ const childPath = matchedComponent.props.match.route.path;
13
+ const path = lastRoute && !childPath.startsWith("/") ? `${lastRoute.path}/${childPath}` : childPath;
13
14
  if (matchedComponent.props.routeContext?.outlet) return getLastRoute(matchedComponent.props.routeContext.outlet, {
14
15
  path,
15
16
  url: matchedComponent.props.match.pathname
@@ -1 +1 @@
1
- {"version":3,"file":"withMXLRouting.cjs","names":["getNavigationInstrumentation","MXL_NAVIGATION_INSTRUMENTATIONS"],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts"],"sourcesContent":["import hoistNonReactStatics from 'hoist-non-react-statics';\nimport type React from 'react';\nimport { createElement } from 'react';\nimport type { Route } from '../../../../../api-page/index.ts';\nimport { MXL_NAVIGATION_INSTRUMENTATIONS } from '../../../../../constants/index.ts';\nimport { getNavigationInstrumentation } from '../../index.ts';\nimport type { RoutesFunctionalComponentReturn } from './types.ts';\n\n// Routes can be nested, we need to traverse the routeContext to find the last route\nconst getLastRoute = (\n matchedComponent: RoutesFunctionalComponentReturn,\n lastRoute: Route | null,\n): Route | null => {\n if (!matchedComponent.props.match || !matchedComponent.props.match.route) {\n return null;\n }\n\n const path = lastRoute\n ? `${lastRoute.path}/${matchedComponent.props.match.route.path}`\n : matchedComponent.props.match.route.path;\n\n if (matchedComponent.props.routeContext?.outlet) {\n return getLastRoute(matchedComponent.props.routeContext.outlet, {\n path,\n url: matchedComponent.props.match.pathname,\n });\n }\n\n return {\n path,\n url: matchedComponent.props.match.pathname,\n };\n};\n\nexport const withMXLRouting = <P extends object>(\n WrappedComponent: React.FunctionComponent<P>,\n) => {\n const navigationInstrumentation = getNavigationInstrumentation();\n navigationInstrumentation.setInstrumentationType(\n MXL_NAVIGATION_INSTRUMENTATIONS.Declarative,\n );\n\n const RoutesWithMXLRouting: React.FC<P> = (props: P) => {\n /**\n * React-router v6+ implementation is very different from v5\n * It doesn't have a <Switch> component that injects props into <Route>\n * Instead, it has <Routes> which internally calculates the matched route\n * and returns it as a children, <Route> cannot be wrapped since it requires all children to be a <Route> component\n * here we rely on that matching to get the current route.\n * It's not ideal to rely on internal implementation details, but it's the easier way of getting the current route\n * without having to manually match it or using hooks on each children component\n *\n * See: https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/hooks.tsx#L553\n */\n const matchedComponent = WrappedComponent(\n props,\n ) as unknown as RoutesFunctionalComponentReturn;\n\n if (matchedComponent.props.match?.route) {\n const lastRoute = getLastRoute(matchedComponent, null);\n if (lastRoute) {\n navigationInstrumentation.setCurrentRoute(lastRoute);\n }\n }\n\n return createElement<P>(WrappedComponent, props);\n };\n\n // Keep wrapped component metadata\n RoutesWithMXLRouting.displayName = `withMXLRouting(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;\n hoistNonReactStatics(RoutesWithMXLRouting, WrappedComponent);\n\n return RoutesWithMXLRouting;\n};\n"],"mappings":";;;;;;;;;AASA,MAAM,gBACJ,kBACA,cACiB;AACjB,KAAI,CAAC,iBAAiB,MAAM,SAAS,CAAC,iBAAiB,MAAM,MAAM,MACjE,QAAO;CAGT,MAAM,OAAO,YACT,GAAG,UAAU,KAAK,GAAG,iBAAiB,MAAM,MAAM,MAAM,SACxD,iBAAiB,MAAM,MAAM,MAAM;AAEvC,KAAI,iBAAiB,MAAM,cAAc,OACvC,QAAO,aAAa,iBAAiB,MAAM,aAAa,QAAQ;EAC9D;EACA,KAAK,iBAAiB,MAAM,MAAM;EACnC,CAAC;AAGJ,QAAO;EACL;EACA,KAAK,iBAAiB,MAAM,MAAM;EACnC;;AAGH,MAAa,kBACX,qBACG;CACH,MAAM,4BAA4BA,qGAA8B;AAChE,2BAA0B,uBACxBC,6DAAgC,YACjC;CAED,MAAM,wBAAqC,UAAa;;;;;;;;;;;;EAYtD,MAAM,mBAAmB,iBACvB,MACD;AAED,MAAI,iBAAiB,MAAM,OAAO,OAAO;GACvC,MAAM,YAAY,aAAa,kBAAkB,KAAK;AACtD,OAAI,UACF,2BAA0B,gBAAgB,UAAU;;AAIxD,kCAAwB,kBAAkB,MAAM;;AAIlD,sBAAqB,cAAc,kBAAkB,iBAAiB,eAAe,iBAAiB,QAAQ,YAAY;AAC1H,sCAAqB,sBAAsB,iBAAiB;AAE5D,QAAO"}
1
+ {"version":3,"file":"withMXLRouting.cjs","names":["getNavigationInstrumentation","MXL_NAVIGATION_INSTRUMENTATIONS"],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts"],"sourcesContent":["import hoistNonReactStatics from 'hoist-non-react-statics';\nimport type React from 'react';\nimport { createElement } from 'react';\nimport type { Route } from '../../../../../api-page/index.ts';\nimport { MXL_NAVIGATION_INSTRUMENTATIONS } from '../../../../../constants/index.ts';\nimport { getNavigationInstrumentation } from '../../index.ts';\nimport type { RoutesFunctionalComponentReturn } from './types.ts';\n\n// Routes can be nested, we need to traverse the routeContext to find the last route\nconst getLastRoute = (\n matchedComponent: RoutesFunctionalComponentReturn,\n lastRoute: Route | null,\n): Route | null => {\n if (!matchedComponent.props.match || !matchedComponent.props.match.route) {\n return null;\n }\n\n const childPath = matchedComponent.props.match.route.path;\n const path =\n lastRoute && !childPath.startsWith('/')\n ? `${lastRoute.path}/${childPath}`\n : childPath;\n\n if (matchedComponent.props.routeContext?.outlet) {\n return getLastRoute(matchedComponent.props.routeContext.outlet, {\n path,\n url: matchedComponent.props.match.pathname,\n });\n }\n\n return {\n path,\n url: matchedComponent.props.match.pathname,\n };\n};\n\nexport const withMXLRouting = <P extends object>(\n WrappedComponent: React.FunctionComponent<P>,\n) => {\n const navigationInstrumentation = getNavigationInstrumentation();\n navigationInstrumentation.setInstrumentationType(\n MXL_NAVIGATION_INSTRUMENTATIONS.Declarative,\n );\n\n const RoutesWithMXLRouting: React.FC<P> = (props: P) => {\n /**\n * React-router v6+ implementation is very different from v5\n * It doesn't have a <Switch> component that injects props into <Route>\n * Instead, it has <Routes> which internally calculates the matched route\n * and returns it as a children, <Route> cannot be wrapped since it requires all children to be a <Route> component\n * here we rely on that matching to get the current route.\n * It's not ideal to rely on internal implementation details, but it's the easier way of getting the current route\n * without having to manually match it or using hooks on each children component\n *\n * See: https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/hooks.tsx#L553\n */\n const matchedComponent = WrappedComponent(\n props,\n ) as unknown as RoutesFunctionalComponentReturn;\n\n if (matchedComponent.props.match?.route) {\n const lastRoute = getLastRoute(matchedComponent, null);\n if (lastRoute) {\n navigationInstrumentation.setCurrentRoute(lastRoute);\n }\n }\n\n return createElement<P>(WrappedComponent, props);\n };\n\n // Keep wrapped component metadata\n RoutesWithMXLRouting.displayName = `withMXLRouting(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;\n hoistNonReactStatics(RoutesWithMXLRouting, WrappedComponent);\n\n return RoutesWithMXLRouting;\n};\n"],"mappings":";;;;;;;;;AASA,MAAM,gBACJ,kBACA,cACiB;AACjB,KAAI,CAAC,iBAAiB,MAAM,SAAS,CAAC,iBAAiB,MAAM,MAAM,MACjE,QAAO;CAGT,MAAM,YAAY,iBAAiB,MAAM,MAAM,MAAM;CACrD,MAAM,OACJ,aAAa,CAAC,UAAU,WAAW,IAAI,GACnC,GAAG,UAAU,KAAK,GAAG,cACrB;AAEN,KAAI,iBAAiB,MAAM,cAAc,OACvC,QAAO,aAAa,iBAAiB,MAAM,aAAa,QAAQ;EAC9D;EACA,KAAK,iBAAiB,MAAM,MAAM;EACnC,CAAC;AAGJ,QAAO;EACL;EACA,KAAK,iBAAiB,MAAM,MAAM;EACnC;;AAGH,MAAa,kBACX,qBACG;CACH,MAAM,4BAA4BA,qGAA8B;AAChE,2BAA0B,uBACxBC,6DAAgC,YACjC;CAED,MAAM,wBAAqC,UAAa;;;;;;;;;;;;EAYtD,MAAM,mBAAmB,iBACvB,MACD;AAED,MAAI,iBAAiB,MAAM,OAAO,OAAO;GACvC,MAAM,YAAY,aAAa,kBAAkB,KAAK;AACtD,OAAI,UACF,2BAA0B,gBAAgB,UAAU;;AAIxD,kCAAwB,kBAAkB,MAAM;;AAIlD,sBAAqB,cAAc,kBAAkB,iBAAiB,eAAe,iBAAiB,QAAQ,YAAY;AAC1H,sCAAqB,sBAAsB,iBAAiB;AAE5D,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"withMXLRouting.d.cts","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts"],"mappings":";;;cAkCa,cAAA,qBACX,gBAAA,EAAkB,KAAA,CAAM,iBAAA,CAAkB,CAAA,MAAE,KAAA,CAAA,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"withMXLRouting.d.cts","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts"],"mappings":";;;cAoCa,cAAA,qBACX,gBAAA,EAAkB,KAAA,CAAM,iBAAA,CAAkB,CAAA,MAAE,KAAA,CAAA,EAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"withMXLRouting.d.ts","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts"],"mappings":";;;cAkCa,cAAA,qBACX,gBAAA,EAAkB,KAAA,CAAM,iBAAA,CAAkB,CAAA,MAAE,KAAA,CAAA,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"withMXLRouting.d.ts","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts"],"mappings":";;;cAoCa,cAAA,qBACX,gBAAA,EAAkB,KAAA,CAAM,iBAAA,CAAkB,CAAA,MAAE,KAAA,CAAA,EAAA,CAAA,CAAA"}
@@ -6,7 +6,8 @@ import hoistNonReactStatics from "hoist-non-react-statics";
6
6
  //#region src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts
7
7
  const getLastRoute = (matchedComponent, lastRoute) => {
8
8
  if (!matchedComponent.props.match || !matchedComponent.props.match.route) return null;
9
- const path = lastRoute ? `${lastRoute.path}/${matchedComponent.props.match.route.path}` : matchedComponent.props.match.route.path;
9
+ const childPath = matchedComponent.props.match.route.path;
10
+ const path = lastRoute && !childPath.startsWith("/") ? `${lastRoute.path}/${childPath}` : childPath;
10
11
  if (matchedComponent.props.routeContext?.outlet) return getLastRoute(matchedComponent.props.routeContext.outlet, {
11
12
  path,
12
13
  url: matchedComponent.props.match.pathname
@@ -1 +1 @@
1
- {"version":3,"file":"withMXLRouting.js","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts"],"sourcesContent":["import hoistNonReactStatics from 'hoist-non-react-statics';\nimport type React from 'react';\nimport { createElement } from 'react';\nimport type { Route } from '../../../../../api-page/index.ts';\nimport { MXL_NAVIGATION_INSTRUMENTATIONS } from '../../../../../constants/index.ts';\nimport { getNavigationInstrumentation } from '../../index.ts';\nimport type { RoutesFunctionalComponentReturn } from './types.ts';\n\n// Routes can be nested, we need to traverse the routeContext to find the last route\nconst getLastRoute = (\n matchedComponent: RoutesFunctionalComponentReturn,\n lastRoute: Route | null,\n): Route | null => {\n if (!matchedComponent.props.match || !matchedComponent.props.match.route) {\n return null;\n }\n\n const path = lastRoute\n ? `${lastRoute.path}/${matchedComponent.props.match.route.path}`\n : matchedComponent.props.match.route.path;\n\n if (matchedComponent.props.routeContext?.outlet) {\n return getLastRoute(matchedComponent.props.routeContext.outlet, {\n path,\n url: matchedComponent.props.match.pathname,\n });\n }\n\n return {\n path,\n url: matchedComponent.props.match.pathname,\n };\n};\n\nexport const withMXLRouting = <P extends object>(\n WrappedComponent: React.FunctionComponent<P>,\n) => {\n const navigationInstrumentation = getNavigationInstrumentation();\n navigationInstrumentation.setInstrumentationType(\n MXL_NAVIGATION_INSTRUMENTATIONS.Declarative,\n );\n\n const RoutesWithMXLRouting: React.FC<P> = (props: P) => {\n /**\n * React-router v6+ implementation is very different from v5\n * It doesn't have a <Switch> component that injects props into <Route>\n * Instead, it has <Routes> which internally calculates the matched route\n * and returns it as a children, <Route> cannot be wrapped since it requires all children to be a <Route> component\n * here we rely on that matching to get the current route.\n * It's not ideal to rely on internal implementation details, but it's the easier way of getting the current route\n * without having to manually match it or using hooks on each children component\n *\n * See: https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/hooks.tsx#L553\n */\n const matchedComponent = WrappedComponent(\n props,\n ) as unknown as RoutesFunctionalComponentReturn;\n\n if (matchedComponent.props.match?.route) {\n const lastRoute = getLastRoute(matchedComponent, null);\n if (lastRoute) {\n navigationInstrumentation.setCurrentRoute(lastRoute);\n }\n }\n\n return createElement<P>(WrappedComponent, props);\n };\n\n // Keep wrapped component metadata\n RoutesWithMXLRouting.displayName = `withMXLRouting(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;\n hoistNonReactStatics(RoutesWithMXLRouting, WrappedComponent);\n\n return RoutesWithMXLRouting;\n};\n"],"mappings":";;;;;;AASA,MAAM,gBACJ,kBACA,cACiB;AACjB,KAAI,CAAC,iBAAiB,MAAM,SAAS,CAAC,iBAAiB,MAAM,MAAM,MACjE,QAAO;CAGT,MAAM,OAAO,YACT,GAAG,UAAU,KAAK,GAAG,iBAAiB,MAAM,MAAM,MAAM,SACxD,iBAAiB,MAAM,MAAM,MAAM;AAEvC,KAAI,iBAAiB,MAAM,cAAc,OACvC,QAAO,aAAa,iBAAiB,MAAM,aAAa,QAAQ;EAC9D;EACA,KAAK,iBAAiB,MAAM,MAAM;EACnC,CAAC;AAGJ,QAAO;EACL;EACA,KAAK,iBAAiB,MAAM,MAAM;EACnC;;AAGH,MAAa,kBACX,qBACG;CACH,MAAM,4BAA4B,8BAA8B;AAChE,2BAA0B,uBACxB,gCAAgC,YACjC;CAED,MAAM,wBAAqC,UAAa;;;;;;;;;;;;EAYtD,MAAM,mBAAmB,iBACvB,MACD;AAED,MAAI,iBAAiB,MAAM,OAAO,OAAO;GACvC,MAAM,YAAY,aAAa,kBAAkB,KAAK;AACtD,OAAI,UACF,2BAA0B,gBAAgB,UAAU;;AAIxD,SAAO,cAAiB,kBAAkB,MAAM;;AAIlD,sBAAqB,cAAc,kBAAkB,iBAAiB,eAAe,iBAAiB,QAAQ,YAAY;AAC1H,sBAAqB,sBAAsB,iBAAiB;AAE5D,QAAO"}
1
+ {"version":3,"file":"withMXLRouting.js","names":[],"sources":["../../../../../../src/instrumentations/navigation/NavigationInstrumentation/react/reactRouterV6Declarative/withMXLRouting.ts"],"sourcesContent":["import hoistNonReactStatics from 'hoist-non-react-statics';\nimport type React from 'react';\nimport { createElement } from 'react';\nimport type { Route } from '../../../../../api-page/index.ts';\nimport { MXL_NAVIGATION_INSTRUMENTATIONS } from '../../../../../constants/index.ts';\nimport { getNavigationInstrumentation } from '../../index.ts';\nimport type { RoutesFunctionalComponentReturn } from './types.ts';\n\n// Routes can be nested, we need to traverse the routeContext to find the last route\nconst getLastRoute = (\n matchedComponent: RoutesFunctionalComponentReturn,\n lastRoute: Route | null,\n): Route | null => {\n if (!matchedComponent.props.match || !matchedComponent.props.match.route) {\n return null;\n }\n\n const childPath = matchedComponent.props.match.route.path;\n const path =\n lastRoute && !childPath.startsWith('/')\n ? `${lastRoute.path}/${childPath}`\n : childPath;\n\n if (matchedComponent.props.routeContext?.outlet) {\n return getLastRoute(matchedComponent.props.routeContext.outlet, {\n path,\n url: matchedComponent.props.match.pathname,\n });\n }\n\n return {\n path,\n url: matchedComponent.props.match.pathname,\n };\n};\n\nexport const withMXLRouting = <P extends object>(\n WrappedComponent: React.FunctionComponent<P>,\n) => {\n const navigationInstrumentation = getNavigationInstrumentation();\n navigationInstrumentation.setInstrumentationType(\n MXL_NAVIGATION_INSTRUMENTATIONS.Declarative,\n );\n\n const RoutesWithMXLRouting: React.FC<P> = (props: P) => {\n /**\n * React-router v6+ implementation is very different from v5\n * It doesn't have a <Switch> component that injects props into <Route>\n * Instead, it has <Routes> which internally calculates the matched route\n * and returns it as a children, <Route> cannot be wrapped since it requires all children to be a <Route> component\n * here we rely on that matching to get the current route.\n * It's not ideal to rely on internal implementation details, but it's the easier way of getting the current route\n * without having to manually match it or using hooks on each children component\n *\n * See: https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/hooks.tsx#L553\n */\n const matchedComponent = WrappedComponent(\n props,\n ) as unknown as RoutesFunctionalComponentReturn;\n\n if (matchedComponent.props.match?.route) {\n const lastRoute = getLastRoute(matchedComponent, null);\n if (lastRoute) {\n navigationInstrumentation.setCurrentRoute(lastRoute);\n }\n }\n\n return createElement<P>(WrappedComponent, props);\n };\n\n // Keep wrapped component metadata\n RoutesWithMXLRouting.displayName = `withMXLRouting(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;\n hoistNonReactStatics(RoutesWithMXLRouting, WrappedComponent);\n\n return RoutesWithMXLRouting;\n};\n"],"mappings":";;;;;;AASA,MAAM,gBACJ,kBACA,cACiB;AACjB,KAAI,CAAC,iBAAiB,MAAM,SAAS,CAAC,iBAAiB,MAAM,MAAM,MACjE,QAAO;CAGT,MAAM,YAAY,iBAAiB,MAAM,MAAM,MAAM;CACrD,MAAM,OACJ,aAAa,CAAC,UAAU,WAAW,IAAI,GACnC,GAAG,UAAU,KAAK,GAAG,cACrB;AAEN,KAAI,iBAAiB,MAAM,cAAc,OACvC,QAAO,aAAa,iBAAiB,MAAM,aAAa,QAAQ;EAC9D;EACA,KAAK,iBAAiB,MAAM,MAAM;EACnC,CAAC;AAGJ,QAAO;EACL;EACA,KAAK,iBAAiB,MAAM,MAAM;EACnC;;AAGH,MAAa,kBACX,qBACG;CACH,MAAM,4BAA4B,8BAA8B;AAChE,2BAA0B,uBACxB,gCAAgC,YACjC;CAED,MAAM,wBAAqC,UAAa;;;;;;;;;;;;EAYtD,MAAM,mBAAmB,iBACvB,MACD;AAED,MAAI,iBAAiB,MAAM,OAAO,OAAO;GACvC,MAAM,YAAY,aAAa,kBAAkB,KAAK;AACtD,OAAI,UACF,2BAA0B,gBAAgB,UAAU;;AAIxD,SAAO,cAAiB,kBAAkB,MAAM;;AAIlD,sBAAqB,cAAc,kBAAkB,iBAAiB,eAAe,iBAAiB,QAAQ,YAAY;AAC1H,sBAAqB,sBAAsB,iBAAiB;AAE5D,QAAO"}
@@ -151,6 +151,7 @@ var WebVitalsInstrumentation = class extends require_instrumentations_MXLInstrum
151
151
  const attrs = {
152
152
  [require_constants_attributes.KEY_MXL_TYPE]: require_constants_attributes.MXL_TYPES.WebVital,
153
153
  [_opentelemetry_semantic_conventions.ATTR_URL_FULL]: attributedPage.fullURL,
154
+ [require_constants_attributes.KEY_BROWSER_URL_FULL]: attributedPage.fullURL,
154
155
  "mxl.web_vital.navigation_type": metric.navigationType,
155
156
  "mxl.web_vital.name": metric.name,
156
157
  "mxl.web_vital.rating": metric.rating,
@@ -1 +1 @@
1
- {"version":3,"file":"WebVitalsInstrumentation.cjs","names":["MXLInstrumentationBase","WEB_VITALS_ID_TO_LISTENER","page","KEY_MXL_TYPE","MXL_TYPES","ATTR_URL_FULL","KEY_MXL_PAGE_PATH","KEY_MXL_PAGE_ID","KEY_APP_SURFACE_LABEL","MXL_WEB_VITALS_PREFIX"],"sources":["../../../../src/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.ts"],"sourcesContent":["import type { Attributes } from '@opentelemetry/api';\nimport { ATTR_URL_FULL } from '@opentelemetry/semantic-conventions';\nimport type {\n CLSAttribution,\n CLSMetricWithAttribution,\n INPAttribution,\n LCPAttribution,\n Metric,\n MetricWithAttribution,\n} from 'web-vitals/attribution';\nimport type { PageManager } from '../../../api-page/index.ts';\nimport { page } from '../../../api-page/index.ts';\nimport type { URLDocument } from '../../../common/index.ts';\nimport {\n KEY_APP_SURFACE_LABEL,\n KEY_MXL_PAGE_ID,\n KEY_MXL_PAGE_PATH,\n KEY_MXL_TYPE,\n MXL_TYPES,\n} from '../../../constants/index.ts';\nimport { MXLInstrumentationBase } from '../../MXLInstrumentationBase/index.ts';\nimport {\n ALL_WEB_VITALS,\n MXL_WEB_VITALS_PREFIX,\n WEB_VITALS_ID_TO_LISTENER,\n} from './constants.ts';\nimport type {\n WebVitalListeners,\n WebVitalsInstrumentationArgs,\n} from './types.ts';\n\ntype AttributedPage = {\n fullURL: string;\n path?: string;\n pageID?: string;\n label?: string;\n};\n\nconst webVitalAttributionToReport = (\n name: Metric['name'],\n metric: MetricWithAttribution,\n) => {\n const attributes: Attributes = {};\n const toReport: {\n key: string;\n value: string | boolean | number | undefined;\n }[] = [];\n\n if (name === 'CLS') {\n // https://www.npmjs.com/package/web-vitals#CLSAttribution\n const attribution = metric.attribution as CLSAttribution;\n toReport.push(\n ...[\n {\n key: 'largestShiftTarget',\n value: attribution.largestShiftTarget,\n },\n {\n key: 'largestShiftValue',\n value: attribution.largestShiftValue,\n },\n ],\n );\n } else if (name === 'INP') {\n // https://www.npmjs.com/package/web-vitals#inpattribution\n const attribution = metric.attribution as INPAttribution;\n toReport.push(\n ...[\n { key: 'interactionTarget', value: attribution.interactionTarget },\n { key: 'interactionType', value: attribution.interactionType },\n { key: 'nextPaintTime', value: attribution.nextPaintTime },\n { key: 'inputDelay', value: attribution.inputDelay },\n { key: 'processingDuration', value: attribution.processingDuration },\n { key: 'presentationDelay', value: attribution.presentationDelay },\n { key: 'totalScriptDuration', value: attribution.totalScriptDuration },\n {\n key: 'totalStyleAndLayoutDuration',\n value: attribution.totalStyleAndLayoutDuration,\n },\n { key: 'totalPaintDuration', value: attribution.totalPaintDuration },\n {\n key: 'totalUnattributedDuration',\n value: attribution.totalUnattributedDuration,\n },\n { key: 'loadState', value: attribution.loadState },\n ],\n );\n } else if (name === 'LCP') {\n // https://www.npmjs.com/package/web-vitals#lcpattribution\n const attribution = metric.attribution as LCPAttribution;\n toReport.push(\n ...[\n { key: 'target', value: attribution.target },\n { key: 'url', value: attribution.url },\n { key: 'timeToFirstByte', value: attribution.timeToFirstByte },\n { key: 'resourceLoadDelay', value: attribution.resourceLoadDelay },\n {\n key: 'resourceLoadDuration',\n value: attribution.resourceLoadDuration,\n },\n { key: 'elementRenderDelay', value: attribution.elementRenderDelay },\n ],\n );\n }\n\n toReport.forEach((report) => {\n if (report.value !== undefined) {\n attributes[`mxl.web_vital.attribution.${report.key}`] = report.value;\n }\n });\n\n return attributes;\n};\n\nexport class WebVitalsInstrumentation extends MXLInstrumentationBase {\n private readonly _listeners: WebVitalListeners;\n private readonly _urlDocument: URLDocument;\n private readonly _urlAttribution: boolean;\n private readonly _pageManager: PageManager;\n private readonly _attributedPage: Record<\n Metric['name'],\n AttributedPage | undefined\n > = {\n INP: undefined,\n LCP: undefined,\n CLS: undefined,\n FCP: undefined,\n TTFB: undefined,\n };\n private _largestShiftTargetForCLS: string | undefined;\n private _listenersRegistered = false;\n private _isEnabled = false;\n\n // instrumentation that adds an event to the session span for each web vital report\n public constructor({\n diag,\n perf,\n listeners = WEB_VITALS_ID_TO_LISTENER,\n urlDocument = window.document,\n urlAttribution = true,\n pageManager,\n }: WebVitalsInstrumentationArgs = {}) {\n super({\n instrumentationName: 'WebVitalsInstrumentation',\n instrumentationVersion: '1.0.0',\n diag,\n perf,\n config: {},\n });\n this._listeners = listeners;\n this._urlDocument = urlDocument;\n this._urlAttribution = urlAttribution;\n this._pageManager = pageManager ?? page.getPageManager();\n\n if (this._config.enabled) {\n this.enable();\n }\n }\n\n public override disable(): void {\n // web-vitals library doesn't support removing listeners, so we just pause emission\n // https://github.com/GoogleChrome/web-vitals/issues/357#issuecomment-1593439036\n this._isEnabled = false;\n this._diag.debug('WebVitalsInstrumentation disabled, pausing emission');\n }\n\n public enable(): void {\n this._isEnabled = true;\n\n // web-vitals library doesn't support removing listeners, so only register once\n if (this._listenersRegistered) {\n this._diag.debug(\n 'WebVitalsInstrumentation listeners already registered, resuming emission',\n );\n return;\n }\n this._listenersRegistered = true;\n\n ALL_WEB_VITALS.forEach((name) => {\n this._listeners[name]?.((metric) => {\n if (!this._isEnabled) {\n return;\n }\n\n const currentSessionSpan = this.sessionManager.getSessionSpan();\n\n if (!currentSessionSpan) {\n return;\n }\n\n // first thing record the time when this cb was invoked\n const metricTime = this._getTimeForMetric(metric);\n\n const attributedPage = this._getAttributedPageForMetric(metric);\n\n const attrs: Attributes = {\n [KEY_MXL_TYPE]: MXL_TYPES.WebVital,\n [ATTR_URL_FULL]: attributedPage.fullURL,\n 'mxl.web_vital.navigation_type': metric.navigationType,\n 'mxl.web_vital.name': metric.name,\n 'mxl.web_vital.rating': metric.rating,\n 'mxl.web_vital.id': metric.id,\n 'mxl.web_vital.delta': metric.delta,\n 'mxl.web_vital.value': metric.value,\n ...webVitalAttributionToReport(name, metric),\n };\n\n // Add page attributes if route and page ID exist\n if (attributedPage.path && attributedPage.pageID) {\n attrs[KEY_MXL_PAGE_PATH] = attributedPage.path;\n attrs[KEY_MXL_PAGE_ID] = attributedPage.pageID;\n }\n\n if (attributedPage.label) {\n attrs[KEY_APP_SURFACE_LABEL] = attributedPage.label;\n }\n\n currentSessionSpan.addEvent(\n `${MXL_WEB_VITALS_PREFIX}-report-${name}`,\n attrs,\n metricTime,\n );\n });\n });\n\n if (this._urlAttribution) {\n // When these web vitals make their final report (e.g. when the listeners w/ reportAllChanges=false trigger) the\n // document's URL at that time may not match what it was at the time the scores were last updated. Instead, listen\n // for updates to the scores and keep track of the Page information to attribute for each\n this._listeners.TTFB?.(\n () => {\n this._attributedPage.TTFB = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.FCP?.(\n () => {\n this._attributedPage.FCP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.INP?.(\n () => {\n this._attributedPage.INP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.LCP?.(\n () => {\n this._attributedPage.LCP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.CLS?.(\n (metric: MetricWithAttribution) => {\n const clsMetric = metric as CLSMetricWithAttribution;\n // A layout shift could cause CLS to change its rating but because the score is cumulative this might not\n // correspond with an updated `largestShiftTarget`. Since we want to tie the attributed URL to the page that\n // the `largestShiftTarget` was on we only update the attributed URL if that target has changed\n if (\n this._largestShiftTargetForCLS !==\n clsMetric.attribution.largestShiftTarget\n ) {\n this._largestShiftTargetForCLS =\n clsMetric.attribution.largestShiftTarget;\n this._attributedPage.CLS = this._currentAttributedPage();\n }\n },\n {\n reportAllChanges: true,\n },\n );\n }\n }\n\n private _getTimeForMetric(metric: MetricWithAttribution): number {\n if (metric.name === 'CLS' && metric.attribution.largestShiftTime) {\n return this.perf.epochMillisFromOriginOffset(\n metric.attribution.largestShiftTime,\n );\n }\n\n if (metric.name === 'INP' && metric.attribution.interactionTime) {\n return this.perf.epochMillisFromOriginOffset(\n metric.attribution.interactionTime,\n );\n }\n\n return this.perf.getNowMillis();\n }\n\n private _currentAttributedPage(): AttributedPage {\n const attributed: AttributedPage = {\n fullURL: this._urlDocument.URL,\n };\n\n const currentRoute = this._pageManager.getCurrentRoute();\n const currentPageId = this._pageManager.getCurrentPageId();\n if (currentRoute && currentPageId) {\n attributed.path = currentRoute.path;\n attributed.pageID = currentPageId;\n }\n\n const pageLabel = this._pageManager.getPageLabel();\n if (pageLabel) {\n attributed.label = pageLabel;\n }\n\n return attributed;\n }\n\n private _getAttributedPageForMetric(\n metric: MetricWithAttribution,\n ): AttributedPage {\n if (metric.name === 'FCP' && this._attributedPage.FCP) {\n return this._attributedPage.FCP;\n }\n\n if (metric.name === 'TTFB' && this._attributedPage.TTFB) {\n return this._attributedPage.TTFB;\n }\n\n if (metric.name === 'INP' && this._attributedPage.INP) {\n return this._attributedPage.INP;\n }\n\n if (metric.name === 'LCP' && this._attributedPage.LCP) {\n return this._attributedPage.LCP;\n }\n\n if (\n metric.name === 'CLS' &&\n this._attributedPage.CLS &&\n metric.attribution.largestShiftTarget === this._largestShiftTargetForCLS\n ) {\n return this._attributedPage.CLS;\n }\n\n return this._currentAttributedPage();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WebVitalsInstrumentation.cjs","names":["MXLInstrumentationBase","WEB_VITALS_ID_TO_LISTENER","page","KEY_MXL_TYPE","MXL_TYPES","ATTR_URL_FULL","KEY_BROWSER_URL_FULL","KEY_MXL_PAGE_PATH","KEY_MXL_PAGE_ID","KEY_APP_SURFACE_LABEL","MXL_WEB_VITALS_PREFIX"],"sources":["../../../../src/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.ts"],"sourcesContent":["import type { Attributes } from '@opentelemetry/api';\nimport { ATTR_URL_FULL } from '@opentelemetry/semantic-conventions';\nimport type {\n CLSAttribution,\n CLSMetricWithAttribution,\n INPAttribution,\n LCPAttribution,\n Metric,\n MetricWithAttribution,\n} from 'web-vitals/attribution';\nimport type { PageManager } from '../../../api-page/index.ts';\nimport { page } from '../../../api-page/index.ts';\nimport type { URLDocument } from '../../../common/index.ts';\nimport {\n KEY_APP_SURFACE_LABEL,\n KEY_MXL_PAGE_ID,\n KEY_MXL_PAGE_PATH,\n KEY_MXL_TYPE,\n KEY_BROWSER_URL_FULL,\n MXL_TYPES,\n} from '../../../constants/index.ts';\nimport { MXLInstrumentationBase } from '../../MXLInstrumentationBase/index.ts';\nimport {\n ALL_WEB_VITALS,\n MXL_WEB_VITALS_PREFIX,\n WEB_VITALS_ID_TO_LISTENER,\n} from './constants.ts';\nimport type {\n WebVitalListeners,\n WebVitalsInstrumentationArgs,\n} from './types.ts';\n\ntype AttributedPage = {\n fullURL: string;\n path?: string;\n pageID?: string;\n label?: string;\n};\n\nconst webVitalAttributionToReport = (\n name: Metric['name'],\n metric: MetricWithAttribution,\n) => {\n const attributes: Attributes = {};\n const toReport: {\n key: string;\n value: string | boolean | number | undefined;\n }[] = [];\n\n if (name === 'CLS') {\n // https://www.npmjs.com/package/web-vitals#CLSAttribution\n const attribution = metric.attribution as CLSAttribution;\n toReport.push(\n ...[\n {\n key: 'largestShiftTarget',\n value: attribution.largestShiftTarget,\n },\n {\n key: 'largestShiftValue',\n value: attribution.largestShiftValue,\n },\n ],\n );\n } else if (name === 'INP') {\n // https://www.npmjs.com/package/web-vitals#inpattribution\n const attribution = metric.attribution as INPAttribution;\n toReport.push(\n ...[\n { key: 'interactionTarget', value: attribution.interactionTarget },\n { key: 'interactionType', value: attribution.interactionType },\n { key: 'nextPaintTime', value: attribution.nextPaintTime },\n { key: 'inputDelay', value: attribution.inputDelay },\n { key: 'processingDuration', value: attribution.processingDuration },\n { key: 'presentationDelay', value: attribution.presentationDelay },\n { key: 'totalScriptDuration', value: attribution.totalScriptDuration },\n {\n key: 'totalStyleAndLayoutDuration',\n value: attribution.totalStyleAndLayoutDuration,\n },\n { key: 'totalPaintDuration', value: attribution.totalPaintDuration },\n {\n key: 'totalUnattributedDuration',\n value: attribution.totalUnattributedDuration,\n },\n { key: 'loadState', value: attribution.loadState },\n ],\n );\n } else if (name === 'LCP') {\n // https://www.npmjs.com/package/web-vitals#lcpattribution\n const attribution = metric.attribution as LCPAttribution;\n toReport.push(\n ...[\n { key: 'target', value: attribution.target },\n { key: 'url', value: attribution.url },\n { key: 'timeToFirstByte', value: attribution.timeToFirstByte },\n { key: 'resourceLoadDelay', value: attribution.resourceLoadDelay },\n {\n key: 'resourceLoadDuration',\n value: attribution.resourceLoadDuration,\n },\n { key: 'elementRenderDelay', value: attribution.elementRenderDelay },\n ],\n );\n }\n\n toReport.forEach((report) => {\n if (report.value !== undefined) {\n attributes[`mxl.web_vital.attribution.${report.key}`] = report.value;\n }\n });\n\n return attributes;\n};\n\nexport class WebVitalsInstrumentation extends MXLInstrumentationBase {\n private readonly _listeners: WebVitalListeners;\n private readonly _urlDocument: URLDocument;\n private readonly _urlAttribution: boolean;\n private readonly _pageManager: PageManager;\n private readonly _attributedPage: Record<\n Metric['name'],\n AttributedPage | undefined\n > = {\n INP: undefined,\n LCP: undefined,\n CLS: undefined,\n FCP: undefined,\n TTFB: undefined,\n };\n private _largestShiftTargetForCLS: string | undefined;\n private _listenersRegistered = false;\n private _isEnabled = false;\n\n // instrumentation that adds an event to the session span for each web vital report\n public constructor({\n diag,\n perf,\n listeners = WEB_VITALS_ID_TO_LISTENER,\n urlDocument = window.document,\n urlAttribution = true,\n pageManager,\n }: WebVitalsInstrumentationArgs = {}) {\n super({\n instrumentationName: 'WebVitalsInstrumentation',\n instrumentationVersion: '1.0.0',\n diag,\n perf,\n config: {},\n });\n this._listeners = listeners;\n this._urlDocument = urlDocument;\n this._urlAttribution = urlAttribution;\n this._pageManager = pageManager ?? page.getPageManager();\n\n if (this._config.enabled) {\n this.enable();\n }\n }\n\n public override disable(): void {\n // web-vitals library doesn't support removing listeners, so we just pause emission\n // https://github.com/GoogleChrome/web-vitals/issues/357#issuecomment-1593439036\n this._isEnabled = false;\n this._diag.debug('WebVitalsInstrumentation disabled, pausing emission');\n }\n\n public enable(): void {\n this._isEnabled = true;\n\n // web-vitals library doesn't support removing listeners, so only register once\n if (this._listenersRegistered) {\n this._diag.debug(\n 'WebVitalsInstrumentation listeners already registered, resuming emission',\n );\n return;\n }\n this._listenersRegistered = true;\n\n ALL_WEB_VITALS.forEach((name) => {\n this._listeners[name]?.((metric) => {\n if (!this._isEnabled) {\n return;\n }\n\n const currentSessionSpan = this.sessionManager.getSessionSpan();\n\n if (!currentSessionSpan) {\n return;\n }\n\n // first thing record the time when this cb was invoked\n const metricTime = this._getTimeForMetric(metric);\n\n const attributedPage = this._getAttributedPageForMetric(metric);\n\n const attrs: Attributes = {\n [KEY_MXL_TYPE]: MXL_TYPES.WebVital,\n [ATTR_URL_FULL]: attributedPage.fullURL,\n [KEY_BROWSER_URL_FULL]: attributedPage.fullURL,\n 'mxl.web_vital.navigation_type': metric.navigationType,\n 'mxl.web_vital.name': metric.name,\n 'mxl.web_vital.rating': metric.rating,\n 'mxl.web_vital.id': metric.id,\n 'mxl.web_vital.delta': metric.delta,\n 'mxl.web_vital.value': metric.value,\n ...webVitalAttributionToReport(name, metric),\n };\n\n // Add page attributes if route and page ID exist\n if (attributedPage.path && attributedPage.pageID) {\n attrs[KEY_MXL_PAGE_PATH] = attributedPage.path;\n attrs[KEY_MXL_PAGE_ID] = attributedPage.pageID;\n }\n\n if (attributedPage.label) {\n attrs[KEY_APP_SURFACE_LABEL] = attributedPage.label;\n }\n\n currentSessionSpan.addEvent(\n `${MXL_WEB_VITALS_PREFIX}-report-${name}`,\n attrs,\n metricTime,\n );\n });\n });\n\n if (this._urlAttribution) {\n // When these web vitals make their final report (e.g. when the listeners w/ reportAllChanges=false trigger) the\n // document's URL at that time may not match what it was at the time the scores were last updated. Instead, listen\n // for updates to the scores and keep track of the Page information to attribute for each\n this._listeners.TTFB?.(\n () => {\n this._attributedPage.TTFB = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.FCP?.(\n () => {\n this._attributedPage.FCP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.INP?.(\n () => {\n this._attributedPage.INP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.LCP?.(\n () => {\n this._attributedPage.LCP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.CLS?.(\n (metric: MetricWithAttribution) => {\n const clsMetric = metric as CLSMetricWithAttribution;\n // A layout shift could cause CLS to change its rating but because the score is cumulative this might not\n // correspond with an updated `largestShiftTarget`. Since we want to tie the attributed URL to the page that\n // the `largestShiftTarget` was on we only update the attributed URL if that target has changed\n if (\n this._largestShiftTargetForCLS !==\n clsMetric.attribution.largestShiftTarget\n ) {\n this._largestShiftTargetForCLS =\n clsMetric.attribution.largestShiftTarget;\n this._attributedPage.CLS = this._currentAttributedPage();\n }\n },\n {\n reportAllChanges: true,\n },\n );\n }\n }\n\n private _getTimeForMetric(metric: MetricWithAttribution): number {\n if (metric.name === 'CLS' && metric.attribution.largestShiftTime) {\n return this.perf.epochMillisFromOriginOffset(\n metric.attribution.largestShiftTime,\n );\n }\n\n if (metric.name === 'INP' && metric.attribution.interactionTime) {\n return this.perf.epochMillisFromOriginOffset(\n metric.attribution.interactionTime,\n );\n }\n\n return this.perf.getNowMillis();\n }\n\n private _currentAttributedPage(): AttributedPage {\n const attributed: AttributedPage = {\n fullURL: this._urlDocument.URL,\n };\n\n const currentRoute = this._pageManager.getCurrentRoute();\n const currentPageId = this._pageManager.getCurrentPageId();\n if (currentRoute && currentPageId) {\n attributed.path = currentRoute.path;\n attributed.pageID = currentPageId;\n }\n\n const pageLabel = this._pageManager.getPageLabel();\n if (pageLabel) {\n attributed.label = pageLabel;\n }\n\n return attributed;\n }\n\n private _getAttributedPageForMetric(\n metric: MetricWithAttribution,\n ): AttributedPage {\n if (metric.name === 'FCP' && this._attributedPage.FCP) {\n return this._attributedPage.FCP;\n }\n\n if (metric.name === 'TTFB' && this._attributedPage.TTFB) {\n return this._attributedPage.TTFB;\n }\n\n if (metric.name === 'INP' && this._attributedPage.INP) {\n return this._attributedPage.INP;\n }\n\n if (metric.name === 'LCP' && this._attributedPage.LCP) {\n return this._attributedPage.LCP;\n }\n\n if (\n metric.name === 'CLS' &&\n this._attributedPage.CLS &&\n metric.attribution.largestShiftTarget === this._largestShiftTargetForCLS\n ) {\n return this._attributedPage.CLS;\n }\n\n return this._currentAttributedPage();\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"WebVitalsInstrumentation.d.cts","names":[],"sources":["../../../../src/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.ts"],"mappings":";;;;cAkHa,wBAAA,SAAiC,sBAAA;EAAA,iBAC3B,UAAA;EAAA,iBACA,YAAA;EAAA,iBACA,eAAA;EAAA,iBACA,YAAA;EAAA,iBACA,eAAA;EAAA,QAUT,yBAAA;EAAA,QACA,oBAAA;EAAA,QACA,UAAA;;IAIN,IAAA;IACA,IAAA;IACA,SAAA;IACA,WAAA;IACA,cAAA;IACA;EAAA,IACC,4BAAA;EAkBa,OAAA,CAAA;EAOT,MAAA,CAAA;EAAA,QAqHC,iBAAA;EAAA,QAgBA,sBAAA;EAAA,QAoBA,2BAAA;AAAA"}
1
+ {"version":3,"file":"WebVitalsInstrumentation.d.cts","names":[],"sources":["../../../../src/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.ts"],"mappings":";;;;cAmHa,wBAAA,SAAiC,sBAAA;EAAA,iBAC3B,UAAA;EAAA,iBACA,YAAA;EAAA,iBACA,eAAA;EAAA,iBACA,YAAA;EAAA,iBACA,eAAA;EAAA,QAUT,yBAAA;EAAA,QACA,oBAAA;EAAA,QACA,UAAA;;IAIN,IAAA;IACA,IAAA;IACA,SAAA;IACA,WAAA;IACA,cAAA;IACA;EAAA,IACC,4BAAA;EAkBa,OAAA,CAAA;EAOT,MAAA,CAAA;EAAA,QAsHC,iBAAA;EAAA,QAgBA,sBAAA;EAAA,QAoBA,2BAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"WebVitalsInstrumentation.d.ts","names":[],"sources":["../../../../src/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.ts"],"mappings":";;;;;cAkHa,wBAAA,SAAiC,sBAAA;EAAA,iBAC3B,UAAA;EAAA,iBACA,YAAA;EAAA,iBACA,eAAA;EAAA,iBACA,YAAA;EAAA,iBACA,eAAA;EAAA,QAUT,yBAAA;EAAA,QACA,oBAAA;EAAA,QACA,UAAA;;IAIN,IAAA;IACA,IAAA;IACA,SAAA;IACA,WAAA;IACA,cAAA;IACA;EAAA,IACC,4BAAA;EAkBa,OAAA,CAAA;EAOT,MAAA,CAAA;EAAA,QAqHC,iBAAA;EAAA,QAgBA,sBAAA;EAAA,QAoBA,2BAAA;AAAA"}
1
+ {"version":3,"file":"WebVitalsInstrumentation.d.ts","names":[],"sources":["../../../../src/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.ts"],"mappings":";;;;;cAmHa,wBAAA,SAAiC,sBAAA;EAAA,iBAC3B,UAAA;EAAA,iBACA,YAAA;EAAA,iBACA,eAAA;EAAA,iBACA,YAAA;EAAA,iBACA,eAAA;EAAA,QAUT,yBAAA;EAAA,QACA,oBAAA;EAAA,QACA,UAAA;;IAIN,IAAA;IACA,IAAA;IACA,SAAA;IACA,WAAA;IACA,cAAA;IACA;EAAA,IACC,4BAAA;EAkBa,OAAA,CAAA;EAOT,MAAA,CAAA;EAAA,QAsHC,iBAAA;EAAA,QAgBA,sBAAA;EAAA,QAoBA,2BAAA;AAAA"}
@@ -1,4 +1,4 @@
1
- import { KEY_APP_SURFACE_LABEL, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_TYPE, MXL_TYPES } from "../../../constants/attributes.js";
1
+ import { KEY_APP_SURFACE_LABEL, KEY_BROWSER_URL_FULL, KEY_MXL_PAGE_ID, KEY_MXL_PAGE_PATH, KEY_MXL_TYPE, MXL_TYPES } from "../../../constants/attributes.js";
2
2
  import { page } from "../../../api-page/pageAPI.js";
3
3
  import { MXLInstrumentationBase } from "../../MXLInstrumentationBase/MXLInstrumentationBase.js";
4
4
  import { ALL_WEB_VITALS, MXL_WEB_VITALS_PREFIX, WEB_VITALS_ID_TO_LISTENER } from "./constants.js";
@@ -149,6 +149,7 @@ var WebVitalsInstrumentation = class extends MXLInstrumentationBase {
149
149
  const attrs = {
150
150
  [KEY_MXL_TYPE]: MXL_TYPES.WebVital,
151
151
  [ATTR_URL_FULL]: attributedPage.fullURL,
152
+ [KEY_BROWSER_URL_FULL]: attributedPage.fullURL,
152
153
  "mxl.web_vital.navigation_type": metric.navigationType,
153
154
  "mxl.web_vital.name": metric.name,
154
155
  "mxl.web_vital.rating": metric.rating,
@@ -1 +1 @@
1
- {"version":3,"file":"WebVitalsInstrumentation.js","names":[],"sources":["../../../../src/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.ts"],"sourcesContent":["import type { Attributes } from '@opentelemetry/api';\nimport { ATTR_URL_FULL } from '@opentelemetry/semantic-conventions';\nimport type {\n CLSAttribution,\n CLSMetricWithAttribution,\n INPAttribution,\n LCPAttribution,\n Metric,\n MetricWithAttribution,\n} from 'web-vitals/attribution';\nimport type { PageManager } from '../../../api-page/index.ts';\nimport { page } from '../../../api-page/index.ts';\nimport type { URLDocument } from '../../../common/index.ts';\nimport {\n KEY_APP_SURFACE_LABEL,\n KEY_MXL_PAGE_ID,\n KEY_MXL_PAGE_PATH,\n KEY_MXL_TYPE,\n MXL_TYPES,\n} from '../../../constants/index.ts';\nimport { MXLInstrumentationBase } from '../../MXLInstrumentationBase/index.ts';\nimport {\n ALL_WEB_VITALS,\n MXL_WEB_VITALS_PREFIX,\n WEB_VITALS_ID_TO_LISTENER,\n} from './constants.ts';\nimport type {\n WebVitalListeners,\n WebVitalsInstrumentationArgs,\n} from './types.ts';\n\ntype AttributedPage = {\n fullURL: string;\n path?: string;\n pageID?: string;\n label?: string;\n};\n\nconst webVitalAttributionToReport = (\n name: Metric['name'],\n metric: MetricWithAttribution,\n) => {\n const attributes: Attributes = {};\n const toReport: {\n key: string;\n value: string | boolean | number | undefined;\n }[] = [];\n\n if (name === 'CLS') {\n // https://www.npmjs.com/package/web-vitals#CLSAttribution\n const attribution = metric.attribution as CLSAttribution;\n toReport.push(\n ...[\n {\n key: 'largestShiftTarget',\n value: attribution.largestShiftTarget,\n },\n {\n key: 'largestShiftValue',\n value: attribution.largestShiftValue,\n },\n ],\n );\n } else if (name === 'INP') {\n // https://www.npmjs.com/package/web-vitals#inpattribution\n const attribution = metric.attribution as INPAttribution;\n toReport.push(\n ...[\n { key: 'interactionTarget', value: attribution.interactionTarget },\n { key: 'interactionType', value: attribution.interactionType },\n { key: 'nextPaintTime', value: attribution.nextPaintTime },\n { key: 'inputDelay', value: attribution.inputDelay },\n { key: 'processingDuration', value: attribution.processingDuration },\n { key: 'presentationDelay', value: attribution.presentationDelay },\n { key: 'totalScriptDuration', value: attribution.totalScriptDuration },\n {\n key: 'totalStyleAndLayoutDuration',\n value: attribution.totalStyleAndLayoutDuration,\n },\n { key: 'totalPaintDuration', value: attribution.totalPaintDuration },\n {\n key: 'totalUnattributedDuration',\n value: attribution.totalUnattributedDuration,\n },\n { key: 'loadState', value: attribution.loadState },\n ],\n );\n } else if (name === 'LCP') {\n // https://www.npmjs.com/package/web-vitals#lcpattribution\n const attribution = metric.attribution as LCPAttribution;\n toReport.push(\n ...[\n { key: 'target', value: attribution.target },\n { key: 'url', value: attribution.url },\n { key: 'timeToFirstByte', value: attribution.timeToFirstByte },\n { key: 'resourceLoadDelay', value: attribution.resourceLoadDelay },\n {\n key: 'resourceLoadDuration',\n value: attribution.resourceLoadDuration,\n },\n { key: 'elementRenderDelay', value: attribution.elementRenderDelay },\n ],\n );\n }\n\n toReport.forEach((report) => {\n if (report.value !== undefined) {\n attributes[`mxl.web_vital.attribution.${report.key}`] = report.value;\n }\n });\n\n return attributes;\n};\n\nexport class WebVitalsInstrumentation extends MXLInstrumentationBase {\n private readonly _listeners: WebVitalListeners;\n private readonly _urlDocument: URLDocument;\n private readonly _urlAttribution: boolean;\n private readonly _pageManager: PageManager;\n private readonly _attributedPage: Record<\n Metric['name'],\n AttributedPage | undefined\n > = {\n INP: undefined,\n LCP: undefined,\n CLS: undefined,\n FCP: undefined,\n TTFB: undefined,\n };\n private _largestShiftTargetForCLS: string | undefined;\n private _listenersRegistered = false;\n private _isEnabled = false;\n\n // instrumentation that adds an event to the session span for each web vital report\n public constructor({\n diag,\n perf,\n listeners = WEB_VITALS_ID_TO_LISTENER,\n urlDocument = window.document,\n urlAttribution = true,\n pageManager,\n }: WebVitalsInstrumentationArgs = {}) {\n super({\n instrumentationName: 'WebVitalsInstrumentation',\n instrumentationVersion: '1.0.0',\n diag,\n perf,\n config: {},\n });\n this._listeners = listeners;\n this._urlDocument = urlDocument;\n this._urlAttribution = urlAttribution;\n this._pageManager = pageManager ?? page.getPageManager();\n\n if (this._config.enabled) {\n this.enable();\n }\n }\n\n public override disable(): void {\n // web-vitals library doesn't support removing listeners, so we just pause emission\n // https://github.com/GoogleChrome/web-vitals/issues/357#issuecomment-1593439036\n this._isEnabled = false;\n this._diag.debug('WebVitalsInstrumentation disabled, pausing emission');\n }\n\n public enable(): void {\n this._isEnabled = true;\n\n // web-vitals library doesn't support removing listeners, so only register once\n if (this._listenersRegistered) {\n this._diag.debug(\n 'WebVitalsInstrumentation listeners already registered, resuming emission',\n );\n return;\n }\n this._listenersRegistered = true;\n\n ALL_WEB_VITALS.forEach((name) => {\n this._listeners[name]?.((metric) => {\n if (!this._isEnabled) {\n return;\n }\n\n const currentSessionSpan = this.sessionManager.getSessionSpan();\n\n if (!currentSessionSpan) {\n return;\n }\n\n // first thing record the time when this cb was invoked\n const metricTime = this._getTimeForMetric(metric);\n\n const attributedPage = this._getAttributedPageForMetric(metric);\n\n const attrs: Attributes = {\n [KEY_MXL_TYPE]: MXL_TYPES.WebVital,\n [ATTR_URL_FULL]: attributedPage.fullURL,\n 'mxl.web_vital.navigation_type': metric.navigationType,\n 'mxl.web_vital.name': metric.name,\n 'mxl.web_vital.rating': metric.rating,\n 'mxl.web_vital.id': metric.id,\n 'mxl.web_vital.delta': metric.delta,\n 'mxl.web_vital.value': metric.value,\n ...webVitalAttributionToReport(name, metric),\n };\n\n // Add page attributes if route and page ID exist\n if (attributedPage.path && attributedPage.pageID) {\n attrs[KEY_MXL_PAGE_PATH] = attributedPage.path;\n attrs[KEY_MXL_PAGE_ID] = attributedPage.pageID;\n }\n\n if (attributedPage.label) {\n attrs[KEY_APP_SURFACE_LABEL] = attributedPage.label;\n }\n\n currentSessionSpan.addEvent(\n `${MXL_WEB_VITALS_PREFIX}-report-${name}`,\n attrs,\n metricTime,\n );\n });\n });\n\n if (this._urlAttribution) {\n // When these web vitals make their final report (e.g. when the listeners w/ reportAllChanges=false trigger) the\n // document's URL at that time may not match what it was at the time the scores were last updated. Instead, listen\n // for updates to the scores and keep track of the Page information to attribute for each\n this._listeners.TTFB?.(\n () => {\n this._attributedPage.TTFB = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.FCP?.(\n () => {\n this._attributedPage.FCP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.INP?.(\n () => {\n this._attributedPage.INP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.LCP?.(\n () => {\n this._attributedPage.LCP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.CLS?.(\n (metric: MetricWithAttribution) => {\n const clsMetric = metric as CLSMetricWithAttribution;\n // A layout shift could cause CLS to change its rating but because the score is cumulative this might not\n // correspond with an updated `largestShiftTarget`. Since we want to tie the attributed URL to the page that\n // the `largestShiftTarget` was on we only update the attributed URL if that target has changed\n if (\n this._largestShiftTargetForCLS !==\n clsMetric.attribution.largestShiftTarget\n ) {\n this._largestShiftTargetForCLS =\n clsMetric.attribution.largestShiftTarget;\n this._attributedPage.CLS = this._currentAttributedPage();\n }\n },\n {\n reportAllChanges: true,\n },\n );\n }\n }\n\n private _getTimeForMetric(metric: MetricWithAttribution): number {\n if (metric.name === 'CLS' && metric.attribution.largestShiftTime) {\n return this.perf.epochMillisFromOriginOffset(\n metric.attribution.largestShiftTime,\n );\n }\n\n if (metric.name === 'INP' && metric.attribution.interactionTime) {\n return this.perf.epochMillisFromOriginOffset(\n metric.attribution.interactionTime,\n );\n }\n\n return this.perf.getNowMillis();\n }\n\n private _currentAttributedPage(): AttributedPage {\n const attributed: AttributedPage = {\n fullURL: this._urlDocument.URL,\n };\n\n const currentRoute = this._pageManager.getCurrentRoute();\n const currentPageId = this._pageManager.getCurrentPageId();\n if (currentRoute && currentPageId) {\n attributed.path = currentRoute.path;\n attributed.pageID = currentPageId;\n }\n\n const pageLabel = this._pageManager.getPageLabel();\n if (pageLabel) {\n attributed.label = pageLabel;\n }\n\n return attributed;\n }\n\n private _getAttributedPageForMetric(\n metric: MetricWithAttribution,\n ): AttributedPage {\n if (metric.name === 'FCP' && this._attributedPage.FCP) {\n return this._attributedPage.FCP;\n }\n\n if (metric.name === 'TTFB' && this._attributedPage.TTFB) {\n return this._attributedPage.TTFB;\n }\n\n if (metric.name === 'INP' && this._attributedPage.INP) {\n return this._attributedPage.INP;\n }\n\n if (metric.name === 'LCP' && this._attributedPage.LCP) {\n return this._attributedPage.LCP;\n }\n\n if (\n metric.name === 'CLS' &&\n this._attributedPage.CLS &&\n metric.attribution.largestShiftTarget === this._largestShiftTargetForCLS\n ) {\n return this._attributedPage.CLS;\n }\n\n return this._currentAttributedPage();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WebVitalsInstrumentation.js","names":[],"sources":["../../../../src/instrumentations/web-vitals/WebVitalsInstrumentation/WebVitalsInstrumentation.ts"],"sourcesContent":["import type { Attributes } from '@opentelemetry/api';\nimport { ATTR_URL_FULL } from '@opentelemetry/semantic-conventions';\nimport type {\n CLSAttribution,\n CLSMetricWithAttribution,\n INPAttribution,\n LCPAttribution,\n Metric,\n MetricWithAttribution,\n} from 'web-vitals/attribution';\nimport type { PageManager } from '../../../api-page/index.ts';\nimport { page } from '../../../api-page/index.ts';\nimport type { URLDocument } from '../../../common/index.ts';\nimport {\n KEY_APP_SURFACE_LABEL,\n KEY_MXL_PAGE_ID,\n KEY_MXL_PAGE_PATH,\n KEY_MXL_TYPE,\n KEY_BROWSER_URL_FULL,\n MXL_TYPES,\n} from '../../../constants/index.ts';\nimport { MXLInstrumentationBase } from '../../MXLInstrumentationBase/index.ts';\nimport {\n ALL_WEB_VITALS,\n MXL_WEB_VITALS_PREFIX,\n WEB_VITALS_ID_TO_LISTENER,\n} from './constants.ts';\nimport type {\n WebVitalListeners,\n WebVitalsInstrumentationArgs,\n} from './types.ts';\n\ntype AttributedPage = {\n fullURL: string;\n path?: string;\n pageID?: string;\n label?: string;\n};\n\nconst webVitalAttributionToReport = (\n name: Metric['name'],\n metric: MetricWithAttribution,\n) => {\n const attributes: Attributes = {};\n const toReport: {\n key: string;\n value: string | boolean | number | undefined;\n }[] = [];\n\n if (name === 'CLS') {\n // https://www.npmjs.com/package/web-vitals#CLSAttribution\n const attribution = metric.attribution as CLSAttribution;\n toReport.push(\n ...[\n {\n key: 'largestShiftTarget',\n value: attribution.largestShiftTarget,\n },\n {\n key: 'largestShiftValue',\n value: attribution.largestShiftValue,\n },\n ],\n );\n } else if (name === 'INP') {\n // https://www.npmjs.com/package/web-vitals#inpattribution\n const attribution = metric.attribution as INPAttribution;\n toReport.push(\n ...[\n { key: 'interactionTarget', value: attribution.interactionTarget },\n { key: 'interactionType', value: attribution.interactionType },\n { key: 'nextPaintTime', value: attribution.nextPaintTime },\n { key: 'inputDelay', value: attribution.inputDelay },\n { key: 'processingDuration', value: attribution.processingDuration },\n { key: 'presentationDelay', value: attribution.presentationDelay },\n { key: 'totalScriptDuration', value: attribution.totalScriptDuration },\n {\n key: 'totalStyleAndLayoutDuration',\n value: attribution.totalStyleAndLayoutDuration,\n },\n { key: 'totalPaintDuration', value: attribution.totalPaintDuration },\n {\n key: 'totalUnattributedDuration',\n value: attribution.totalUnattributedDuration,\n },\n { key: 'loadState', value: attribution.loadState },\n ],\n );\n } else if (name === 'LCP') {\n // https://www.npmjs.com/package/web-vitals#lcpattribution\n const attribution = metric.attribution as LCPAttribution;\n toReport.push(\n ...[\n { key: 'target', value: attribution.target },\n { key: 'url', value: attribution.url },\n { key: 'timeToFirstByte', value: attribution.timeToFirstByte },\n { key: 'resourceLoadDelay', value: attribution.resourceLoadDelay },\n {\n key: 'resourceLoadDuration',\n value: attribution.resourceLoadDuration,\n },\n { key: 'elementRenderDelay', value: attribution.elementRenderDelay },\n ],\n );\n }\n\n toReport.forEach((report) => {\n if (report.value !== undefined) {\n attributes[`mxl.web_vital.attribution.${report.key}`] = report.value;\n }\n });\n\n return attributes;\n};\n\nexport class WebVitalsInstrumentation extends MXLInstrumentationBase {\n private readonly _listeners: WebVitalListeners;\n private readonly _urlDocument: URLDocument;\n private readonly _urlAttribution: boolean;\n private readonly _pageManager: PageManager;\n private readonly _attributedPage: Record<\n Metric['name'],\n AttributedPage | undefined\n > = {\n INP: undefined,\n LCP: undefined,\n CLS: undefined,\n FCP: undefined,\n TTFB: undefined,\n };\n private _largestShiftTargetForCLS: string | undefined;\n private _listenersRegistered = false;\n private _isEnabled = false;\n\n // instrumentation that adds an event to the session span for each web vital report\n public constructor({\n diag,\n perf,\n listeners = WEB_VITALS_ID_TO_LISTENER,\n urlDocument = window.document,\n urlAttribution = true,\n pageManager,\n }: WebVitalsInstrumentationArgs = {}) {\n super({\n instrumentationName: 'WebVitalsInstrumentation',\n instrumentationVersion: '1.0.0',\n diag,\n perf,\n config: {},\n });\n this._listeners = listeners;\n this._urlDocument = urlDocument;\n this._urlAttribution = urlAttribution;\n this._pageManager = pageManager ?? page.getPageManager();\n\n if (this._config.enabled) {\n this.enable();\n }\n }\n\n public override disable(): void {\n // web-vitals library doesn't support removing listeners, so we just pause emission\n // https://github.com/GoogleChrome/web-vitals/issues/357#issuecomment-1593439036\n this._isEnabled = false;\n this._diag.debug('WebVitalsInstrumentation disabled, pausing emission');\n }\n\n public enable(): void {\n this._isEnabled = true;\n\n // web-vitals library doesn't support removing listeners, so only register once\n if (this._listenersRegistered) {\n this._diag.debug(\n 'WebVitalsInstrumentation listeners already registered, resuming emission',\n );\n return;\n }\n this._listenersRegistered = true;\n\n ALL_WEB_VITALS.forEach((name) => {\n this._listeners[name]?.((metric) => {\n if (!this._isEnabled) {\n return;\n }\n\n const currentSessionSpan = this.sessionManager.getSessionSpan();\n\n if (!currentSessionSpan) {\n return;\n }\n\n // first thing record the time when this cb was invoked\n const metricTime = this._getTimeForMetric(metric);\n\n const attributedPage = this._getAttributedPageForMetric(metric);\n\n const attrs: Attributes = {\n [KEY_MXL_TYPE]: MXL_TYPES.WebVital,\n [ATTR_URL_FULL]: attributedPage.fullURL,\n [KEY_BROWSER_URL_FULL]: attributedPage.fullURL,\n 'mxl.web_vital.navigation_type': metric.navigationType,\n 'mxl.web_vital.name': metric.name,\n 'mxl.web_vital.rating': metric.rating,\n 'mxl.web_vital.id': metric.id,\n 'mxl.web_vital.delta': metric.delta,\n 'mxl.web_vital.value': metric.value,\n ...webVitalAttributionToReport(name, metric),\n };\n\n // Add page attributes if route and page ID exist\n if (attributedPage.path && attributedPage.pageID) {\n attrs[KEY_MXL_PAGE_PATH] = attributedPage.path;\n attrs[KEY_MXL_PAGE_ID] = attributedPage.pageID;\n }\n\n if (attributedPage.label) {\n attrs[KEY_APP_SURFACE_LABEL] = attributedPage.label;\n }\n\n currentSessionSpan.addEvent(\n `${MXL_WEB_VITALS_PREFIX}-report-${name}`,\n attrs,\n metricTime,\n );\n });\n });\n\n if (this._urlAttribution) {\n // When these web vitals make their final report (e.g. when the listeners w/ reportAllChanges=false trigger) the\n // document's URL at that time may not match what it was at the time the scores were last updated. Instead, listen\n // for updates to the scores and keep track of the Page information to attribute for each\n this._listeners.TTFB?.(\n () => {\n this._attributedPage.TTFB = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.FCP?.(\n () => {\n this._attributedPage.FCP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.INP?.(\n () => {\n this._attributedPage.INP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.LCP?.(\n () => {\n this._attributedPage.LCP = this._currentAttributedPage();\n },\n {\n reportAllChanges: true,\n },\n );\n this._listeners.CLS?.(\n (metric: MetricWithAttribution) => {\n const clsMetric = metric as CLSMetricWithAttribution;\n // A layout shift could cause CLS to change its rating but because the score is cumulative this might not\n // correspond with an updated `largestShiftTarget`. Since we want to tie the attributed URL to the page that\n // the `largestShiftTarget` was on we only update the attributed URL if that target has changed\n if (\n this._largestShiftTargetForCLS !==\n clsMetric.attribution.largestShiftTarget\n ) {\n this._largestShiftTargetForCLS =\n clsMetric.attribution.largestShiftTarget;\n this._attributedPage.CLS = this._currentAttributedPage();\n }\n },\n {\n reportAllChanges: true,\n },\n );\n }\n }\n\n private _getTimeForMetric(metric: MetricWithAttribution): number {\n if (metric.name === 'CLS' && metric.attribution.largestShiftTime) {\n return this.perf.epochMillisFromOriginOffset(\n metric.attribution.largestShiftTime,\n );\n }\n\n if (metric.name === 'INP' && metric.attribution.interactionTime) {\n return this.perf.epochMillisFromOriginOffset(\n metric.attribution.interactionTime,\n );\n }\n\n return this.perf.getNowMillis();\n }\n\n private _currentAttributedPage(): AttributedPage {\n const attributed: AttributedPage = {\n fullURL: this._urlDocument.URL,\n };\n\n const currentRoute = this._pageManager.getCurrentRoute();\n const currentPageId = this._pageManager.getCurrentPageId();\n if (currentRoute && currentPageId) {\n attributed.path = currentRoute.path;\n attributed.pageID = currentPageId;\n }\n\n const pageLabel = this._pageManager.getPageLabel();\n if (pageLabel) {\n attributed.label = pageLabel;\n }\n\n return attributed;\n }\n\n private _getAttributedPageForMetric(\n metric: MetricWithAttribution,\n ): AttributedPage {\n if (metric.name === 'FCP' && this._attributedPage.FCP) {\n return this._attributedPage.FCP;\n }\n\n if (metric.name === 'TTFB' && this._attributedPage.TTFB) {\n return this._attributedPage.TTFB;\n }\n\n if (metric.name === 'INP' && this._attributedPage.INP) {\n return this._attributedPage.INP;\n }\n\n if (metric.name === 'LCP' && this._attributedPage.LCP) {\n return this._attributedPage.LCP;\n }\n\n if (\n metric.name === 'CLS' &&\n this._attributedPage.CLS &&\n metric.attribution.largestShiftTarget === this._largestShiftTargetForCLS\n ) {\n return this._attributedPage.CLS;\n }\n\n return this._currentAttributedPage();\n }\n}\n"],"mappings":"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"}