@datalayer/core 1.0.3 → 1.0.11

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 (111) hide show
  1. package/lib/api/constants.d.ts +3 -0
  2. package/lib/api/constants.js +3 -0
  3. package/lib/api/runtimes/checkpoints.d.ts +122 -0
  4. package/lib/api/runtimes/checkpoints.js +118 -0
  5. package/lib/api/runtimes/index.d.ts +1 -0
  6. package/lib/api/runtimes/index.js +1 -0
  7. package/lib/api/runtimes/runtimes.d.ts +84 -0
  8. package/lib/api/runtimes/runtimes.js +50 -0
  9. package/lib/components/auth/Login.js +1 -1
  10. package/lib/components/display/BusyDots.d.ts +9 -0
  11. package/lib/components/display/BusyDots.js +31 -0
  12. package/lib/components/display/LiveRelativeTime.d.ts +10 -0
  13. package/lib/components/display/LiveRelativeTime.js +21 -0
  14. package/lib/components/display/index.d.ts +2 -0
  15. package/lib/components/display/index.js +2 -0
  16. package/lib/components/flashes/FlashSurveys.js +1 -1
  17. package/lib/components/index.d.ts +1 -0
  18. package/lib/components/index.js +1 -0
  19. package/lib/components/navbar/SubdomainNavBar.js +1 -1
  20. package/lib/components/progress/ConsumptionBar.js +6 -7
  21. package/lib/components/progress/CreditsIndicator.js +2 -2
  22. package/lib/components/progress/consumption.d.ts +12 -0
  23. package/lib/components/progress/consumption.js +31 -0
  24. package/lib/components/progress/index.d.ts +1 -0
  25. package/lib/components/progress/index.js +1 -0
  26. package/lib/components/sparklines/Sparklines.d.ts +16 -0
  27. package/lib/components/sparklines/Sparklines.js +65 -0
  28. package/lib/components/sparklines/SparklinesLine.d.ts +8 -0
  29. package/lib/components/sparklines/SparklinesLine.js +37 -0
  30. package/lib/components/sparklines/dataProcessing.d.ts +25 -0
  31. package/lib/components/sparklines/dataProcessing.js +35 -0
  32. package/lib/components/sparklines/index.d.ts +4 -0
  33. package/lib/components/sparklines/index.js +7 -0
  34. package/lib/components/sparklines/types.d.ts +36 -0
  35. package/lib/components/sparklines/types.js +5 -0
  36. package/lib/components/storage/ContentsBrowser.js +17 -1
  37. package/lib/components/subnav/SubNav.js +1 -1
  38. package/lib/hooks/useCache.d.ts +5 -67
  39. package/lib/hooks/useCache.js +15 -213
  40. package/lib/hooks/useProjects.d.ts +1 -1
  41. package/lib/models/ItemDTO.js +1 -1
  42. package/lib/models/RolesPlatform.js +2 -2
  43. package/lib/models/User.d.ts +2 -0
  44. package/lib/models/User.js +4 -1
  45. package/lib/otel/client/OtelClient.d.ts +93 -0
  46. package/lib/otel/client/OtelClient.js +232 -0
  47. package/lib/otel/client/index.d.ts +2 -0
  48. package/lib/otel/client/index.js +5 -0
  49. package/lib/otel/{hooks.d.ts → hooks/index.d.ts} +15 -1
  50. package/lib/otel/{hooks.js → hooks/index.js} +58 -16
  51. package/lib/otel/index.d.ts +29 -20
  52. package/lib/otel/index.js +19 -15
  53. package/lib/otel/{OtelLive.d.ts → views/OtelLive.d.ts} +1 -1
  54. package/lib/otel/{OtelLive.js → views/OtelLive.js} +22 -4
  55. package/lib/otel/{OtelLogsList.d.ts → views/OtelLogsList.d.ts} +1 -1
  56. package/lib/otel/{OtelLogsList.js → views/OtelLogsList.js} +1 -1
  57. package/lib/otel/{OtelMetricsChart.d.ts → views/OtelMetricsChart.d.ts} +1 -1
  58. package/lib/otel/{OtelMetricsList.d.ts → views/OtelMetricsList.d.ts} +1 -1
  59. package/lib/otel/{OtelMetricsList.js → views/OtelMetricsList.js} +1 -1
  60. package/lib/otel/{OtelSearchBar.d.ts → views/OtelSearchBar.d.ts} +1 -1
  61. package/lib/otel/{OtelSpanDetail.d.ts → views/OtelSpanDetail.d.ts} +1 -1
  62. package/lib/otel/{OtelSpanDetail.js → views/OtelSpanDetail.js} +1 -1
  63. package/lib/otel/{OtelSpanTree.d.ts → views/OtelSpanTree.d.ts} +1 -1
  64. package/lib/otel/{OtelSpanTree.js → views/OtelSpanTree.js} +1 -1
  65. package/lib/otel/{OtelSqlView.js → views/OtelSqlView.js} +1 -1
  66. package/lib/otel/{OtelSystemView.js → views/OtelSystemView.js} +1 -1
  67. package/lib/otel/{OtelTimeline.d.ts → views/OtelTimeline.d.ts} +1 -1
  68. package/lib/otel/{OtelTimeline.js → views/OtelTimeline.js} +1 -1
  69. package/lib/otel/{OtelTimelineRangeSlider.d.ts → views/OtelTimelineRangeSlider.d.ts} +1 -1
  70. package/lib/otel/{OtelTracesList.d.ts → views/OtelTracesList.d.ts} +1 -1
  71. package/lib/otel/{OtelTracesList.js → views/OtelTracesList.js} +1 -1
  72. package/lib/otel/views/index.d.ts +20 -0
  73. package/lib/otel/views/index.js +21 -0
  74. package/lib/state/substates/CoreState.js +6 -6
  75. package/lib/utils/Date.d.ts +6 -0
  76. package/lib/utils/Date.js +37 -0
  77. package/lib/views/iam/SignInSimple.d.ts +5 -0
  78. package/lib/views/iam/SignInSimple.js +39 -6
  79. package/lib/views/iam-tokens/IAMTokenEdit.d.ts +5 -1
  80. package/lib/views/iam-tokens/IAMTokenEdit.js +3 -3
  81. package/lib/views/iam-tokens/IAMTokenNew.js +2 -2
  82. package/lib/views/iam-tokens/IAMTokens.d.ts +4 -2
  83. package/lib/views/iam-tokens/IAMTokens.js +4 -4
  84. package/lib/views/index.d.ts +1 -0
  85. package/lib/views/index.js +1 -0
  86. package/lib/views/otel/DashboardView.d.ts +16 -0
  87. package/lib/views/otel/DashboardView.js +4 -0
  88. package/lib/views/otel/LogsView.d.ts +12 -0
  89. package/lib/views/otel/LogsView.js +4 -0
  90. package/lib/views/otel/MetricsView.d.ts +12 -0
  91. package/lib/views/otel/MetricsView.js +4 -0
  92. package/lib/views/otel/OtelHeader.d.ts +33 -0
  93. package/lib/views/otel/OtelHeader.js +105 -0
  94. package/lib/views/otel/SqlView.d.ts +9 -0
  95. package/lib/views/otel/SqlView.js +4 -0
  96. package/lib/views/otel/SystemView.d.ts +9 -0
  97. package/lib/views/otel/SystemView.js +4 -0
  98. package/lib/views/otel/TracesView.d.ts +12 -0
  99. package/lib/views/otel/TracesView.js +4 -0
  100. package/lib/views/otel/index.d.ts +16 -0
  101. package/lib/views/otel/index.js +12 -0
  102. package/lib/views/otel/simpleAuthStore.d.ts +21 -0
  103. package/lib/views/otel/simpleAuthStore.js +22 -0
  104. package/lib/views/profile/UserBadge.d.ts +2 -0
  105. package/lib/views/profile/UserBadge.js +3 -3
  106. package/package.json +1 -26
  107. /package/lib/otel/{OtelMetricsChart.js → views/OtelMetricsChart.js} +0 -0
  108. /package/lib/otel/{OtelSearchBar.js → views/OtelSearchBar.js} +0 -0
  109. /package/lib/otel/{OtelSqlView.d.ts → views/OtelSqlView.d.ts} +0 -0
  110. /package/lib/otel/{OtelSystemView.d.ts → views/OtelSystemView.d.ts} +0 -0
  111. /package/lib/otel/{OtelTimelineRangeSlider.js → views/OtelTimelineRangeSlider.js} +0 -0
