@sandbox-kit/sandbox 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,70 +1,130 @@
1
- # Sandbox Kit for TypeScript
1
+ # `@sandbox-kit/sandbox`
2
2
 
3
- Core client package (`@sandbox-kit/sandbox`). Providers such as
4
- `@sandbox-kit/daytona` and `@sandbox-kit/modal` are published
5
- separately and plug into this module. Apps and providers share public
6
- `CreateOptions` / `ClientConfig` (`Config` plus `provider`): nested exclusive
7
- fields (`auth: { apiKey: … }`, `source: { image: … }`, `readiness: { command: … }`),
8
- plain maps/allowlists (`outboundCidrs: string[]`), and millisecond timeouts.
9
- `ErrorInfo.field` uses canonical protobuf paths (`CreateField*` / `ConfigField*` /
10
- `InfoField*`), matching Go. Closing the client releases local provider SDK
11
- resources only; it does not stop or delete cloud sandboxes.
3
+ Create and manage cloud sandboxes from one TypeScript API. Pick a provider
4
+ package (`@sandbox-kit/daytona` or `@sandbox-kit/modal`), construct a client,
5
+ then create or open sandboxes through the same methods.
12
6
 
13
- ## Public input → wire boundary
7
+ Closing a client or handle releases **local** SDK resources only. It does not
8
+ stop, terminate, or delete the remote sandbox.
14
9
 
15
- Applications and provider backends speak the **public** shapes above. Inside
16
- `Client`, requests are converted before Protovalidate and provider mapping:
10
+ ## Install
17
11
 
18
- 1. **Public input** — ms numbers, nested oneofs, `string[]` allowlists, plain
19
- `providerOptions` maps.
20
- 2. **`materialize*`** — package-private conversion to protobuf wire messages.
21
- 3. **Validate** — shared Protovalidate rules (`secure_endpoint` stays handwritten),
22
- then provider checks.
23
- 4. **Provider mappings** — native SDK calls using the validated wire request.
12
+ ```sh
13
+ npm install @sandbox-kit/sandbox @sandbox-kit/daytona
14
+ # or
15
+ npm install @sandbox-kit/sandbox @sandbox-kit/modal
16
+ ```
24
17
 
25
- Wire types stay package-private to the client.
18
+ Requires Node.js 20, 22, or 24.15+.
26
19
 
27
- ## Usage
20
+ ## Quick start
28
21
 
29
22
  ```ts
30
- import {
31
- Client,
32
- type ClientConfig,
33
- type CreateOptions,
34
- } from "@sandbox-kit/sandbox";
35
23
  import { daytona } from "@sandbox-kit/daytona";
24
+ import { Client } from "@sandbox-kit/sandbox";
36
25
 
37
- const config: ClientConfig = {
26
+ await using client = new Client({
38
27
  provider: daytona(),
39
28
  auth: { apiKey: { key: process.env.DAYTONA_API_KEY! } },
40
29
  timeout: 120_000,
41
- };
30
+ });
31
+
32
+ const sandbox = await client.create();
33
+ console.log(sandbox.id, client.providerName);
34
+ ```
35
+
36
+ Prefer `await using` when available. Otherwise call `await client.close()` in a
37
+ `finally` block.
38
+
39
+ ## Client configuration
40
+
41
+ Pass the provider on `ClientConfig`, then shared settings:
42
42
 
