@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.
- package/lib/__tests__/shared/cleanup-shared.d.ts +4 -0
- package/lib/__tests__/shared/cleanup-shared.js +228 -0
- package/lib/__tests__/shared/test-config.d.ts +51 -0
- package/lib/__tests__/shared/test-config.js +110 -0
- package/lib/__tests__/shared/test-constants.d.ts +66 -0
- package/lib/__tests__/shared/test-constants.js +79 -0
- package/lib/api/DatalayerApi.d.ts +1 -1
- package/lib/api/DatalayerApi.js +73 -42
- package/lib/api/__tests__/iam.authentication.integration.test.d.ts +1 -0
- package/lib/api/__tests__/iam.authentication.integration.test.js +247 -0
- package/lib/api/__tests__/iam.healthz.integration.test.d.ts +1 -0
- package/lib/api/__tests__/iam.healthz.integration.test.js +63 -0
- package/lib/api/__tests__/iam.profile.integration.test.d.ts +1 -0
- package/lib/api/__tests__/iam.profile.integration.test.js +252 -0
- package/lib/api/__tests__/runtimes.environments.integration.test.d.ts +1 -0
- package/lib/api/__tests__/runtimes.environments.integration.test.js +122 -0
- package/lib/api/__tests__/runtimes.healthz.integration.test.d.ts +1 -0
- package/lib/api/__tests__/runtimes.healthz.integration.test.js +50 -0
- package/lib/api/__tests__/runtimes.integration.test.d.ts +1 -0
- package/lib/api/__tests__/runtimes.integration.test.js +369 -0
- package/lib/api/__tests__/spacer.healthz.integration.test.d.ts +1 -0
- package/lib/api/__tests__/spacer.healthz.integration.test.js +50 -0
- package/lib/api/__tests__/spacer.integration.test.d.ts +1 -0
- package/lib/api/__tests__/spacer.integration.test.js +519 -0
- package/lib/api/constants.d.ts +19 -0
- package/lib/api/constants.js +23 -0
- package/lib/api/iam/__tests__/authentication.unit.test.d.ts +1 -0
- package/lib/api/iam/__tests__/authentication.unit.test.js +63 -0
- package/lib/api/iam/__tests__/healthz.unit.test.d.ts +1 -0
- package/lib/api/iam/__tests__/healthz.unit.test.js +60 -0
- package/lib/api/iam/__tests__/profile.unit.test.d.ts +1 -0
- package/lib/api/iam/__tests__/profile.unit.test.js +57 -0
- package/lib/api/iam/authentication.d.ts +40 -0
- package/lib/api/iam/authentication.js +128 -0
- package/lib/api/iam/healthz.d.ts +15 -0
- package/lib/api/iam/healthz.js +43 -0
- package/lib/api/iam/index.d.ts +12 -0
- package/lib/api/iam/index.js +17 -0
- package/lib/api/iam/profile.d.ts +15 -0
- package/lib/api/iam/profile.js +41 -0
- package/lib/api/index.d.ts +20 -3
- package/lib/api/index.js +22 -3
- package/lib/api/runtimes/__tests__/environments.unit.test.d.ts +1 -0
- package/lib/api/runtimes/__tests__/environments.unit.test.js +77 -0
- package/lib/api/runtimes/__tests__/healthz.unit.test.d.ts +1 -0
- package/lib/api/runtimes/__tests__/healthz.unit.test.js +57 -0
- package/lib/api/runtimes/__tests__/runtimes.unit.test.d.ts +1 -0
- package/lib/api/runtimes/__tests__/runtimes.unit.test.js +139 -0
- package/lib/api/runtimes/__tests__/snapshots.unit.test.d.ts +1 -0
- package/lib/api/runtimes/__tests__/snapshots.unit.test.js +96 -0
- package/lib/api/runtimes/environments.d.ts +9 -0
- package/lib/api/runtimes/environments.js +28 -0
- package/lib/api/runtimes/healthz.d.ts +25 -0
- package/lib/api/runtimes/healthz.js +43 -0
- package/lib/api/runtimes/index.d.ts +10 -5
- package/lib/api/runtimes/index.js +10 -5
- package/lib/api/runtimes/runtimes.d.ts +54 -0
- package/lib/api/runtimes/runtimes.js +169 -0
- package/lib/api/runtimes/snapshots.d.ts +34 -21
- package/lib/api/runtimes/snapshots.js +69 -138
- package/lib/api/spacer/__tests__/healthz.unit.test.d.ts +1 -0
- package/lib/api/spacer/__tests__/healthz.unit.test.js +57 -0
- package/lib/api/spacer/__tests__/items.unit.test.d.ts +1 -0
- package/lib/api/spacer/__tests__/items.unit.test.js +165 -0
- package/lib/api/spacer/__tests__/lexicals.unit.test.d.ts +1 -0
- package/lib/api/spacer/__tests__/lexicals.unit.test.js +323 -0
- package/lib/api/spacer/__tests__/notebooks.unit.test.d.ts +1 -0
- package/lib/api/spacer/__tests__/notebooks.unit.test.js +224 -0
- package/lib/api/spacer/__tests__/users.unit.test.d.ts +1 -0
- package/lib/api/spacer/__tests__/users.unit.test.js +132 -0
- package/lib/api/spacer/healthz.d.ts +25 -0
- package/lib/api/spacer/healthz.js +43 -0
- package/lib/api/spacer/index.d.ts +13 -0
- package/lib/api/spacer/index.js +17 -0
- package/lib/api/spacer/items.d.ts +17 -0
- package/lib/api/spacer/items.js +40 -0
- package/lib/api/spacer/lexicals.d.ts +26 -0
- package/lib/api/spacer/lexicals.js +74 -0
- package/lib/api/spacer/notebooks.d.ts +26 -0
- package/lib/api/spacer/notebooks.js +74 -0
- package/lib/api/spacer/spaces.d.ts +9 -0
- package/lib/api/spacer/spaces.js +29 -0
- package/lib/api/spacer/users.d.ts +9 -0
- package/lib/api/spacer/users.js +28 -0
- package/lib/api/types/iam.d.ts +180 -0
- package/lib/api/types/index.d.ts +32 -0
- package/lib/api/types/index.js +36 -0
- package/lib/api/types/runtimes.d.ts +235 -0
- package/lib/api/types/runtimes.js +5 -0
- package/lib/api/types/spacer.d.ts +271 -0
- package/lib/api/types/spacer.js +5 -0
- package/lib/api/utils/__tests__/validation.test.d.ts +1 -0
- package/lib/api/utils/__tests__/validation.test.js +109 -0
- package/lib/api/utils/validation.d.ts +24 -0
- package/lib/api/utils/validation.js +133 -0
- package/lib/components/display/JupyterDialog.js +4 -8
- package/lib/components/progress/CreditsIndicator.d.ts +1 -1
- package/lib/components/runtimes/RuntimeCellVariablesDialog.js +2 -2
- package/lib/components/runtimes/RuntimeLauncherDialog.d.ts +1 -1
- package/lib/components/runtimes/RuntimeLauncherDialog.js +5 -2
- package/lib/components/runtimes/RuntimePickerBase.d.ts +1 -1
- package/lib/components/runtimes/RuntimePickerBase.js +1 -1
- package/lib/components/runtimes/RuntimePickerCell.js +2 -1
- package/lib/components/runtimes/RuntimePickerNotebook.d.ts +1 -1
- package/lib/components/runtimes/RuntimePickerNotebook.js +1 -1
- package/lib/components/runtimes/RuntimeSimplePicker.js +2 -1
- package/lib/components/runtimes/RuntimeTransfer.d.ts +1 -1
- package/lib/components/runtimes/RuntimeUtils.d.ts +1 -1
- package/lib/components/snapshots/RuntimeSnapshotMenu.d.ts +1 -1
- package/lib/components/snapshots/RuntimeSnapshotMenu.js +2 -2
- package/lib/components/snippets/SnippetDialog.js +1 -1
- package/lib/components/storage/ContentsBrowser.js +2 -2
- package/lib/components/tables/DataTable.js +2 -1
- package/lib/hooks/useDatalayer.d.ts +1 -1
- package/lib/hooks/useDatalayer.js +1 -1
- package/lib/hooks/useIAM.js +1 -1
- package/lib/hooks/useRuntimes.js +1 -1
- package/lib/index.d.ts +9 -0
- package/lib/index.js +10 -0
- package/lib/sdk/client/__tests__/sdk.health.integration.test.d.ts +1 -0
- package/lib/sdk/client/__tests__/sdk.health.integration.test.js +110 -0
- package/lib/sdk/client/__tests__/sdk.iam.integration.test.d.ts +1 -0
- package/lib/sdk/client/__tests__/sdk.iam.integration.test.js +179 -0
- package/lib/sdk/client/__tests__/sdk.models.integration.test.d.ts +1 -0
- package/lib/sdk/client/__tests__/sdk.models.integration.test.js +376 -0
- package/lib/sdk/client/__tests__/sdk.runtimes.integration.test.d.ts +1 -0
- package/lib/sdk/client/__tests__/sdk.runtimes.integration.test.js +276 -0
- package/lib/sdk/client/__tests__/sdk.spacer.integration.test.d.ts +1 -0
- package/lib/sdk/client/__tests__/sdk.spacer.integration.test.js +361 -0
- package/lib/sdk/client/base.d.ts +88 -0
- package/lib/sdk/client/base.js +112 -0
- package/lib/sdk/client/index.d.ts +192 -0
- package/lib/sdk/client/index.js +128 -0
- package/lib/sdk/client/mixins/HealthMixin.d.ts +100 -0
- package/lib/sdk/client/mixins/HealthMixin.js +133 -0
- package/lib/sdk/client/mixins/IAMMixin.d.ts +59 -0
- package/lib/sdk/client/mixins/IAMMixin.js +83 -0
- package/lib/sdk/client/mixins/RuntimesMixin.d.ts +134 -0
- package/lib/sdk/client/mixins/RuntimesMixin.js +221 -0
- package/lib/sdk/client/mixins/SpacerMixin.d.ts +184 -0
- package/lib/sdk/client/mixins/SpacerMixin.js +278 -0
- package/lib/sdk/client/models/Lexical.d.ts +156 -0
- package/lib/sdk/client/models/Lexical.js +275 -0
- package/lib/sdk/client/models/Notebook.d.ts +174 -0
- package/lib/sdk/client/models/Notebook.js +311 -0
- package/lib/sdk/client/models/Runtime.d.ts +221 -0
- package/lib/sdk/client/models/Runtime.js +341 -0
- package/lib/sdk/client/models/Snapshot.d.ts +156 -0
- package/lib/sdk/client/models/Snapshot.js +244 -0
- package/lib/sdk/client/models/Space.d.ts +182 -0
- package/lib/sdk/client/models/Space.js +276 -0
- package/lib/sdk/client/models/__tests__/Lexical.test.d.ts +1 -0
- package/lib/sdk/client/models/__tests__/Lexical.test.js +288 -0
- package/lib/sdk/client/models/__tests__/Notebook.test.d.ts +1 -0
- package/lib/sdk/client/models/__tests__/Notebook.test.js +206 -0
- package/lib/sdk/client/models/__tests__/Runtime.test.d.ts +1 -0
- package/lib/sdk/client/models/__tests__/Runtime.test.js +133 -0
- package/lib/sdk/client/models/__tests__/Snapshot.test.d.ts +1 -0
- package/lib/sdk/client/models/__tests__/Snapshot.test.js +244 -0
- package/lib/sdk/client/models/__tests__/Space.test.d.ts +1 -0
- package/lib/sdk/client/models/__tests__/Space.test.js +334 -0
- package/lib/sdk/client/models/index.d.ts +30 -0
- package/lib/sdk/client/models/index.js +30 -0
- package/lib/sdk/client/utils/mixins.d.ts +42 -0
- package/lib/sdk/client/utils/mixins.js +47 -0
- package/lib/sdk/index.d.ts +26 -0
- package/lib/sdk/index.js +32 -0
- package/lib/sdk/stateful/index.d.ts +3 -0
- package/lib/sdk/stateful/index.js +7 -0
- package/lib/{api → sdk/stateful}/runtimes/actions.d.ts +1 -1
- package/lib/{api → sdk/stateful}/runtimes/actions.js +3 -3
- package/lib/{api → sdk/stateful}/runtimes/apis.d.ts +1 -1
- package/lib/sdk/stateful/runtimes/apis.js +5 -0
- package/lib/sdk/stateful/runtimes/index.d.ts +5 -0
- package/lib/sdk/stateful/runtimes/index.js +9 -0
- package/lib/sdk/stateful/runtimes/snapshots.d.ts +25 -0
- package/lib/sdk/stateful/runtimes/snapshots.js +150 -0
- package/lib/services/DatalayerServiceManager.js +1 -1
- package/lib/state/substates/IAMState.js +1 -1
- package/lib/state/substates/RuntimesState.d.ts +1 -1
- package/lib/state/substates/RuntimesState.js +1 -1
- package/lib/state/substates/SurveysState.js +1 -1
- package/lib/test-setup.js +1 -0
- package/package.json +19 -9
- /package/lib/api/{runtimes/apis.js → types/iam.js} +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/exec/Python.d.ts +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/exec/Python.js +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/exec/Snippets.d.ts +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/exec/Snippets.js +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/exec/index.d.ts +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/exec/index.js +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/index.d.ts +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/index.js +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/kernelsHandler.d.ts +0 -0
- /package/lib/{api → sdk/stateful}/jupyter/kernelsHandler.js +0 -0
- /package/lib/{api → sdk/stateful}/runtimes/settings.d.ts +0 -0
- /package/lib/{api → sdk/stateful}/runtimes/settings.js +0 -0
- /package/lib/{api → sdk/stateful}/runtimes/utils.d.ts +0 -0
- /package/lib/{api → sdk/stateful}/runtimes/utils.js +0 -0
|
@@ -1,25 +1,38 @@
|
|
|
1
|
-
import {
|
|
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
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
|
10
|
+
export declare const createSnapshot: (token: string, data: CreateRuntimeSnapshotRequest, baseUrl?: string) => Promise<SnapshotCreateResponse>;
|
|
16
11
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
*
|
|
6
|
+
* @module api/runtimes/snapshots
|
|
7
|
+
* @description Runtime snapshots API functions for the Datalayer platform.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
9
|
+
* Provides functions for managing runtime snapshots (saved runtime states).
|
|
11
10
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
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
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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 {};
|