@@ -272,13 +272,6 @@ export const queryKeys = {
272
272
  bySpace: (spaceId) => [...queryKeys.items.all(), 'space', spaceId],
273
273
  search: (opts) => [...queryKeys.items.all(), 'search', opts],
274
274
  },
275
- // Agent Runtimes (runtimes with ai-agents environment)
276
- agentRuntimes: {
277
- all: () => ['agentRuntimes'],
278
- lists: () => [...queryKeys.agentRuntimes.all(), 'list'],
279
- details: () => [...queryKeys.agentRuntimes.all(), 'detail'],
280
- detail: (podName) => [...queryKeys.agentRuntimes.details(), podName],
281
- },
282
275
  // Layout
283
276
  layout: {
284
277
  byAccount: (accountHandle, spaceHandle) => spaceHandle
@@ -1362,206 +1355,6 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
1362
1355
  },
1363
1356
  });
1364
1357
  };
1365
- /**
1366
- * List agent runtimes (runtimes with ai-agents-env environment)
1367
- */
1368
- /**
1369
- * Get all agent runtimes for the current user.
1370
- *
1371
- * Note on phase/status mapping:
1372
- * The backend (operator) RuntimePod model does not include a 'phase' field.
1373
- * The operator only keeps active/assigned runtimes in its cache (OperatorCache.USER_RUNTIMES),
1374
- * so any runtime returned by this endpoint is inherently running or starting.
1375
- * Therefore, if rt.phase is undefined (which it will be), we default to 'running'.
1376
- * A 'paused' state would require explicit backend support to track paused runtimes.
1377
- */
1378
- const useAgentRuntimes = () => {
1379
- return useQuery({
1380
- queryKey: queryKeys.agentRuntimes.lists(),
1381
- queryFn: async () => {
1382
- const resp = await requestDatalayer({
1383
- url: `${configuration.runtimesRunUrl}/api/runtimes/v1/runtimes`,
1384
- method: 'GET',
1385
- });
1386
- if (resp.success && resp.runtimes) {
1387
- // Filter to only include ai-agents-env runtimes
1388
- const agentRuntimes = resp.runtimes
1389
- .filter((rt) => rt.environment_name === 'ai-agents-env')
1390
- .map((rt) => ({
1391
- ...rt,
1392
- // Phase/status mapping: see hook JSDoc for details.
1393
- // Backend returns only active runtimes, so default to 'running'.
1394
- status: rt.phase === 'Pending'
1395
- ? 'starting'
1396
- : rt.phase === 'Terminated'
1397
- ? 'terminated'
1398
- : rt.phase === 'Paused'
1399
- ? 'paused'
1400
- : rt.phase === 'Archived'
1401
- ? 'archived'
1402
- : 'running',
1403
- name: rt.given_name || rt.pod_name,
1404
- id: rt.pod_name,
1405
- // Map ingress URL to url for UI consistency
1406
- url: rt.ingress,
1407
- messageCount: 0, // Default for UI compatibility
1408
- agent_spec_id: rt.agent_spec_id || undefined,
1409
- }));
1410
- // Set detail cache for each runtime
1411
- agentRuntimes.forEach((runtime) => {
1412
- queryClient.setQueryData(queryKeys.agentRuntimes.detail(runtime.pod_name), runtime);
1413
- });
1414
- return agentRuntimes;
1415
- }
1416
- return [];
1417
- },
1418
- ...DEFAULT_QUERY_OPTIONS,
1419
- refetchInterval: 10000, // Refetch every 10 seconds for status updates
1420
- enabled: !!user,
1421
- });
1422
- };
1423
- /**
1424
- * Get a single agent runtime by pod name.
1425
- *
1426
- * Note on phase/status mapping:
1427
- * Same as useAgentRuntimes - the backend RuntimePod model has no 'phase' field,
1428
- * and only active runtimes exist in the operator cache. Default to 'running'.
1429
- */
1430
- const useAgentRuntime = (podName) => {
1431
- return useQuery({
1432
- queryKey: queryKeys.agentRuntimes.detail(podName ?? ''),
1433
- queryFn: async () => {
1434
- const resp = await requestDatalayer({
1435
- url: `${configuration.runtimesRunUrl}/api/runtimes/v1/runtimes/${podName}`,
1436
- method: 'GET',
1437
- });
1438
- if (resp.runtime) {
1439
- const rt = resp.runtime;
1440
- return {
1441
- ...rt,
1442
- // Phase/status mapping: see useAgentRuntimes JSDoc for details.
1443
- status: rt.phase === 'Pending'
1444
- ? 'starting'
1445
- : rt.phase === 'Terminated'
1446
- ? 'terminated'
1447
- : rt.phase === 'Paused'
1448
- ? 'paused'
1449
- : rt.phase === 'Archived'
1450
- ? 'archived'
1451
- : 'running',
1452
- name: rt.given_name || rt.pod_name,
1453
- id: rt.pod_name,
1454
- // Map ingress URL to url for UI consistency
1455
- url: rt.ingress,
1456
- messageCount: 0,
1457
- agent_spec_id: rt.agent_spec_id || undefined,
1458
- };
1459
- }
1460
- throw new Error('Failed to fetch agent runtime');
1461
- },
1462
- ...DEFAULT_QUERY_OPTIONS,
1463
- // Poll every 5 seconds while the runtime exists. Stop polling on error
1464
- // (e.g. 404 — runtime deleted, 500 — broken state) to avoid hammering the server.
1465
- refetchInterval: query => {
1466
- if (query.state.error)
1467
- return false;
1468
- return 5000;
1469
- },
1470
- // Don't retry failed detail requests. The refetchInterval handles
1471
- // periodic re-checks, so retrying only generates duplicate failing requests.
1472
- retry: false,
1473
- enabled: !!podName,
1474
- });
1475
- };
1476
- /**
1477
- * Create a new agent runtime.
1478
- *
1479
- * Note on phase/status mapping:
1480
- * Newly created runtimes are immediately active (the operator assigns a pod from the pool).
1481
- * The response won't have a 'phase' field, so we default to 'running'.
1482
- * See useAgentRuntimes JSDoc for full explanation.
1483
- */
1484
- const useCreateAgentRuntime = () => {
1485
- return useMutation({
1486
- mutationFn: async (data) => {
1487
- return requestDatalayer({
1488
- url: `${configuration.runtimesRunUrl}/api/runtimes/v1/runtimes`,
1489
- method: 'POST',
1490
- body: {
1491
- environment_name: data.environmentName || 'ai-agents-env',
1492
- given_name: data.givenName || 'Agent',
1493
- credits_limit: data.creditsLimit || 10,
1494
- type: data.type || 'notebook',
1495
- editor_variant: data.editorVariant || 'none',
1496
- enable_codemode: data.enableCodemode ?? false,
1497
- agent_spec_id: data.agentSpecId || undefined,
1498
- },
1499
- });
1500
- },
1501
- onSuccess: resp => {
1502
- if (resp.success && resp.runtime) {
1503
- const rt = resp.runtime;
1504
- // Phase/status mapping: see useAgentRuntimes JSDoc for details.
1505
- queryClient.setQueryData(queryKeys.agentRuntimes.detail(rt.pod_name), {
1506
- ...rt,
1507
- status: rt.phase === 'Pending'
1508
- ? 'starting'
1509
- : 'running',
1510
- name: rt.given_name || rt.pod_name,
1511
- id: rt.pod_name,
1512
- // Map ingress URL to url for UI consistency
1513
- url: rt.ingress,
1514
- messageCount: 0,
1515
- agent_spec_id: rt.agent_spec_id || undefined,
1516
- });
1517
- // Invalidate list
1518
- queryClient.invalidateQueries({
1519
- queryKey: queryKeys.agentRuntimes.all(),
1520
- });
1521
- }
1522
- },
1523
- });
1524
- };
1525
- /**
1526
- * Delete agent runtime
1527
- */
1528
- const useDeleteAgentRuntime = () => {
1529
- return useMutation({
1530
- mutationFn: async (podName) => {
1531
- return requestDatalayer({
1532
- url: `${configuration.runtimesRunUrl}/api/runtimes/v1/runtimes/${podName}`,
1533
- method: 'DELETE',
1534
- });
1535
- },
1536
- onSuccess: (_data, podName) => {
1537
- // Cancel any in-flight queries for the deleted runtime so they
1538
- // don't re-fetch a resource that no longer exists.
1539
- queryClient.cancelQueries({
1540
- queryKey: queryKeys.agentRuntimes.detail(podName),
1541
- });
1542
- // Remove the detail cache entry immediately — prevents React
1543
- // Query from triggering a stale re-fetch while the component
1544
- // unmounts.
1545
- queryClient.removeQueries({
1546
- queryKey: queryKeys.agentRuntimes.detail(podName),
1547
- });
1548
- // Invalidate the list so the sidebar refreshes.
1549
- queryClient.invalidateQueries({
1550
- queryKey: queryKeys.agentRuntimes.lists(),
1551
- });
1552
- },
1553
- });
1554
- };
1555
- /**
1556
- * Refresh agent runtimes list
1557
- */
1558
- const useRefreshAgentRuntimes = () => {
1559
- return () => {
1560
- queryClient.invalidateQueries({
1561
- queryKey: queryKeys.agentRuntimes.all(),
1562
- });
1563
- };
1564
- };
1565
1358
  // ============================================================================