43
- const createOptions: CreateOptions = {
43
+ | Field | Purpose |
44
+ | ---------- | --------------------------------------------------------------- |
45
+ | `provider` | Provider factory (`daytona()`, `modal()`, …) |
46
+ | `auth` | One credential shape (`apiKey`, `bearerToken`, `tokenPair`, …) |
47
+ | `scope` | App, environment, organization, or project (provider-dependent) |
48
+ | `endpoint` | API URL when the provider supports it |
49
+ | `region` | Target or placement preference |
50
+ | `timeout` | Default operation deadline in **milliseconds** |
51
+
52
+ Omit `auth` when the provider SDK should resolve credentials from its own
53
+ environment. Provider-specific auth and scope rules live in each provider
54
+ package README.
55
+
56
+ ## Create a sandbox
57
+
58
+ ```ts
59
+ const sandbox = await client.create({
44
60
  source: { image: { reference: "daytonaio/playground:latest" } },
45
61
  provisioning: { timeout: 120_000 },
46
- };
62
+ });
63
+ ```
64
+
65
+ `create()` with no options uses the provider default when that is valid (for
66
+ example Daytona's default snapshot). Timeouts and delays are millisecond
67
+ numbers. Nested exclusive fields use shapes like `source: { image: … }` or
68
+ `auth: { apiKey: … }`.
69
+
70
+ ## Open an existing sandbox
47
71
 
48
- await using client = new Client(config);
49
- const sandbox = await client.create(createOptions);
50
- console.log(sandbox.id);
72
+ ```ts
73
+ const attached = await client.attach(id); // provider must support attach
74
+ const fetched = await client.get(id); // provider-verified lookup
51
75
  ```
52
76
 
53
- Prefer `await using` when the runtime supports explicit resource management;
54
- otherwise call `await client.close()` in `finally`. Both forms have identical
55
- cleanup semantics.
77
+ ## Sandbox handle
56
78
 
57
- ## Examples
79
+ | Method | Purpose |
80
+ | ---------------- | --------------------------------------------- |
81
+ | `id` | Sandbox identifier |
82
+ | `info()` | Copied metadata |
83
+ | `capabilities()` | Lifecycle operations this handle can run |
84
+ | `supports(...)` | Check one capability |
85
+ | `refresh` | Refresh metadata from the provider |
86
+ | `start` | Start |
87
+ | `stop` | Stop (`force` when supported) |
88
+ | `pause` | Pause |
89
+ | `archive` | Archive |
90
+ | `delete` | Delete (`wait` when supported) |
91
+ | `terminate` | Terminate (`wait` when supported) |
92
+ | `close` | Drop the local handle (not the cloud sandbox) |
58
93
 
59
- | Language | Index |
60
- | ---------- | ------------------------------------------------------------- |
61
- | TypeScript | [examples/typescript](../../../examples/typescript/README.md) |
62
- | Go | [examples/go](../../../examples/go/README.md) |
94
+ Unsupported operations throw before the provider call. Use `supports(...)` when
95
+ the sandbox class may differ (for example Daytona container vs VM).
63
96
 
64
- ```sh
65
- npm install @sandbox-kit/sandbox @sandbox-kit/daytona
66
- # or: npm install @sandbox-kit/sandbox @sandbox-kit/modal
97
+ ## Errors
98
+
99
+ Failures throw `SandboxError` with `kind`, `provider`, `operation`, `field`,
100
+ and `message`:
101
+
102
+ ```ts
103
+ import { Client, SandboxError } from "@sandbox-kit/sandbox";
104
+
105
+ try {
106
+ await client.create({ resources: { cpuCores: -1 } });
107
+ } catch (error) {
108
+ if (error instanceof SandboxError) {
109
+ console.error(error.kind, error.field, error.message);
110
+ } else {
111
+ throw error;
112
+ }
113
+ }
67
114
  ```
68
115
 
69
- See the [root README](../../../README.md) for a full create snippet and the
70
- [TypeScript workspace README](../README.md) for local development.
116
+ ## Providers
117
+
118
+ | Package | Role |
119
+ | ---------------------- | ----------------- |
120
+ | `@sandbox-kit/daytona` | Daytona sandboxes |
121
+ | `@sandbox-kit/modal` | Modal sandboxes |
122
+
123
+ ## Examples
124
+
125
+ Runnable projects:
126
+ [examples/typescript](https://github.com/sandbox-kit/kit/tree/main/examples/typescript).
127
+
128
+ ## License
129
+
130
+ MIT
@@ -1,128 +1,10 @@
1
- import { type MessageInitShape } from "@bufbuild/protobuf";
2
- import { ConfigSchema, type APIKeyCredentials as WireAPIKeyCredentials, type AuthConfig, type BearerTokenCredentials as WireBearerTokenCredentials, type OAuthCredentials as WireOAuthCredentials, type TokenPairCredentials as WireTokenPairCredentials } from "@sandbox-kit/contracts/client";
3
- import { ErrorKind as ProtoErrorKind } from "@sandbox-kit/contracts/sandbox";
4
- import { type ArchiveOptions, type CreateOptions, type CreateResult, type DeleteOptions, type ErrorInfo, type ExitResult, type LifecycleCapability, type PauseOptions, type SandboxInfo, type StartOptions, type StopOptions, type TerminateOptions } from "#contracts/sandbox_data_contracts.js";
5
- import { type DurationFieldsToMs } from "#internal/duration_ms.js";
6
- import type { RemapFields } from "#internal/input_remap.js";
7
- import type { FlattenOneof } from "#internal/oneof_input.js";
8
- import type { StripProto } from "#internal/strip_proto.js";
9
- /** Public credential shapes (no protobuf `$typeName` / getters). */
10
- export type APIKeyCredentials = StripProto<WireAPIKeyCredentials>;
11
- export type TokenPairCredentials = StripProto<WireTokenPairCredentials>;
12
- export type BearerTokenCredentials = StripProto<WireBearerTokenCredentials>;
13
- export type OAuthCredentials = StripProto<WireOAuthCredentials>;
14
- export type Scope = StripProto<import("@sandbox-kit/contracts/client").Scope>;
15
- /** Public auth: set exactly one credential variant (no protobuf `{ case, value }`). */
16
- export type AuthInput = FlattenOneof<NonNullable<AuthConfig["credentials"]>>;
17
- /**
18
- * Public client settings (ms timeout, flat auth).
19
- * Prefer {@link ClientConfig} at construction (`Config` plus `provider`).
20
- */
21
- export type Config = DurationFieldsToMs<RemapFields<StripProto<MessageInitShape<typeof ConfigSchema>>, {
22
- auth: AuthInput;
23
- }>>;
24
- export declare const ErrorKind: {
25
- readonly Unknown: ProtoErrorKind.UNKNOWN;
26
- readonly InvalidArgument: ProtoErrorKind.INVALID_ARGUMENT;
27
- readonly Unsupported: ProtoErrorKind.UNSUPPORTED;
28
- readonly Authentication: ProtoErrorKind.AUTHENTICATION;
29
- readonly PermissionDenied: ProtoErrorKind.PERMISSION_DENIED;
30
- readonly NotFound: ProtoErrorKind.NOT_FOUND;
31
- readonly AlreadyExists: ProtoErrorKind.ALREADY_EXISTS;
32
- readonly Conflict: ProtoErrorKind.CONFLICT;
33
- readonly RateLimited: ProtoErrorKind.RATE_LIMITED;
34
- readonly ResourceExhausted: ProtoErrorKind.RESOURCE_EXHAUSTED;
35
- readonly Timeout: ProtoErrorKind.TIMEOUT;
36
- readonly Canceled: ProtoErrorKind.CANCELED;
37
- readonly Unavailable: ProtoErrorKind.UNAVAILABLE;
38
- readonly InvalidResponse: ProtoErrorKind.INVALID_RESPONSE;
39
- readonly Internal: ProtoErrorKind.INTERNAL;
40
- readonly FailedPrecondition: ProtoErrorKind.FAILED_PRECONDITION;
41
- };
42
- export type ErrorKind = (typeof ErrorKind)[keyof typeof ErrorKind];
43
- export interface OperationOptions {
44
- readonly signal?: AbortSignal;
45
- /** Operation deadline in milliseconds. */
46
- readonly timeout?: number;
47
- }
48
- /** Public stop options: Kit call options plus optional force. */
49
- export type StopCallOptions = OperationOptions & {
50
- readonly force?: boolean;
51
- };
52
- /** Public terminate options: Kit call options plus optional wait. */
53
- export type TerminateCallOptions = OperationOptions & {
54
- readonly wait?: boolean;
55
- };
56
- /** Public delete options: Kit call options plus optional wait. */
57
- export type DeleteCallOptions = OperationOptions & {
58
- readonly wait?: boolean;
59
- };
60
- export interface Backend {
61
- readonly name: string;
62
- create?(request: CreateOptions, options: OperationOptions): Promise<CreateResult>;
63
- attach?(id: string, options: OperationOptions): Promise<SandboxInfo>;
64
- refresh?(id: string, options: OperationOptions): Promise<SandboxInfo>;
65
- start?(id: string, request: StartOptions, options: OperationOptions): Promise<SandboxInfo>;
66
- stop?(id: string, request: StopOptions, options: OperationOptions): Promise<SandboxInfo>;
67
- pause?(id: string, request: PauseOptions, options: OperationOptions): Promise<SandboxInfo>;
68
- terminate?(id: string, request: TerminateOptions, options: OperationOptions): Promise<ExitResult>;
69
- archive?(id: string, request: ArchiveOptions, options: OperationOptions): Promise<SandboxInfo>;
70
- delete?(id: string, request: DeleteOptions, options: OperationOptions): Promise<SandboxInfo>;
71
- close(options: OperationOptions): Promise<void>;
72
- closeSandbox?(id: string, options: OperationOptions): Promise<void>;
73
- capabilities?(info: SandboxInfo): readonly LifecycleCapability[];
74
- }
75
- export interface Provider {
76
- readonly name: string;
77
- /** Receives public {@link Config}. */
78
- initialize(config: Config): Backend;
79
- }
80
- /** Provider selection stays handwritten and is never part of the portable Config message. */
81
- export type ClientConfig = Config & {
82
- readonly provider: Provider;
83
- };
84
- export declare class SandboxError extends Error {
85
- readonly kind: ErrorInfo["kind"];
86
- readonly provider: string;
87
- readonly operation: string;
88
- readonly field: string;
89
- readonly rule: string | undefined;
90
- readonly statusCode: number | undefined;
91
- readonly providerCode: string | undefined;
92
- readonly providerSource: string | undefined;
93
- constructor(info: ErrorInfo, options?: ErrorOptions);
94
- }
95
- export declare function sandboxError(info: ErrorInfo, cause?: unknown): SandboxError;
96
- /**
97
- * Rejects public {@link CreateOptions} the shared contract cannot represent.
98
- * Materializes wire form privately for Protovalidate. Provider-specific checks
99
- * remain in each provider adapter.
100
- */
101
- export declare function validateCreateOptions(value: CreateOptions, provider?: string, operation?: string): void;
102
- export declare function validateConfig(value: Config, provider?: string, operation?: string): void;
103
- interface ClientLifecycle {
104
- begin(operation: string): () => void;
105
- isClosed(): boolean;
106
- }
107
- declare const sandboxConstructorToken: unique symbol;
108
- export declare class Sandbox implements AsyncDisposable {
109
- #private;
110
- constructor(token: typeof sandboxConstructorToken, backend: Backend, owner: ClientLifecycle, info: SandboxInfo, timeout?: number);
111
- get id(): string;
112
- get providerName(): string;
113
- info(): SandboxInfo;
114
- capabilities(): readonly LifecycleCapability[];
115
- supports(capability: LifecycleCapability): boolean;
116
- refresh(options?: OperationOptions): Promise<SandboxInfo>;
117
- start(options?: OperationOptions): Promise<SandboxInfo>;
118
- stop(options?: StopCallOptions): Promise<SandboxInfo>;
119
- pause(options?: OperationOptions): Promise<SandboxInfo>;
120
- terminate(options?: TerminateCallOptions): Promise<ExitResult>;
121
- archive(options?: OperationOptions): Promise<SandboxInfo>;
122
- delete(options?: DeleteCallOptions): Promise<SandboxInfo>;
123
- close(options?: OperationOptions): Promise<void>;
124
- [Symbol.asyncDispose](): Promise<void>;
125
- }
1
+ import type { CreateOptions } from "#contracts/sandbox_data_contracts.js";
2
+ import { Sandbox } from "#client/sandbox.js";
3
+ import type { ClientConfig, OperationOptions } from "#client/types.js";
4
+ export type { APIKeyCredentials, AuthInput, Backend, BearerTokenCredentials, ClientConfig, Config, DeleteCallOptions, OAuthCredentials, OperationOptions, Provider, Scope, StopCallOptions, TerminateCallOptions, TokenPairCredentials, } from "#client/types.js";
5
+ export { ErrorKind, SandboxError, sandboxError } from "#client/errors.js";
6
+ export { Sandbox } from "#client/sandbox.js";
7
+ export { validateConfig, validateCreateOptions } from "#client/validation.js";
126
8
  export declare class Client implements AsyncDisposable {
127
9
  #private;
128
10
  constructor(config: ClientConfig);
@@ -133,4 +15,3 @@ export declare class Client implements AsyncDisposable {
133
15
  close(options?: OperationOptions): Promise<void>;
134
16
  [Symbol.asyncDispose](): Promise<void>;
135
17
  }
136
- export {};