@localstack/appinspector-ui 1.0.174 → 1.0.175

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.
package/dist/index.cjs CHANGED
@@ -16960,76 +16960,14 @@ var toSpanFilterProjection = (span) => ({
16960
16960
  });
16961
16961
 
16962
16962
  // src/hooks/use-spans-compute.ts
16963
- var import_react43 = require("react");
16964
-
16965
- // inline-worker:/home/runner/work/localstack-appinspector-ui/localstack-appinspector-ui/src/workers/spans-worker.worker.ts
16966
- var source = '(() => {\n // src/types/error-levels.ts\n var ErrorLevel = {\n ERROR: 3,\n // General error\n IAM_PERMISSION: 5,\n // IAM permission issues\n OK: 2,\n // OK\n // Standard OTEL status codes\n UNSET: 1,\n // Unset\n // Extended custom levels\n WARNING: 4\n // Warning\n };\n\n // src/utils/iam-utils.ts\n function determinePermissionStatus(payload) {\n if (payload.explicit_deny_count && payload.explicit_deny_count > 0) {\n return "explicitly_denied";\n }\n if (payload.is_allowed && payload.explicit_allow_count && payload.explicit_allow_count > 0) {\n return "explicitly_allowed";\n }\n if (payload.is_allowed) {\n return "implicitly_allowed";\n }\n return "implicitly_denied";\n }\n function parseIAMEvent(payloadString) {\n try {\n const payload = JSON.parse(payloadString);\n const permission = determinePermissionStatus(payload);\n const actions = [];\n const resources = [];\n if (payload.explicit_allows) {\n for (const allow of payload.explicit_allows) {\n if (!actions.includes(allow.action)) actions.push(allow.action);\n if (!resources.includes(allow.resource)) resources.push(allow.resource);\n }\n }\n if (payload.explicit_denies) {\n for (const deny of payload.explicit_denies) {\n if (!actions.includes(deny.action)) actions.push(deny.action);\n if (!resources.includes(deny.resource)) resources.push(deny.resource);\n }\n }\n if (payload.implicit_denies) {\n for (const deny of payload.implicit_denies) {\n if (!actions.includes(deny.action)) actions.push(deny.action);\n if (!resources.includes(deny.resource)) resources.push(deny.resource);\n }\n }\n return {\n details: {\n actions,\n explicitAllows: payload.explicit_allow_count,\n explicitDenies: payload.explicit_deny_count,\n implicitDenies: payload.implicit_deny_count,\n resources\n },\n operation: payload.operation,\n permission,\n principal: payload.principal_arn,\n service: payload.service\n };\n } catch (error) {\n console.error("Error parsing IAM event payload:", error);\n return void 0;\n }\n }\n\n // src/utils/error-level.ts\n var calculateHighestErrorLevel = (span) => {\n if (span.operation_status) {\n switch (span.operation_status) {\n case "error": {\n return ErrorLevel.ERROR;\n }\n case "iam_explicit_deny":\n case "iam_explicit_warn":\n case "iam_implicit_deny":\n case "iam_implicit_warn": {\n return ErrorLevel.IAM_PERMISSION;\n }\n default: {\n return ErrorLevel.OK;\n }\n }\n }\n const hasIamDenial = span.events.some((event) => {\n if (!event.event_type?.toLowerCase().includes("iam")) return false;\n if (typeof event.attributes?.payload !== "string") return false;\n const parsed = parseIAMEvent(event.attributes.payload);\n return parsed?.permission === "explicitly_denied" || parsed?.permission === "implicitly_denied";\n });\n if (hasIamDenial) return ErrorLevel.IAM_PERMISSION;\n if (span.status_code === 2) return ErrorLevel.ERROR;\n const hasErrorInErrors = span.errors?.some((error) => error.level === "error");\n if (hasErrorInErrors) return ErrorLevel.ERROR;\n const hasWarning = span.errors?.some((error) => error.level === "warning");\n if (hasWarning) return ErrorLevel.WARNING;\n return span.status_code || ErrorLevel.UNSET;\n };\n\n // src/utils/spans-filters.ts\n var EMPTY_FILTERS = {\n consumerService: [],\n producerService: [],\n status: []\n };\n var EXTERNAL_PRODUCER_VALUE = "__external__";\n function isFiltersEmpty(filters) {\n return filters.consumerService.length === 0 && filters.producerService.length === 0 && filters.status.length === 0;\n }\n var collapseStatusValue = (status) => {\n if (status === "iam_explicit_deny" || status === "iam_implicit_deny") return "iam_deny";\n if (status === "iam_explicit_warn" || status === "iam_implicit_warn") return "iam_warn";\n return status;\n };\n function applyFilters(spans, filters) {\n if (isFiltersEmpty(filters)) return spans;\n return spans.filter((span) => {\n if (filters.consumerService.length > 0 && !filters.consumerService.includes(span.service_name)) {\n return false;\n }\n if (filters.producerService.length > 0) {\n const includesExternal = filters.producerService.includes(EXTERNAL_PRODUCER_VALUE);\n const namedServices = filters.producerService.filter((value) => value !== EXTERNAL_PRODUCER_VALUE);\n const matchesExternal = includesExternal && !span.parent_service_name;\n const matchesNamed = namedServices.length > 0 && !!span.parent_service_name && namedServices.includes(span.parent_service_name);\n if (!matchesExternal && !matchesNamed) return false;\n }\n if (filters.status.length > 0) {\n if (!span.operation_status) return false;\n if (!filters.status.includes(collapseStatusValue(span.operation_status))) return false;\n }\n return true;\n });\n }\n\n // src/workers/spans-reducer.ts\n var compareByStartTime = (a, b) => a.start_time_unix_nano < b.start_time_unix_nano ? -1 : 1;\n var insertSorted = (array, item, compareFunction, hint) => {\n let left;\n let right;\n if (hint === "back") {\n left = array.length;\n right = array.length;\n let step = 1;\n while (left > 0 && compareFunction(array[left - 1], item) > 0) {\n right = left;\n left = Math.max(0, left - step);\n step *= 2;\n }\n } else {\n left = 0;\n right = 0;\n let step = 1;\n while (right < array.length && compareFunction(array[right], item) <= 0) {\n left = right + 1;\n right = Math.min(array.length, right + step);\n step *= 2;\n }\n }\n while (left < right) {\n const mid = left + right >>> 1;\n if (compareFunction(array[mid], item) <= 0) {\n left = mid + 1;\n } else {\n right = mid;\n }\n }\n array.splice(left, 0, item);\n };\n var createSpansReducer = () => {\n let corpus = [];\n let filters = EMPTY_FILTERS;\n const computeResult = () => {\n const filtered = applyFilters(corpus, filters);\n let errorCount = 0;\n let warningCount = 0;\n const orderedFilteredIds = [];\n for (const entry of filtered) {\n orderedFilteredIds.push(entry.span_id);\n if (entry.errorLevel === ErrorLevel.ERROR || entry.errorLevel === ErrorLevel.IAM_PERMISSION) {\n errorCount++;\n } else if (entry.errorLevel === ErrorLevel.WARNING) {\n warningCount++;\n }\n }\n const producers = /* @__PURE__ */ new Set();\n const consumers = /* @__PURE__ */ new Set();\n const statuses = /* @__PURE__ */ new Set();\n let hasExternalProducer = false;\n for (const entry of corpus) {\n if (entry.parent_service_name) producers.add(entry.parent_service_name);\n else hasExternalProducer = true;\n consumers.add(entry.service_name);\n if (entry.operation_status) statuses.add(collapseStatusValue(entry.operation_status));\n }\n return {\n consumerValues: [...consumers].toSorted(),\n errorCount,\n hasExternalProducer,\n orderedFilteredIds,\n producerValues: [...producers].toSorted(),\n statusValues: [...statuses].toSorted(),\n warningCount\n };\n };\n return {\n addPage: (direction, projections) => {\n const hint = direction === "forward" ? "back" : "front";\n const sorted = projections.toSorted(compareByStartTime);\n for (const projection of sorted) {\n insertSorted(corpus, { ...projection, errorLevel: calculateHighestErrorLevel(projection) }, compareByStartTime, hint);\n }\n return computeResult();\n },\n clear: () => {\n corpus = [];\n filters = EMPTY_FILTERS;\n return computeResult();\n },\n setFilters: (next) => {\n filters = next;\n return computeResult();\n }\n };\n };\n\n // src/workers/spans-worker.worker.ts\n var context = globalThis;\n var reducer = createSpansReducer();\n context.addEventListener("message", (event) => {\n const request = event.data;\n const result = request.op === "addPage" ? reducer.addPage(request.direction, request.projections) : request.op === "setFilters" ? reducer.setFilters(request.filters) : reducer.clear();\n context.postMessage({ result, seq: request.seq });\n });\n})();\n';
16967
- function createInlineWorker() {
16968
- const url = URL.createObjectURL(new Blob([source], { type: "text/javascript" }));
16969
- try {
16970
- return new Worker(url);
16971
- } finally {
16972
- URL.revokeObjectURL(url);
16973
- }
16974
- }
16963
+ var import_react46 = require("react");
16975
16964
 