1566
1359
  // Notebook Hooks
1567
1360
  // ============================================================================
@@ -4712,6 +4505,20 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
4712
4505
  },
4713
4506
  });
4714
4507
  };
4508
+ /**
4509
+ * Create URL for password change (sends clickable link via email)
4510
+ */
4511
+ const useCreateUrlForPasswordChange = () => {
4512
+ return useMutation({
4513
+ mutationFn: async ({ handle, password, passwordConfirm, }) => {
4514
+ return requestDatalayer({
4515
+ url: `${configuration.iamRunUrl}/api/iam/v1/password`,
4516
+ method: 'PUT',
4517
+ body: { handle, password, passwordConfirm },
4518
+ });
4519
+ },
4520
+ });
4521
+ };
4715
4522
  /**
4716
4523
  * Confirm password change with token
4717
4524
  */
@@ -6264,6 +6071,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
6264
6071
  useJoinWithInvite,
6265
6072
  useConfirmJoinWithToken,
6266
6073
  useCreateTokenForPasswordChange,
6074
+ useCreateUrlForPasswordChange,
6267
6075
  useConfirmPasswordWithToken,
6268
6076
  useOAuth2AuthorizationURL,
6269
6077
  useOAuth2AuthorizationLinkURL,
@@ -6344,12 +6152,6 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
6344
6152
  useRefreshUserSpace,
