@cloudflare/sandbox 0.4.5 → 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.
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  isLocalhostPattern,
3
3
  proxyToSandbox
4
- } from "./chunk-WK36EMRB.js";
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
@@ -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
  /**
@@ -457,6 +462,11 @@ declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox
457
462
  */
458
463
  destroy(): Promise<void>;
459
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;
460
470
  onStop(): void;
461
471
  onError(error: unknown): void;
462
472
  fetch(request: Request): Promise<Response>;
package/dist/sandbox.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import '@repo/shared';
2
2
  import 'cloudflare:workers';
3
3
  import '@cloudflare/containers';
4
- export { b as Sandbox, g as getSandbox } from './sandbox-B1TT7PZP.js';
4
+ export { b as Sandbox, g as getSandbox } from './sandbox-DMlNr93l.js';
package/dist/sandbox.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  Sandbox,
3
3
  getSandbox
4
- } from "./chunk-WK36EMRB.js";
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 };
@@ -0,0 +1,7 @@
1
+ import {
2
+ SDK_VERSION
3
+ } from "./chunk-UZQBJBJF.js";
4
+ export {
5
+ SDK_VERSION
6
+ };
7
+ //# sourceMappingURL=version.js.map
@@ -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.5",
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
  },
@@ -59,5 +59,6 @@ export type {
59
59
  export type {
60
60
  CommandsResponse,
61
61
  PingResponse,
62
+ VersionResponse,
62
63
  } from './utility-client';
63
64
  export { UtilityClient } from './utility-client';
@@ -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
@@ -29,6 +29,7 @@ import {
29
29
  validatePort
30
30
  } from "./security";
31
31
  import { parseSSEStream } from "./sse-parser";
32
+ import { SDK_VERSION } from "./version";
32
33
 
33
34
  export function getSandbox(
34
35
  ns: DurableObjectNamespace<Sandbox>,
@@ -161,6 +162,54 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
161
162
 
162
163
  override onStart() {
163
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
+ }
164
213
  }
165
214
 
166
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';
@@ -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
+ });