@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
@@ -2,6 +2,7 @@
2
2
  * API base paths for different service domains
3
3
  */
4
4
  export declare const API_BASE_PATHS: {
5
+ readonly AI_AGENTS: "/api/ai-agents/v1";
5
6
  readonly IAM: "/api/iam/v1";
6
7
  readonly OTEL: "/api/otel/v1";
7
8
  readonly RUNTIMES: "/api/runtimes/v1";
@@ -11,6 +12,8 @@ export declare const API_BASE_PATHS: {
11
12
  * Default service URLs for the Datalayer platform
12
13
  */
13
14
  export declare const DEFAULT_SERVICE_URLS: {
15
+ /** Default URL for AI Agents (durable agent management) service */
16
+ readonly AI_AGENTS: "https://prod1.datalayer.run";
14
17
  /** Default URL for IAM (Identity and Access Management) service */
15
18
  readonly IAM: "https://prod1.datalayer.run";
16
19
  /** Default URL for OTEL (OpenTelemetry observability) service */
@@ -6,6 +6,7 @@
6
6
  * API base paths for different service domains
7
7
  */
8
8
  export const API_BASE_PATHS = {
9
+ AI_AGENTS: '/api/ai-agents/v1',
9
10
  IAM: '/api/iam/v1',
10
11
  OTEL: '/api/otel/v1',
11
12
  RUNTIMES: '/api/runtimes/v1',
@@ -15,6 +16,8 @@ export const API_BASE_PATHS = {
15
16
  * Default service URLs for the Datalayer platform
16
17
  */
17
18
  export const DEFAULT_SERVICE_URLS = {
19
+ /** Default URL for AI Agents (durable agent management) service */
20
+ AI_AGENTS: 'https://prod1.datalayer.run',
18
21
  /** Default URL for IAM (Identity and Access Management) service */
19
22
  IAM: 'https://prod1.datalayer.run',
20
23
  /** Default URL for OTEL (OpenTelemetry observability) service */
@@ -0,0 +1,122 @@
1
+ /**
2
+ * A single runtime checkpoint record.
3
+ */
4
+ export interface RuntimeCheckpointData {
5
+ /** Unique identifier (ULID) */
6
+ id: string;
7
+ /** Human-readable name */
8
+ name: string;
9
+ /** Checkpoint description */
10
+ description: string;
11
+ /** Runtime that was checkpointed */
12
+ runtime_uid: string;
13
+ /** Agent spec identifier (e.g. "mocks/monitor-sales-kpis") */
14
+ agent_spec_id: string;
15
+ /** Full agent spec payload */
16
+ agentspec: Record<string, any>;
17
+ /** Additional metadata */
18
+ metadata: Record<string, any>;
19
+ /** Checkpoint mode: criu (full) or light (history-only) */
20
+ checkpoint_mode?: 'criu' | 'light';
21
+ /** Lightweight checkpoint message history */
22
+ messages?: string[];
23
+ /** Status: requested | created | failed | deleted */
24
+ status: string;
25
+ /** Human-readable details about the current status (e.g. error message) */
26
+ status_message?: string;
27
+ /** ISO 8601 timestamp */
28
+ updated_at: string;
29
+ }
30
+ /**
31
+ * Request payload for creating a checkpoint.
32
+ */
33
+ export interface CreateRuntimeCheckpointRequest {
34
+ /** Runtime UID of the runtime that was checkpointed */
35
+ runtime_uid: string;
36
+ /** Human-readable name */
37
+ name?: string;
38
+ /** Checkpoint description */
39
+ description?: string;
40
+ /** Agent spec identifier */
41
+ agentspec_id?: string;
42
+ /** Full agent spec payload to persist */
43
+ agentspec?: Record<string, any>;
44
+ /** Additional metadata */
45
+ metadata?: Record<string, any>;
46
+ }
47
+ /**
48
+ * Response for listing checkpoints.
49
+ */
50
+ export interface ListRuntimeCheckpointsResponse {
51
+ success: boolean;
52
+ message: string;
53
+ checkpoints: RuntimeCheckpointData[];
54
+ }
55
+ /**
56
+ * Response for getting a single checkpoint.
57
+ */
58
+ export interface GetRuntimeCheckpointResponse {
59
+ success: boolean;
60
+ message: string;
61
+ checkpoint: RuntimeCheckpointData;
62
+ }
63
+ /**
64
+ * Response for creating a checkpoint.
65
+ */
66
+ export interface CreateRuntimeCheckpointResponse {
67
+ success: boolean;
68
+ message: string;
69
+ checkpoint: RuntimeCheckpointData;
70
+ }
71
+ /**
72
+ * List runtime checkpoints for a specific runtime.
73
+ * @param token - Authentication token
74
+ * @param baseUrl - Base URL for the runtimes API
75
+ * @param runtimeUid - Runtime UID to list checkpoints for
76
+ * @returns Promise resolving to list of checkpoints
77
+ */
78
+ export declare const listCheckpoints: (token: string, baseUrl?: string, runtimeUid?: string) => Promise<ListRuntimeCheckpointsResponse>;
79
+ /**
80
+ * Get a single runtime checkpoint by ID.
81
+ * @param token - Authentication token
82
+ * @param runtimeUid - The runtime UID
83
+ * @param checkpointId - The checkpoint ID (ULID)
84
+ * @param baseUrl - Base URL for the runtimes API
85
+ * @returns Promise resolving to checkpoint details
86
+ */
87
+ export declare const getCheckpoint: (token: string, runtimeUid: string, checkpointId: string, baseUrl?: string) => Promise<GetRuntimeCheckpointResponse>;
88
+ /**
89
+ * Create a checkpoint record (after a CRIU checkpoint has been taken).
90
+ * @param token - Authentication token
91
+ * @param data - Checkpoint creation payload (runtime_uid, agentspec, etc.)
92
+ * @param baseUrl - Base URL for the runtimes API
93
+ * @returns Promise resolving to the created checkpoint
94
+ */
95
+ export declare const createCheckpoint: (token: string, data: CreateRuntimeCheckpointRequest, baseUrl?: string) => Promise<CreateRuntimeCheckpointResponse>;
96
+ /**
97
+ * Poll a checkpoint until it reaches one of the target statuses.
98
+ *
99
+ * Useful for waiting until an async pause (status "paused")
100
+ * completes before proceeding. Checkpoint status stays "paused"
101
+ * during resume — only the agent runtime status transitions.
102
+ *
103
+ * @param token - Authentication token
104
+ * @param runtimeUid - The runtime UID that owns the checkpoint
105
+ * @param checkpointId - The checkpoint ID (ULID) to poll
106
+ * @param targetStatuses - Set of statuses that signal completion (e.g. ["paused", "failed"])
107
+ * @param baseUrl - Base URL for the runtimes API
108
+ * @param intervalMs - Polling interval in milliseconds (default: 2000)
109
+ * @param timeoutMs - Maximum wait time in milliseconds (default: 600000 = 10 min)
110
+ * @returns Promise resolving to the checkpoint data once a target status is reached
111
+ * @throws {Error} If polling times out or the request fails
112
+ */
113
+ export declare const waitForCheckpointStatus: (token: string, runtimeUid: string, checkpointId: string, targetStatuses: string[], baseUrl?: string, intervalMs?: number, timeoutMs?: number) => Promise<RuntimeCheckpointData>;
114
+ /**
115
+ * Delete a runtime checkpoint.
116
+ * @param token - Authentication token
117
+ * @param runtimeUid - The runtime UID that owns the checkpoint
118
+ * @param checkpointId - The checkpoint ID (ULID) to delete
119
+ * @param baseUrl - Base URL for the runtimes API
120
+ * @returns Promise resolving when deletion is complete
121
+ */
122
+ export declare const deleteCheckpoint: (token: string, runtimeUid: string, checkpointId: string, baseUrl?: string) => Promise<void>;
@@ -0,0 +1,118 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Runtime checkpoints API functions for the Datalayer platform.
7
+ *
8
+ * Provides functions for managing CRIU full-pod checkpoints.
9
+ * These are distinct from runtime snapshots (Jupyter sandbox snapshots).
10
+ *
11
+ * @module api/runtimes/checkpoints
12
+ */
13
+ import { requestDatalayerAPI } from '../DatalayerApi';
14
+ import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants';
15
+ import { validateToken, validateRequiredString } from '../utils/validation';
16
+ // ─── API Functions ─────────────────────────────────────────────────────────
17
+ /**
18
+ * List runtime checkpoints for a specific runtime.
19
+ * @param token - Authentication token
20
+ * @param baseUrl - Base URL for the runtimes API
21
+ * @param runtimeUid - Runtime UID to list checkpoints for
22
+ * @returns Promise resolving to list of checkpoints
23
+ */
24
+ export const listCheckpoints = async (token, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES, runtimeUid) => {
25
+ validateToken(token);
26
+ if (!runtimeUid) {
27
+ throw new Error('runtimeUid is required to list checkpoints');
28
+ }
29
+ return requestDatalayerAPI({
30
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtime-checkpoints/${encodeURIComponent(runtimeUid)}`,
31
+ method: 'GET',
32
+ token,
33
+ });
34
+ };
35
+ /**
36
+ * Get a single runtime checkpoint by ID.
37
+ * @param token - Authentication token
38
+ * @param runtimeUid - The runtime UID
39
+ * @param checkpointId - The checkpoint ID (ULID)
40
+ * @param baseUrl - Base URL for the runtimes API
41
+ * @returns Promise resolving to checkpoint details
42
+ */
43
+ export const getCheckpoint = async (token, runtimeUid, checkpointId, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
44
+ validateToken(token);
45
+ validateRequiredString(runtimeUid, 'Runtime UID');
46
+ validateRequiredString(checkpointId, 'Checkpoint ID');
47
+ return requestDatalayerAPI({
48
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtime-checkpoints/${encodeURIComponent(runtimeUid)}/${checkpointId}`,
49
+ method: 'GET',
50
+ token,
51
+ });
52
+ };
53
+ /**
54
+ * Create a checkpoint record (after a CRIU checkpoint has been taken).
55
+ * @param token - Authentication token
56
+ * @param data - Checkpoint creation payload (runtime_uid, agentspec, etc.)
57
+ * @param baseUrl - Base URL for the runtimes API
58
+ * @returns Promise resolving to the created checkpoint
59
+ */
60
+ export const createCheckpoint = async (token, data, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
61
+ validateToken(token);
62
+ return requestDatalayerAPI({
63
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtime-checkpoints`,
64
+ method: 'POST',
65
+ token,
66
+ body: data,
67
+ });
68
+ };
69
+ /**
70
+ * Poll a checkpoint until it reaches one of the target statuses.
71
+ *
72
+ * Useful for waiting until an async pause (status "paused")
73
+ * completes before proceeding. Checkpoint status stays "paused"
74
+ * during resume — only the agent runtime status transitions.
75
+ *
76
+ * @param token - Authentication token
77
+ * @param runtimeUid - The runtime UID that owns the checkpoint
78
+ * @param checkpointId - The checkpoint ID (ULID) to poll
79
+ * @param targetStatuses - Set of statuses that signal completion (e.g. ["paused", "failed"])
80
+ * @param baseUrl - Base URL for the runtimes API
81
+ * @param intervalMs - Polling interval in milliseconds (default: 2000)
82
+ * @param timeoutMs - Maximum wait time in milliseconds (default: 600000 = 10 min)
83
+ * @returns Promise resolving to the checkpoint data once a target status is reached
84
+ * @throws {Error} If polling times out or the request fails
85
+ */
86
+ export const waitForCheckpointStatus = async (token, runtimeUid, checkpointId, targetStatuses, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES, intervalMs = 2000, timeoutMs = 600_000) => {
87
+ validateToken(token);
88
+ validateRequiredString(runtimeUid, 'Runtime UID');
89
+ validateRequiredString(checkpointId, 'Checkpoint ID');
90
+ const deadline = Date.now() + timeoutMs;
91
+ while (Date.now() < deadline) {
92
+ const resp = await getCheckpoint(token, runtimeUid, checkpointId, baseUrl);
93
+ if (targetStatuses.includes(resp.checkpoint.status)) {
94
+ return resp.checkpoint;
95
+ }
96
+ // Wait before next poll
97
+ await new Promise(resolve => setTimeout(resolve, intervalMs));
98
+ }
99
+ throw new Error(`Checkpoint ${checkpointId} did not reach status [${targetStatuses.join(', ')}] within ${timeoutMs / 1000}s`);
100
+ };
101
+ /**
102
+ * Delete a runtime checkpoint.
103
+ * @param token - Authentication token
104
+ * @param runtimeUid - The runtime UID that owns the checkpoint
105
+ * @param checkpointId - The checkpoint ID (ULID) to delete
106
+ * @param baseUrl - Base URL for the runtimes API
107
+ * @returns Promise resolving when deletion is complete
108
+ */
109
+ export const deleteCheckpoint = async (token, runtimeUid, checkpointId, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
110
+ validateToken(token);
111
+ validateRequiredString(runtimeUid, 'Runtime UID');
112
+ validateRequiredString(checkpointId, 'Checkpoint ID');
113
+ return requestDatalayerAPI({
114
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtime-checkpoints/${encodeURIComponent(runtimeUid)}/${checkpointId}`,
115
+ method: 'DELETE',
116
+ token,
117
+ });
118
+ };
@@ -9,3 +9,4 @@ export * as environments from './environments';
9
9
  export * as healthz from './healthz';
10
10
  export * as runtimes from './runtimes';
11
11
  export * as snapshots from './snapshots';
12
+ export * as checkpoints from './checkpoints';
@@ -13,3 +13,4 @@ export * as environments from './environments';
13
13
  export * as healthz from './healthz';
14
14
  export * as runtimes from './runtimes';
15
15
  export * as snapshots from './snapshots';
16
+ export * as checkpoints from './checkpoints';
@@ -52,3 +52,87 @@ export declare const deleteRuntime: (token: string, podName: string, baseUrl?: s
52
52
  * @throws {Error} With status 404 if the runtime is not found
53
53
  */
54
54
  export declare const updateRuntime: (token: string, podName: string, from: string, baseUrl?: string) => Promise<RuntimeData>;
55
+ /**
56
+ * Response from the pause/resume runtime endpoints.
57
+ * The server returns 202 Accepted and provides a checkpoint UID
58
+ * that can be polled for status updates.
59
+ */
60
+ export interface PauseResumeResponse {
61
+ success: boolean;
62
+ message: string;
63
+ checkpoint_id: string | null;
64
+ }
65
+ /**
66
+ * Optional body for the pause endpoint.
67
+ * Metadata is stored in the checkpoint Solr record created by the backend.
68
+ */
69
+ export interface PauseRuntimeBody {
70
+ /** Checkpoint mode: 'criu' (full) or 'light' (history-only) */
71
+ checkpoint_mode?: 'criu' | 'light';
72
+ /** Human-readable checkpoint name */
73
+ name?: string;
74
+ /** Checkpoint description */
75
+ description?: string;
76
+ /** Agent spec identifier */
77
+ agent_spec_id?: string;
78
+ /** Full agent spec payload to persist with the checkpoint */
79
+ agentspec?: Record<string, any>;
80
+ /** Additional metadata */
81
+ metadata?: Record<string, any>;
82
+ /** Lightweight checkpoint message history */
83
+ messages?: string[];
84
+ }
85
+ /**
86
+ * Pause a runtime by creating a checkpoint (async, light mode by default).
87
+ *
88
+ * Returns immediately with a 202 Accepted response. The actual checkpoint
89
+ * process runs in the background. Use the returned `checkpoint_id` to
90
+ * poll for status via the runtime-checkpoints API.
91
+ *
92
+ * @param token - Authentication token
93
+ * @param podName - The unique pod name of the runtime to pause
94
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
95
+ * @param body - Optional metadata to store in the checkpoint record
96
+ * @returns Promise resolving with the checkpoint ID for status tracking
97
+ * @throws {Error} If authentication token is missing or invalid
98
+ * @throws {Error} If pod name is missing or invalid
99
+ */
100
+ export declare const pauseRuntime: (token: string, podName: string, baseUrl?: string, body?: PauseRuntimeBody) => Promise<PauseResumeResponse>;
101
+ /**
102
+ * Optional body for the resume endpoint.
103
+ * Contains information needed by the operator to restore from a checkpoint.
104
+ */
105
+ export interface ResumeRuntimeBody {
106
+ /** Checkpoint mode to resume from: 'criu' or 'light' */
107
+ checkpoint_mode?: 'criu' | 'light';
108
+ /** Explicit checkpoint identifier */
109
+ checkpoint_id?: string;
110
+ /** Agent spec identifier (required by the operator for restore) */
111
+ agent_spec_id?: string;
112
+ /** Specific checkpoint timestamp to restore from */
113
+ checkpoint_timestamp?: string;
114
+ /** Environment name override */
115
+ environment_name?: string;
116
+ /** Container image override */
117
+ container_image?: string;
118
+ /** Target node name */
119
+ node_name?: string;
120
+ /** Additional metadata */
121
+ metadata?: Record<string, any>;
122
+ }
123
+ /**
124
+ * Resume a paused runtime by restoring from a checkpoint (async).
125
+ *
126
+ * Returns immediately with a 202 Accepted response. The actual restore
127
+ * process runs in the background. Use the returned `checkpoint_id` to
128
+ * poll for status.
129
+ *
130
+ * @param token - Authentication token
131
+ * @param podName - The unique pod name of the runtime to resume
132
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
133
+ * @param body - Optional body with agent_spec_id and restore options
134
+ * @returns Promise resolving with the checkpoint ID for status tracking
135
+ * @throws {Error} If authentication token is missing or invalid
136
+ * @throws {Error} If pod name is missing or invalid
137
+ */
138
+ export declare const resumeRuntime: (token: string, podName: string, baseUrl?: string, body?: ResumeRuntimeBody) => Promise<PauseResumeResponse>;
@@ -178,3 +178,53 @@ export const updateRuntime = async (token, podName, from, baseUrl = DEFAULT_SERV
178
178
  throw error;
179
179
  }
180
180
  };
181
+ /**
182
+ * Pause a runtime by creating a checkpoint (async, light mode by default).
183
+ *
184
+ * Returns immediately with a 202 Accepted response. The actual checkpoint
185
+ * process runs in the background. Use the returned `checkpoint_id` to
186
+ * poll for status via the runtime-checkpoints API.
187
+ *
188
+ * @param token - Authentication token
189
+ * @param podName - The unique pod name of the runtime to pause
190
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
191
+ * @param body - Optional metadata to store in the checkpoint record
192
+ * @returns Promise resolving with the checkpoint ID for status tracking
193
+ * @throws {Error} If authentication token is missing or invalid
194
+ * @throws {Error} If pod name is missing or invalid
195
+ */
196
+ export const pauseRuntime = async (token, podName, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES, body) => {
197
+ validateToken(token);
198
+ validateRequiredString(podName, 'Pod name');
199
+ return await requestDatalayerAPI({
200
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtimes/${encodeURIComponent(podName)}/pause`,
201
+ method: 'POST',
202
+ token,
203
+ ...(body ? { body } : {}),
204
+ });
205
+ };
206
+ /**
207
+ * Resume a paused runtime by restoring from a checkpoint (async).
208
+ *
209
+ * Returns immediately with a 202 Accepted response. The actual restore
210
+ * process runs in the background. Use the returned `checkpoint_id` to
211
+ * poll for status.
212
+ *
213
+ * @param token - Authentication token
214
+ * @param podName - The unique pod name of the runtime to resume
215
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
216
+ * @param body - Optional body with agent_spec_id and restore options
217
+ * @returns Promise resolving with the checkpoint ID for status tracking
218
+ * @throws {Error} If authentication token is missing or invalid
219
+ * @throws {Error} If pod name is missing or invalid
220
+ */
221
+ export const resumeRuntime = async (token, podName, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES, body) => {
222
+ validateToken(token);
223
+ validateRequiredString(podName, 'Pod name');
224
+ return await requestDatalayerAPI({
225
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtimes/${encodeURIComponent(podName)}/resume`,
226
+ method: 'POST',
227
+ token,
228
+ ...(body ? { body } : {}),
229
+ });
230
+ };
@@ -167,7 +167,7 @@ export const Login = (props) => {
167
167
  ? 'Login…'
168
168
  : heading
169
169
  ? 'Login with Datalayer'
170
- : 'Login' }), _jsx(Box, { pt: 6 }), _jsx(Link, { href: "https://datalayer.app/password", target: "_blank", children: "Forgot password?" })] })] })), _jsx(Box, { children: _jsxs(Box, { display: "flex", flexDirection: "column", sx: { margin: 'auto' }, children: [showGitHubLogin &&
170
+ : 'Login' }), _jsx(Box, { pt: 6 }), _jsx(Link, { href: "https://datalayer.ai/password", target: "_blank", children: "Forgot password?" })] })] })), _jsx(Box, { children: _jsxs(Box, { display: "flex", flexDirection: "column", sx: { margin: 'auto' }, children: [showGitHubLogin &&
171
171
  iamProvidersAuthorizationURL[IAMProvidersSpecs.GitHub.name] && (_jsx(Button, { leadingVisual: MarkGithubIcon, href: iamProvidersAuthorizationURL[IAMProvidersSpecs.GitHub.name], as: "a", style: { margin: '10px 0' }, children: "Login with GitHub" })), showGoogleLogin &&
172
172
  iamProvidersAuthorizationURL[IAMProvidersSpecs.Google.name] && (_jsx(Button, { leadingVisual: GoogleIcon, href: iamProvidersAuthorizationURL[IAMProvidersSpecs.Google.name], as: "a", style: { margin: '10px 0' }, children: "Login with Google" })), showTokenLogin && (_jsx(LoginToken, { homeRoute: homeRoute, style: { margin: '10px 0' } }))] }) })] }) })) : loadingWithToken ? (_jsx(CenteredSpinner, { message: "Checking authentication\u2026" })) : (_jsx(_Fragment, {})) })] }));
