@atlaskit/react-ufo 5.0.13 → 5.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/create-payload/index.js +2 -2
  3. package/dist/cjs/experience-trace-id-context/context-manager.js +180 -0
  4. package/dist/cjs/experience-trace-id-context/index.js +67 -11
  5. package/dist/cjs/interaction-metrics-init/index.js +15 -6
  6. package/dist/cjs/typing-performance-tracing/index.js +7 -14
  7. package/dist/cjs/vc/index.js +6 -6
  8. package/dist/cjs/vc/vc-observer/observers/ssr-placeholders/index.js +1 -3
  9. package/dist/es2019/create-payload/index.js +1 -1
  10. package/dist/es2019/experience-trace-id-context/context-manager.js +142 -0
  11. package/dist/es2019/experience-trace-id-context/index.js +65 -9
  12. package/dist/es2019/interaction-metrics-init/index.js +15 -6
  13. package/dist/es2019/typing-performance-tracing/index.js +7 -14
  14. package/dist/es2019/vc/index.js +6 -6
  15. package/dist/es2019/vc/vc-observer/observers/ssr-placeholders/index.js +1 -3
  16. package/dist/esm/create-payload/index.js +2 -2
  17. package/dist/esm/experience-trace-id-context/context-manager.js +172 -0
  18. package/dist/esm/experience-trace-id-context/index.js +67 -11
  19. package/dist/esm/interaction-metrics-init/index.js +15 -6
  20. package/dist/esm/typing-performance-tracing/index.js +7 -14
  21. package/dist/esm/vc/index.js +6 -6
  22. package/dist/esm/vc/vc-observer/observers/ssr-placeholders/index.js +1 -3
  23. package/dist/types/common/react-ufo-payload-schema.d.ts +5 -0
  24. package/dist/types/config/index.d.ts +6 -0
  25. package/dist/types/experience-trace-id-context/context-manager.d.ts +65 -0
  26. package/dist/types-ts4.5/common/react-ufo-payload-schema.d.ts +5 -0
  27. package/dist/types-ts4.5/config/index.d.ts +6 -0
  28. package/dist/types-ts4.5/experience-trace-id-context/context-manager.d.ts +65 -0
  29. package/package.json +6 -8
