@datalayer/core 0.0.10 → 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/progress/CreditsIndicator.d.ts +1 -1
- package/lib/components/runtimes/RuntimeCellVariablesDialog.js +1 -1
- package/lib/components/runtimes/RuntimeLauncherDialog.d.ts +1 -1
- package/lib/components/runtimes/RuntimeLauncherDialog.js +2 -1
- 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 +1 -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
|
@@ -0,0 +1,60 @@
|
|
|
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 { ping } from '../healthz';
|
|
7
|
+
import { requestDatalayerAPI } from '../../DatalayerApi';
|
|
8
|
+
// Mock the DatalayerAPI module
|
|
9
|
+
vi.mock('../../DatalayerApi');
|
|
10
|
+
describe('IAM Healthz Unit Tests', () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
vi.clearAllMocks();
|
|
13
|
+
});
|
|
14
|
+
describe('ping', () => {
|
|
15
|
+
it('should return health status on successful health check', async () => {
|
|
16
|
+
const mockResponse = {
|
|
17
|
+
success: true,
|
|
18
|
+
message: 'datalayer_iam is up and running.',
|
|
19
|
+
status: { status: 'OK' },
|
|
20
|
+
version: '1.0.7',
|
|
21
|
+
};
|
|
22
|
+
vi.mocked(requestDatalayerAPI).mockResolvedValueOnce(mockResponse);
|
|
23
|
+
const result = await ping();
|
|
24
|
+
expect(result).toEqual(mockResponse);
|
|
25
|
+
expect(requestDatalayerAPI).toHaveBeenCalledWith({
|
|
26
|
+
url: 'https://prod1.datalayer.run/api/iam/v1/ping',
|
|
27
|
+
method: 'GET',
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
it('should use custom base URL when provided', async () => {
|
|
31
|
+
const mockResponse = {
|
|
32
|
+
success: true,
|
|
33
|
+
message: 'Service is healthy',
|
|
34
|
+
status: { status: 'OK' },
|
|
35
|
+
version: '2.0.0',
|
|
36
|
+
};
|
|
37
|
+
const customUrl = 'https://custom.example.com';
|
|
38
|
+
vi.mocked(requestDatalayerAPI).mockResolvedValueOnce(mockResponse);
|
|
39
|
+
const result = await ping(customUrl);
|
|
40
|
+
expect(result).toEqual(mockResponse);
|
|
41
|
+
expect(requestDatalayerAPI).toHaveBeenCalledWith({
|
|
42
|
+
url: `${customUrl}/api/iam/v1/ping`,
|
|
43
|
+
method: 'GET',
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
it('should throw error with status code on failure', async () => {
|
|
47
|
+
const mockError = {
|
|
48
|
+
response: { status: 500 },
|
|
49
|
+
message: 'Internal Server Error',
|
|
50
|
+
};
|
|
51
|
+
vi.mocked(requestDatalayerAPI).mockRejectedValueOnce(mockError);
|
|
52
|
+
await expect(ping()).rejects.toThrow('Health check failed: Service unhealthy (status 500) - Internal Server Error');
|
|
53
|
+
});
|
|
54
|
+
it('should throw generic error on network failure', async () => {
|
|
55
|
+
const mockError = new Error('Network error');
|
|
56
|
+
vi.mocked(requestDatalayerAPI).mockRejectedValueOnce(mockError);
|
|
57
|
+
await expect(ping()).rejects.toThrow('Health check failed: Network error');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -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 } from 'vitest';
|
|
6
|
+
import { profile } from '..';
|
|
7
|
+
describe('IAM Profile Unit Tests', () => {
|
|
8
|
+
describe('parameter validation', () => {
|
|
9
|
+
it('should handle undefined token parameter at runtime', async () => {
|
|
10
|
+
console.log('Testing that undefined token is caught by validation...');
|
|
11
|
+
// In JavaScript/TypeScript at runtime, calling a function without
|
|
12
|
+
// required parameters just passes undefined for those parameters.
|
|
13
|
+
// Our validation code inside the function should catch this.
|
|
14
|
+
// Test me() with undefined token
|
|
15
|
+
await expect(profile.me(undefined)).rejects.toThrow('Authentication token is required');
|
|
16
|
+
// Test whoami() with undefined token
|
|
17
|
+
await expect(profile.whoami(undefined)).rejects.toThrow('Authentication token is required');
|
|
18
|
+
console.log('Validation correctly rejects undefined token');
|
|
19
|
+
});
|
|
20
|
+
it('should handle null token parameter at runtime', async () => {
|
|
21
|
+
console.log('Testing that null token is caught by validation...');
|
|
22
|
+
// Test me() with null token
|
|
23
|
+
await expect(profile.me(null)).rejects.toThrow('Authentication token is required');
|
|
24
|
+
// Test whoami() with null token
|
|
25
|
+
await expect(profile.whoami(null)).rejects.toThrow('Authentication token is required');
|
|
26
|
+
console.log('Validation correctly rejects null token');
|
|
27
|
+
});
|
|
28
|
+
it('should handle empty string token', async () => {
|
|
29
|
+
console.log('Testing that empty string token is caught by validation...');
|
|
30
|
+
// Test me() with empty string
|
|
31
|
+
await expect(profile.me('')).rejects.toThrow('Authentication token is required');
|
|
32
|
+
// Test whoami() with empty string
|
|
33
|
+
await expect(profile.whoami('')).rejects.toThrow('Authentication token is required');
|
|
34
|
+
console.log('Validation correctly rejects empty string token');
|
|
35
|
+
});
|
|
36
|
+
it('should handle whitespace-only token', async () => {
|
|
37
|
+
console.log('Testing that whitespace-only token is caught by validation...');
|
|
38
|
+
// Test me() with whitespace
|
|
39
|
+
await expect(profile.me(' ')).rejects.toThrow('Authentication token is required');
|
|
40
|
+
// Test whoami() with whitespace
|
|
41
|
+
await expect(profile.whoami(' ')).rejects.toThrow('Authentication token is required');
|
|
42
|
+
console.log('Validation correctly rejects whitespace-only token');
|
|
43
|
+
});
|
|
44
|
+
it('demonstrates JavaScript runtime behavior with missing parameters', () => {
|
|
45
|
+
console.log('Demonstrating JS runtime behavior...');
|
|
46
|
+
// This demonstrates that JavaScript doesn't throw errors for missing parameters
|
|
47
|
+
// The function receives undefined for missing parameters
|
|
48
|
+
function testFunction(required) {
|
|
49
|
+
return required === undefined;
|
|
50
|
+
}
|
|
51
|
+
// @ts-expect-error TypeScript knows this is wrong, but JS allows it
|
|
52
|
+
const result = testFunction();
|
|
53
|
+
expect(result).toBe(true); // The parameter is undefined
|
|
54
|
+
console.log('JavaScript passes undefined for missing parameters');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { LoginRequest, LoginResponse } from '../types/iam';
|
|
2
|
+
/**
|
|
3
|
+
* Authenticate a user with credentials or token
|
|
4
|
+
* @param data - Login credentials (either handle+password or token)
|
|
5
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
6
|
+
* @returns Login response with tokens
|
|
7
|
+
* @throws {Error} If both credential and token authentication are provided
|
|
8
|
+
* @throws {Error} If neither authentication method is provided
|
|
9
|
+
* @throws {Error} If handle is provided without password or vice versa
|
|
10
|
+
* @throws {Error} If server returns unexpected status code (expects 201 for success, 401 for failure)
|
|
11
|
+
*
|
|
12
|
+
* @description
|
|
13
|
+
* Expected status codes:
|
|
14
|
+
* - 201: Login succeeded
|
|
15
|
+
* - 401: Login failed (invalid credentials)
|
|
16
|
+
*/
|
|
17
|
+
export declare const login: (data: LoginRequest, baseUrl?: string) => Promise<LoginResponse>;
|
|
18
|
+
/**
|
|
19
|
+
* Log out the current user
|
|
20
|
+
* @param token - Authentication token
|
|
21
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
22
|
+
* @returns Void response
|
|
23
|
+
*/
|
|
24
|
+
export declare const logout: (token: string, baseUrl?: string) => Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Validate authentication through proxy
|
|
27
|
+
* @param token - Authentication token (required)
|
|
28
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
29
|
+
* @returns Promise that resolves if authenticated (200), rejects if unauthorized (401) or forbidden (403)
|
|
30
|
+
* @throws {Error} If authentication token is missing or invalid
|
|
31
|
+
*
|
|
32
|
+
* @description
|
|
33
|
+
* This endpoint validates authentication status through a proxy.
|
|
34
|
+
*
|
|
35
|
+
* Expected status codes:
|
|
36
|
+
* - 200: Authenticated successfully
|
|
37
|
+
* - 401: Unauthorized - invalid or missing credentials
|
|
38
|
+
* - 403: Forbidden - valid credentials but access denied
|
|
39
|
+
*/
|
|
40
|
+
export declare const proxyAuth: (token: string, baseUrl?: string) => Promise<void>;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module api/iam/authentication
|
|
7
|
+
* @description Authentication API functions for the Datalayer platform.
|
|
8
|
+
*
|
|
9
|
+
* Provides functions for user login, logout, and authentication management.
|
|
10
|
+
*/
|
|
11
|
+
import { requestDatalayerAPI } from '../DatalayerApi';
|
|
12
|
+
import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants';
|
|
13
|
+
import { validateToken } from '../utils/validation';
|
|
14
|
+
/**
|
|
15
|
+
* Authenticate a user with credentials or token
|
|
16
|
+
* @param data - Login credentials (either handle+password or token)
|
|
17
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
18
|
+
* @returns Login response with tokens
|
|
19
|
+
* @throws {Error} If both credential and token authentication are provided
|
|
20
|
+
* @throws {Error} If neither authentication method is provided
|
|
21
|
+
* @throws {Error} If handle is provided without password or vice versa
|
|
22
|
+
* @throws {Error} If server returns unexpected status code (expects 201 for success, 401 for failure)
|
|
23
|
+
*
|
|
24
|
+
* @description
|
|
25
|
+
* Expected status codes:
|
|
26
|
+
* - 201: Login succeeded
|
|
27
|
+
* - 401: Login failed (invalid credentials)
|
|
28
|
+
*/
|
|
29
|
+
export const login = async (data, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
30
|
+
// Validate that we have either handle+password OR token, but not both
|
|
31
|
+
const hasCredentials = Boolean(data.handle || data.password);
|
|
32
|
+
const hasToken = Boolean(data.token);
|
|
33
|
+
if (hasCredentials && hasToken) {
|
|
34
|
+
throw new Error('Cannot provide both credentials (handle/password) and token. Use either handle+password or token.');
|
|
35
|
+
}
|
|
36
|
+
if (!hasCredentials && !hasToken) {
|
|
37
|
+
throw new Error('Must provide either credentials (handle+password) or token for authentication.');
|
|
38
|
+
}
|
|
39
|
+
// If using credentials, ensure both handle and password are provided
|
|
40
|
+
if (hasCredentials) {
|
|
41
|
+
if (!data.handle || !data.password) {
|
|
42
|
+
throw new Error('Both handle and password are required for credential-based authentication.');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const response = await requestDatalayerAPI({
|
|
47
|
+
url: `${baseUrl}${API_BASE_PATHS.IAM}/login`,
|
|
48
|
+
method: 'POST',
|
|
49
|
+
body: data,
|
|
50
|
+
});
|
|
51
|
+
// Note: requestDatalayerAPI already handles successful responses (2xx status codes)
|
|
52
|
+
// If we get here, the login was successful
|
|
53
|
+
return response;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// Check if it's a response error with status code information
|
|
57
|
+
if (error.response) {
|
|
58
|
+
const status = error.response.status;
|
|
59
|
+
// Expected error: 401 for invalid credentials
|
|
60
|
+
if (status === 401) {
|
|
61
|
+
throw new Error(`Login failed: Invalid credentials (${status})`);
|
|
62
|
+
}
|
|
63
|
+
// Unexpected status codes
|
|
64
|
+
throw new Error(`Login failed: Unexpected status code ${status} - ${error.message}`);
|
|
65
|
+
}
|
|
66
|
+
// Re-throw other errors (network errors, etc.)
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Log out the current user
|
|
72
|
+
* @param token - Authentication token
|
|
73
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
74
|
+
* @returns Void response
|
|
75
|
+
*/
|
|
76
|
+
export const logout = async (token, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
77
|
+
validateToken(token);
|
|
78
|
+
return requestDatalayerAPI({
|
|
79
|
+
url: `${baseUrl}${API_BASE_PATHS.IAM}/logout`,
|
|
80
|
+
method: 'GET',
|
|
81
|
+
token,
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Validate authentication through proxy
|
|
86
|
+
* @param token - Authentication token (required)
|
|
87
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
88
|
+
* @returns Promise that resolves if authenticated (200), rejects if unauthorized (401) or forbidden (403)
|
|
89
|
+
* @throws {Error} If authentication token is missing or invalid
|
|
90
|
+
*
|
|
91
|
+
* @description
|
|
92
|
+
* This endpoint validates authentication status through a proxy.
|
|
93
|
+
*
|
|
94
|
+
* Expected status codes:
|
|
95
|
+
* - 200: Authenticated successfully
|
|
96
|
+
* - 401: Unauthorized - invalid or missing credentials
|
|
97
|
+
* - 403: Forbidden - valid credentials but access denied
|
|
98
|
+
*/
|
|
99
|
+
export const proxyAuth = async (token, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
100
|
+
validateToken(token);
|
|
101
|
+
try {
|
|
102
|
+
const response = await requestDatalayerAPI({
|
|
103
|
+
url: `${baseUrl}${API_BASE_PATHS.IAM}/proxy-auth`,
|
|
104
|
+
method: 'GET',
|
|
105
|
+
token,
|
|
106
|
+
});
|
|
107
|
+
// Note: requestDatalayerAPI already handles successful responses (2xx status codes)
|
|
108
|
+
// If we get here, authentication was successful (200)
|
|
109
|
+
return response;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
// Check if it's a response error with status code information
|
|
113
|
+
if (error.response) {
|
|
114
|
+
const status = error.response.status;
|
|
115
|
+
// Expected errors
|
|
116
|
+
if (status === 401) {
|
|
117
|
+
throw new Error(`Proxy authentication failed: Unauthorized (${status})`);
|
|
118
|
+
}
|
|
119
|
+
if (status === 403) {
|
|
120
|
+
throw new Error(`Proxy authentication failed: Forbidden (${status})`);
|
|
121
|
+
}
|
|
122
|
+
// Unexpected status codes
|
|
123
|
+
throw new Error(`Proxy authentication failed: Unexpected status code ${status} - ${error.message}`);
|
|
124
|
+
}
|
|
125
|
+
// Re-throw other errors (network errors, etc.)
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { HealthzPingResponse } from '../types/iam';
|
|
2
|
+
/**
|
|
3
|
+
* Health check ping endpoint
|
|
4
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
5
|
+
* @returns Health check response with user count
|
|
6
|
+
* @throws {Error} If the health check fails
|
|
7
|
+
*
|
|
8
|
+
* @description
|
|
9
|
+
* This endpoint provides a basic health check for the IAM service.
|
|
10
|
+
* It returns the current user count in the system.
|
|
11
|
+
*
|
|
12
|
+
* Expected status codes:
|
|
13
|
+
* - 200: Service is healthy
|
|
14
|
+
*/
|
|
15
|
+
export declare const ping: (baseUrl?: string) => Promise<HealthzPingResponse>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module api/iam/healthz
|
|
7
|
+
* @description Health check API functions for the Datalayer IAM service.
|
|
8
|
+
*
|
|
9
|
+
* Provides functions for checking the health status of the IAM service.
|
|
10
|
+
*/
|
|
11
|
+
import { requestDatalayerAPI } from '../DatalayerApi';
|
|
12
|
+
import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants';
|
|
13
|
+
/**
|
|
14
|
+
* Health check ping endpoint
|
|
15
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
16
|
+
* @returns Health check response with user count
|
|
17
|
+
* @throws {Error} If the health check fails
|
|
18
|
+
*
|
|
19
|
+
* @description
|
|
20
|
+
* This endpoint provides a basic health check for the IAM service.
|
|
21
|
+
* It returns the current user count in the system.
|
|
22
|
+
*
|
|
23
|
+
* Expected status codes:
|
|
24
|
+
* - 200: Service is healthy
|
|
25
|
+
*/
|
|
26
|
+
export const ping = async (baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
27
|
+
try {
|
|
28
|
+
const response = await requestDatalayerAPI({
|
|
29
|
+
url: `${baseUrl}${API_BASE_PATHS.IAM}/ping`,
|
|
30
|
+
method: 'GET',
|
|
31
|
+
});
|
|
32
|
+
return response;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
// Check if it's a response error with status code information
|
|
36
|
+
if (error.response) {
|
|
37
|
+
const status = error.response.status;
|
|
38
|
+
throw new Error(`Health check failed: Service unhealthy (status ${status}) - ${error.message}`);
|
|
39
|
+
}
|
|
40
|
+
// Re-throw other errors (network errors, etc.)
|
|
41
|
+
throw new Error(`Health check failed: ${error.message}`);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module api/iam
|
|
3
|
+
* @description IAM (Identity and Access Management) API exports.
|
|
4
|
+
*
|
|
5
|
+
* Provides organized access to authentication and user profile functionality.
|
|
6
|
+
*/
|
|
7
|
+
export * as authentication from './authentication';
|
|
8
|
+
export * as profile from './profile';
|
|
9
|
+
export * as healthz from './healthz';
|
|
10
|
+
export { login, logout, proxyAuth } from './authentication';
|
|
11
|
+
export { me, whoami } from './profile';
|
|
12
|
+
export { ping } from './healthz';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module api/iam
|
|
7
|
+
* @description IAM (Identity and Access Management) API exports.
|
|
8
|
+
*
|
|
9
|
+
* Provides organized access to authentication and user profile functionality.
|
|
10
|
+
*/
|
|
11
|
+
export * as authentication from './authentication';
|
|
12
|
+
export * as profile from './profile';
|
|
13
|
+
export * as healthz from './healthz';
|
|
14
|
+
// For backward compatibility, export the old API structure
|
|
15
|
+
export { login, logout, proxyAuth } from './authentication';
|
|
16
|
+
export { me, whoami } from './profile';
|
|
17
|
+
export { ping } from './healthz';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { UserMeResponse, WhoAmIResponse } from '../types/iam';
|
|
2
|
+
/**
|
|
3
|
+
* Get current authenticated user profile
|
|
4
|
+
* @param token - Authentication token (required)
|
|
5
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
6
|
+
* @returns Current user profile information
|
|
7
|
+
*/
|
|
8
|
+
export declare const me: (token: string, baseUrl?: string) => Promise<UserMeResponse>;
|
|
9
|
+
/**
|
|
10
|
+
* Get current user identity information
|
|
11
|
+
* @param token - Authentication token (required)
|
|
12
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
13
|
+
* @returns Current user identity and profile information
|
|
14
|
+
*/
|
|
15
|
+
export declare const whoami: (token: string, baseUrl?: string) => Promise<WhoAmIResponse>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module api/iam/profile
|
|
7
|
+
* @description User profile management API functions for the Datalayer platform.
|
|
8
|
+
*
|
|
9
|
+
* Provides functions for retrieving and managing user profile information.
|
|
10
|
+
*/
|
|
11
|
+
import { requestDatalayerAPI } from '../DatalayerApi';
|
|
12
|
+
import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants';
|
|
13
|
+
import { validateToken } from '../utils/validation';
|
|
14
|
+
/**
|
|
15
|
+
* Get current authenticated user profile
|
|
16
|
+
* @param token - Authentication token (required)
|
|
17
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
18
|
+
* @returns Current user profile information
|
|
19
|
+
*/
|
|
20
|
+
export const me = async (token, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
21
|
+
validateToken(token);
|
|
22
|
+
return requestDatalayerAPI({
|
|
23
|
+
url: `${baseUrl}${API_BASE_PATHS.IAM}/me`,
|
|
24
|
+
method: 'GET',
|
|
25
|
+
token,
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Get current user identity information
|
|
30
|
+
* @param token - Authentication token (required)
|
|
31
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
32
|
+
* @returns Current user identity and profile information
|
|
33
|
+
*/
|
|
34
|
+
export const whoami = async (token, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
35
|
+
validateToken(token);
|
|
36
|
+
return requestDatalayerAPI({
|
|
37
|
+
url: `${baseUrl}${API_BASE_PATHS.IAM}/whoami`,
|
|
38
|
+
method: 'GET',
|
|
39
|
+
token,
|
|
40
|
+
});
|
|
41
|
+
};
|
package/lib/api/index.d.ts
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module @datalayer/core/api
|
|
3
|
+
* @description Minimal API layer for the Datalayer platform providing base HTTP client and functional API methods.
|
|
4
|
+
*
|
|
5
|
+
* This module contains the low-level API functionality. For high-level object-oriented
|
|
6
|
+
* SDK classes, use @datalayer/core/sdk instead.
|
|
7
|
+
*/
|
|
8
|
+
export { requestDatalayerAPI, RunResponseError, NetworkError, } from './DatalayerApi';
|
|
9
|
+
export type { IRequestDatalayerAPIOptions } from './DatalayerApi';
|
|
10
|
+
export * from './types';
|
|
11
|
+
export * as iam from './iam';
|
|
12
|
+
export * as runtimes from './runtimes';
|
|
13
|
+
export * as spacer from './spacer';
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Please import directly from '@datalayer/core/sdk/stateful' instead.
|
|
16
|
+
* This module provides backward compatibility for the moved apiv1 modules.
|
|
17
|
+
*/
|
|
18
|
+
export * from '../sdk/stateful/jupyter';
|
|
19
|
+
export * from '../sdk/stateful/runtimes';
|
|
20
|
+
export * from '../api/DatalayerApi';
|
package/lib/api/index.js
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @module @datalayer/core/api
|
|
7
|
+
* @description Minimal API layer for the Datalayer platform providing base HTTP client and functional API methods.
|
|
8
|
+
*
|
|
9
|
+
* This module contains the low-level API functionality. For high-level object-oriented
|
|
10
|
+
* SDK classes, use @datalayer/core/sdk instead.
|
|
11
|
+
*/
|
|
12
|
+
// Base client exports
|
|
13
|
+
export { requestDatalayerAPI, RunResponseError, NetworkError, } from './DatalayerApi';
|
|
14
|
+
// Type exports
|
|
15
|
+
export * from './types';
|
|
16
|
+
// Domain-organized API exports
|
|
17
|
+
export * as iam from './iam';
|
|
18
|
+
export * as runtimes from './runtimes';
|
|
19
|
+
export * as spacer from './spacer';
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated Please import directly from '@datalayer/core/sdk/stateful' instead.
|
|
22
|
+
* This module provides backward compatibility for the moved apiv1 modules.
|
|
23
|
+
*/
|
|
24
|
+
export * from '../sdk/stateful/jupyter';
|
|
25
|
+
export * from '../sdk/stateful/runtimes';
|
|
26
|
+
export * from '../api/DatalayerApi';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
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 { environments } from '..';
|
|
7
|
+
import { requestDatalayerAPI } from '../../DatalayerApi';
|
|
8
|
+
import { MOCK_JWT_TOKEN, MOCK_ENVIRONMENTS_RESPONSE, } from '../../../__tests__/shared/test-constants';
|
|
9
|
+
// Mock the DatalayerAPI module
|
|
10
|
+
vi.mock('../../DatalayerApi');
|
|
11
|
+
describe('Runtimes Environments Unit Tests', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
describe('listEnvironments', () => {
|
|
16
|
+
it('should list environments with valid token', async () => {
|
|
17
|
+
vi.mocked(requestDatalayerAPI).mockResolvedValueOnce(MOCK_ENVIRONMENTS_RESPONSE);
|
|
18
|
+
const result = await environments.listEnvironments(MOCK_JWT_TOKEN);
|
|
19
|
+
expect(result).toEqual(MOCK_ENVIRONMENTS_RESPONSE);
|
|
20
|
+
expect(requestDatalayerAPI).toHaveBeenCalledWith({
|
|
21
|
+
url: 'https://prod1.datalayer.run/api/runtimes/v1/environments',
|
|
22
|
+
method: 'GET',
|
|
23
|
+
token: MOCK_JWT_TOKEN,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
it('should use custom base URL when provided', async () => {
|
|
27
|
+
const mockResponse = {
|
|
28
|
+
success: true,
|
|
29
|
+
message: 'Environments retrieved',
|
|
30
|
+
environments: [],
|
|
31
|
+
};
|
|
32
|
+
const customUrl = 'https://staging.datalayer.run';
|
|
33
|
+
vi.mocked(requestDatalayerAPI).mockResolvedValueOnce(mockResponse);
|
|
34
|
+
const result = await environments.listEnvironments(MOCK_JWT_TOKEN, customUrl);
|
|
35
|
+
expect(result).toEqual(mockResponse);
|
|
36
|
+
expect(requestDatalayerAPI).toHaveBeenCalledWith({
|
|
37
|
+
url: `${customUrl}/api/runtimes/v1/environments`,
|
|
38
|
+
method: 'GET',
|
|
39
|
+
token: MOCK_JWT_TOKEN,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
it('should throw error when token is missing', async () => {
|
|
43
|
+
await expect(environments.listEnvironments('')).rejects.toThrow('Authentication token is required');
|
|
44
|
+
expect(requestDatalayerAPI).not.toHaveBeenCalled();
|
|
45
|
+
});
|
|
46
|
+
it('should throw error when token is null', async () => {
|
|
47
|
+
// @ts-expect-error Testing null token
|
|
48
|
+
await expect(environments.listEnvironments(null)).rejects.toThrow('Authentication token is required');
|
|
49
|
+
expect(requestDatalayerAPI).not.toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
it('should throw error when token is undefined', async () => {
|
|
52
|
+
// @ts-expect-error Testing undefined token
|
|
53
|
+
await expect(environments.listEnvironments(undefined)).rejects.toThrow('Authentication token is required');
|
|
54
|
+
expect(requestDatalayerAPI).not.toHaveBeenCalled();
|
|
55
|
+
});
|
|
56
|
+
it('should throw error when token is only whitespace', async () => {
|
|
57
|
+
await expect(environments.listEnvironments(' ')).rejects.toThrow('Authentication token is required');
|
|
58
|
+
expect(requestDatalayerAPI).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
it('should handle API errors properly', async () => {
|
|
61
|
+
const mockError = new Error('Network error');
|
|
62
|
+
vi.mocked(requestDatalayerAPI).mockRejectedValueOnce(mockError);
|
|
63
|
+
await expect(environments.listEnvironments(MOCK_JWT_TOKEN)).rejects.toThrow('Network error');
|
|
64
|
+
});
|
|
65
|
+
it('should handle empty environments list', async () => {
|
|
66
|
+
const mockResponse = {
|
|
67
|
+
success: true,
|
|
68
|
+
message: 'No environments available',
|
|
69
|
+
environments: [],
|
|
70
|
+
};
|
|
71
|
+
vi.mocked(requestDatalayerAPI).mockResolvedValueOnce(mockResponse);
|
|
72
|
+
const result = await environments.listEnvironments(MOCK_JWT_TOKEN);
|
|
73
|
+
expect(result).toEqual(mockResponse);
|
|
74
|
+
expect(result.environments).toHaveLength(0);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -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('Runtimes 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: 'Runtimes 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/runtimes/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/runtimes/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 {};
|