6345
6153
  useRefreshLayout,
6346
6154
  useExportSpace,
6347
- // Agent Runtimes (runtimes with ai-agents environment)
6348
- useAgentRuntime,
6349
- useAgentRuntimes,
6350
- useCreateAgentRuntime,
6351
- useDeleteAgentRuntime,
6352
- useRefreshAgentRuntimes,
6353
6155
  // Courses
6354
6156
  useCourse,
6355
6157
  useUpdateCourse,
@@ -20,7 +20,7 @@ export type ProjectData = {
20
20
  isPublic: boolean;
21
21
  /** Attached agent (runtime) pod name, if any */
22
22
  attachedAgentPodName?: string;
23
- /** Attached agent spec ID (e.g. 'datalayer-ai/data-acquisition'), if any */
23
+ /** Attached agent spec ID (e.g. 'data-acquisition'), if any */
24
24
  attachedAgentSpecId?: string;
25
25
  };
26
26
  /**
@@ -59,7 +59,7 @@ export class ItemDTO {
59
59
  if (this._data.space_id) {
60
60
  return this._data.space_id;
61
61
  }
62
- // Extract from s3_path_s if available: "datalayer.app/SPACE_ID/..."
62
+ // Extract from s3_path_s if available: "datalayer.ai/SPACE_ID/..."
63
63
  const s3Path = this._data.s3_path_s;
64
64
  if (s3Path && typeof s3Path === 'string') {
65
65
  const match = s3Path.match(/^datalayer\.app\/([^/]+)\//);
@@ -43,8 +43,8 @@ export class PlatformRoles {
43
43
  static IAMToken = {
44
44
  id: 'platform_iam_token',
45
45
  handle: 'platform_iam_token',
46
- displayName: 'Platform IAM Token',
47
- description: 'A Platform IAM Token.',
46
+ displayName: 'Platform API Key',
47
+ description: 'A Platform API Key.',
48
48
  permissions: PLATFORM_IAM_TOKEN_PERMSSIONS,
49
49
  icon: UserIcon,
50
50
  };
@@ -18,6 +18,7 @@ export declare class User implements IUser {
18
18
  lastName: string;
19
19
  initials: string;
20
20
  displayName: string;
21
+ friendlyName?: string;
21
22
  joinDate?: Date;
22
23
  roles: string[];
23
24
  credits?: number;
@@ -48,6 +49,7 @@ export type IBaseUser = {
48
49
  lastName: string;
49
50
  initials: string;
50
51
  displayName: string;
52
+ friendlyName?: string;
51
53
  joinDate?: Date;
52
54
  roles: string[];
53
55
  setRoles: (roles: string[]) => void;
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) 2023-2025 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- import { asDisplayName, namesAsInitials } from '../utils';
5
+ import { asDisplayName, namesAsInitials, toFriendlyName } from '../utils';
6
6
  import { asIAMProviderLinked } from './IAMProviderLinked';
7
7
  import { BOOTSTRAP_USER_ONBOARDING } from './UserOnboarding';
8
8
  import { UserSettings } from './UserSettings';
@@ -34,6 +34,7 @@ export class User {
34
34
  lastName;
35
35
  initials;
36
36
  displayName;
37
+ friendlyName;
37
38
  joinDate;
38
39
  roles;
39
40
  credits;
@@ -57,6 +58,8 @@ export class User {
57
58
  this.initials = namesAsInitials(u.first_name_t, u.last_name_t);
58
59
  const displayName = asDisplayName(u.first_name_t, u.last_name_t);
59
60
  this.displayName = displayName === '' ? u.handle_s : displayName;
61
+ this.friendlyName =
62
+ toFriendlyName(u.first_name_t, u.last_name_t) || u.handle_s;
60
63
  this.avatarUrl = u.avatar_url_s;
61
64
  this.origin = u.origin_s;
62
65
  this.joinDate = u.join_ts_dt ? new Date(u.join_ts_dt) : undefined;
@@ -0,0 +1,93 @@
1
+ import type { OtelSpan, OtelLog, OtelMetric, OtelQueryResult } from '../types';
2
+ import type { OtelSystemData, OtelSystemProcess, OtelSystemDisk, OtelSystemTable } from '../hooks';
3
+ export interface OtelClientOptions {
4
+ /**
5
+ * Base URL of the OTEL service.
6
+ * Defaults to `configuration.otelRunUrl` from the Datalayer core config
7
+ * (i.e. `https://prod1.datalayer.run`).
8
+ */
9
+ baseUrl?: string;
10
+ /** JWT bearer token or API key for authentication. */
11
+ token?: string;
12
+ }
13
+ export interface FetchTracesOptions {
14
+ serviceName?: string;
15
+ limit?: number;
16
+ }
17
+ export interface FetchLogsOptions {
18
+ serviceName?: string;
19
+ severity?: string;
20
+ traceId?: string;
21
+ limit?: number;
22
+ }
23
+ export interface FetchMetricsOptions {
24
+ serviceName?: string;
25
+ metricName?: string;
26
+ limit?: number;
27
+ }
28
+ export interface FetchMetricTotalOptions {
29
+ serviceName?: string;
30
+ limit?: number;
31
+ fallbackWithoutService?: boolean;
32
+ }
33
+ /**
34
+ * Typed HTTP client for all OTEL service endpoints.
35
+ *
36
+ * Construct via `createOtelClient()` or `new OtelClient(options)`.
37
+ */
38
+ export declare class OtelClient {
39
+ private readonly baseUrl;
40
+ private readonly token?;
41
+ constructor(options?: OtelClientOptions);
42
+ /** List recent spans / traces. */
43
+ fetchTraces(options?: FetchTracesOptions): Promise<{
44
+ data: OtelSpan[];
45
+ count: number;
46
+ }>;
47
+ /** Fetch all spans for a single trace by `traceId`. */
48
+ fetchTrace(traceId: string): Promise<{
49
+ data: OtelSpan[];
50
+ }>;
51
+ /** List recent log records. */
52
+ fetchLogs(options?: FetchLogsOptions): Promise<{
53
+ data: OtelLog[];
54
+ count: number;
55
+ }>;
56
+ /** List recent metric data points. */
57
+ fetchMetrics(options?: FetchMetricsOptions): Promise<{
58
+ data: OtelMetric[];
59
+ count: number;
60
+ }>;
61
+ /** Sum all values for one metric name, with optional service filter. */
62
+ fetchMetricTotal(metricName: string, options?: FetchMetricTotalOptions): Promise<number>;
63
+ /** List known service names observed in traces. */
64
+ fetchServices(): Promise<string[]>;
65
+ /** Fetch storage / ingestion statistics. */
66
+ fetchStats(): Promise<Record<string, unknown>>;
67
+ /**
68
+ * Execute an ad-hoc DataFusion SQL query against the OTEL service.
69
+ *
70
+ * Available tables: `spans`, `logs`, `metrics`.
71
+ */
72
+ executeQuery(sql: string): Promise<OtelQueryResult>;
73
+ /**
74
+ * Fetch system statistics (platform_admin only).
75
+ *
76
+ * Returns process memory/CPU, disk usage, and per-table row counts.
77
+ */
78
+ fetchSystem(): Promise<OtelSystemData>;
79
+ }
80
+ /**
81
+ * Create a new `OtelClient`.
82
+ *
83
+ * The `baseUrl` defaults to `configuration.otelRunUrl` from the Datalayer core
84
+ * configuration store, so only pass it when you want to override the default.
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * const client = createOtelClient({ token: jwt });
89
+ * const services = await client.fetchServices();
90
+ * ```
91
+ */
92
+ export declare function createOtelClient(options?: OtelClientOptions): OtelClient;
93
+ export type { OtelSystemData, OtelSystemProcess, OtelSystemDisk, OtelSystemTable, };
@@ -0,0 +1,232 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * OtelClient – Typed HTTP client for the Datalayer OTEL service.
7
+ *
8
+ * Reads the OTEL service URL from the Datalayer core configuration by default,
9
+ * so callers don't need to pass `baseUrl` unless they want to override it.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { createOtelClient } from '@datalayer/core/otel';
14
+ *
15
+ * const client = createOtelClient({ token: myJwt });
16
+ * const { data: spans } = await client.fetchTraces({ limit: 50 });
17
+ * ```
18
+ */
19
+ import { coreStore } from '../../state/substates/CoreState';
20
+ // ── Fetch helper ────────────────────────────────────────────────────────────
21
+ async function otelFetch(url, token, options) {
22
+ const headers = {
23
+ Accept: 'application/json',
24
+ 'Cache-Control': 'no-store, no-cache, must-revalidate',
25
+ };
26
+ if (token) {
27
+ headers['Authorization'] = `Bearer ${token}`;
28
+ }
29
+ if (options?.body) {
30
+ headers['Content-Type'] = 'application/json';
31
+ }
32
+ const resp = await fetch(url, {
33
+ method: options?.method ?? 'GET',
34
+ headers,
35
+ body: options?.body != null ? JSON.stringify(options.body) : undefined,
36
+ });
37
+ if (!resp.ok) {
38
+ const text = await resp.text().catch(() => '');
39
+ throw new Error(`OTEL API error ${resp.status}: ${text}`);
40
+ }
41
+ return resp.json();
42
+ }
43
+ function parseMetricValue(raw) {
44
+ const candidates = [raw.value, raw.value_double, raw.value_int];
45
+ for (const candidate of candidates) {
46
+ if (typeof candidate === 'number' && Number.isFinite(candidate)) {
47
+ return candidate;
48
+ }
49
+ if (typeof candidate === 'string') {
50
+ const parsed = Number(candidate);
51
+ if (Number.isFinite(parsed)) {
52
+ return parsed;
53
+ }
54
+ }
55
+ }
56
+ return 0;
57
+ }
58
+ function parseMetricTimestamp(raw) {
59
+ const candidate = raw.timestamp ??
60
+ raw.Timestamp ??
61
+ raw.timestamp_unix_nano ??
62
+ raw.start_time_unix_nano;
63
+ if (typeof candidate === 'string' && candidate.trim().length > 0) {
64
+ return candidate;
65
+ }
66
+ const numeric = Number(candidate);
67
+ if (!Number.isFinite(numeric)) {
68
+ return '';
69
+ }
70
+ if (numeric > 1e15) {
71
+ return new Date(numeric / 1e6).toISOString();
72
+ }
73
+ if (numeric > 1e12) {
74
+ return new Date(numeric / 1e3).toISOString();
75
+ }
76
+ return new Date(numeric).toISOString();
77
+ }
78
+ function normalizeMetric(raw) {
79
+ return {
80
+ metric_name: String(raw.metric_name ?? raw.MetricName ?? raw.name ?? raw.Name ?? ''),
81
+ service_name: String(raw.service_name ?? raw.ServiceName ?? ''),
82
+ value: parseMetricValue(raw),
83
+ unit: raw.metric_unit != null
84
+ ? String(raw.metric_unit)
85
+ : raw.MetricUnit != null
86
+ ? String(raw.MetricUnit)
87
+ : raw.unit != null
88
+ ? String(raw.unit)
89
+ : raw.Unit != null
90
+ ? String(raw.Unit)
91
+ : undefined,
92
+ timestamp: parseMetricTimestamp(raw),
93
+ metric_type: raw.metric_type != null
94
+ ? String(raw.metric_type)
95
+ : raw.MetricType != null
96
+ ? String(raw.MetricType)
97
+ : undefined,
98
+ attributes: typeof raw.attributes === 'object' && raw.attributes !== null
99
+ ? raw.attributes
100
+ : undefined,
101
+ };
102
+ }
103
+ // ── OtelClient class ─────────────────────────────────────────────────────────
104
+ /**
105
+ * Typed HTTP client for all OTEL service endpoints.
106
+ *
107
+ * Construct via `createOtelClient()` or `new OtelClient(options)`.
108
+ */
109
+ export class OtelClient {
110
+ baseUrl;
111
+ token;
112
+ constructor(options = {}) {
113
+ this.baseUrl =
114
+ options.baseUrl ?? coreStore.getState().configuration.otelRunUrl;
115
+ this.token = options.token;
116
+ }
117
+ // ── Traces ────────────────────────────────────────────────────────────────
118
+ /** List recent spans / traces. */
119
+ async fetchTraces(options = {}) {
120
+ const params = new URLSearchParams({ limit: String(options.limit ?? 50) });
121
+ if (options.serviceName)
122
+ params.set('service_name', options.serviceName);
123
+ const resp = await otelFetch(`${this.baseUrl}/api/otel/v1/traces/?${params}`, this.token);
124
+ const rows = (Array.isArray(resp) ? resp : resp.data) ?? [];
125
+ return { data: rows, count: rows.length };
126
+ }
127
+ /** Fetch all spans for a single trace by `traceId`. */
128
+ async fetchTrace(traceId) {
129
+ const resp = await otelFetch(`${this.baseUrl}/api/otel/v1/traces/${traceId}`, this.token);
130
+ const rows = (Array.isArray(resp) ? resp : resp.data) ?? [];
131
+ return { data: rows };
132
+ }
133
+ // ── Logs ──────────────────────────────────────────────────────────────────
134
+ /** List recent log records. */
135
+ async fetchLogs(options = {}) {
136
+ const params = new URLSearchParams({ limit: String(options.limit ?? 100) });
137
+ if (options.serviceName)
138
+ params.set('service_name', options.serviceName);
139
+ if (options.severity)
140
+ params.set('severity', options.severity);
141
+ if (options.traceId)
142
+ params.set('trace_id', options.traceId);
143
+ const resp = await otelFetch(`${this.baseUrl}/api/otel/v1/logs/?${params}`, this.token);
144
+ const rows = (Array.isArray(resp) ? resp : resp.data) ?? [];
145
+ return { data: rows, count: rows.length };
146
+ }
147
+ // ── Metrics ───────────────────────────────────────────────────────────────
148
+ /** List recent metric data points. */
149
+ async fetchMetrics(options = {}) {
150
+ const params = new URLSearchParams({ limit: String(options.limit ?? 50) });
151
+ if (options.serviceName)
152
+ params.set('service_name', options.serviceName);
153
+ if (options.metricName)
154
+ params.set('metric_name', options.metricName);
155
+ const resp = await otelFetch(`${this.baseUrl}/api/otel/v1/metrics/?${params}`, this.token);
156
+ const rows = (Array.isArray(resp) ? resp : resp.data) ?? [];
157
+ const normalized = Array.isArray(rows)
158
+ ? rows.map(row => normalizeMetric(row))
159
+ : [];
160
+ return { data: normalized, count: normalized.length };
161
+ }
162
+ /** Sum all values for one metric name, with optional service filter. */
163
+ async fetchMetricTotal(metricName, options = {}) {
164
+ const { serviceName, limit = 500, fallbackWithoutService = true } = options;
165
+ const filtered = await this.fetchMetrics({
166
+ metricName,
167
+ serviceName,
168
+ limit,
169
+ });
170
+ const filteredTotal = filtered.data.reduce((sum, row) => sum + Number(row.value || 0), 0);
171
+ if (filteredTotal > 0 || !serviceName || !fallbackWithoutService) {
172
+ return filteredTotal;
173
+ }
174
+ const unfiltered = await this.fetchMetrics({ metricName, limit });
175
+ return unfiltered.data.reduce((sum, row) => sum + Number(row.value || 0), 0);
176
+ }
177
+ // ── Services ──────────────────────────────────────────────────────────────
178
+ /** List known service names observed in traces. */
179
+ async fetchServices() {
180
+ const resp = await otelFetch(`${this.baseUrl}/api/otel/v1/traces/services/list`, this.token);
181
+ if (Array.isArray(resp))
182
+ return resp;
183
+ const byServices = resp.services;
184
+ if (Array.isArray(byServices))
185
+ return byServices;
186
+ const byData = resp.data;
187
+ if (Array.isArray(byData)) {
188
+ return byData.map((r) => String(r.service_name ?? r.name ?? ''));
189
+ }
190
+ return [];
191
+ }
192
+ // ── Stats ─────────────────────────────────────────────────────────────────
193
+ /** Fetch storage / ingestion statistics. */
194
+ async fetchStats() {
195
+ return otelFetch(`${this.baseUrl}/api/otel/v1/stats/`, this.token);
196
+ }
197
+ // ── SQL query ─────────────────────────────────────────────────────────────
198
+ /**
199
+ * Execute an ad-hoc DataFusion SQL query against the OTEL service.
200
+ *
201
+ * Available tables: `spans`, `logs`, `metrics`.
202
+ */
203
+ async executeQuery(sql) {
204
+ return otelFetch(`${this.baseUrl}/api/otel/v1/query/`, this.token, { method: 'POST', body: { sql } });
205
+ }
206
+ // ── System ────────────────────────────────────────────────────────────────
207
+ /**
208
+ * Fetch system statistics (platform_admin only).
209
+ *
210
+ * Returns process memory/CPU, disk usage, and per-table row counts.
211
+ */
212
+ async fetchSystem() {
213
+ const resp = await otelFetch(`${this.baseUrl}/api/otel/v1/system/`, this.token);
214
+ return (resp.data ?? resp);
215
+ }
216
+ }
217
+ // ── Factory ──────────────────────────────────────────────────────────────────
218
+ /**
219
+ * Create a new `OtelClient`.
220
+ *
221
+ * The `baseUrl` defaults to `configuration.otelRunUrl` from the Datalayer core
222
+ * configuration store, so only pass it when you want to override the default.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * const client = createOtelClient({ token: jwt });
227
+ * const services = await client.fetchServices();
228
+ * ```
229
+ */
230
+ export function createOtelClient(options = {}) {
231
+ return new OtelClient(options);
232
+ }
@@ -0,0 +1,2 @@
1
+ export { OtelClient, createOtelClient } from './OtelClient';
2
+ export type { OtelClientOptions, FetchTracesOptions, FetchLogsOptions, FetchMetricsOptions, FetchMetricTotalOptions, OtelSystemData, OtelSystemProcess, OtelSystemDisk, OtelSystemTable, } from './OtelClient';
@@ -0,0 +1,5 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export { OtelClient, createOtelClient } from './OtelClient';