@@ -0,0 +1,142 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { ROOT_CONTEXT } from '@opentelemetry/api';
3
+
4
+ /**
5
+ * We need to store a reference to the Context manager so that we can get it later.
6
+ * This is because the OTel JS API doesn't allow us to get the registered context manager,
7
+ * and we need to get it because we need to call a function that's not available in the OTel API:
8
+ * `setActive`. The OTel JS API design doesn't allow us to manually set the active context
9
+ * despite the spec allowing for the capability. Sigh.
10
+ *
11
+ * I imagine this situation might not be permanent if we can move to a system were we can rely
12
+ * solely on the API, but for the purposes of the first change being React UFO API compatible,
13
+ * we'll need to do this.
14
+ */
15
+
16
+ let contextManager;
17
+ export function setContextManager(ctxMgr) {
18
+ contextManager = ctxMgr;
19
+ }
20
+ export function getContextManager() {
21
+ return contextManager;
22
+ }
23
+
24
+ /**
25
+ * The below is shamelessly borrowed from StackContextManager from @opentelemetry/sdk-trace-web
26
+ * Using this rather than importing the entire package because this is all we need for now
27
+ */
28
+
29
+ /**
30
+ * UFO Context Manager for managing the state in web
31
+ * it doesn't fully support the async calls though
32
+ */
33
+ export class UFOContextManager {
34
+ constructor() {
35
+ /**
36
+ * whether the context manager is enabled or not
37
+ */
38
+ _defineProperty(this, "_enabled", false);
39
+ /**
40
+ * Keeps the reference to current context
41
+ */
42
+ _defineProperty(this, "_currentContext", ROOT_CONTEXT);
43
+ }
44
+ /**
45
+ *
46
+ * @param context
47
+ * @param target Function to be executed within the context
48
+ */
49
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
50
+ _bindFunction(context = ROOT_CONTEXT, target) {
51
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
52
+ const manager = this;
53
+ const contextWrapper = function (...args) {
54
+ return manager.with(context, () => target.apply(this, args));
55
+ };
56
+ Object.defineProperty(contextWrapper, 'length', {
57
+ enumerable: false,
58
+ configurable: true,
59
+ writable: false,
60
+ value: target.length
61
+ });
62
+ return contextWrapper;
63
+ }
64
+
65
+ /**
66
+ * Returns the active context
67
+ */
68
+ active() {
69
+ return this._currentContext;
70
+ }
71
+
72
+ /**
73
+ * Binds a the certain context or the active one to the target function and then returns the target
74
+ * @param context A context (span) to be bind to target
75
+ * @param target a function or event emitter. When target or one of its callbacks is called,
76
+ * the provided context will be used as the active context for the duration of the call.
77
+ */
78
+ bind(context, target) {
79
+ // if no specific context to propagate is given, we use the current one
80
+ if (context === undefined) {
81
+ context = this.active();
82
+ }
83
+ if (typeof target === 'function') {
84
+ return this._bindFunction(context, target);
85
+ }
86
+ return target;
87
+ }
88
+
89
+ /**
90
+ * Disable the context manager (clears the current context)
91
+ */
92
+ disable() {
93
+ this._currentContext = ROOT_CONTEXT;
94
+ this._enabled = false;
95
+ return this;
96
+ }
97
+
98
+ /**
99
+ * Enables the context manager and creates a default(root) context
100
+ */
101
+ enable() {
102
+ if (this._enabled) {
103
+ return this;
104
+ }
105
+ this._enabled = true;
106
+ this._currentContext = ROOT_CONTEXT;
107
+ return this;
108
+ }
109
+
110
+ /**
111
+ * Calls the callback function [fn] with the provided [context]. If [context] is undefined then it will use the window.
112
+ * The context will be set as active
113
+ * @param context
114
+ * @param fn Callback function
115
+ * @param thisArg optional receiver to be used for calling fn
116
+ * @param args optional arguments forwarded to fn
117
+ */
118
+ with(context, fn, thisArg, ...args) {
119
+ const previousContext = this._currentContext;
120
+ this._currentContext = context || ROOT_CONTEXT;
121
+ try {
122
+ return fn.call(thisArg, ...args);
123
+ } finally {
124
+ this._currentContext = previousContext;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Sets the active context.
130
+ * This function is an extension of the OTel spec, in order to facilitate the current API of React UFO trace context handling.
131
+ * It doesn't keep track of any previously set active contexts, because it's assumed (for now) that only one trace context
132
+ * will ever exist at a time.
133
+ * The next step in the work to improve tracing in the FE will likely remove this function as we need to track the
134
+ * hierarchy of contexts (likely using the `with()` function above).
135
+ * @param context The context to be made the globally active one
136
+ */
137
+ setActive(context) {
138
+ if (this._enabled) {
139
+ this._currentContext = context;
140
+ }
141
+ }
142
+ }
@@ -1,34 +1,90 @@
1
+ import { context, createContextKey, ROOT_CONTEXT } from '@opentelemetry/api';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
3
+ import { getContextManager, UFOContextManager } from './context-manager';
1
4
  import { makeTraceHttpRequestHeaders } from './utils/make-trace-http-request-headers';
2
5
  const state = {
3
6
  context: null
4
7
  };
8
+ const traceIdKey = createContextKey("traceId");
9
+ const spanIdKey = createContextKey("spanId");
10
+ const experienceTypeKey = createContextKey("type");
11
+
12
+ // DO NOT CALL THIS FUNCTION DIRECTLY!!!!
13
+ // It is only to be called by React UFO libraries for the automatic handling of trace context for experiences.
14
+ // Calling this may cause trace context to be broken
5
15
  export function generateSpanId() {
6
16
  return Array.from(new Array(16), () => Math.floor(Math.random() * 16).toString(16)).join('');
7
17
  }
18
+
19
+ // DO NOT CALL THIS FUNCTION DIRECTLY!!!!
20
+ // It is only to be called by React UFO libraries for the automatic handling of trace context for experiences.
21
+ // Calling this may cause trace context to be broken
8
22
  export function setInteractionActiveTrace(interactionId, experienceType) {
9
23
  setActiveTrace(interactionId.replace(/-/g, ''), generateSpanId(), experienceType);
10
24
  }
25
+
26
+ // DO NOT CALL THIS FUNCTION DIRECTLY!!!!
27
+ // It is only to be called by React UFO libraries for the automatic handling of trace context for experiences.
28
+ // Calling this may cause trace context to be broken
11
29
  export function setActiveTrace(traceId, spanId, type) {
12
- state.context = {
13
- traceId,
14
- spanId,
15
- type
16
- };
30
+ if (fg('platform_ufo_enable_otel_context_manager')) {
31
+ const activeTraceContext = ROOT_CONTEXT.setValue(traceIdKey, traceId).setValue(spanIdKey, spanId).setValue(experienceTypeKey, type);
32
+
33
+ // Now we need to get the global Context Manager and set the active context
34
+ // Using type assertion because we've "extended" the ContextManager type
35
+ if (getContextManager() instanceof UFOContextManager) {
36
+ let contextManager = getContextManager();
37
+ contextManager.setActive(activeTraceContext);
38
+ }
39
+ } else {
40
+ state.context = {
41
+ traceId,
42
+ spanId,
43
+ type
44
+ };
45
+ }
17
46
  }
18
47
  export function getActiveTrace() {
19
- return state.context || undefined;
48
+ if (fg('platform_ufo_enable_otel_context_manager')) {
49
+ // Get trace context from active context
50
+ const activeTraceContext = {
51
+ traceId: String(context.active().getValue(traceIdKey)),
52
+ spanId: String(context.active().getValue(spanIdKey)),
53
+ type: String(context.active().getValue(experienceTypeKey))
54
+ };
55
+
56
+ // Return activeTraceContext if traceId and spanId are not "undefined"
57
+ return activeTraceContext.traceId !== 'undefined' && activeTraceContext.spanId !== 'undefined' ? activeTraceContext : undefined;
58
+ } else {
59
+ return state.context || undefined;
60
+ }
20
61
  }
62
+
63
+ // DO NOT CALL THIS FUNCTION DIRECTLY!!!!
64
+ // It is only to be called by React UFO libraries for the automatic handling of trace context for experiences.
65
+ // Calling this may cause trace context to be broken
21
66
  export function clearActiveTrace() {
22
- state.context = null;
67
+ if (fg('platform_ufo_enable_otel_context_manager')) {
68
+ // Now we need to get the global Context Manager and set the active context
69
+ // Using type assertion because we've "extended" the ContextManager type
70
+ if (getContextManager() instanceof UFOContextManager) {
71
+ let contextManager = getContextManager();
72
+
73
+ // ROOT_CONTEXT is an empty context used to initialise ContextManagers
74
+ contextManager.setActive(ROOT_CONTEXT);
75
+ }
76
+ } else {
77
+ state.context = null;
78
+ }
23
79
  }
24
80
  export function getActiveTraceHttpRequestHeaders(_url) {
25
- if (state.context === null) {
81
+ if (getActiveTrace() === undefined) {
26
82
  return null;
27
83
  }
28
84
  const {
29
85
  traceId,
30
86
  spanId
31
- } = state.context;
87
+ } = getActiveTrace();
32
88
  return makeTraceHttpRequestHeaders(traceId, spanId);
33
89
  }
34
90
  export function getActiveTraceAsQueryParams(_url) {
@@ -1,8 +1,10 @@
1
+ import { context } from '@opentelemetry/api';
1
2
  import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { startLighthouseObserver } from '../additional-payload';
3
4
  import { setUFOConfig } from '../config';
4
5
  import { experimentalVC, sinkExperimentalHandler } from '../create-experimental-interaction-metrics-payload';
5
6
  import { sinkExtraSearchPageInteractionHandler } from '../create-extra-search-page-interaction-payload';
7
+ import { setContextManager, UFOContextManager } from '../experience-trace-id-context/context-manager';
6
8
  import { setupHiddenTimingCapture } from '../hidden-timing';
7
9
  import { interactionExtraMetrics, postInteractionLog, sinkInteractionHandler, sinkPostInteractionLogHandler } from '../interaction-metrics';
8
10
  import { getPerformanceObserver } from '../interactions-performance-observer';
@@ -131,6 +133,15 @@ export function init(analyticsWebClientAsync, config) {
131
133
  initialisePressureObserver();
132
134
  initialiseMemoryObserver();
133
135
  setUFOConfig(config);
136
+ if (fg('platform_ufo_enable_otel_context_manager')) {
137
+ // Configure global OTel context manager
138
+ const contextManager = new UFOContextManager();
139
+ // set the contextmanager somewhere we can reference it later
140
+ setContextManager(contextManager);
141
+ // Register the context manager with the global OTel API
142
+ contextManager.enable();
143
+ context.setGlobalContextManager(contextManager);
144
+ }
134
145
  if ((_config$vc = config.vc) !== null && _config$vc !== void 0 && _config$vc.enabled) {
135
146
  var _config$experimentalI, _config$extraInteract;
136
147
  const vcOptions = {
@@ -164,11 +175,10 @@ export function init(analyticsWebClientAsync, config) {
164
175
  Promise.all([analyticsWebClientAsync, import( /* webpackChunkName: "create-payloads" */'../create-payload'), import( /* webpackChunkName: "create-post-interaction-log-payload" */'../create-post-interaction-log-payload'), import( /* webpackChunkName: "create-interaction-extra-metrics-payload" */'../create-interaction-extra-metrics-payload'), import( /* webpackChunkName: "create-terminal-error-payload@atlaskit-internal_terminal_errors" */'../create-terminal-error-payload')]).then(([awc, payloadPackage, createPostInteractionLogPayloadPackage, createInteractionExtraMetricsPayloadPackage, createTerminalErrorPayloadPackage]) => {
165
176
  if (awc.getAnalyticsWebClientPromise) {
166
177
  awc.getAnalyticsWebClientPromise().then(client => {
167
- var _config$experimentalI2, _config$postInteracti, _config$extraInteract2, _config$extraSearchPa;
178
+ var _config$terminalError, _config$experimentalI2, _config$postInteracti, _config$extraInteract2, _config$extraSearchPa;
168
179
  const instance = client.getInstance();
169
180
  sinkInteraction(instance, payloadPackage);
170
- // TODO: make this configurable
171
- if (fg('platform_ufo_enable_terminal_errors')) {
181
+ if (config !== null && config !== void 0 && (_config$terminalError = config.terminalErrors) !== null && _config$terminalError !== void 0 && _config$terminalError.enabled && fg('platform_ufo_enable_terminal_errors')) {
172
182
  sinkTerminalErrors(instance, createTerminalErrorPayloadPackage.default);
173
183
  }
174
184
  if (config !== null && config !== void 0 && (_config$experimentalI2 = config.experimentalInteractionMetrics) !== null && _config$experimentalI2 !== void 0 && _config$experimentalI2.enabled) {
@@ -185,10 +195,9 @@ export function init(analyticsWebClientAsync, config) {
185
195
  }
186
196
  });
187
197
  } else if (awc.sendOperationalEvent) {
188
- var _config$experimentalI3, _config$postInteracti2, _config$extraInteract3, _config$extraSearchPa2;
198
+ var _config$terminalError2, _config$experimentalI3, _config$postInteracti2, _config$extraInteract3, _config$extraSearchPa2;
189
199
  sinkInteraction(awc, payloadPackage);
190
- // TODO: make this configurable
191
- if (fg('platform_ufo_enable_terminal_errors')) {
200
+ if (config !== null && config !== void 0 && (_config$terminalError2 = config.terminalErrors) !== null && _config$terminalError2 !== void 0 && _config$terminalError2.enabled && fg('platform_ufo_enable_terminal_errors')) {
192
201
  sinkTerminalErrors(awc, createTerminalErrorPayloadPackage.default);
193
202
  }
194
203
  if (config !== null && config !== void 0 && (_config$experimentalI3 = config.experimentalInteractionMetrics) !== null && _config$experimentalI3 !== void 0 && _config$experimentalI3.enabled) {
@@ -2,7 +2,6 @@ import { useEffect, useRef } from 'react';
2
2
  import { unstable_IdlePriority as idlePriority, unstable_scheduleCallback as scheduleCallback } from 'scheduler';
3
3
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
4
4
  import { v4 as createUUID } from 'uuid';
5
- import { fg } from '@atlaskit/platform-feature-flags';
6
5
  import coinflip from '../coinflip';
7
6
  import { getInteractionRate, getTypingPerformanceTracingMethod } from '../config';
8
7
  import { addMetadata, addNewInteraction, tryComplete } from '../interaction-metrics';
@@ -73,13 +72,13 @@ function typingPerformanceTracingTimeout(element, name, rate) {
73
72
  tsubmit = setTimeout(end, 2000); // debounce
74
73
  }, 0);
75
74
  };
76
- if (typeof (element === null || element === void 0 ? void 0 : element.addEventListener) !== 'function' && fg('jfp-magma-ufo-event-listener-error')) {
75
+ if (typeof (element === null || element === void 0 ? void 0 : element.addEventListener) !== 'function') {
77
76
  return;
78
77
  }
79
78
  // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
80
79
  element.addEventListener('keypress', onKeyPressHandler);
81
80
  return () => {
82
- if (typeof (element === null || element === void 0 ? void 0 : element.removeEventListener) !== 'function' && fg('jfp-magma-ufo-event-listener-error')) {
81
+ if (typeof (element === null || element === void 0 ? void 0 : element.removeEventListener) !== 'function') {
83
82
  return;
84
83
  }
85
84
  // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
@@ -150,13 +149,13 @@ function typingPerformanceTracingTimeoutNoAlloc(element, name, rate) {
150
149
  tsubmit = setTimeout(end, 2000); // debounce
151
150
  }, 0);
152
151
  };
153
- if (typeof (element === null || element === void 0 ? void 0 : element.addEventListener) !== 'function' && fg('jfp-magma-ufo-event-listener-error')) {
152
+ if (typeof (element === null || element === void 0 ? void 0 : element.addEventListener) !== 'function') {
154
153
  return;
155
154
  }
156
155
  // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
157
156
  element.addEventListener('keypress', onKeyPressHandler);
158
157
  return () => {
159
- if (typeof (element === null || element === void 0 ? void 0 : element.removeEventListener) !== 'function' && fg('jfp-magma-ufo-event-listener-error')) {
158
+ if (typeof (element === null || element === void 0 ? void 0 : element.removeEventListener) !== 'function') {
160
159
  return;
161
160
  }
162
161
  // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
@@ -243,23 +242,17 @@ function typingPerformanceTracingMutationObserver(element, name, rate) {
243
242
  childList: true,
244
243
  subtree: true
245
244
  });
246
- if (typeof (element === null || element === void 0 ? void 0 : element.addEventListener) !== 'function' && fg('jfp-magma-ufo-event-listener-error')) {
245
+ if (typeof (element === null || element === void 0 ? void 0 : element.addEventListener) !== 'function') {
247
246
  return () => mo.disconnect();
248
247
  }
249
248
  // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
250
249
  element.addEventListener('keypress', onKeyPressHandler);
251
250
  return () => {
252
- if (fg('jfp-magma-ufo-event-listener-error')) {
253
- if (typeof (element === null || element === void 0 ? void 0 : element.removeEventListener) === 'function') {
254
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
255
- element.removeEventListener('keypress', onKeyPressHandler);
256
- }
257
- mo.disconnect();
258
- } else {
251
+ if (typeof (element === null || element === void 0 ? void 0 : element.removeEventListener) === 'function') {
259
252
  // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
260
253
  element.removeEventListener('keypress', onKeyPressHandler);
261
- mo.disconnect();
262
254
  }
255
+ mo.disconnect();
263
256
  };
264
257
  }
265
258
  const typingPerformanceTracingMethods = {
@@ -65,7 +65,7 @@ export class VCObserverWrapper {
65
65
  startTime
66
66
  });
67
67
  }
68
- if (isVCRevisionEnabled('fy25.03', experienceKey)) {
68
+ if (isVCRevisionEnabled('fy25.03', experienceKey) || isVCRevisionEnabled('fy26.04', experienceKey)) {
69
69
  var _this$newVCObserver;
70
70
  (_this$newVCObserver = this.newVCObserver) === null || _this$newVCObserver === void 0 ? void 0 : _this$newVCObserver.start({
71
71
  startTime
@@ -80,7 +80,7 @@ export class VCObserverWrapper {
80
80
  var _this$oldVCObserver2;
81
81
  (_this$oldVCObserver2 = this.oldVCObserver) === null || _this$oldVCObserver2 === void 0 ? void 0 : _this$oldVCObserver2.stop();
82
82
  }
83
- if (isVCRevisionEnabled('fy25.03', experienceKey)) {
83
+ if (isVCRevisionEnabled('fy25.03', experienceKey) || isVCRevisionEnabled('fy26.04', experienceKey)) {
84
84
  var _this$newVCObserver2;
85
85
  (_this$newVCObserver2 = this.newVCObserver) === null || _this$newVCObserver2 === void 0 ? void 0 : _this$newVCObserver2.stop();
86
86
  }
@@ -93,7 +93,7 @@ export class VCObserverWrapper {
93
93
  return (_this$oldVCObserver$g = (_this$oldVCObserver3 = this.oldVCObserver) === null || _this$oldVCObserver3 === void 0 ? void 0 : _this$oldVCObserver3.getVCRawData()) !== null && _this$oldVCObserver$g !== void 0 ? _this$oldVCObserver$g : null;
94
94
  }
95
95
  async getVCResult(param) {
96
- var _this$oldVCObserver4, _this$newVCObserver3, _ref;
96
+ var _this$oldVCObserver4, _this$newVCObserver3, _v3v4Result$, _ref;
97
97
  const {
98
98
  experienceKey,
99
99
  include3p,
@@ -102,7 +102,7 @@ export class VCObserverWrapper {
102
102
  includeRawData
103
103
  } = param;
104
104
  const v1v2Result = isVCRevisionEnabled('fy25.01', experienceKey) || isVCRevisionEnabled('fy25.02', experienceKey) ? await ((_this$oldVCObserver4 = this.oldVCObserver) === null || _this$oldVCObserver4 === void 0 ? void 0 : _this$oldVCObserver4.getVCResult(param)) : {};
105
- const v3v4Result = isVCRevisionEnabled('fy25.03', experienceKey) ? await ((_this$newVCObserver3 = this.newVCObserver) === null || _this$newVCObserver3 === void 0 ? void 0 : _this$newVCObserver3.getVCResult({
105
+ const v3v4Result = isVCRevisionEnabled('fy25.03', experienceKey) || isVCRevisionEnabled('fy26.04', experienceKey) ? await ((_this$newVCObserver3 = this.newVCObserver) === null || _this$newVCObserver3 === void 0 ? void 0 : _this$newVCObserver3.getVCResult({
106
106
  start: param.start,
107
107
  stop: param.stop,
108
108
  interactionId: param.interactionId,
@@ -117,10 +117,10 @@ export class VCObserverWrapper {
117
117
  includeSSRInV3: param.includeSSRInV3,
118
118
  rawDataStopTime: param.rawDataStopTime
119
119
  })) : [];
120
- if (!v3v4Result) {
120
+ if (!v3v4Result || v3v4Result.length === 0) {
121
121
  return v1v2Result !== null && v1v2Result !== void 0 ? v1v2Result : {};
122
122
  }
123
- const ssrRatio = v3v4Result[0].ssrRatio;
123
+ const ssrRatio = v3v4Result === null || v3v4Result === void 0 ? void 0 : (_v3v4Result$ = v3v4Result[0]) === null || _v3v4Result$ === void 0 ? void 0 : _v3v4Result$.ssrRatio;
124
124
  return {
125
125
  ...(includeSSRRatio && ssrRatio !== undefined ? {
126
126
  'ufo:vc:ssrRatio': ssrRatio
@@ -1,5 +1,4 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
- import { fg } from '@atlaskit/platform-feature-flags';
3
2
  const ANCESTOR_LOOKUP_LIMIT = 10;
4
3
  const PAGE_LAYOUT_ID = 'page-layout.root';
5
4
  export class SSRPlaceholderHandlers {
@@ -277,8 +276,7 @@ export class SSRPlaceholderHandlers {
277
276
  });
278
277
  }
279
278
  validateReactComponentMatchToPlaceholderV4(el) {
280
- el = fg('platform_ufo_v4_fix_nested_ssr_placeholder') ? this.findNearestPlaceholderOrContainer(el, 2) // We are using 2 due to over-eagerness of the default, only check itself and 1 ancestor
281
- : this.findNearestPlaceholderContainerIfIgnored(el);
279
+ el = this.findNearestPlaceholderOrContainer(el, 2); // We are using 2 due to over-eagerness of the default, only check itself and 1 ancestor
282
280
  const id = this.getPlaceholderReplacementId(el);
283
281
  return this.staticPlaceholders.has(id);
284
282
  }
@@ -9,9 +9,9 @@ try{return acc+item.cssRules.length;}catch(_unused3){return acc;}},0);var styleE
9
9
  getInitialPageLoadSSRMetrics=function getInitialPageLoadSSRMetrics(){var _config$ssr;if(!isPageLoad){return{};}var config=getConfig();var SSRDoneTimeValue=getSSRDoneTimeValue(config);var SSRDoneTime=SSRDoneTimeValue!==undefined?{SSRDoneTime:Math.round(SSRDoneTimeValue)}:{};var isBM3ConfigSSRDoneAsFmp=interaction.metaData.__legacy__bm3ConfigSSRDoneAsFmp;var isUFOConfigSSRDoneAsFmp=interaction.metaData.__legacy__bm3ConfigSSRDoneAsFmp||!!(config!==null&&config!==void 0&&(_config$ssr=config.ssr)!==null&&_config$ssr!==void 0&&_config$ssr.getSSRDoneTime);if(!experimental&&(isBM3ConfigSSRDoneAsFmp||isUFOConfigSSRDoneAsFmp)&&SSRDoneTimeValue!==undefined){try{performance.mark("FMP",{startTime:SSRDoneTimeValue,detail:{devtools:{dataType:'marker'}}});}catch(_unused6){}}return _objectSpread(_objectSpread({},SSRDoneTime),{},{isBM3ConfigSSRDoneAsFmp:isBM3ConfigSSRDoneAsFmp,isUFOConfigSSRDoneAsFmp:isUFOConfigSSRDoneAsFmp});};pageLoadInteractionMetrics=getInitialPageLoadSSRMetrics();// Detailed payload. Page visibility = visible
10
10
  getDetailedInteractionMetrics=function getDetailedInteractionMetrics(resourceTimings){if(experimental||window.__UFO_COMPACT_PAYLOAD__||!isDetailedPayload){return{};}var spans=[].concat(_toConsumableArray(interaction.spans),_toConsumableArray(atlaskitInteractionSpans));atlaskitInteractionSpans.length=0;var shouldInclude3pHolds=shouldUseRawDataThirdPartyBehavior(ufoName,type);var basePayload={errors:interaction.errors.map(function(_ref2){var labelStack=_ref2.labelStack,others=_objectWithoutProperties(_ref2,_excluded);return _objectSpread(_objectSpread({},others),{},{labelStack:labelStack&&optimizeLabelStack(labelStack,getReactUFOPayloadVersion(interaction.type))});}),holdActive:_toConsumableArray(interaction.holdActive.values()),redirects:optimizeRedirects(interaction.redirects,start),holdInfo:optimizeHoldInfo(experimental?interaction.holdExpInfo:interaction.holdInfo,start,getReactUFOPayloadVersion(interaction.type)),spans:optimizeSpans(spans,start,getReactUFOPayloadVersion(interaction.type)),requestInfo:optimizeRequestInfo(interaction.requestInfo,start,getReactUFOPayloadVersion(interaction.type)),customTimings:optimizeCustomTimings(interaction.customTimings,start),bundleEvalTimings:objectToArray(getBundleEvalTimings(start)),resourceTimings:objectToArray(resourceTimings)};// Include third-party holds when feature flag is active
11
11
  if(shouldInclude3pHolds){var _interaction$hold3pIn;return _objectSpread(_objectSpread({},basePayload),{},{hold3pActive:interaction.hold3pActive?_toConsumableArray(interaction.hold3pActive.values()):[],hold3pInfo:optimizeHoldInfo((_interaction$hold3pIn=interaction.hold3pInfo)!==null&&_interaction$hold3pIn!==void 0?_interaction$hold3pIn:[],start,getReactUFOPayloadVersion(interaction.type))});}return basePayload;};// Page load & detailed payload
12
- getPageLoadDetailedInteractionMetrics=function getPageLoadDetailedInteractionMetrics(){var _config$ssr2,_config$ssr2$getSSRTi;if(!isPageLoad||!isDetailedPayload){return{};}var initialPageLoadExtraTimings=objectToArray(initialPageLoadExtraTiming.getTimings());var config=getConfig();var defaultSSRTimings=objectToArray(ssr.getSSRTimings());var ssrTimingsFromConfig=config===null||config===void 0||(_config$ssr2=config.ssr)===null||_config$ssr2===void 0||(_config$ssr2$getSSRTi=_config$ssr2.getSSRTimings)===null||_config$ssr2$getSSRTi===void 0?void 0:_config$ssr2$getSSRTi.call(_config$ssr2);return{initialPageLoadExtraTimings:initialPageLoadExtraTimings,SSRTimings:ssrTimingsFromConfig?[].concat(_toConsumableArray(ssrTimingsFromConfig),_toConsumableArray(defaultSSRTimings)):defaultSSRTimings};};if(experimental){expTTAI=getTTAI(interaction);}else{regularTTAI=getTTAI(interaction);}newUFOName=sanitizeUfoName(ufoName);resourceTimings=getResourceTimings(start,end);_context.t0=Promise;_context.t1=vcMetrics;if(_context.t1){_context.next=29;break;}_context.next=28;return getVCMetrics(interaction);case 28:_context.t1=_context.sent;case 29:_context.t2=_context.t1;_context.t3=experimental?getExperimentalVCMetrics(interaction):Promise.resolve(undefined);_context.t4=getPaintMetricsToLegacyFormat(type,end);_context.t5=getBatteryInfoToLegacyFormat();_context.t6=[_context.t2,_context.t3,_context.t4,_context.t5];_context.next=36;return _context.t0.all.call(_context.t0,_context.t6);case 36:_yield$Promise$all=_context.sent;_yield$Promise$all2=_slicedToArray(_yield$Promise$all,4);finalVCMetrics=_yield$Promise$all2[0];experimentalMetrics=_yield$Promise$all2[1];paintMetrics=_yield$Promise$all2[2];batteryInfo=_yield$Promise$all2[3];if(!experimental){addPerformanceMeasures(interaction.start,_toConsumableArray((finalVCMetrics===null||finalVCMetrics===void 0?void 0:finalVCMetrics['ufo:vc:rev'])||[]));}getReactHydrationStats=function getReactHydrationStats(){if(!hydration){return{};}return{hydration:hydration};};payload={actionSubject:'experience',action:'measured',eventType:'operational',source:'measured',tags:['observability'],attributes:{properties:_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({// basic
12
+ getPageLoadDetailedInteractionMetrics=function getPageLoadDetailedInteractionMetrics(){var _config$ssr2,_config$ssr2$getSSRTi;if(!isPageLoad||!isDetailedPayload){return{};}var initialPageLoadExtraTimings=objectToArray(initialPageLoadExtraTiming.getTimings());var config=getConfig();var defaultSSRTimings=objectToArray(ssr.getSSRTimings());var ssrTimingsFromConfig=config===null||config===void 0||(_config$ssr2=config.ssr)===null||_config$ssr2===void 0||(_config$ssr2$getSSRTi=_config$ssr2.getSSRTimings)===null||_config$ssr2$getSSRTi===void 0?void 0:_config$ssr2$getSSRTi.call(_config$ssr2);return{initialPageLoadExtraTimings:initialPageLoadExtraTimings,SSRTimings:ssrTimingsFromConfig?[].concat(_toConsumableArray(ssrTimingsFromConfig),_toConsumableArray(defaultSSRTimings)):defaultSSRTimings};};if(experimental){expTTAI=getTTAI(interaction);}else{regularTTAI=getTTAI(interaction);}newUFOName=sanitizeUfoName(ufoName);resourceTimings=getResourceTimings(start,end);_context.t0=Promise;_context.t1=vcMetrics;if(_context.t1){_context.next=29;break;}_context.next=28;return getVCMetrics(interaction);case 28:_context.t1=_context.sent;case 29:_context.t2=_context.t1;_context.t3=experimental?getExperimentalVCMetrics(interaction):Promise.resolve(undefined);_context.t4=getPaintMetricsToLegacyFormat(type,end);_context.t5=getBatteryInfoToLegacyFormat();_context.t6=[_context.t2,_context.t3,_context.t4,_context.t5];_context.next=36;return _context.t0.all.call(_context.t0,_context.t6);case 36:_yield$Promise$all=_context.sent;_yield$Promise$all2=_slicedToArray(_yield$Promise$all,4);finalVCMetrics=_yield$Promise$all2[0];experimentalMetrics=_yield$Promise$all2[1];paintMetrics=_yield$Promise$all2[2];batteryInfo=_yield$Promise$all2[3];if(!experimental){addPerformanceMeasures(interaction.start,_toConsumableArray((finalVCMetrics===null||finalVCMetrics===void 0?void 0:finalVCMetrics['ufo:vc:rev'])||[]));}getReactHydrationStats=function getReactHydrationStats(){if(!hydration){return{};}return{hydration:hydration};};payload={actionSubject:'experience',action:'measured',eventType:'operational',source:'measured',tags:['observability'],attributes:{properties:_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({// basic
13
13
  'event:hostname':((_window$location=window.location)===null||_window$location===void 0?void 0:_window$location.hostname)||'unknown','event:product':config.product,'event:population':config.population,'event:schema':'1.0.0','event:sizeInKb':0,'event:source':{name:'react-ufo/web',version:getReactUFOPayloadVersion(interaction.type)},'event:region':config.region||'unknown','experience:key':experimental?'custom.experimental-interaction-metrics':'custom.interaction-metrics','experience:name':newUFOName,// Include CPU usage monitoring data
14
- 'event:cpu:usage':createPressureStateReport(interaction.start,interaction.end),'event:memory:usage':createMemoryStateReport(interaction.start,interaction.end)},criticalPayloadCount!==undefined?{'ufo:multipayload':true,'ufo:criticalPayloadCount':criticalPayloadCount}:{}),fg('platform_ufo_browser_backgrounded_abort_timestamp')?{'ufo:pageVisibilityHiddenTimestamp':getEarliestHiddenTiming(interaction.start,interaction.end)}:{}),fg('platform_ufo_native_pagevisibility_monitoring')?{'ufo:wasPageHiddenBeforeInit':getHasHiddenTimingBeforeSetup()}:{}),fg('platform_ufo_is_opened_in_background')?{'ufo:isOpenedInBackground':isOpenedInBackground(interaction.type)}:{}),getBrowserMetadataToLegacyFormat()),batteryInfo),getSSRProperties(type)),getAssetsMetrics(interaction,pageLoadInteractionMetrics===null||pageLoadInteractionMetrics===void 0?void 0:pageLoadInteractionMetrics.SSRDoneTime)),getPPSMetrics(interaction)),paintMetrics),getNavigationMetricsToLegacyFormat(type)),finalVCMetrics),experimentalMetrics),(_config$additionalPay=config.additionalPayloadData)===null||_config$additionalPay===void 0?void 0:_config$additionalPay.call(config,interaction)),getTracingContextData(interaction)),getStylesheetMetrics()),getErrorCounts(interaction)),getReactHydrationStats()),{},{interactionMetrics:_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({namePrefix:config.namePrefix||'',segmentPrefix:config.segmentPrefix||'',interactionId:interactionId,pageVisibilityAtTTI:pageVisibilityAtTTI,pageVisibilityAtTTAI:pageVisibilityAtTTAI,experimental__pageVisibilityAtTTI:moreAccuratePageVisibilityAtTTI,experimental__pageVisibilityAtTTAI:moreAccuratePageVisibilityAtTTAI,// raw interaction metrics
14
+ 'event:cpu:usage':createPressureStateReport(interaction.start,interaction.end),'event:memory:usage':createMemoryStateReport(interaction.start,interaction.end)},criticalPayloadCount!==undefined?{'ufo:multipayload':true,'ufo:criticalPayloadCount':criticalPayloadCount}:{}),fg('platform_ufo_browser_backgrounded_abort_timestamp')?{'ufo:pageVisibilityHiddenTimestamp':getEarliestHiddenTiming(interaction.start,interaction.end)}:{}),fg('platform_ufo_native_pagevisibility_monitoring')?{'ufo:wasPageHiddenBeforeInit':getHasHiddenTimingBeforeSetup()}:{}),{},{'ufo:isOpenedInBackground':isOpenedInBackground(interaction.type)},getBrowserMetadataToLegacyFormat()),batteryInfo),getSSRProperties(type)),getAssetsMetrics(interaction,pageLoadInteractionMetrics===null||pageLoadInteractionMetrics===void 0?void 0:pageLoadInteractionMetrics.SSRDoneTime)),getPPSMetrics(interaction)),paintMetrics),getNavigationMetricsToLegacyFormat(type)),finalVCMetrics),experimentalMetrics),(_config$additionalPay=config.additionalPayloadData)===null||_config$additionalPay===void 0?void 0:_config$additionalPay.call(config,interaction)),getTracingContextData(interaction)),getStylesheetMetrics()),getErrorCounts(interaction)),getReactHydrationStats()),{},{interactionMetrics:_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({namePrefix:config.namePrefix||'',segmentPrefix:config.segmentPrefix||'',interactionId:interactionId,pageVisibilityAtTTI:pageVisibilityAtTTI,pageVisibilityAtTTAI:pageVisibilityAtTTAI,experimental__pageVisibilityAtTTI:moreAccuratePageVisibilityAtTTI,experimental__pageVisibilityAtTTAI:moreAccuratePageVisibilityAtTTAI,// raw interaction metrics
15
15
  rate:rate,routeName:routeName,type:type,abortReason:abortReason,featureFlags:featureFlags,previousInteractionName:previousInteractionName,isPreviousInteractionAborted:isPreviousInteractionAborted,abortedByInteractionName:abortedByInteractionName,// performance
16
16
  apdex:optimizeApdex(interaction.apdex,getReactUFOPayloadVersion(interaction.type)),end:Math.round(end)},interaction.end3p?{end3p:Math.round(interaction.end3p)}:{}),{},{start:Math.round(start),segments:getReactUFOPayloadVersion(interaction.type)==='2.0.0'?segmentTree:getOldSegmentsLabelStack(segments,interaction.type),marks:optimizeMarks(interaction.marks,getReactUFOPayloadVersion(interaction.type)),customData:optimizeCustomData(interaction),reactProfilerTimings:optimizeReactProfilerTimings(interaction.reactProfilerTimings,start,getReactUFOPayloadVersion(interaction.type)),minorInteractions:interaction.minorInteractions},responsiveness?{responsiveness:responsiveness}:{}),labelStack),pageLoadInteractionMetrics),getDetailedInteractionMetrics(resourceTimings)),getPageLoadDetailedInteractionMetrics()),getBm3TrackerTimings(interaction)),{},{'metric:ttai':experimental?regularTTAI||expTTAI:undefined,'metric:experimental:ttai':expTTAI},unknownElementName?{unknownElementName:unknownElementName}:{}),unknownElementHierarchy?{unknownElementHierarchy:unknownElementHierarchy}:{}),'ufo:payloadTime':roundEpsilon(performance.now()-interactionPayloadStart)})}};if(experimental){regularTTAI=undefined;expTTAI=undefined;}if(fg('platform_ufo_enable_vc_raw_data')){size=getPayloadSize(payload.attributes.properties);vcRev=payload.attributes.properties['ufo:vc:rev'];rawData=vcRev.find(function(item){return item.revision==='raw-handler';});if(rawData){rawDataSize=getPayloadSize(rawData);payload.attributes.properties['ufo:vc:raw:size']=rawDataSize;if(size>MAX_PAYLOAD_SIZE&&Array.isArray(vcRev)&&vcRev.length>0){payload.attributes.properties['ufo:vc:rev']=vcRev.filter(function(item){return item.revision!=='raw-handler';});payload.attributes.properties['ufo:vc:raw:removed']=true;}}payload.attributes.properties['event:sizeInKb']=getPayloadSize(payload.attributes.properties);}else{payload.attributes.properties['event:sizeInKb']=getPayloadSize(payload.attributes.properties);}// in order of importance, first one being least important
