@datalayer/core 0.0.9 → 0.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 (199) hide show
  1. package/lib/__tests__/shared/cleanup-shared.d.ts +4 -0
  2. package/lib/__tests__/shared/cleanup-shared.js +228 -0
  3. package/lib/__tests__/shared/test-config.d.ts +51 -0
  4. package/lib/__tests__/shared/test-config.js +110 -0
  5. package/lib/__tests__/shared/test-constants.d.ts +66 -0
  6. package/lib/__tests__/shared/test-constants.js +79 -0
  7. package/lib/api/DatalayerApi.d.ts +1 -1
  8. package/lib/api/DatalayerApi.js +73 -42
  9. package/lib/api/__tests__/iam.authentication.integration.test.d.ts +1 -0
  10. package/lib/api/__tests__/iam.authentication.integration.test.js +247 -0
  11. package/lib/api/__tests__/iam.healthz.integration.test.d.ts +1 -0
  12. package/lib/api/__tests__/iam.healthz.integration.test.js +63 -0
  13. package/lib/api/__tests__/iam.profile.integration.test.d.ts +1 -0
  14. package/lib/api/__tests__/iam.profile.integration.test.js +252 -0
  15. package/lib/api/__tests__/runtimes.environments.integration.test.d.ts +1 -0
  16. package/lib/api/__tests__/runtimes.environments.integration.test.js +122 -0
  17. package/lib/api/__tests__/runtimes.healthz.integration.test.d.ts +1 -0
  18. package/lib/api/__tests__/runtimes.healthz.integration.test.js +50 -0
  19. package/lib/api/__tests__/runtimes.integration.test.d.ts +1 -0
  20. package/lib/api/__tests__/runtimes.integration.test.js +369 -0
  21. package/lib/api/__tests__/spacer.healthz.integration.test.d.ts +1 -0
  22. package/lib/api/__tests__/spacer.healthz.integration.test.js +50 -0
  23. package/lib/api/__tests__/spacer.integration.test.d.ts +1 -0
  24. package/lib/api/__tests__/spacer.integration.test.js +519 -0
  25. package/lib/api/constants.d.ts +19 -0
  26. package/lib/api/constants.js +23 -0
  27. package/lib/api/iam/__tests__/authentication.unit.test.d.ts +1 -0
  28. package/lib/api/iam/__tests__/authentication.unit.test.js +63 -0
  29. package/lib/api/iam/__tests__/healthz.unit.test.d.ts +1 -0
  30. package/lib/api/iam/__tests__/healthz.unit.test.js +60 -0
  31. package/lib/api/iam/__tests__/profile.unit.test.d.ts +1 -0
  32. package/lib/api/iam/__tests__/profile.unit.test.js +57 -0
  33. package/lib/api/iam/authentication.d.ts +40 -0
  34. package/lib/api/iam/authentication.js +128 -0
  35. package/lib/api/iam/healthz.d.ts +15 -0
  36. package/lib/api/iam/healthz.js +43 -0
  37. package/lib/api/iam/index.d.ts +12 -0
  38. package/lib/api/iam/index.js +17 -0
  39. package/lib/api/iam/profile.d.ts +15 -0
  40. package/lib/api/iam/profile.js +41 -0
  41. package/lib/api/index.d.ts +20 -3
  42. package/lib/api/index.js +22 -3
  43. package/lib/api/runtimes/__tests__/environments.unit.test.d.ts +1 -0
  44. package/lib/api/runtimes/__tests__/environments.unit.test.js +77 -0
  45. package/lib/api/runtimes/__tests__/healthz.unit.test.d.ts +1 -0
  46. package/lib/api/runtimes/__tests__/healthz.unit.test.js +57 -0
  47. package/lib/api/runtimes/__tests__/runtimes.unit.test.d.ts +1 -0
  48. package/lib/api/runtimes/__tests__/runtimes.unit.test.js +139 -0
  49. package/lib/api/runtimes/__tests__/snapshots.unit.test.d.ts +1 -0
  50. package/lib/api/runtimes/__tests__/snapshots.unit.test.js +96 -0
  51. package/lib/api/runtimes/environments.d.ts +9 -0
  52. package/lib/api/runtimes/environments.js +28 -0
  53. package/lib/api/runtimes/healthz.d.ts +25 -0
  54. package/lib/api/runtimes/healthz.js +43 -0
  55. package/lib/api/runtimes/index.d.ts +10 -5
  56. package/lib/api/runtimes/index.js +10 -5
  57. package/lib/api/runtimes/runtimes.d.ts +54 -0
  58. package/lib/api/runtimes/runtimes.js +169 -0
  59. package/lib/api/runtimes/snapshots.d.ts +34 -21
  60. package/lib/api/runtimes/snapshots.js +69 -138
  61. package/lib/api/spacer/__tests__/healthz.unit.test.d.ts +1 -0
  62. package/lib/api/spacer/__tests__/healthz.unit.test.js +57 -0
  63. package/lib/api/spacer/__tests__/items.unit.test.d.ts +1 -0
  64. package/lib/api/spacer/__tests__/items.unit.test.js +165 -0
  65. package/lib/api/spacer/__tests__/lexicals.unit.test.d.ts +1 -0
  66. package/lib/api/spacer/__tests__/lexicals.unit.test.js +323 -0
  67. package/lib/api/spacer/__tests__/notebooks.unit.test.d.ts +1 -0
  68. package/lib/api/spacer/__tests__/notebooks.unit.test.js +224 -0
  69. package/lib/api/spacer/__tests__/users.unit.test.d.ts +1 -0
  70. package/lib/api/spacer/__tests__/users.unit.test.js +132 -0
  71. package/lib/api/spacer/healthz.d.ts +25 -0
  72. package/lib/api/spacer/healthz.js +43 -0
  73. package/lib/api/spacer/index.d.ts +13 -0
  74. package/lib/api/spacer/index.js +17 -0
  75. package/lib/api/spacer/items.d.ts +17 -0
  76. package/lib/api/spacer/items.js +40 -0
  77. package/lib/api/spacer/lexicals.d.ts +26 -0
  78. package/lib/api/spacer/lexicals.js +74 -0
  79. package/lib/api/spacer/notebooks.d.ts +26 -0
  80. package/lib/api/spacer/notebooks.js +74 -0
  81. package/lib/api/spacer/spaces.d.ts +9 -0
  82. package/lib/api/spacer/spaces.js +29 -0
  83. package/lib/api/spacer/users.d.ts +9 -0
  84. package/lib/api/spacer/users.js +28 -0
  85. package/lib/api/types/iam.d.ts +180 -0
  86. package/lib/api/types/index.d.ts +32 -0
  87. package/lib/api/types/index.js +36 -0
  88. package/lib/api/types/runtimes.d.ts +235 -0
  89. package/lib/api/types/runtimes.js +5 -0
  90. package/lib/api/types/spacer.d.ts +271 -0
  91. package/lib/api/types/spacer.js +5 -0
  92. package/lib/api/utils/__tests__/validation.test.d.ts +1 -0
  93. package/lib/api/utils/__tests__/validation.test.js +109 -0
  94. package/lib/api/utils/validation.d.ts +24 -0
  95. package/lib/api/utils/validation.js +133 -0
  96. package/lib/components/display/JupyterDialog.js +4 -8
  97. package/lib/components/progress/CreditsIndicator.d.ts +1 -1
  98. package/lib/components/runtimes/RuntimeCellVariablesDialog.js +2 -2
  99. package/lib/components/runtimes/RuntimeLauncherDialog.d.ts +1 -1
  100. package/lib/components/runtimes/RuntimeLauncherDialog.js +5 -2
  101. package/lib/components/runtimes/RuntimePickerBase.d.ts +1 -1
  102. package/lib/components/runtimes/RuntimePickerBase.js +1 -1
  103. package/lib/components/runtimes/RuntimePickerCell.js +2 -1
  104. package/lib/components/runtimes/RuntimePickerNotebook.d.ts +1 -1
  105. package/lib/components/runtimes/RuntimePickerNotebook.js +1 -1
  106. package/lib/components/runtimes/RuntimeSimplePicker.js +2 -1
  107. package/lib/components/runtimes/RuntimeTransfer.d.ts +1 -1
  108. package/lib/components/runtimes/RuntimeUtils.d.ts +1 -1
  109. package/lib/components/snapshots/RuntimeSnapshotMenu.d.ts +1 -1
  110. package/lib/components/snapshots/RuntimeSnapshotMenu.js +2 -2
  111. package/lib/components/snippets/SnippetDialog.js +1 -1
  112. package/lib/components/storage/ContentsBrowser.js +2 -2
  113. package/lib/components/tables/DataTable.js +2 -1
  114. package/lib/hooks/useDatalayer.d.ts +1 -1
  115. package/lib/hooks/useDatalayer.js +1 -1
  116. package/lib/hooks/useIAM.js +1 -1
  117. package/lib/hooks/useRuntimes.js +1 -1
  118. package/lib/index.d.ts +9 -0
  119. package/lib/index.js +10 -0
  120. package/lib/sdk/client/__tests__/sdk.health.integration.test.d.ts +1 -0
  121. package/lib/sdk/client/__tests__/sdk.health.integration.test.js +110 -0
  122. package/lib/sdk/client/__tests__/sdk.iam.integration.test.d.ts +1 -0
  123. package/lib/sdk/client/__tests__/sdk.iam.integration.test.js +179 -0
  124. package/lib/sdk/client/__tests__/sdk.models.integration.test.d.ts +1 -0
  125. package/lib/sdk/client/__tests__/sdk.models.integration.test.js +376 -0
  126. package/lib/sdk/client/__tests__/sdk.runtimes.integration.test.d.ts +1 -0
  127. package/lib/sdk/client/__tests__/sdk.runtimes.integration.test.js +276 -0
  128. package/lib/sdk/client/__tests__/sdk.spacer.integration.test.d.ts +1 -0
  129. package/lib/sdk/client/__tests__/sdk.spacer.integration.test.js +361 -0
  130. package/lib/sdk/client/base.d.ts +88 -0
  131. package/lib/sdk/client/base.js +112 -0
  132. package/lib/sdk/client/index.d.ts +192 -0
  133. package/lib/sdk/client/index.js +128 -0
  134. package/lib/sdk/client/mixins/HealthMixin.d.ts +100 -0
  135. package/lib/sdk/client/mixins/HealthMixin.js +133 -0
  136. package/lib/sdk/client/mixins/IAMMixin.d.ts +59 -0
  137. package/lib/sdk/client/mixins/IAMMixin.js +83 -0
  138. package/lib/sdk/client/mixins/RuntimesMixin.d.ts +134 -0
  139. package/lib/sdk/client/mixins/RuntimesMixin.js +221 -0
  140. package/lib/sdk/client/mixins/SpacerMixin.d.ts +184 -0
  141. package/lib/sdk/client/mixins/SpacerMixin.js +278 -0
  142. package/lib/sdk/client/models/Lexical.d.ts +156 -0
  143. package/lib/sdk/client/models/Lexical.js +275 -0
  144. package/lib/sdk/client/models/Notebook.d.ts +174 -0
  145. package/lib/sdk/client/models/Notebook.js +311 -0
  146. package/lib/sdk/client/models/Runtime.d.ts +221 -0
  147. package/lib/sdk/client/models/Runtime.js +341 -0
  148. package/lib/sdk/client/models/Snapshot.d.ts +156 -0
  149. package/lib/sdk/client/models/Snapshot.js +244 -0
  150. package/lib/sdk/client/models/Space.d.ts +182 -0
  151. package/lib/sdk/client/models/Space.js +276 -0
  152. package/lib/sdk/client/models/__tests__/Lexical.test.d.ts +1 -0
  153. package/lib/sdk/client/models/__tests__/Lexical.test.js +288 -0
  154. package/lib/sdk/client/models/__tests__/Notebook.test.d.ts +1 -0
  155. package/lib/sdk/client/models/__tests__/Notebook.test.js +206 -0
  156. package/lib/sdk/client/models/__tests__/Runtime.test.d.ts +1 -0
  157. package/lib/sdk/client/models/__tests__/Runtime.test.js +133 -0
  158. package/lib/sdk/client/models/__tests__/Snapshot.test.d.ts +1 -0
  159. package/lib/sdk/client/models/__tests__/Snapshot.test.js +244 -0
  160. package/lib/sdk/client/models/__tests__/Space.test.d.ts +1 -0
  161. package/lib/sdk/client/models/__tests__/Space.test.js +334 -0
  162. package/lib/sdk/client/models/index.d.ts +30 -0
  163. package/lib/sdk/client/models/index.js +30 -0
  164. package/lib/sdk/client/utils/mixins.d.ts +42 -0
  165. package/lib/sdk/client/utils/mixins.js +47 -0
  166. package/lib/sdk/index.d.ts +26 -0
  167. package/lib/sdk/index.js +32 -0
  168. package/lib/sdk/stateful/index.d.ts +3 -0
  169. package/lib/sdk/stateful/index.js +7 -0
  170. package/lib/{api → sdk/stateful}/runtimes/actions.d.ts +1 -1
  171. package/lib/{api → sdk/stateful}/runtimes/actions.js +3 -3
  172. package/lib/{api → sdk/stateful}/runtimes/apis.d.ts +1 -1
  173. package/lib/sdk/stateful/runtimes/apis.js +5 -0
  174. package/lib/sdk/stateful/runtimes/index.d.ts +5 -0
  175. package/lib/sdk/stateful/runtimes/index.js +9 -0
  176. package/lib/sdk/stateful/runtimes/snapshots.d.ts +25 -0
  177. package/lib/sdk/stateful/runtimes/snapshots.js +150 -0
  178. package/lib/services/DatalayerServiceManager.js +1 -1
  179. package/lib/state/substates/IAMState.js +1 -1
  180. package/lib/state/substates/RuntimesState.d.ts +1 -1
  181. package/lib/state/substates/RuntimesState.js +1 -1
  182. package/lib/state/substates/SurveysState.js +1 -1
  183. package/lib/test-setup.js +1 -0
  184. package/package.json +19 -9
  185. /package/lib/api/{runtimes/apis.js → types/iam.js} +0 -0
  186. /package/lib/{api → sdk/stateful}/jupyter/exec/Python.d.ts +0 -0
  187. /package/lib/{api → sdk/stateful}/jupyter/exec/Python.js +0 -0
  188. /package/lib/{api → sdk/stateful}/jupyter/exec/Snippets.d.ts +0 -0
  189. /package/lib/{api → sdk/stateful}/jupyter/exec/Snippets.js +0 -0
  190. /package/lib/{api → sdk/stateful}/jupyter/exec/index.d.ts +0 -0
  191. /package/lib/{api → sdk/stateful}/jupyter/exec/index.js +0 -0
  192. /package/lib/{api → sdk/stateful}/jupyter/index.d.ts +0 -0
  193. /package/lib/{api → sdk/stateful}/jupyter/index.js +0 -0
  194. /package/lib/{api → sdk/stateful}/jupyter/kernelsHandler.d.ts +0 -0
  195. /package/lib/{api → sdk/stateful}/jupyter/kernelsHandler.js +0 -0
  196. /package/lib/{api → sdk/stateful}/runtimes/settings.d.ts +0 -0
  197. /package/lib/{api → sdk/stateful}/runtimes/settings.js +0 -0
  198. /package/lib/{api → sdk/stateful}/runtimes/utils.d.ts +0 -0
  199. /package/lib/{api → sdk/stateful}/runtimes/utils.js +0 -0
