@cloudflare/sandbox 0.4.4 → 0.4.6
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/.turbo/turbo-build.log +16 -11
- package/CHANGELOG.md +12 -0
- package/Dockerfile +6 -0
- package/dist/chunk-UZQBJBJF.js +7 -0
- package/dist/chunk-UZQBJBJF.js.map +1 -0
- package/dist/{chunk-2P3MDMNJ.js → chunk-YEZBBFK7.js} +55 -2
- package/dist/chunk-YEZBBFK7.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/interpreter.d.ts +1 -1
- package/dist/request-handler.d.ts +1 -1
- package/dist/request-handler.js +2 -1
- package/dist/{sandbox-CZTMzV2R.d.ts → sandbox-DMlNr93l.d.ts} +14 -5
- package/dist/sandbox.d.ts +1 -1
- package/dist/sandbox.js +2 -1
- package/dist/version.d.ts +8 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/package.json +4 -4
- package/src/clients/index.ts +1 -0
- package/src/clients/utility-client.ts +25 -0
- package/src/sandbox.ts +66 -5
- package/src/version.ts +6 -0
- package/tests/get-sandbox.test.ts +110 -0
- package/tests/utility-client.test.ts +67 -1
- package/tests/version.test.ts +16 -0
- package/dist/chunk-2P3MDMNJ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
UtilityClient,
|
|
14
14
|
getSandbox,
|
|
15
15
|
proxyToSandbox
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YEZBBFK7.js";
|
|
17
17
|
import {
|
|
18
18
|
CodeInterpreter,
|
|
19
19
|
Execution,
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
parseSSEStream,
|
|
35
35
|
responseToAsyncIterable
|
|
36
36
|
} from "./chunk-EKSWCBCA.js";
|
|
37
|
+
import "./chunk-UZQBJBJF.js";
|
|
37
38
|
export {
|
|
38
39
|
CodeInterpreter,
|
|
39
40
|
CommandClient,
|
package/dist/interpreter.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CreateContextOptions, CodeContext, RunCodeOptions, Execution } from '@repo/shared';
|
|
2
|
-
import { b as Sandbox } from './sandbox-
|
|
2
|
+
import { b as Sandbox } from './sandbox-DMlNr93l.js';
|
|
3
3
|
import 'cloudflare:workers';
|
|
4
4
|
import '@cloudflare/containers';
|
|
5
5
|
|
package/dist/request-handler.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isLocalhostPattern,
|
|
3
3
|
proxyToSandbox
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YEZBBFK7.js";
|
|
5
5
|
import "./chunk-JXZMAU2C.js";
|
|
6
6
|
import "./chunk-Z532A7QC.js";
|
|
7
7
|
import "./chunk-EKSWCBCA.js";
|
|
8
|
+
import "./chunk-UZQBJBJF.js";
|
|
8
9
|
export {
|
|
9
10
|
isLocalhostPattern,
|
|
10
11
|
proxyToSandbox
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _repo_shared from '@repo/shared';
|
|
2
|
-
import { Logger, MkdirResult, WriteFileResult, ReadFileResult, DeleteFileResult, RenameFileResult, MoveFileResult, ListFilesOptions, ListFilesResult, GitCheckoutResult, CreateContextOptions, CodeContext, OutputMessage, Result, ExecutionError, PortExposeResult, PortCloseResult, PortListResult, ProcessStartResult, ProcessListResult, ProcessInfoResult, ProcessKillResult, ProcessCleanupResult, ProcessLogsResult, ISandbox, ExecOptions, ExecResult, ProcessOptions, Process, StreamOptions, SessionOptions, ExecutionSession, RunCodeOptions, ExecutionResult } from '@repo/shared';
|
|
2
|
+
import { Logger, MkdirResult, WriteFileResult, ReadFileResult, DeleteFileResult, RenameFileResult, MoveFileResult, ListFilesOptions, ListFilesResult, GitCheckoutResult, CreateContextOptions, CodeContext, OutputMessage, Result, ExecutionError, PortExposeResult, PortCloseResult, PortListResult, ProcessStartResult, ProcessListResult, ProcessInfoResult, ProcessKillResult, ProcessCleanupResult, ProcessLogsResult, ISandbox, ExecOptions, ExecResult, ProcessOptions, Process, StreamOptions, SessionOptions, ExecutionSession, RunCodeOptions, ExecutionResult, SandboxOptions } from '@repo/shared';
|
|
3
3
|
import { DurableObject } from 'cloudflare:workers';
|
|
4
4
|
import { Container } from '@cloudflare/containers';
|
|
5
5
|
|
|
@@ -418,6 +418,11 @@ declare class UtilityClient extends BaseHttpClient {
|
|
|
418
418
|
* @param options - Session configuration (id, env, cwd)
|
|
419
419
|
*/
|
|
420
420
|
createSession(options: CreateSessionRequest): Promise<CreateSessionResponse>;
|
|
421
|
+
/**
|
|
422
|
+
* Get the container version
|
|
423
|
+
* Returns the version embedded in the Docker image during build
|
|
424
|
+
*/
|
|
425
|
+
getVersion(): Promise<string>;
|
|
421
426
|
}
|
|
422
427
|
|
|
423
428
|
/**
|
|
@@ -435,12 +440,10 @@ declare class SandboxClient {
|
|
|
435
440
|
constructor(options: HttpClientOptions);
|
|
436
441
|
}
|
|
437
442
|
|
|
438
|
-
declare function getSandbox(ns: DurableObjectNamespace<Sandbox>, id: string, options?:
|
|
439
|
-
baseUrl: string;
|
|
440
|
-
}): DurableObjectStub<Sandbox<unknown>>;
|
|
443
|
+
declare function getSandbox(ns: DurableObjectNamespace<Sandbox>, id: string, options?: SandboxOptions): DurableObjectStub<Sandbox<unknown>>;
|
|
441
444
|
declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
442
445
|
defaultPort: number;
|
|
443
|
-
sleepAfter: string;
|
|
446
|
+
sleepAfter: string | number;
|
|
444
447
|
client: SandboxClient;
|
|
445
448
|
private codeInterpreter;
|
|
446
449
|
private sandboxName;
|
|
@@ -452,12 +455,18 @@ declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox
|
|
|
452
455
|
constructor(ctx: DurableObject['ctx'], env: Env);
|
|
453
456
|
setSandboxName(name: string): Promise<void>;
|
|
454
457
|
setBaseUrl(baseUrl: string): Promise<void>;
|
|
458
|
+
setSleepAfter(sleepAfter: string | number): Promise<void>;
|
|
455
459
|
setEnvVars(envVars: Record<string, string>): Promise<void>;
|
|
456
460
|
/**
|
|
457
461
|
* Cleanup and destroy the sandbox container
|
|
458
462
|
*/
|
|
459
463
|
destroy(): Promise<void>;
|
|
460
464
|
onStart(): void;
|
|
465
|
+
/**
|
|
466
|
+
* Check if the container version matches the SDK version
|
|
467
|
+
* Logs a warning if there's a mismatch
|
|
468
|
+
*/
|
|
469
|
+
private checkVersionCompatibility;
|
|
461
470
|
onStop(): void;
|
|
462
471
|
onError(error: unknown): void;
|
|
463
472
|
fetch(request: Request): Promise<Response>;
|
package/dist/sandbox.d.ts
CHANGED
package/dist/sandbox.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Sandbox,
|
|
3
3
|
getSandbox
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YEZBBFK7.js";
|
|
5
5
|
import "./chunk-JXZMAU2C.js";
|
|
6
6
|
import "./chunk-Z532A7QC.js";
|
|
7
7
|
import "./chunk-EKSWCBCA.js";
|
|
8
|
+
import "./chunk-UZQBJBJF.js";
|
|
8
9
|
export {
|
|
9
10
|
Sandbox,
|
|
10
11
|
getSandbox
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK version - automatically synchronized with package.json by Changesets
|
|
3
|
+
* This file is auto-updated by .github/changeset-version.ts during releases
|
|
4
|
+
* DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
|
|
5
|
+
*/
|
|
6
|
+
declare const SDK_VERSION = "0.4.6";
|
|
7
|
+
|
|
8
|
+
export { SDK_VERSION };
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudflare/sandbox",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/cloudflare/sandbox-sdk"
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"check": "biome check && npm run typecheck",
|
|
25
25
|
"fix": "biome check --fix && npm run typecheck",
|
|
26
26
|
"typecheck": "tsc --noEmit",
|
|
27
|
-
"docker:local": "cd ../.. && docker build -f packages/sandbox/Dockerfile -t cloudflare/sandbox-test:$npm_package_version .",
|
|
28
|
-
"docker:publish": "cd ../.. && docker buildx build --platform linux/amd64,linux/arm64 -f packages/sandbox/Dockerfile -t cloudflare/sandbox:$npm_package_version --push .",
|
|
29
|
-
"docker:publish:beta": "cd ../.. && docker buildx build --platform linux/amd64,linux/arm64 -f packages/sandbox/Dockerfile -t cloudflare/sandbox:$npm_package_version-beta --push .",
|
|
27
|
+
"docker:local": "cd ../.. && docker build -f packages/sandbox/Dockerfile --build-arg SANDBOX_VERSION=$npm_package_version -t cloudflare/sandbox-test:$npm_package_version .",
|
|
28
|
+
"docker:publish": "cd ../.. && docker buildx build --platform linux/amd64,linux/arm64 -f packages/sandbox/Dockerfile --build-arg SANDBOX_VERSION=$npm_package_version -t cloudflare/sandbox:$npm_package_version --push .",
|
|
29
|
+
"docker:publish:beta": "cd ../.. && docker buildx build --platform linux/amd64,linux/arm64 -f packages/sandbox/Dockerfile --build-arg SANDBOX_VERSION=$npm_package_version -t cloudflare/sandbox:$npm_package_version-beta --push .",
|
|
30
30
|
"test": "vitest run --config vitest.config.ts",
|
|
31
31
|
"test:e2e": "cd ../.. && vitest run --config vitest.e2e.config.ts \"$@\""
|
|
32
32
|
},
|
package/src/clients/index.ts
CHANGED
|
@@ -17,6 +17,13 @@ export interface CommandsResponse extends BaseApiResponse {
|
|
|
17
17
|
count: number;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Response interface for getting container version
|
|
22
|
+
*/
|
|
23
|
+
export interface VersionResponse extends BaseApiResponse {
|
|
24
|
+
version: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
/**
|
|
21
28
|
* Request interface for creating sessions
|
|
22
29
|
*/
|
|
@@ -91,4 +98,22 @@ export class UtilityClient extends BaseHttpClient {
|
|
|
91
98
|
throw error;
|
|
92
99
|
}
|
|
93
100
|
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get the container version
|
|
104
|
+
* Returns the version embedded in the Docker image during build
|
|
105
|
+
*/
|
|
106
|
+
async getVersion(): Promise<string> {
|
|
107
|
+
try {
|
|
108
|
+
const response = await this.get<VersionResponse>('/api/version');
|
|
109
|
+
|
|
110
|
+
this.logSuccess('Version retrieved', response.version);
|
|
111
|
+
return response.version;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
// If version endpoint doesn't exist (old container), return 'unknown'
|
|
114
|
+
// This allows for backward compatibility
|
|
115
|
+
this.logger.debug('Failed to get container version (may be old container)', { error });
|
|
116
|
+
return 'unknown';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
94
119
|
}
|
package/src/sandbox.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
ProcessOptions,
|
|
14
14
|
ProcessStatus,
|
|
15
15
|
RunCodeOptions,
|
|
16
|
+
SandboxOptions,
|
|
16
17
|
SessionOptions,
|
|
17
18
|
StreamOptions
|
|
18
19
|
} from "@repo/shared";
|
|
@@ -28,25 +29,32 @@ import {
|
|
|
28
29
|
validatePort
|
|
29
30
|
} from "./security";
|
|
30
31
|
import { parseSSEStream } from "./sse-parser";
|
|
32
|
+
import { SDK_VERSION } from "./version";
|
|
31
33
|
|
|
32
|
-
export function getSandbox(
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
export function getSandbox(
|
|
35
|
+
ns: DurableObjectNamespace<Sandbox>,
|
|
36
|
+
id: string,
|
|
37
|
+
options?: SandboxOptions
|
|
38
|
+
) {
|
|
35
39
|
const stub = getContainer(ns, id);
|
|
36
40
|
|
|
37
41
|
// Store the name on first access
|
|
38
42
|
stub.setSandboxName?.(id);
|
|
39
43
|
|
|
40
|
-
if(options?.baseUrl) {
|
|
44
|
+
if (options?.baseUrl) {
|
|
41
45
|
stub.setBaseUrl(options.baseUrl);
|
|
42
46
|
}
|
|
43
47
|
|
|
48
|
+
if (options?.sleepAfter !== undefined) {
|
|
49
|
+
stub.setSleepAfter(options.sleepAfter);
|
|
50
|
+
}
|
|
51
|
+
|
|
44
52
|
return stub;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
48
56
|
defaultPort = 3000; // Default port for the container's Bun server
|
|
49
|
-
sleepAfter = "
|
|
57
|
+
sleepAfter: string | number = "10m"; // Sleep the sandbox if no requests are made in this timeframe
|
|
50
58
|
|
|
51
59
|
client: SandboxClient;
|
|
52
60
|
private codeInterpreter: CodeInterpreter;
|
|
@@ -118,6 +126,11 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
|
|
129
|
+
// RPC method to set the sleep timeout
|
|
130
|
+
async setSleepAfter(sleepAfter: string | number): Promise<void> {
|
|
131
|
+
this.sleepAfter = sleepAfter;
|
|
132
|
+
}
|
|
133
|
+
|
|
121
134
|
// RPC method to set environment variables
|
|
122
135
|
async setEnvVars(envVars: Record<string, string>): Promise<void> {
|
|
123
136
|
// Update local state for new sessions
|
|
@@ -149,6 +162,54 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
149
162
|
|
|
150
163
|
override onStart() {
|
|
151
164
|
this.logger.debug('Sandbox started');
|
|
165
|
+
|
|
166
|
+
// Check version compatibility asynchronously (don't block startup)
|
|
167
|
+
this.checkVersionCompatibility().catch(error => {
|
|
168
|
+
this.logger.error('Version compatibility check failed', error instanceof Error ? error : new Error(String(error)));
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Check if the container version matches the SDK version
|
|
174
|
+
* Logs a warning if there's a mismatch
|
|
175
|
+
*/
|
|
176
|
+
private async checkVersionCompatibility(): Promise<void> {
|
|
177
|
+
try {
|
|
178
|
+
// Get the SDK version (imported from version.ts)
|
|
179
|
+
const sdkVersion = SDK_VERSION;
|
|
180
|
+
|
|
181
|
+
// Get container version
|
|
182
|
+
const containerVersion = await this.client.utils.getVersion();
|
|
183
|
+
|
|
184
|
+
// If container version is unknown, it's likely an old container without the endpoint
|
|
185
|
+
if (containerVersion === 'unknown') {
|
|
186
|
+
this.logger.warn(
|
|
187
|
+
'Container version check: Container version could not be determined. ' +
|
|
188
|
+
'This may indicate an outdated container image. ' +
|
|
189
|
+
'Please update your container to match SDK version ' + sdkVersion
|
|
190
|
+
);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Check if versions match
|
|
195
|
+
if (containerVersion !== sdkVersion) {
|
|
196
|
+
const message =
|
|
197
|
+
`Version mismatch detected! SDK version (${sdkVersion}) does not match ` +
|
|
198
|
+
`container version (${containerVersion}). This may cause compatibility issues. ` +
|
|
199
|
+
`Please update your container image to version ${sdkVersion}`;
|
|
200
|
+
|
|
201
|
+
// Log warning - we can't reliably detect dev vs prod environment in Durable Objects
|
|
202
|
+
// so we always use warning level as requested by the user
|
|
203
|
+
this.logger.warn(message);
|
|
204
|
+
} else {
|
|
205
|
+
this.logger.debug('Version check passed', { sdkVersion, containerVersion });
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
// Don't fail the sandbox initialization if version check fails
|
|
209
|
+
this.logger.debug('Version compatibility check encountered an error', {
|
|
210
|
+
error: error instanceof Error ? error.message : String(error)
|
|
211
|
+
});
|
|
212
|
+
}
|
|
152
213
|
}
|
|
153
214
|
|
|
154
215
|
override onStop() {
|
package/src/version.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK version - automatically synchronized with package.json by Changesets
|
|
3
|
+
* This file is auto-updated by .github/changeset-version.ts during releases
|
|
4
|
+
* DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
|
|
5
|
+
*/
|
|
6
|
+
export const SDK_VERSION = '0.4.6';
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { getSandbox } from '../src/sandbox';
|
|
3
|
+
|
|
4
|
+
// Mock the Container module
|
|
5
|
+
vi.mock('@cloudflare/containers', () => ({
|
|
6
|
+
Container: class Container {
|
|
7
|
+
ctx: any;
|
|
8
|
+
env: any;
|
|
9
|
+
sleepAfter: string | number = '10m';
|
|
10
|
+
constructor(ctx: any, env: any) {
|
|
11
|
+
this.ctx = ctx;
|
|
12
|
+
this.env = env;
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
getContainer: vi.fn(),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
describe('getSandbox', () => {
|
|
19
|
+
let mockStub: any;
|
|
20
|
+
let mockGetContainer: any;
|
|
21
|
+
|
|
22
|
+
beforeEach(async () => {
|
|
23
|
+
vi.clearAllMocks();
|
|
24
|
+
|
|
25
|
+
// Create a fresh mock stub for each test
|
|
26
|
+
mockStub = {
|
|
27
|
+
sleepAfter: '10m',
|
|
28
|
+
setSandboxName: vi.fn(),
|
|
29
|
+
setBaseUrl: vi.fn(),
|
|
30
|
+
setSleepAfter: vi.fn((value: string | number) => {
|
|
31
|
+
mockStub.sleepAfter = value;
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Mock getContainer to return our stub
|
|
36
|
+
const containers = await import('@cloudflare/containers');
|
|
37
|
+
mockGetContainer = vi.mocked(containers.getContainer);
|
|
38
|
+
mockGetContainer.mockReturnValue(mockStub);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should create a sandbox instance with default sleepAfter', () => {
|
|
42
|
+
const mockNamespace = {} as any;
|
|
43
|
+
const sandbox = getSandbox(mockNamespace, 'test-sandbox');
|
|
44
|
+
|
|
45
|
+
expect(sandbox).toBeDefined();
|
|
46
|
+
expect(sandbox.setSandboxName).toHaveBeenCalledWith('test-sandbox');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should apply sleepAfter option when provided as string', () => {
|
|
50
|
+
const mockNamespace = {} as any;
|
|
51
|
+
const sandbox = getSandbox(mockNamespace, 'test-sandbox', {
|
|
52
|
+
sleepAfter: '5m',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(sandbox.sleepAfter).toBe('5m');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should apply sleepAfter option when provided as number', () => {
|
|
59
|
+
const mockNamespace = {} as any;
|
|
60
|
+
const sandbox = getSandbox(mockNamespace, 'test-sandbox', {
|
|
61
|
+
sleepAfter: 300, // 5 minutes in seconds
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
expect(sandbox.sleepAfter).toBe(300);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should apply baseUrl option when provided', () => {
|
|
68
|
+
const mockNamespace = {} as any;
|
|
69
|
+
const sandbox = getSandbox(mockNamespace, 'test-sandbox', {
|
|
70
|
+
baseUrl: 'https://example.com',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
expect(sandbox.setBaseUrl).toHaveBeenCalledWith('https://example.com');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should apply both sleepAfter and baseUrl options together', () => {
|
|
77
|
+
const mockNamespace = {} as any;
|
|
78
|
+
const sandbox = getSandbox(mockNamespace, 'test-sandbox', {
|
|
79
|
+
sleepAfter: '10m',
|
|
80
|
+
baseUrl: 'https://example.com',
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(sandbox.sleepAfter).toBe('10m');
|
|
84
|
+
expect(sandbox.setBaseUrl).toHaveBeenCalledWith('https://example.com');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should not apply sleepAfter when not provided', () => {
|
|
88
|
+
const mockNamespace = {} as any;
|
|
89
|
+
const sandbox = getSandbox(mockNamespace, 'test-sandbox');
|
|
90
|
+
|
|
91
|
+
// Should remain default value from Container
|
|
92
|
+
expect(sandbox.sleepAfter).toBe('10m');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should accept various time string formats for sleepAfter', () => {
|
|
96
|
+
const mockNamespace = {} as any;
|
|
97
|
+
const testCases = ['30s', '1m', '10m', '1h', '2h'];
|
|
98
|
+
|
|
99
|
+
for (const timeString of testCases) {
|
|
100
|
+
// Reset the mock stub for each iteration
|
|
101
|
+
mockStub.sleepAfter = '3m';
|
|
102
|
+
|
|
103
|
+
const sandbox = getSandbox(mockNamespace, `test-sandbox-${timeString}`, {
|
|
104
|
+
sleepAfter: timeString,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
expect(sandbox.sleepAfter).toBe(timeString);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import type {
|
|
3
3
|
CommandsResponse,
|
|
4
|
-
PingResponse
|
|
4
|
+
PingResponse,
|
|
5
|
+
VersionResponse
|
|
5
6
|
} from '../src/clients';
|
|
6
7
|
import { UtilityClient } from '../src/clients/utility-client';
|
|
7
8
|
import {
|
|
@@ -25,6 +26,13 @@ const mockCommandsResponse = (commands: string[], overrides: Partial<CommandsRes
|
|
|
25
26
|
...overrides
|
|
26
27
|
});
|
|
27
28
|
|
|
29
|
+
const mockVersionResponse = (version: string = '0.4.5', overrides: Partial<VersionResponse> = {}): VersionResponse => ({
|
|
30
|
+
success: true,
|
|
31
|
+
version,
|
|
32
|
+
timestamp: '2023-01-01T00:00:00Z',
|
|
33
|
+
...overrides
|
|
34
|
+
});
|
|
35
|
+
|
|
28
36
|
describe('UtilityClient', () => {
|
|
29
37
|
let client: UtilityClient;
|
|
30
38
|
let mockFetch: ReturnType<typeof vi.fn>;
|
|
@@ -249,6 +257,64 @@ describe('UtilityClient', () => {
|
|
|
249
257
|
});
|
|
250
258
|
});
|
|
251
259
|
|
|
260
|
+
describe('version checking', () => {
|
|
261
|
+
it('should get container version successfully', async () => {
|
|
262
|
+
mockFetch.mockResolvedValue(new Response(
|
|
263
|
+
JSON.stringify(mockVersionResponse('0.4.5')),
|
|
264
|
+
{ status: 200 }
|
|
265
|
+
));
|
|
266
|
+
|
|
267
|
+
const result = await client.getVersion();
|
|
268
|
+
|
|
269
|
+
expect(result).toBe('0.4.5');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('should handle different version formats', async () => {
|
|
273
|
+
const versions = ['1.0.0', '2.5.3-beta', '0.0.1', '10.20.30'];
|
|
274
|
+
|
|
275
|
+
for (const version of versions) {
|
|
276
|
+
mockFetch.mockResolvedValueOnce(new Response(
|
|
277
|
+
JSON.stringify(mockVersionResponse(version)),
|
|
278
|
+
{ status: 200 }
|
|
279
|
+
));
|
|
280
|
+
|
|
281
|
+
const result = await client.getVersion();
|
|
282
|
+
expect(result).toBe(version);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('should return "unknown" when version endpoint does not exist (backward compatibility)', async () => {
|
|
287
|
+
// Simulate 404 or other error for old containers
|
|
288
|
+
mockFetch.mockResolvedValue(new Response(
|
|
289
|
+
JSON.stringify({ error: 'Not Found' }),
|
|
290
|
+
{ status: 404 }
|
|
291
|
+
));
|
|
292
|
+
|
|
293
|
+
const result = await client.getVersion();
|
|
294
|
+
|
|
295
|
+
expect(result).toBe('unknown');
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should return "unknown" on network failure (backward compatibility)', async () => {
|
|
299
|
+
mockFetch.mockRejectedValue(new Error('Network connection failed'));
|
|
300
|
+
|
|
301
|
+
const result = await client.getVersion();
|
|
302
|
+
|
|
303
|
+
expect(result).toBe('unknown');
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should handle version response with unknown value', async () => {
|
|
307
|
+
mockFetch.mockResolvedValue(new Response(
|
|
308
|
+
JSON.stringify(mockVersionResponse('unknown')),
|
|
309
|
+
{ status: 200 }
|
|
310
|
+
));
|
|
311
|
+
|
|
312
|
+
const result = await client.getVersion();
|
|
313
|
+
|
|
314
|
+
expect(result).toBe('unknown');
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
|
|
252
318
|
describe('constructor options', () => {
|
|
253
319
|
it('should initialize with minimal options', () => {
|
|
254
320
|
const minimalClient = new UtilityClient();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import packageJson from '../package.json';
|
|
3
|
+
import { SDK_VERSION } from '../src/version';
|
|
4
|
+
|
|
5
|
+
describe('Version Sync', () => {
|
|
6
|
+
test('SDK_VERSION matches package.json version', () => {
|
|
7
|
+
// Verify versions match
|
|
8
|
+
expect(SDK_VERSION).toBe(packageJson.version);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('SDK_VERSION is a valid semver version', () => {
|
|
12
|
+
// Check if version matches semver pattern (major.minor.patch)
|
|
13
|
+
const semverPattern = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
|
|
14
|
+
expect(SDK_VERSION).toMatch(semverPattern);
|
|
15
|
+
});
|
|
16
|
+
});
|