17
17
  // we can add more fields as necessary
@@ -0,0 +1,172 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
+ import _createClass from "@babel/runtime/helpers/createClass";
3
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
+ import { ROOT_CONTEXT } from '@opentelemetry/api';
5
+
6
+ /**
7
+ * We need to store a reference to the Context manager so that we can get it later.
8
+ * This is because the OTel JS API doesn't allow us to get the registered context manager,
9
+ * and we need to get it because we need to call a function that's not available in the OTel API:
10
+ * `setActive`. The OTel JS API design doesn't allow us to manually set the active context
11
+ * despite the spec allowing for the capability. Sigh.
12
+ *
13
+ * I imagine this situation might not be permanent if we can move to a system were we can rely
14
+ * solely on the API, but for the purposes of the first change being React UFO API compatible,
15
+ * we'll need to do this.
16
+ */
17
+
18
+ var contextManager;
19
+ export function setContextManager(ctxMgr) {
20
+ contextManager = ctxMgr;
21
+ }
22
+ export function getContextManager() {
23
+ return contextManager;
24
+ }
25
+
26
+ /**
27
+ * The below is shamelessly borrowed from StackContextManager from @opentelemetry/sdk-trace-web
28
+ * Using this rather than importing the entire package because this is all we need for now
29
+ */
30
+
31
+ /**
32
+ * UFO Context Manager for managing the state in web
33
+ * it doesn't fully support the async calls though
34
+ */
35
+ export var UFOContextManager = /*#__PURE__*/function () {
36
+ function UFOContextManager() {
37
+ _classCallCheck(this, UFOContextManager);
38
+ /**
39
+ * whether the context manager is enabled or not
40
+ */
41
+ _defineProperty(this, "_enabled", false);
42
+ /**
43
+ * Keeps the reference to current context
44
+ */
45
+ _defineProperty(this, "_currentContext", ROOT_CONTEXT);
46
+ }
47
+ return _createClass(UFOContextManager, [{
48
+ key: "_bindFunction",
49
+ value:
50
+ /**
51
+ *
52
+ * @param context
53
+ * @param target Function to be executed within the context
54
+ */
55
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
56
+ function _bindFunction() {
57
+ var context = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ROOT_CONTEXT;
58
+ var target = arguments.length > 1 ? arguments[1] : undefined;
59
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
60
+ var manager = this;
61
+ var contextWrapper = function contextWrapper() {
62
+ var _this = this;
63
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
64
+ args[_key] = arguments[_key];
65
+ }
66
+ return manager.with(context, function () {
67
+ return target.apply(_this, args);
68
+ });
69
+ };
70
+ Object.defineProperty(contextWrapper, 'length', {
71
+ enumerable: false,
72
+ configurable: true,
73
+ writable: false,
74
+ value: target.length
75
+ });
76
+ return contextWrapper;
77
+ }
78
+
79
+ /**
80
+ * Returns the active context
81
+ */
82
+ }, {
83
+ key: "active",
84
+ value: function active() {
85
+ return this._currentContext;
86
+ }
87
+
88
+ /**
89
+ * Binds a the certain context or the active one to the target function and then returns the target
90
+ * @param context A context (span) to be bind to target
91
+ * @param target a function or event emitter. When target or one of its callbacks is called,
92
+ * the provided context will be used as the active context for the duration of the call.
93
+ */
94
+ }, {
95
+ key: "bind",
96
+ value: function bind(context, target) {
97
+ // if no specific context to propagate is given, we use the current one
98
+ if (context === undefined) {
99
+ context = this.active();
100
+ }
101
+ if (typeof target === 'function') {
102
+ return this._bindFunction(context, target);
103
+ }
104
+ return target;
105
+ }
106
+
107
+ /**
108
+ * Disable the context manager (clears the current context)
109
+ */
110
+ }, {
111
+ key: "disable",
112
+ value: function disable() {
113
+ this._currentContext = ROOT_CONTEXT;
114
+ this._enabled = false;
115
+ return this;
116
+ }
117
+
118
+ /**
119
+ * Enables the context manager and creates a default(root) context
120
+ */
121
+ }, {
122
+ key: "enable",
123
+ value: function enable() {
124
+ if (this._enabled) {
125
+ return this;
126
+ }
127
+ this._enabled = true;
128
+ this._currentContext = ROOT_CONTEXT;
129
+ return this;
130
+ }
131
+
132
+ /**
133
+ * Calls the callback function [fn] with the provided [context]. If [context] is undefined then it will use the window.
134
+ * The context will be set as active
135
+ * @param context
136
+ * @param fn Callback function
137
+ * @param thisArg optional receiver to be used for calling fn
138
+ * @param args optional arguments forwarded to fn
139
+ */
140
+ }, {
141
+ key: "with",
142
+ value: function _with(context, fn, thisArg) {
143
+ var previousContext = this._currentContext;
144
+ this._currentContext = context || ROOT_CONTEXT;
145
+ try {
146
+ for (var _len2 = arguments.length, args = new Array(_len2 > 3 ? _len2 - 3 : 0), _key2 = 3; _key2 < _len2; _key2++) {
147
+ args[_key2 - 3] = arguments[_key2];
148
+ }
149
+ return fn.call.apply(fn, [thisArg].concat(args));
150
+ } finally {
151
+ this._currentContext = previousContext;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Sets the active context.
157
+ * This function is an extension of the OTel spec, in order to facilitate the current API of React UFO trace context handling.
158
+ * It doesn't keep track of any previously set active contexts, because it's assumed (for now) that only one trace context
159
+ * will ever exist at a time.
160
+ * The next step in the work to improve tracing in the FE will likely remove this function as we need to track the
161
+ * hierarchy of contexts (likely using the `with()` function above).
162
+ * @param context The context to be made the globally active one
163
+ */
164
+ }, {
165
+ key: "setActive",
166
+ value: function setActive(context) {
167
+ if (this._enabled) {
168
+ this._currentContext = context;
169
+ }
170
+ }
171
+ }]);
172
+ }();