@@ -1,25 +1,38 @@
1
- import { Kernel } from '@jupyterlab/services';
2
- type Props = {
3
- connection: Kernel.IKernelConnection;
4
- metadata: {
5
- filename: string;
6
- [key: string]: string;
7
- };
8
- onUploadProgress?: (bytesUploaded: number, bytesTotal: number) => void;
9
- };
1
+ import { CreateRuntimeSnapshotRequest, SnapshotsListResponse, SnapshotGetResponse, SnapshotCreateResponse } from '../types/runtimes';
10
2
  /**
11
- * Snapshot a runtime through the frontend and upload it to the cloud.
12
- *
13
- * Note: You should use this only for browser runtimes.
3
+ * Create a snapshot of a runtime instance.
4
+ * @param token - Authentication token
5
+ * @param data - Snapshot creation configuration
6
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
7
+ * @returns Promise resolving to the created snapshot response
8
+ * @throws {Error} If authentication token is missing or invalid
14
9
  */
15
- export declare function createRuntimeSnapshot(props: Props): Promise<void>;
10
+ export declare const createSnapshot: (token: string, data: CreateRuntimeSnapshotRequest, baseUrl?: string) => Promise<SnapshotCreateResponse>;
16
11
  /**
17
- * Load a snapshot within a browser kernel.
18
- *
19
- * Note: You should use this only for browser kernels.
12
+ * List all runtime snapshots.
13
+ * @param token - Authentication token
14
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
15
+ * @returns Promise resolving to list of snapshots
16
+ * @throws {Error} If authentication token is missing or invalid
20
17
  */
