@cloudflare/sandbox 0.4.10 → 0.4.12
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 +12 -12
- package/CHANGELOG.md +12 -0
- package/dist/chunk-UJ3TV4M6.js +7 -0
- package/dist/{chunk-E3RB3JOS.js.map → chunk-UJ3TV4M6.js.map} +1 -1
- package/dist/{chunk-I6PJN47O.js → chunk-YE265ASX.js} +30 -2
- package/dist/chunk-YE265ASX.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/interpreter.d.ts +1 -1
- package/dist/request-handler.d.ts +1 -1
- package/dist/request-handler.js +2 -2
- package/dist/{sandbox-DWQVgVTY.d.ts → sandbox-CLZWpfGc.d.ts} +10 -0
- package/dist/sandbox.d.ts +1 -1
- package/dist/sandbox.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/src/request-handler.ts +1 -1
- package/src/sandbox.ts +35 -3
- package/src/version.ts +1 -1
- package/tests/get-sandbox.test.ts +39 -0
- package/tests/sandbox.test.ts +2 -2
- package/dist/chunk-E3RB3JOS.js +0 -7
- package/dist/chunk-I6PJN47O.js.map +0 -1
package/dist/request-handler.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isLocalhostPattern,
|
|
3
3
|
proxyToSandbox
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YE265ASX.js";
|
|
5
5
|
import "./chunk-JXZMAU2C.js";
|
|
6
6
|
import "./chunk-Z532A7QC.js";
|
|
7
7
|
import "./chunk-EKSWCBCA.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-UJ3TV4M6.js";
|
|
9
9
|
export {
|
|
10
10
|
isLocalhostPattern,
|
|
11
11
|
proxyToSandbox
|
|
@@ -458,10 +458,12 @@ declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox
|
|
|
458
458
|
private defaultSession;
|
|
459
459
|
envVars: Record<string, string>;
|
|
460
460
|
private logger;
|
|
461
|
+
private keepAliveEnabled;
|
|
461
462
|
constructor(ctx: DurableObject['ctx'], env: Env);
|
|
462
463
|
setSandboxName(name: string): Promise<void>;
|
|
463
464
|
setBaseUrl(baseUrl: string): Promise<void>;
|
|
464
465
|
setSleepAfter(sleepAfter: string | number): Promise<void>;
|
|
466
|
+
setKeepAlive(keepAlive: boolean): Promise<void>;
|
|
465
467
|
setEnvVars(envVars: Record<string, string>): Promise<void>;
|
|
466
468
|
/**
|
|
467
469
|
* Cleanup and destroy the sandbox container
|
|
@@ -475,6 +477,11 @@ declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox
|
|
|
475
477
|
private checkVersionCompatibility;
|
|
476
478
|
onStop(): void;
|
|
477
479
|
onError(error: unknown): void;
|
|
480
|
+
/**
|
|
481
|
+
* Override onActivityExpired to prevent automatic shutdown when keepAlive is enabled
|
|
482
|
+
* When keepAlive is disabled, calls parent implementation which stops the container
|
|
483
|
+
*/
|
|
484
|
+
onActivityExpired(): Promise<void>;
|
|
478
485
|
fetch(request: Request): Promise<Response>;
|
|
479
486
|
private determinePort;
|
|
480
487
|
/**
|
|
@@ -516,6 +523,9 @@ declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox
|
|
|
516
523
|
* Internal session-aware execStream implementation
|
|
517
524
|
*/
|
|
518
525
|
private execStreamWithSession;
|
|
526
|
+
/**
|
|
527
|
+
* Stream logs from a background process as a ReadableStream.
|
|
528
|
+
*/
|
|
519
529
|
streamProcessLogs(processId: string, options?: {
|
|
520
530
|
signal?: AbortSignal;
|
|
521
531
|
}): Promise<ReadableStream<Uint8Array>>;
|
package/dist/sandbox.d.ts
CHANGED
package/dist/sandbox.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Sandbox,
|
|
3
3
|
getSandbox
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YE265ASX.js";
|
|
5
5
|
import "./chunk-JXZMAU2C.js";
|
|
6
6
|
import "./chunk-Z532A7QC.js";
|
|
7
7
|
import "./chunk-EKSWCBCA.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-UJ3TV4M6.js";
|
|
9
9
|
export {
|
|
10
10
|
Sandbox,
|
|
11
11
|
getSandbox
|
package/dist/version.d.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* This file is auto-updated by .github/changeset-version.ts during releases
|
|
4
4
|
* DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
|
|
5
5
|
*/
|
|
6
|
-
declare const SDK_VERSION = "0.4.
|
|
6
|
+
declare const SDK_VERSION = "0.4.12";
|
|
7
7
|
|
|
8
8
|
export { SDK_VERSION };
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudflare/sandbox",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.12",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/cloudflare/sandbox-sdk"
|
|
7
7
|
},
|
|
8
8
|
"description": "A sandboxed environment for running commands",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@cloudflare/containers": "^0.0.
|
|
10
|
+
"@cloudflare/containers": "^0.0.29"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"@repo/shared": "^0.0.0"
|
package/src/request-handler.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createLogger, type LogContext, TraceContext } from "@repo/shared";
|
|
2
1
|
import { switchPort } from "@cloudflare/containers";
|
|
2
|
+
import { createLogger, type LogContext, TraceContext } from "@repo/shared";
|
|
3
3
|
import { getSandbox, type Sandbox } from "./sandbox";
|
|
4
4
|
import {
|
|
5
5
|
sanitizeSandboxId,
|
package/src/sandbox.ts
CHANGED
|
@@ -49,6 +49,10 @@ export function getSandbox(
|
|
|
49
49
|
stub.setSleepAfter(options.sleepAfter);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
if (options?.keepAlive !== undefined) {
|
|
53
|
+
stub.setKeepAlive(options.keepAlive);
|
|
54
|
+
}
|
|
55
|
+
|
|
52
56
|
return stub;
|
|
53
57
|
}
|
|
54
58
|
|
|
@@ -64,6 +68,7 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
64
68
|
private defaultSession: string | null = null;
|
|
65
69
|
envVars: Record<string, string> = {};
|
|
66
70
|
private logger: ReturnType<typeof createLogger>;
|
|
71
|
+
private keepAliveEnabled: boolean = false;
|
|
67
72
|
|
|
68
73
|
constructor(ctx: DurableObject['ctx'], env: Env) {
|
|
69
74
|
super(ctx, env);
|
|
@@ -131,6 +136,16 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
131
136
|
this.sleepAfter = sleepAfter;
|
|
132
137
|
}
|
|
133
138
|
|
|
139
|
+
// RPC method to enable keepAlive mode
|
|
140
|
+
async setKeepAlive(keepAlive: boolean): Promise<void> {
|
|
141
|
+
this.keepAliveEnabled = keepAlive;
|
|
142
|
+
if (keepAlive) {
|
|
143
|
+
this.logger.info('KeepAlive mode enabled - container will stay alive until explicitly destroyed');
|
|
144
|
+
} else {
|
|
145
|
+
this.logger.info('KeepAlive mode disabled - container will timeout normally');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
134
149
|
// RPC method to set environment variables
|
|
135
150
|
async setEnvVars(envVars: Record<string, string>): Promise<void> {
|
|
136
151
|
// Update local state for new sessions
|
|
@@ -220,6 +235,22 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
220
235
|
this.logger.error('Sandbox error', error instanceof Error ? error : new Error(String(error)));
|
|
221
236
|
}
|
|
222
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Override onActivityExpired to prevent automatic shutdown when keepAlive is enabled
|
|
240
|
+
* When keepAlive is disabled, calls parent implementation which stops the container
|
|
241
|
+
*/
|
|
242
|
+
override async onActivityExpired(): Promise<void> {
|
|
243
|
+
if (this.keepAliveEnabled) {
|
|
244
|
+
this.logger.debug('Activity expired but keepAlive is enabled - container will stay alive');
|
|
245
|
+
// Do nothing - don't call stop(), container stays alive
|
|
246
|
+
} else {
|
|
247
|
+
// Default behavior: stop the container
|
|
248
|
+
this.logger.debug('Activity expired - stopping container');
|
|
249
|
+
await super.onActivityExpired();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
|
|
223
254
|
// Override fetch to route internal container requests to appropriate ports
|
|
224
255
|
override async fetch(request: Request): Promise<Response> {
|
|
225
256
|
// Extract or generate trace ID from request
|
|
@@ -327,7 +358,6 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
327
358
|
const startTime = Date.now();
|
|
328
359
|
const timestamp = new Date().toISOString();
|
|
329
360
|
|
|
330
|
-
// Handle timeout
|
|
331
361
|
let timeoutId: NodeJS.Timeout | undefined;
|
|
332
362
|
|
|
333
363
|
try {
|
|
@@ -592,8 +622,7 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
592
622
|
};
|
|
593
623
|
}
|
|
594
624
|
|
|
595
|
-
|
|
596
|
-
// Streaming methods - return ReadableStream for RPC compatibility
|
|
625
|
+
// Streaming methods - return ReadableStream for RPC compatibility
|
|
597
626
|
async execStream(command: string, options?: StreamOptions): Promise<ReadableStream<Uint8Array>> {
|
|
598
627
|
// Check for cancellation
|
|
599
628
|
if (options?.signal?.aborted) {
|
|
@@ -617,6 +646,9 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
617
646
|
return this.client.commands.executeStream(command, sessionId);
|
|
618
647
|
}
|
|
619
648
|
|
|
649
|
+
/**
|
|
650
|
+
* Stream logs from a background process as a ReadableStream.
|
|
651
|
+
*/
|
|
620
652
|
async streamProcessLogs(processId: string, options?: { signal?: AbortSignal }): Promise<ReadableStream<Uint8Array>> {
|
|
621
653
|
// Check for cancellation
|
|
622
654
|
if (options?.signal?.aborted) {
|
package/src/version.ts
CHANGED
|
@@ -30,6 +30,7 @@ describe('getSandbox', () => {
|
|
|
30
30
|
setSleepAfter: vi.fn((value: string | number) => {
|
|
31
31
|
mockStub.sleepAfter = value;
|
|
32
32
|
}),
|
|
33
|
+
setKeepAlive: vi.fn(),
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
// Mock getContainer to return our stub
|
|
@@ -107,4 +108,42 @@ describe('getSandbox', () => {
|
|
|
107
108
|
expect(sandbox.sleepAfter).toBe(timeString);
|
|
108
109
|
}
|
|
109
110
|
});
|
|
111
|
+
|
|
112
|
+
it('should apply keepAlive option when provided as true', () => {
|
|
113
|
+
const mockNamespace = {} as any;
|
|
114
|
+
const sandbox = getSandbox(mockNamespace, 'test-sandbox', {
|
|
115
|
+
keepAlive: true,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(sandbox.setKeepAlive).toHaveBeenCalledWith(true);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should apply keepAlive option when provided as false', () => {
|
|
122
|
+
const mockNamespace = {} as any;
|
|
123
|
+
const sandbox = getSandbox(mockNamespace, 'test-sandbox', {
|
|
124
|
+
keepAlive: false,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(sandbox.setKeepAlive).toHaveBeenCalledWith(false);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should not call setKeepAlive when keepAlive option not provided', () => {
|
|
131
|
+
const mockNamespace = {} as any;
|
|
132
|
+
getSandbox(mockNamespace, 'test-sandbox');
|
|
133
|
+
|
|
134
|
+
expect(mockStub.setKeepAlive).not.toHaveBeenCalled();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should apply keepAlive alongside other options', () => {
|
|
138
|
+
const mockNamespace = {} as any;
|
|
139
|
+
const sandbox = getSandbox(mockNamespace, 'test-sandbox', {
|
|
140
|
+
sleepAfter: '5m',
|
|
141
|
+
baseUrl: 'https://example.com',
|
|
142
|
+
keepAlive: true,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(sandbox.sleepAfter).toBe('5m');
|
|
146
|
+
expect(sandbox.setBaseUrl).toHaveBeenCalledWith('https://example.com');
|
|
147
|
+
expect(sandbox.setKeepAlive).toHaveBeenCalledWith(true);
|
|
148
|
+
});
|
|
110
149
|
});
|
package/tests/sandbox.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { Container } from '@cloudflare/containers';
|
|
1
2
|
import type { DurableObjectState } from '@cloudflare/workers-types';
|
|
2
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
4
|
import { Sandbox } from '../src/sandbox';
|
|
4
|
-
import { Container } from '@cloudflare/containers';
|
|
5
5
|
|
|
6
6
|
// Mock dependencies before imports
|
|
7
7
|
vi.mock('./interpreter', () => ({
|
|
@@ -48,7 +48,7 @@ describe('Sandbox - Automatic Session Management', () => {
|
|
|
48
48
|
delete: vi.fn().mockResolvedValue(undefined),
|
|
49
49
|
list: vi.fn().mockResolvedValue(new Map()),
|
|
50
50
|
} as any,
|
|
51
|
-
blockConcurrencyWhile: vi.fn((
|
|
51
|
+
blockConcurrencyWhile: vi.fn().mockImplementation(<T>(callback: () => Promise<T>): Promise<T> => callback()),
|
|
52
52
|
id: {
|
|
53
53
|
toString: () => 'test-sandbox-id',
|
|
54
54
|
equals: vi.fn(),
|