173
173
  };
@@ -0,0 +1,9 @@
1
+ type BusyDotsProps = {
2
+ color?: string;
3
+ fontSize?: number;
4
+ ml?: number;
5
+ ariaLabel?: string;
6
+ intervalMs?: number;
7
+ };
8
+ export declare function BusyDots({ color, fontSize, ml, ariaLabel, intervalMs, }: BusyDotsProps): import("react/jsx-runtime").JSX.Element;
9
+ export default BusyDots;
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2023-2025 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ import { useEffect, useState } from 'react';
7
+ import { Text } from '@primer/react';
8
+ const DOTS = ['.', '..', '...'];
9
+ export function BusyDots({ color = 'fg.muted', fontSize = 0, ml = 1, ariaLabel = 'In progress', intervalMs = 450, }) {
10
+ const [index, setIndex] = useState(0);
11
+ useEffect(() => {
12
+ const timer = window.setInterval(() => {
13
+ setIndex(prev => (prev + 1) % DOTS.length);
14
+ }, intervalMs);
15
+ return () => window.clearInterval(timer);
16
+ }, [intervalMs]);
17
+ return (_jsxs(Text, { as: "span", sx: {
18
+ ml,
19
+ color,
20
+ fontSize,
21
+ display: 'inline-block',
22
+ position: 'relative',
23
+ fontWeight: 'semibold',
24
+ }, "aria-label": ariaLabel, children: [_jsx(Text, { as: "span", sx: { visibility: 'hidden' }, children: "..." }), _jsx(Text, { as: "span", sx: {
25
+ position: 'absolute',
26
+ left: 0,
27
+ top: 0,
28
+ whiteSpace: 'nowrap',
29
+ }, children: DOTS[index] })] }));
30
+ }
31
+ export default BusyDots;
@@ -0,0 +1,10 @@
1
+ type ILiveRelativeTimeProps = {
2
+ value?: Date | string | number;
3
+ refreshIntervalMs?: number;
4
+ fallback?: string;
5
+ };
6
+ /**
7
+ * Display a live-updating relative time label (e.g. "5m ago").
8
+ */
9
+ export declare function LiveRelativeTime({ value, refreshIntervalMs, fallback, }: ILiveRelativeTimeProps): JSX.Element;
10
+ export {};
@@ -0,0 +1,21 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2023-2025 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ import { useEffect, useMemo, useState } from 'react';
7
+ import { formatRelativeTime } from '../../utils';
8
+ /**
9
+ * Display a live-updating relative time label (e.g. "5m ago").
10
+ */
11
+ export function LiveRelativeTime({ value, refreshIntervalMs = 1000, fallback = '—', }) {
12
+ const [now, setNow] = useState(() => new Date());
13
+ useEffect(() => {
14
+ const timer = window.setInterval(() => {
15
+ setNow(new Date());
16
+ }, refreshIntervalMs);
17
+ return () => window.clearInterval(timer);
18
+ }, [refreshIntervalMs]);
19
+ const label = useMemo(() => formatRelativeTime(value, now), [value, now]);
20
+ return _jsx(_Fragment, { children: label ?? fallback });
21
+ }
@@ -4,9 +4,11 @@ export * from './CodePreview';
4
4
  export * from './DatalayerBox';