16976
- // src/hooks/use-spans-compute.ts
16977
- var EMPTY_RESULT = {
16978
- consumerValues: [],
16979
- errorCount: 0,
16980
- hasExternalProducer: false,
16981
- orderedFilteredIds: [],
16982
- producerValues: [],
16983
- statusValues: [],
16984
- warningCount: 0
16985
- };
16986
- var useSpansCompute = () => {
16987
- const [result, setResult] = (0, import_react43.useState)(EMPTY_RESULT);
16988
- const [workerError, setWorkerError] = (0, import_react43.useState)();
16989
- const [retryCount, setRetryCount] = (0, import_react43.useState)(0);
16990
- const workerRef = (0, import_react43.useRef)();
16991
- const seqRef = (0, import_react43.useRef)(0);
16992
- const lastAppliedRef = (0, import_react43.useRef)(0);
16993
- (0, import_react43.useEffect)(() => {
16994
- try {
16995
- const worker = createInlineWorker();
16996
- worker.addEventListener("message", (event) => {
16997
- const { result: nextResult, seq } = event.data;
16998
- if (seq < lastAppliedRef.current) return;
16999
- lastAppliedRef.current = seq;
17000
- setResult(nextResult);
17001
- });
17002
- worker.addEventListener("error", (event) => {
17003
- setWorkerError(new Error(event.message || "Spans filter worker crashed."));
17004
- });
17005
- workerRef.current = worker;
17006
- return () => {
17007
- worker.terminate();
17008
- workerRef.current = void 0;
17009
- };
17010
- } catch (error) {
17011
- setWorkerError(error instanceof Error ? error : new Error("Failed to start the spans filter worker."));
17012
- return;
17013
- }
17014
- }, [retryCount]);
17015
- const retryWorker = (0, import_react43.useCallback)(() => {
17016
- setWorkerError(void 0);
17017
- setRetryCount((count2) => count2 + 1);
17018
- }, []);
17019
- const addPage = (0, import_react43.useCallback)((direction, projections) => {
17020
- workerRef.current?.postMessage({ direction, op: "addPage", projections, seq: ++seqRef.current });
17021
- }, []);
17022
- const setFilters = (0, import_react43.useCallback)((filters) => {
17023
- workerRef.current?.postMessage({ filters, op: "setFilters", seq: ++seqRef.current });
17024
- }, []);
17025
- const clear = (0, import_react43.useCallback)(() => {
17026
- workerRef.current?.postMessage({ op: "clear", seq: ++seqRef.current });
17027
- }, []);
17028
- return { addPage, clear, result, retryWorker, setFilters, workerError };
17029
- };
16965
+ // src/context.tsx
16966
+ var import_react44 = require("react");
16967
+ var import_react45 = require("react");
17030
16968
 