21
- export declare function loadBrowserRuntimeSnapshot({ connection, id, }: {
22
- connection: Kernel.IKernelConnection;
23
- id: string;
24
- }): Promise<void>;
25
- export {};
18
+ export declare const listSnapshots: (token: string, baseUrl?: string) => Promise<SnapshotsListResponse>;
19
+ /**
20
+ * Get details for a specific runtime snapshot.
21
+ * @param token - Authentication token
22
+ * @param snapshotId - The unique identifier of the snapshot
23
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
24
+ * @returns Promise resolving to snapshot details wrapped in response
25
+ * @throws {Error} If authentication token is missing or invalid
26
+ * @throws {Error} If snapshot ID is missing or invalid
27
+ */
28
+ export declare const getSnapshot: (token: string, snapshotId: string, baseUrl?: string) => Promise<SnapshotGetResponse>;
29
+ /**
30
+ * Delete a runtime snapshot.
31
+ * @param token - Authentication token
32
+ * @param snapshotId - The unique identifier of the snapshot to delete
33
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
34
+ * @returns Promise resolving when deletion is complete
35
+ * @throws {Error} If authentication token is missing or invalid
36
+ * @throws {Error} If snapshot ID is missing or invalid
37
+ */
38
+ export declare const deleteSnapshot: (token: string, snapshotId: string, baseUrl?: string) => Promise<void>;
@@ -2,149 +2,80 @@
2
2
  * Copyright (c) 2023-2025 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- import { KernelExecutor } from '@datalayer/jupyter-react';