5
5
  export * from './HorizontalCenter';
6
6
  export * from './JupyterDialog';
7
+ export * from './LiveRelativeTime';
7
8
  export * from './Markdown';
8
9
  export * from './NavLink';
9
10
  export * from './NotebookSkeleton';
11
+ export * from './BusyDots';
10
12
  export * from './Placeholder';
11
13
  export * from './ToTopBranded';
12
14
  export * from './VisuallyHidden';
@@ -8,9 +8,11 @@ export * from './CodePreview';
8
8
  export * from './DatalayerBox';
9
9
  export * from './HorizontalCenter';
10
10
  export * from './JupyterDialog';
11
+ export * from './LiveRelativeTime';
11
12
  export * from './Markdown';
12
13
  export * from './NavLink';
13
14
  export * from './NotebookSkeleton';
15
+ export * from './BusyDots';
14
16
  export * from './Placeholder';
15
17
  export * from './ToTopBranded';
16
18
  export * from './VisuallyHidden';
@@ -30,6 +30,6 @@ export const FlashSurveys = (props) => {
30
30
  setShow(false);
31
31
  enqueueToast('Thank you for your answers.', { variant: 'success' });
32
32
  };
33
- return (_jsx(_Fragment, { children: surveys && (show || surveyName) && !configuration.whiteLabel && (_jsxs(FlashClosable, { variant: "default", children: [_jsx(Box, { children: _jsx(Text, { as: "h2", children: "We'd love to know a bit more about you and your needs..." }) }), _jsx(Box, { children: _jsx(Survey2025_1, { formData: surveyName ? surveys.get(SURVEY_2025_1_NAME)?.form : undefined, onSubmit: onSubmit }) }), _jsx(Box, { mt: 3, children: _jsxs(Text, { children: ["The information you give will remain fully private, read our", ' ', _jsx(Link, { href: "https://datalayer.app/privacy", target: "_blank", children: "privacy policy" }), "."] }) })] })) }));
33
+ return (_jsx(_Fragment, { children: surveys && (show || surveyName) && !configuration.whiteLabel && (_jsxs(FlashClosable, { variant: "default", children: [_jsx(Box, { children: _jsx(Text, { as: "h2", children: "We'd love to know a bit more about you and your needs..." }) }), _jsx(Box, { children: _jsx(Survey2025_1, { formData: surveyName ? surveys.get(SURVEY_2025_1_NAME)?.form : undefined, onSubmit: onSubmit }) }), _jsx(Box, { mt: 3, children: _jsxs(Text, { children: ["The information you give will remain fully private, read our", ' ', _jsx(Link, { href: "https://datalayer.ai/privacy", target: "_blank", children: "privacy policy" }), "."] }) })] })) }));
34
34
  };