17031
- // src/hooks/use-spans-ws.tsx
17032
- var import_react47 = require("react");
16969
+ // src/api/client.ts
16970
+ var import_semver2 = __toESM(require_semver2(), 1);
17033
16971
 
17034
16972
  // src/config.ts
17035
16973
  var APPINSPECTOR_API_PREFIX = "/_localstack/appinspector";
@@ -17057,13 +16995,6 @@ var getAppInspectorApiUrl = (localstackEndpoint, endpoint) => {
17057
16995
  };
17058
16996
  var LOCALSTACK_INFO_PATH = "/_localstack/info";
17059
16997
 
17060
- // src/context.tsx
17061
- var import_react45 = require("react");
17062
- var import_react46 = require("react");
17063
-
17064
- // src/api/client.ts
17065
- var import_semver2 = __toESM(require_semver2(), 1);
17066
-
17067
16998
  // src/constants/error-messages.ts
17068
16999
  var ERROR_MESSAGES = {
17069
17000
  APP_INSPECTOR_DISABLED: "App Inspector is currently disabled.",
@@ -17328,7 +17259,7 @@ var createApiClient = ({ localstackEndpoint }) => {
17328
17259
  };
17329
17260
 
17330
17261
  // src/hooks/use-appinspector-open-analytics.ts
17331
- var import_react44 = require("react");
17262
+ var import_react43 = require("react");
17332
17263
 
17333
17264
  // node_modules/.pnpm/ua-parser-js@2.0.9/node_modules/ua-parser-js/src/main/ua-parser.mjs
17334
17265
  var LIBVERSION = "2.0.9";
@@ -19210,8 +19141,8 @@ var useAppInspectorOpenAnalytics = () => {
19210
19141
  const api = useAppInspectorApi();
19211
19142
  const { deploymentContainer } = useAppInspector();
19212
19143
  const { status, statusError } = useAppInspectorStatus();
19213
- const firedRef = (0, import_react44.useRef)(false);
19214
- (0, import_react44.useEffect)(() => {
19144
+ const firedRef = (0, import_react43.useRef)(false);
19145
+ (0, import_react43.useEffect)(() => {
19215
19146
  if (firedRef.current) {
19216
19147
  return;
19217
19148
  }
@@ -19232,9 +19163,9 @@ var useAppInspectorOpenAnalytics = () => {
19232
19163
 
19233
19164
  // src/context.tsx
19234
19165
  var import_jsx_runtime132 = require("react/jsx-runtime");
19235
- var AppInspectorContext = (0, import_react45.createContext)(void 0);
19166
+ var AppInspectorContext = (0, import_react44.createContext)(void 0);
19236
19167
  var useAppInspector = () => {
19237
- const context = (0, import_react45.useContext)(AppInspectorContext);
19168
+ const context = (0, import_react44.useContext)(AppInspectorContext);
19238
19169
  if (!context) {
19239
19170
  throw new Error("@localstack-studio/ui: components must be used within a <AppInspectorContextProvider>");
19240
19171
  }
@@ -19245,11 +19176,11 @@ var AppInspectorAnalyticsBoundary = ({ children }) => {
19245
19176
  return /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(import_jsx_runtime132.Fragment, { children });
19246
19177
  };
19247
19178
  var AppInspectorContextProvider = (props) => {
19248
- const api = (0, import_react46.useMemo)(
19179
+ const api = (0, import_react45.useMemo)(
19249
19180
  () => createApiClient({ localstackEndpoint: props.localstackEndpoint }),
19250
19181
  [props.localstackEndpoint]
19251
19182
  );
19252
- const resolveLink = (0, import_react46.useCallback)(
19183
+ const resolveLink = (0, import_react45.useCallback)(
19253
19184
  (options) => {
19254
19185
  if (options.to === "settings") {
19255
19186
  return `${props.routePrefix}/settings`;
@@ -19261,24 +19192,93 @@ var AppInspectorContextProvider = (props) => {
19261
19192
  },
19262
19193
  [props.routePrefix]
19263
19194
  );
19264
- const deploymentContainer = (0, import_react46.useMemo)(
19195
+ const deploymentContainer = (0, import_react45.useMemo)(
19265
19196
  () => props.deploymentContainer ?? { source: "web" },
19266
19197
  [props.deploymentContainer]
19267
19198
  );
19268
- const contextValue = (0, import_react46.useMemo)(
19199
+ const contextValue = (0, import_react45.useMemo)(
19269
19200
  () => ({
19270
19201
  deploymentContainer,
19271
19202
  headerHeight: props.headerHeight ?? 0,
19272
19203
  linkComponent: props.linkComponent,
19273
19204
  localstackEndpoint: props.localstackEndpoint,
19274
- resolveLink
19205
+ resolveLink,
19206
+ spansWorkerUrl: props.spansWorkerUrl
19275
19207
  }),
19276
- [deploymentContainer, props.headerHeight, props.linkComponent, props.localstackEndpoint, resolveLink]
19208
+ [deploymentContainer, props.headerHeight, props.linkComponent, props.localstackEndpoint, props.spansWorkerUrl, resolveLink]
19277
19209
  );
19278
19210
  return /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(ApiProvider, { api, children: /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(StatusProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(AppInspectorContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(AppInspectorAnalyticsBoundary, { children: props.children }) }) }) });
19279
19211
  };
19280
19212
 
19213
+ // inline-worker:/home/runner/work/localstack-appinspector-ui/localstack-appinspector-ui/src/workers/spans-worker.worker.ts
19214
+ var source = '(() => {\n // src/types/error-levels.ts\n var ErrorLevel = {\n ERROR: 3,\n // General error\n IAM_PERMISSION: 5,\n // IAM permission issues\n OK: 2,\n // OK\n // Standard OTEL status codes\n UNSET: 1,\n // Unset\n // Extended custom levels\n WARNING: 4\n // Warning\n };\n\n // src/utils/iam-utils.ts\n function determinePermissionStatus(payload) {\n if (payload.explicit_deny_count && payload.explicit_deny_count > 0) {\n return "explicitly_denied";\n }\n if (payload.is_allowed && payload.explicit_allow_count && payload.explicit_allow_count > 0) {\n return "explicitly_allowed";\n }\n if (payload.is_allowed) {\n return "implicitly_allowed";\n }\n return "implicitly_denied";\n }\n function parseIAMEvent(payloadString) {\n try {\n const payload = JSON.parse(payloadString);\n const permission = determinePermissionStatus(payload);\n const actions = [];\n const resources = [];\n if (payload.explicit_allows) {\n for (const allow of payload.explicit_allows) {\n if (!actions.includes(allow.action)) actions.push(allow.action);\n if (!resources.includes(allow.resource)) resources.push(allow.resource);\n }\n }\n if (payload.explicit_denies) {\n for (const deny of payload.explicit_denies) {\n if (!actions.includes(deny.action)) actions.push(deny.action);\n if (!resources.includes(deny.resource)) resources.push(deny.resource);\n }\n }\n if (payload.implicit_denies) {\n for (const deny of payload.implicit_denies) {\n if (!actions.includes(deny.action)) actions.push(deny.action);\n if (!resources.includes(deny.resource)) resources.push(deny.resource);\n }\n }\n return {\n details: {\n actions,\n explicitAllows: payload.explicit_allow_count,\n explicitDenies: payload.explicit_deny_count,\n implicitDenies: payload.implicit_deny_count,\n resources\n },\n operation: payload.operation,\n permission,\n principal: payload.principal_arn,\n service: payload.service\n };\n } catch (error) {\n console.error("Error parsing IAM event payload:", error);\n return void 0;\n }\n }\n\n // src/utils/error-level.ts\n var calculateHighestErrorLevel = (span) => {\n if (span.operation_status) {\n switch (span.operation_status) {\n case "error": {\n return ErrorLevel.ERROR;\n }\n case "iam_explicit_deny":\n case "iam_explicit_warn":\n case "iam_implicit_deny":\n case "iam_implicit_warn": {\n return ErrorLevel.IAM_PERMISSION;\n }\n default: {\n return ErrorLevel.OK;\n }\n }\n }\n const hasIamDenial = span.events.some((event) => {\n if (!event.event_type?.toLowerCase().includes("iam")) return false;\n if (typeof event.attributes?.payload !== "string") return false;\n const parsed = parseIAMEvent(event.attributes.payload);\n return parsed?.permission === "explicitly_denied" || parsed?.permission === "implicitly_denied";\n });\n if (hasIamDenial) return ErrorLevel.IAM_PERMISSION;\n if (span.status_code === 2) return ErrorLevel.ERROR;\n const hasErrorInErrors = span.errors?.some((error) => error.level === "error");\n if (hasErrorInErrors) return ErrorLevel.ERROR;\n const hasWarning = span.errors?.some((error) => error.level === "warning");\n if (hasWarning) return ErrorLevel.WARNING;\n return span.status_code || ErrorLevel.UNSET;\n };\n\n // src/utils/spans-filters.ts\n var EMPTY_FILTERS = {\n consumerService: [],\n producerService: [],\n status: []\n };\n var EXTERNAL_PRODUCER_VALUE = "__external__";\n function isFiltersEmpty(filters) {\n return filters.consumerService.length === 0 && filters.producerService.length === 0 && filters.status.length === 0;\n }\n var collapseStatusValue = (status) => {\n if (status === "iam_explicit_deny" || status === "iam_implicit_deny") return "iam_deny";\n if (status === "iam_explicit_warn" || status === "iam_implicit_warn") return "iam_warn";\n return status;\n };\n function applyFilters(spans, filters) {\n if (isFiltersEmpty(filters)) return spans;\n return spans.filter((span) => {\n if (filters.consumerService.length > 0 && !filters.consumerService.includes(span.service_name)) {\n return false;\n }\n if (filters.producerService.length > 0) {\n const includesExternal = filters.producerService.includes(EXTERNAL_PRODUCER_VALUE);\n const namedServices = filters.producerService.filter((value) => value !== EXTERNAL_PRODUCER_VALUE);\n const matchesExternal = includesExternal && !span.parent_service_name;\n const matchesNamed = namedServices.length > 0 && !!span.parent_service_name && namedServices.includes(span.parent_service_name);\n if (!matchesExternal && !matchesNamed) return false;\n }\n if (filters.status.length > 0) {\n if (!span.operation_status) return false;\n if (!filters.status.includes(collapseStatusValue(span.operation_status))) return false;\n }\n return true;\n });\n }\n\n // src/workers/spans-reducer.ts\n var compareByStartTime = (a, b) => a.start_time_unix_nano < b.start_time_unix_nano ? -1 : 1;\n var insertSorted = (array, item, compareFunction, hint) => {\n let left;\n let right;\n if (hint === "back") {\n left = array.length;\n right = array.length;\n let step = 1;\n while (left > 0 && compareFunction(array[left - 1], item) > 0) {\n right = left;\n left = Math.max(0, left - step);\n step *= 2;\n }\n } else {\n left = 0;\n right = 0;\n let step = 1;\n while (right < array.length && compareFunction(array[right], item) <= 0) {\n left = right + 1;\n right = Math.min(array.length, right + step);\n step *= 2;\n }\n }\n while (left < right) {\n const mid = left + right >>> 1;\n if (compareFunction(array[mid], item) <= 0) {\n left = mid + 1;\n } else {\n right = mid;\n }\n }\n array.splice(left, 0, item);\n };\n var createSpansReducer = () => {\n let corpus = [];\n let filters = EMPTY_FILTERS;\n const computeResult = () => {\n const filtered = applyFilters(corpus, filters);\n let errorCount = 0;\n let warningCount = 0;\n const orderedFilteredIds = [];\n for (const entry of filtered) {\n orderedFilteredIds.push(entry.span_id);\n if (entry.errorLevel === ErrorLevel.ERROR || entry.errorLevel === ErrorLevel.IAM_PERMISSION) {\n errorCount++;\n } else if (entry.errorLevel === ErrorLevel.WARNING) {\n warningCount++;\n }\n }\n const producers = /* @__PURE__ */ new Set();\n const consumers = /* @__PURE__ */ new Set();\n const statuses = /* @__PURE__ */ new Set();\n let hasExternalProducer = false;\n for (const entry of corpus) {\n if (entry.parent_service_name) producers.add(entry.parent_service_name);\n else hasExternalProducer = true;\n consumers.add(entry.service_name);\n if (entry.operation_status) statuses.add(collapseStatusValue(entry.operation_status));\n }\n return {\n consumerValues: [...consumers].toSorted(),\n errorCount,\n hasExternalProducer,\n orderedFilteredIds,\n producerValues: [...producers].toSorted(),\n statusValues: [...statuses].toSorted(),\n warningCount\n };\n };\n return {\n addPage: (direction, projections) => {\n const hint = direction === "forward" ? "back" : "front";\n const sorted = projections.toSorted(compareByStartTime);\n for (const projection of sorted) {\n insertSorted(corpus, { ...projection, errorLevel: calculateHighestErrorLevel(projection) }, compareByStartTime, hint);\n }\n return computeResult();\n },\n clear: () => {\n corpus = [];\n filters = EMPTY_FILTERS;\n return computeResult();\n },\n setFilters: (next) => {\n filters = next;\n return computeResult();\n }\n };\n };\n\n // src/workers/spans-worker.worker.ts\n var context = globalThis;\n var reducer = createSpansReducer();\n context.addEventListener("message", (event) => {\n const request = event.data;\n const result = request.op === "addPage" ? reducer.addPage(request.direction, request.projections) : request.op === "setFilters" ? reducer.setFilters(request.filters) : reducer.clear();\n context.postMessage({ result, seq: request.seq });\n });\n})();\n';
19215
+ function createInlineWorker() {
19216
+ const url = URL.createObjectURL(new Blob([source], { type: "text/javascript" }));
19217
+ try {
19218
+ return new Worker(url);
19219
+ } finally {
19220
+ URL.revokeObjectURL(url);
19221
+ }
19222
+ }
19223
+
19224
+ // src/hooks/use-spans-compute.ts
19225
+ var EMPTY_RESULT = {
19226
+ consumerValues: [],
19227
+ errorCount: 0,
19228
+ hasExternalProducer: false,
19229
+ orderedFilteredIds: [],
19230
+ producerValues: [],
19231
+ statusValues: [],
19232
+ warningCount: 0
19233
+ };
19234
+ var useSpansCompute = () => {
19235
+ const { spansWorkerUrl } = useAppInspector();
19236
+ const [result, setResult] = (0, import_react46.useState)(EMPTY_RESULT);
19237
+ const [workerError, setWorkerError] = (0, import_react46.useState)();
19238
+ const [retryCount, setRetryCount] = (0, import_react46.useState)(0);
19239
+ const workerRef = (0, import_react46.useRef)();
19240
+ const seqRef = (0, import_react46.useRef)(0);
19241
+ const lastAppliedRef = (0, import_react46.useRef)(0);
19242
+ (0, import_react46.useEffect)(() => {
19243
+ try {
19244
+ const worker = spansWorkerUrl ? new Worker(spansWorkerUrl) : createInlineWorker();
19245
+ worker.addEventListener("message", (event) => {
19246
+ const { result: nextResult, seq } = event.data;
19247
+ if (seq < lastAppliedRef.current) return;
19248
+ lastAppliedRef.current = seq;
19249
+ setResult(nextResult);
19250
+ });
19251
+ worker.addEventListener("error", (event) => {
19252
+ setWorkerError(new Error(event.message || "Spans filter worker crashed."));
19253
+ });
19254
+ workerRef.current = worker;
19255
+ return () => {
19256
+ worker.terminate();
19257
+ workerRef.current = void 0;
19258
+ };
19259
+ } catch (error) {
19260
+ setWorkerError(error instanceof Error ? error : new Error("Failed to start the spans filter worker."));
19261
+ return;
19262
+ }
19263
+ }, [retryCount, spansWorkerUrl]);
19264
+ const retryWorker = (0, import_react46.useCallback)(() => {
19265
+ setWorkerError(void 0);
19266
+ setRetryCount((count2) => count2 + 1);
19267
+ }, []);
19268
+ const addPage = (0, import_react46.useCallback)((direction, projections) => {
19269
+ workerRef.current?.postMessage({ direction, op: "addPage", projections, seq: ++seqRef.current });
19270
+ }, []);
19271
+ const setFilters = (0, import_react46.useCallback)((filters) => {
19272
+ workerRef.current?.postMessage({ filters, op: "setFilters", seq: ++seqRef.current });
19273
+ }, []);
19274
+ const clear = (0, import_react46.useCallback)(() => {
19275
+ workerRef.current?.postMessage({ op: "clear", seq: ++seqRef.current });
19276
+ }, []);
19277
+ return { addPage, clear, result, retryWorker, setFilters, workerError };
19278
+ };
19279
+
19281
19280
  // src/hooks/use-spans-ws.tsx
19281
+ var import_react47 = require("react");
19282
19282
  var wsLogger = createScopedLogger("WS");
19283
19283
  var isLegacySpanFields = (value) => {
19284
19284
  return typeof value.span_id === "string" && typeof value.trace_id === "string" && typeof value.timestamp === "string";