6
- import { createRuntimeSnapshotDownloadURL, uploadRuntimeSnapshot } from '.';
7
5
  /**
8
- * Snapshot a runtime through the frontend and upload it to the cloud.
6
+ * @module api/runtimes/snapshots
7
+ * @description Runtime snapshots API functions for the Datalayer platform.
9
8
  *
10
- * Note: You should use this only for browser runtimes.
9
+ * Provides functions for managing runtime snapshots (saved runtime states).
11
10
  */
12
- export async function createRuntimeSnapshot(props) {
13
- const { connection, metadata, onUploadProgress } = props;
14
- const dump = await new KernelExecutor({ connection }).execute(GET_RUNTIME_SNAPSHOT_SNIPPET, {
15
- storeHistory: false,
11
+ import { requestDatalayerAPI } from '../DatalayerApi';
12
+ import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants';
13
+ import { validateToken, validateRequiredString } from '../utils/validation';
14
+ /**
15
+ * Create a snapshot of a runtime instance.
16
+ * @param token - Authentication token
17
+ * @param data - Snapshot creation configuration
18
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
19
+ * @returns Promise resolving to the created snapshot response
20
+ * @throws {Error} If authentication token is missing or invalid
21
+ */
22
+ export const createSnapshot = async (token, data, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
23
+ validateToken(token);
24
+ return requestDatalayerAPI({
25
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtime-snapshots`,
26
+ method: 'POST',
27
+ token,
28
+ body: data,
29
+ });
30
+ };
31
+ /**
32
+ * List all runtime snapshots.
33
+ * @param token - Authentication token
34
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
35
+ * @returns Promise resolving to list of snapshots
36
+ * @throws {Error} If authentication token is missing or invalid
37
+ */
38
+ export const listSnapshots = async (token, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
39
+ validateToken(token);
40
+ return requestDatalayerAPI({
41
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtime-snapshots`,
42
+ method: 'GET',
43
+ token,
16
44
  });
17
- const serializedData = (dump.get(0)?.data['application/vnd.jupyter.stdout'] ??
18
- '');
19
- // Convert the data to blob.
20
- const bytes = base64ToBytes(serializedData);
21
- const file = new Blob([bytes.buffer]);
22
- return uploadRuntimeSnapshot({
23
- file,
24
- metadata,
25
- onProgress: onUploadProgress,
45
+ };
46
+ /**
47
+ * Get details for a specific runtime snapshot.
48
+ * @param token - Authentication token
49
+ * @param snapshotId - The unique identifier of the snapshot
50
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
51
+ * @returns Promise resolving to snapshot details wrapped in response
52
+ * @throws {Error} If authentication token is missing or invalid
53
+ * @throws {Error} If snapshot ID is missing or invalid
54
+ */
55
+ export const getSnapshot = async (token, snapshotId, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
56
+ validateToken(token);
57
+ validateRequiredString(snapshotId, 'Snapshot ID');
58
+ return requestDatalayerAPI({
59
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtime-snapshots/${snapshotId}`,
60
+ method: 'GET',
61
+ token,
26
62
  });
27
- }
28
- function base64ToBytes(base64) {
29
- // Taken from https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa#unicode_strings
30
- const binString = atob(base64);
31
- // @ts-expect-error TypeScript does not like this
32
- return Uint8Array.from(binString, m => m.codePointAt(0));
33
- }
63
+ };
34
64
  /**
35
- * Load a snapshot within a browser kernel.
36
- *
37
- * Note: You should use this only for browser kernels.
65
+ * Delete a runtime snapshot.
66
+ * @param token - Authentication token
67
+ * @param snapshotId - The unique identifier of the snapshot to delete
68
+ * @param baseUrl - Base URL for the API (defaults to production Runtimes URL)
69
+ * @returns Promise resolving when deletion is complete
70
+ * @throws {Error} If authentication token is missing or invalid
71
+ * @throws {Error} If snapshot ID is missing or invalid
38
72
  */
39
- export async function loadBrowserRuntimeSnapshot({ connection, id, }) {
40
- const downloadURL = createRuntimeSnapshotDownloadURL(id);
41
- const response = await fetch(downloadURL);
42
- const buffer = await response.arrayBuffer();
43
- const base64 = bytesToBase64(new Uint8Array(buffer));
44
- await new KernelExecutor({
45
- connection,
46
- }).execute(getLoadRuntimeSnapshotSnippet(base64), {
47
- storeHistory: false,
48
- silent: true,
73
+ export const deleteSnapshot = async (token, snapshotId, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
74
+ validateToken(token);
75
+ validateRequiredString(snapshotId, 'Snapshot ID');
76
+ return requestDatalayerAPI({
77
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/runtime-snapshots/${snapshotId}`,
78
+ method: 'DELETE',
79
+ token,
49
80
  });
50
- }
51
- function bytesToBase64(bytes) {
52
- // Taken from https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa#unicode_strings
53
- const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join('');
54
- return btoa(binString);
55
- }
56
- const GET_RUNTIME_SNAPSHOT_SNIPPET = `def _create_snapshot():
57
- import logging
58
- import os
59
- import pickle
60
- from base64 import encodebytes
61
- from tempfile import TemporaryFile
62
- from types import BuiltinFunctionType, BuiltinMethodType, FunctionType, MethodType, MethodWrapperType, ModuleType, TracebackType
63
-
64
- # print(pickle.DEFAULT_PROTOCOL)
65
-
66
- class NotFound:
67
- pass
68
-
69
- missing = NotFound()
70
-
71
- FORBIDDEN_TYPES = [type, BuiltinFunctionType, BuiltinMethodType, FunctionType, MethodType, MethodWrapperType, ModuleType, TracebackType, NotFound]
72
- try:
73
- from IPython.core.autocall import ExitAutocall
74
- from IPython.core.interactiveshell import InteractiveShell
75
- FORBIDDEN_TYPES.extend([ExitAutocall, InteractiveShell])
76
- except ImportError:
77
- pass
78
- exclude = tuple(FORBIDDEN_TYPES)
79
-
80
- all = frozenset(filter(lambda n: not n.startswith("_"), globals()))
81
-
82
- line_separator = bytes(os.linesep, "utf-8")
83
- with TemporaryFile() as dump:
84
- for _n in all:
85
- _v = globals().get(_n, missing)
86
-
87
- if not (
88
- isinstance(_v, exclude) or
89
- # Special IPython variables
90
- (_n == "In" and isinstance(_v, list)) or
91
- (_n == "Out" and isinstance(_v, dict))
92
- ):
93
- try:
94
- dumped_n = _n.encode("utf-8") + line_separator + pickle.dumps(_v) + line_separator + b"\\x00" + line_separator
95
- dump.write(dumped_n)
96
- except BaseException as e:
97
- logging.warning("Failed to dump variable [%s ([%s])].", _n, type(_v).__qualname__, exc_info=e)
98
- else:
99
- logging.debug("Variable [%s] dumped", _n)
100
-
101
- dump.seek(0)
102
- print(encodebytes(dump.read()).decode("ascii"))
103
-
104
- _create_snapshot()
105
- del _create_snapshot
106
- `;
107
- function getLoadRuntimeSnapshotSnippet(content) {
108
- return `async def _load_snapshot():
109
- import os
110
- import logging
111
- import platform
112
- import pickle
113
- from base64 import decodebytes
114
- is_pyodide = platform.node() == "emscripten"
115
-
116
- snapshot = decodebytes("${content}".encode("ascii"))
117
- line_sep = bytes(os.linesep, "utf-8")
118
- variable_separator = b"\\x00" + line_sep
119
- name = b""
120
- value = b""
121
- for line in snapshot.splitlines():
122
- line += line_sep
123
- if line == variable_separator:
124
- name_s = name.strip().decode("utf-8")
125
- try:
126
- try:
127
- globals()[name_s] = pickle.loads(value)
128
- except ModuleNotFoundError as m:
129
- if is_pyodide:
130
- import micropip
131
- logging.info(f'Installing %s...', m.name)
132
- await micropip.install(m.name)
133
- globals()[name_s] = pickle.loads(value)
134
- else:
135
- raise m
136
- except BaseException as e:
137
- logging.warning("Failed to load variable [%s].", name_s, exc_info=e)
138
- else:
139
- logging.debug("Variable [%s] loaded", name_s)
140
-
141
- name = b""
142
- value = b""
143
- else:
144
- if not name:
145
- name = line
146
- else:
147
- value += line
148
- await _load_snapshot()
149
- del _load_snapshot`;
150
- }
81
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,57 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
6
+ import { healthz } from '..';
7
+ import { requestDatalayerAPI } from '../../DatalayerApi';
8
+ // Mock the DatalayerAPI module
9
+ vi.mock('../../DatalayerApi');
10
+ describe('Spacer Healthz Unit Tests', () => {
11
+ beforeEach(() => {
12
+ vi.clearAllMocks();
13
+ });
14
+ describe('ping', () => {
15
+ it('should successfully ping the service', async () => {
16
+ const mockResponse = {
17
+ success: true,
18
+ message: 'Spacer service is healthy',
19
+ status: {
20
+ status: 'OK',
21
+ },
22
+ version: '1.0.0',
23
+ };
24
+ vi.mocked(requestDatalayerAPI).mockResolvedValueOnce(mockResponse);
25
+ const result = await healthz.ping('https://test.datalayer.run');
26
+ expect(result).toEqual(mockResponse);
27
+ expect(requestDatalayerAPI).toHaveBeenCalledWith({
28
+ url: 'https://test.datalayer.run/api/spacer/v1/ping',
29
+ method: 'GET',
30
+ });
31
+ });
32
+ it('should use default URL when not provided', async () => {
33
+ const mockResponse = {
34
+ success: true,
35
+ message: 'Service is healthy',
36
+ };
37
+ vi.mocked(requestDatalayerAPI).mockResolvedValueOnce(mockResponse);
38
+ const result = await healthz.ping();
39
+ expect(result).toEqual(mockResponse);
40
+ expect(requestDatalayerAPI).toHaveBeenCalledWith({
41
+ url: 'https://prod1.datalayer.run/api/spacer/v1/ping',
42
+ method: 'GET',
43
+ });
44
+ });
45
+ it('should handle service unhealthy errors', async () => {
46
+ const mockError = new Error('Service error');
47
+ mockError.response = { status: 500 };
48
+ vi.mocked(requestDatalayerAPI).mockRejectedValueOnce(mockError);
49
+ await expect(healthz.ping()).rejects.toThrow('Health check failed: Service unhealthy (status 500)');
50
+ });
51
+ it('should handle network errors', async () => {
52
+ const mockError = new Error('Network error');
53
+ vi.mocked(requestDatalayerAPI).mockRejectedValueOnce(mockError);
54
+ await expect(healthz.ping()).rejects.toThrow('Health check failed: Network error');
55
+ });
56
+ });
57
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,165 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
6
+ import { items } from '..';
7
+ import * as DatalayerApi from '../../DatalayerApi';
8
+ import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../../constants';
9
+ import { MOCK_JWT_TOKEN } from '../../../__tests__/shared/test-constants';
10
+ // Mock the DatalayerApi module
11
+ vi.mock('../../DatalayerApi', () => ({
12
+ requestDatalayerAPI: vi.fn(),
13
+ }));
14
+ describe('Spacer Items Unit Tests', () => {
15
+ beforeEach(() => {
16
+ vi.clearAllMocks();
17
+ });
18
+ describe('getSpaceItems', () => {
19
+ const mockGetItemsResponse = {
20
+ success: true,
21
+ message: 'Items retrieved successfully',
22
+ items: [
23
+ {
24
+ id: 'item-1',
25
+ type: 'notebook',
26
+ space_id: 'space-123',
27
+ item_id: 'notebook-456',
28
+ name: 'My Notebook',
29
+ created_at: '2024-01-01T00:00:00Z',
30
+ updated_at: '2024-01-02T00:00:00Z',
31
+ },
32
+ {
33
+ id: 'item-2',
34
+ type: 'lexical',
35
+ space_id: 'space-123',
36
+ item_id: 'lexical-789',
37
+ name: 'My Document',
38
+ created_at: '2024-01-01T00:00:00Z',
39
+ updated_at: '2024-01-02T00:00:00Z',
40
+ },
41
+ ],
42
+ };
43
+ it('should successfully get space items', async () => {
44
+ console.log('Testing get space items...');
45
+ const mockedRequest = vi.mocked(DatalayerApi.requestDatalayerAPI);
46
+ mockedRequest.mockResolvedValue(mockGetItemsResponse);
47
+ const result = await items.getSpaceItems(MOCK_JWT_TOKEN, 'space-123', DEFAULT_SERVICE_URLS.SPACER);
48
+ expect(mockedRequest).toHaveBeenCalledTimes(1);
49
+ expect(mockedRequest).toHaveBeenCalledWith({
50
+ url: `${DEFAULT_SERVICE_URLS.SPACER}${API_BASE_PATHS.SPACER}/spaces/space-123/items`,
51
+ method: 'GET',
52
+ token: MOCK_JWT_TOKEN,
53
+ });
54
+ expect(result).toEqual(mockGetItemsResponse);
55
+ expect(result.success).toBe(true);
56
+ expect(result.items).toHaveLength(2);
57
+ expect(result.items[0].type).toBe('notebook');
58
+ expect(result.items[1].type).toBe('lexical');
59
+ console.log('Space items retrieved successfully');
60
+ });
61
+ it('should handle empty items list', async () => {
62
+ console.log('Testing get space items with empty response...');
63
+ const emptyResponse = {
64
+ success: true,
65
+ message: 'No items found in space',
66
+ items: [],
67
+ };
68
+ const mockedRequest = vi.mocked(DatalayerApi.requestDatalayerAPI);
69
+ mockedRequest.mockResolvedValue(emptyResponse);
70
+ const result = await items.getSpaceItems(MOCK_JWT_TOKEN, 'empty-space', DEFAULT_SERVICE_URLS.SPACER);
71
+ expect(result).toEqual(emptyResponse);
72
+ expect(result.items).toHaveLength(0);
73
+ console.log('Empty items list handled correctly');
74
+ });
75
+ it('should use custom base URL when provided', async () => {
76
+ console.log('Testing get space items with custom base URL...');
77
+ const customUrl = 'https://custom.spacer.api';
78
+ const mockedRequest = vi.mocked(DatalayerApi.requestDatalayerAPI);
79
+ mockedRequest.mockResolvedValue(mockGetItemsResponse);
80
+ await items.getSpaceItems(MOCK_JWT_TOKEN, 'space-123', customUrl);
81
+ expect(mockedRequest).toHaveBeenCalledWith({
82
+ url: `${customUrl}${API_BASE_PATHS.SPACER}/spaces/space-123/items`,
83
+ method: 'GET',
84
+ token: MOCK_JWT_TOKEN,
85
+ });
86
+ console.log('Custom base URL used correctly');
87
+ });
88
+ it('should handle API errors during get', async () => {
89
+ console.log('Testing get space items with API error...');
90
+ const mockedRequest = vi.mocked(DatalayerApi.requestDatalayerAPI);
91
+ mockedRequest.mockRejectedValue(new Error('Network error'));
92
+ await expect(items.getSpaceItems(MOCK_JWT_TOKEN, 'space-123', DEFAULT_SERVICE_URLS.SPACER)).rejects.toThrow('Network error');
93
+ console.log('API error handled correctly');
94
+ });
95
+ });
96
+ describe('deleteItem', () => {
97
+ const mockDeleteResponse = {
98
+ success: true,
99
+ message: 'Item deleted successfully',
100
+ };
101
+ it('should successfully delete an item', async () => {
102
+ console.log('Testing delete item...');
103
+ const mockedRequest = vi.mocked(DatalayerApi.requestDatalayerAPI);
104
+ mockedRequest.mockResolvedValue(mockDeleteResponse);
105
+ const result = await items.deleteItem(MOCK_JWT_TOKEN, 'item-123', DEFAULT_SERVICE_URLS.SPACER);
106
+ expect(mockedRequest).toHaveBeenCalledTimes(1);
107
+ expect(mockedRequest).toHaveBeenCalledWith({
108
+ url: `${DEFAULT_SERVICE_URLS.SPACER}${API_BASE_PATHS.SPACER}/spaces/items/item-123`,
109
+ method: 'DELETE',
110
+ token: MOCK_JWT_TOKEN,
111
+ });
112
+ expect(result).toEqual(mockDeleteResponse);
113
+ expect(result.success).toBe(true);
114
+ expect(result.message).toBe('Item deleted successfully');
115
+ console.log('Item deleted successfully');
116
+ });
117
+ it('should handle non-existent item deletion', async () => {
118
+ console.log('Testing delete non-existent item...');
119
+ const notFoundResponse = {
120
+ success: false,
121
+ message: 'Item not found',
122
+ };
123
+ const mockedRequest = vi.mocked(DatalayerApi.requestDatalayerAPI);
124
+ mockedRequest.mockResolvedValue(notFoundResponse);
125
+ const result = await items.deleteItem(MOCK_JWT_TOKEN, 'non-existent-item', DEFAULT_SERVICE_URLS.SPACER);
126
+ expect(result).toEqual(notFoundResponse);
127
+ expect(result.success).toBe(false);
128
+ console.log('Non-existent item handled correctly');
129
+ });
130
+ it('should use custom base URL when provided', async () => {
131
+ console.log('Testing delete item with custom base URL...');
132
+ const customUrl = 'https://custom.spacer.api';
133
+ const mockedRequest = vi.mocked(DatalayerApi.requestDatalayerAPI);
134
+ mockedRequest.mockResolvedValue(mockDeleteResponse);
135
+ await items.deleteItem(MOCK_JWT_TOKEN, 'item-123', customUrl);
136
+ expect(mockedRequest).toHaveBeenCalledWith({
137
+ url: `${customUrl}${API_BASE_PATHS.SPACER}/spaces/items/item-123`,
138
+ method: 'DELETE',
139
+ token: MOCK_JWT_TOKEN,
140
+ });
141
+ console.log('Custom base URL used correctly');
142
+ });
143
+ it('should handle API errors during deletion', async () => {
144
+ console.log('Testing delete item with API error...');
145
+ const mockedRequest = vi.mocked(DatalayerApi.requestDatalayerAPI);
146
+ mockedRequest.mockRejectedValue(new Error('Network error'));
147
+ await expect(items.deleteItem(MOCK_JWT_TOKEN, 'item-123', DEFAULT_SERVICE_URLS.SPACER)).rejects.toThrow('Network error');
148
+ console.log('API error handled correctly');
149
+ });
150
+ it('should handle permission denied errors', async () => {
151
+ console.log('Testing delete item with permission denied...');
152
+ const permissionDeniedResponse = {
153
+ success: false,
154
+ message: 'Permission denied: You do not have permission to delete this item',
155
+ };
156
+ const mockedRequest = vi.mocked(DatalayerApi.requestDatalayerAPI);
157
+ mockedRequest.mockResolvedValue(permissionDeniedResponse);
158
+ const result = await items.deleteItem(MOCK_JWT_TOKEN, 'protected-item', DEFAULT_SERVICE_URLS.SPACER);
159
+ expect(result).toEqual(permissionDeniedResponse);
160
+ expect(result.success).toBe(false);
161
+ expect(result.message).toContain('Permission denied');
162
+ console.log('Permission denied handled correctly');
163
+ });
164
+ });
165
+ });
@@ -0,0 +1 @@
1
+ export {};