35
35
  export default FlashSurveys;
@@ -1 +1,2 @@
1
1
  export * from './auth';
2
+ export * from './sparklines';
@@ -3,3 +3,4 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  export * from './auth';
6
+ export * from './sparklines';
@@ -34,7 +34,7 @@ const testIds = {
34
34
  return `${this.root}-search-live-region`;
35
35
  },
36
36
  };
37
- function Root({ children, className, fixed = true, fullWidth = false, logoHref = 'https://datalayer.app', title, titleHref = '/', ...rest }) {
37
+ function Root({ children, className, fixed = true, fullWidth = false, logoHref = 'https://datalayer.ai', title, titleHref = '/', ...rest }) {
38
38
  const navigate = useNavigate();
39
39
  const runStore = useRunStore();
40
40
  const { configuration } = useCoreStore();
@@ -4,9 +4,10 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
6
  import { useEffect, useMemo, useState } from 'react';
7
+ import { useInterval } from 'usehooks-ts';
7
8
  import { ProgressBar, Tooltip, Button } from '@primer/react';
8
9
  import { Box } from '@datalayer/primer-addons';
9
- import { useInterval } from 'usehooks-ts';
10
+ import { getConsumptionDuration, getConsumptionProgress } from './consumption';
10
11
  const CRITICAL_LEVEL = 90;
11
12
  const WARNING_LEVEL = 75;
12
13
  /**
@@ -31,10 +32,8 @@ function formatTimeRemaining(seconds) {
31
32
  */
32
33
  export function ConsumptionBar(props) {
33
34
  const { expiredAt, startedAt, burningRate, onClick, onUpdate, refreshInterval = 2000, style, } = props;
34
- const duration = useMemo(() => (expiredAt ? expiredAt - startedAt : Date.now() / 1000 - startedAt), [expiredAt, startedAt]);
35
- const [progress, setProgress] = useState(expiredAt
36
- ? Math.min(Math.max(0, ((Date.now() / 1000 - startedAt) / duration) * 100), 100)
37
- : 100);
35
+ const duration = useMemo(() => getConsumptionDuration(startedAt, expiredAt), [expiredAt, startedAt]);
36
+ const [progress, setProgress] = useState(getConsumptionProgress(startedAt, expiredAt));
38
37
  useEffect(() => {
39
38
  if (onUpdate) {
40
39
  onUpdate(progress, duration);
@@ -42,7 +41,7 @@ export function ConsumptionBar(props) {
42
41
  }, [onUpdate, progress, duration]);
43
42
  useInterval(() => {
44
43
  if (expiredAt) {
45
- setProgress(Math.min(Math.max(0, ((Date.now() / 1000 - startedAt) / duration) * 100), 100));
44
+ setProgress(getConsumptionProgress(startedAt, expiredAt));
46
45
  }
47
46
  }, refreshInterval);
48
47
  const bg = expiredAt
@@ -57,7 +56,7 @@ export function ConsumptionBar(props) {
57
56
  const title = duration
58
57
  ? `${formatTimeRemaining(secondsRemaining)} left - ${((progress / 100) * burntCredits).toFixed(2)} / ${burntCredits.toFixed(2)} credits`
59
58
  : `Started at ${new Date(startedAt * 1000).toISOString()} - ${burntCredits.toFixed(2)} credits consumed`;
60
- return (_jsx(_Fragment, { children: _jsx(Tooltip, { text: title, direction: "w", children: _jsx(Button, { variant: "invisible", onClick: onClick, onKeyDown: onClick
59
+ return (_jsx(_Fragment, { children: _jsx(Tooltip, { text: title, children: _jsx(Button, { variant: "invisible", onClick: onClick, onKeyDown: onClick
61
60
  ? event => {
62
61
  if (event.key === 'Enter' || event.key === 'Space') {
63
62
  onClick();
@@ -5,8 +5,8 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
5
5
  */
6
6
  import { useState, useEffect } from 'react';
7
7
  import { Box } from '@datalayer/primer-addons';
8
- import { ConsumptionBar } from '../../components/progress';
9
- import useNavigate from '../../hooks/useNavigate';
8
+ import { useNavigate } from '../../hooks/useNavigate';
9
+ import { ConsumptionBar } from './ConsumptionBar';
10
10
  /**
11
11
  * Credits indicator component.
12
12
  */
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Compute the total consumption duration in seconds.
3
+ * When `expiredAt` is undefined, duration is elapsed time since `startedAt`.
4
+ */
5
+ export declare function getConsumptionDuration(startedAt: number, expiredAt?: number, nowSeconds?: number): number;
6
+ /**
7
+ * Compute credit consumption progress (0-100).
8
+ * Mirrors ConsumptionBar logic:
9
+ * - if no `expiredAt`, progress is 100
10
+ * - otherwise progress is elapsed / duration clamped to [0, 100]
11
+ */
12
+ export declare function getConsumptionProgress(startedAt: number, expiredAt?: number, nowSeconds?: number): number;