@sandbox-kit/daytona 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +55 -2
- package/dist/checks/provider_checks.d.ts +2 -0
- package/dist/checks/provider_checks.js +137 -0
- package/dist/config/provider_config.d.ts +4 -0
- package/dist/config/provider_config.js +49 -0
- package/dist/daytona.d.ts +22 -0
- package/dist/daytona.js +108 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +79 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/mappings/mappings.d.ts +7 -0
- package/dist/mappings/mappings.js +341 -0
- package/dist/mappings/provider_mappings.d.ts +14 -0
- package/dist/mappings/provider_mappings.js +282 -0
- package/dist/mappings.d.ts +8 -0
- package/dist/mappings.js +332 -0
- package/dist/provider.checks.gen.d.ts +3 -0
- package/dist/provider.checks.gen.js +91 -0
- package/dist/provider.config.gen.d.ts +5 -0
- package/dist/provider.config.gen.js +36 -0
- package/dist/provider.d.ts +13 -0
- package/dist/provider.errors.gen.d.ts +3 -0
- package/dist/provider.errors.gen.js +78 -0
- package/dist/provider.gen.d.ts +14 -0
- package/dist/provider.gen.js +11 -0
- package/dist/provider.js +10 -0
- package/dist/provider.mappings.gen.d.ts +12 -0
- package/dist/provider.mappings.gen.js +275 -0
- package/dist/provider_checks.d.ts +3 -0
- package/dist/provider_checks.js +137 -0
- package/dist/provider_config.d.ts +5 -0
- package/dist/provider_config.js +49 -0
- package/dist/provider_mappings.d.ts +15 -0
- package/dist/provider_mappings.js +274 -0
- package/package.json +63 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 sandbox-kit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,56 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Daytona provider for Sandbox Kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Independent package over `@daytona/sdk@0.225.0`, published separately from the
|
|
4
|
+
core `@sandbox-kit/sandbox` client. Use it through that shared API.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npm install @sandbox-kit/sandbox @sandbox-kit/daytona
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { Client } from "@sandbox-kit/sandbox";
|
|
14
|
+
import { daytona } from "@sandbox-kit/daytona";
|
|
15
|
+
|
|
16
|
+
await using client = new Client({
|
|
17
|
+
provider: daytona(),
|
|
18
|
+
auth: { apiKey: { key: process.env.DAYTONA_API_KEY! } },
|
|
19
|
+
timeout: 120_000,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const sandbox = await client.create({
|
|
23
|
+
source: { image: { reference: "daytonaio/playground:latest" } },
|
|
24
|
+
runtime: { language: "typescript" },
|
|
25
|
+
});
|
|
26
|
+
console.log(sandbox.id);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Auth may be omitted when the native Daytona SDK should resolve credentials from
|
|
30
|
+
its environment. Closing the client releases local SDK resources only.
|
|
31
|
+
|
|
32
|
+
## Examples
|
|
33
|
+
|
|
34
|
+
| Example | Project |
|
|
35
|
+
| ---------- | -------------------------------------------------------------------------------------------------------------- |
|
|
36
|
+
| Creation | [create-daytona-sandbox](../../../../examples/typescript/daytona/create-daytona-sandbox/README.md) |
|
|
37
|
+
| Policies | [create-daytona-with-policies](../../../../examples/typescript/daytona/create-daytona-with-policies/README.md) |
|
|
38
|
+
| Retrieval | [get-daytona-sandbox](../../../../examples/typescript/daytona/get-daytona-sandbox/README.md) |
|
|
39
|
+
| Full index | [TypeScript examples](../../../../examples/typescript/README.md) |
|
|
40
|
+
|
|
41
|
+
## Implementation notes
|
|
42
|
+
|
|
43
|
+
Checks and portable field mappings are handwritten in `checks/provider_checks.ts`,
|
|
44
|
+
`mappings/provider_mappings.ts`, and `config/provider_config.ts`, kept in sync with
|
|
45
|
+
`specs/providers/daytona.yaml`. `src/daytona.ts` owns typed Daytona SDK call
|
|
46
|
+
ordering and lifecycle orchestration; `src/mappings.ts` owns remaining
|
|
47
|
+
provider-specific composition.
|
|
48
|
+
|
|
49
|
+
## Dependency audit
|
|
50
|
+
|
|
51
|
+
`npm audit` reports four high-severity findings in the pinned
|
|
52
|
+
`@daytona/sdk@0.225.0` dependency chain (`fast-glob` → `micromatch` → `braces`).
|
|
53
|
+
The registry reports no fix (`braces` latest is still vulnerable; Daytona still
|
|
54
|
+
depends on `fast-glob`). The provider does not override those transitive
|
|
55
|
+
packages, because overrides could create an unsupported SDK combination.
|
|
56
|
+
Reassess the audit when Daytona drops or patches that chain.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { ErrorKind, PolicyMode, sandboxError, CreateFieldLifetime, CreateFieldNetworkOutboundCidrsEntries, CreateFieldNetworkOutboundDomainsEntries, CreateFieldNetworkOutboundProxyUrl, CreateFieldRuntimeLanguage, CreateFieldSecuritySecretsEnvironmentVariable } from "@sandbox-kit/sandbox";
|
|
2
|
+
// validateProviderCreate rejects creation settings this provider cannot honor.
|
|
3
|
+
// Rules are inventoried in specs/providers/daytona.yaml checks.
|
|
4
|
+
export function validateProviderCreate(request) {
|
|
5
|
+
const language = request.runtime?.language;
|
|
6
|
+
if (language !== undefined &&
|
|
7
|
+
language !== "python" &&
|
|
8
|
+
language !== "javascript" &&
|
|
9
|
+
language !== "typescript") {
|
|
10
|
+
fail(ErrorKind.Unsupported, CreateFieldRuntimeLanguage, "runtime.language is outside supported values");
|
|
11
|
+
}
|
|
12
|
+
const outboundProxyUrl = request.network?.outboundProxyUrl;
|
|
13
|
+
if (outboundProxyUrl !== undefined && !validHttpUrl(outboundProxyUrl)) {
|
|
14
|
+
fail(ErrorKind.InvalidArgument, CreateFieldNetworkOutboundProxyUrl, "network.outbound_proxy_url is outside supported values");
|
|
15
|
+
}
|
|
16
|
+
for (const value of request.network?.outboundCidrs ?? []) {
|
|
17
|
+
if (!validCidr(value)) {
|
|
18
|
+
fail(ErrorKind.InvalidArgument, CreateFieldNetworkOutboundCidrsEntries, "network.outbound_cidrs.entries is outside supported values");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
for (const value of request.network?.outboundDomains ?? []) {
|
|
22
|
+
if (!validDomain(value)) {
|
|
23
|
+
fail(ErrorKind.InvalidArgument, CreateFieldNetworkOutboundDomainsEntries, "network.outbound_domains.entries is outside supported values");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
for (const item of request.security?.secrets ?? []) {
|
|
27
|
+
const environmentVariable = item.environmentVariable;
|
|
28
|
+
if (environmentVariable !== undefined &&
|
|
29
|
+
!validEnvName(environmentVariable)) {
|
|
30
|
+
fail(ErrorKind.InvalidArgument, CreateFieldSecuritySecretsEnvironmentVariable, "security.secrets.environment_variable is outside supported values");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (delayed(request.lifetime?.idleStop) &&
|
|
34
|
+
delayed(request.lifetime?.idlePause)) {
|
|
35
|
+
invalid(CreateFieldLifetime, "incompatible lifetime policies");
|
|
36
|
+
}
|
|
37
|
+
if (delayed(request.lifetime?.idlePause) &&
|
|
38
|
+
request.lifetime?.ephemeral === true) {
|
|
39
|
+
invalid(CreateFieldLifetime, "incompatible lifetime policies");
|
|
40
|
+
}
|
|
41
|
+
if (delayed(request.lifetime?.idlePause) &&
|
|
42
|
+
immediate(request.lifetime?.stoppedDelete)) {
|
|
43
|
+
invalid(CreateFieldLifetime, "incompatible lifetime policies");
|
|
44
|
+
}
|
|
45
|
+
if (delayed(request.lifetime?.stoppedDelete) &&
|
|
46
|
+
request.lifetime?.ephemeral === true) {
|
|
47
|
+
invalid(CreateFieldLifetime, "incompatible lifetime policies");
|
|
48
|
+
}
|
|
49
|
+
if (delayed(request.lifetime?.stoppedArchive) &&
|
|
50
|
+
request.lifetime?.ephemeral === true) {
|
|
51
|
+
invalid(CreateFieldLifetime, "incompatible lifetime policies");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function delayed(policy) {
|
|
55
|
+
return ((policy?.mode ?? PolicyMode.Default) === PolicyMode.After &&
|
|
56
|
+
policy?.after !== undefined &&
|
|
57
|
+
policy.after > 0);
|
|
58
|
+
}
|
|
59
|
+
function immediate(policy) {
|
|
60
|
+
return ((policy?.mode ?? PolicyMode.Default) === PolicyMode.After &&
|
|
61
|
+
policy?.after !== undefined &&
|
|
62
|
+
policy.after === 0);
|
|
63
|
+
}
|
|
64
|
+
function validEnvName(value) {
|
|
65
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);
|
|
66
|
+
}
|
|
67
|
+
function validHttpUrl(value) {
|
|
68
|
+
try {
|
|
69
|
+
const parsed = new URL(value);
|
|
70
|
+
return (parsed.hostname !== "" &&
|
|
71
|
+
(parsed.protocol === "http:" || parsed.protocol === "https:"));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function validDomain(value) {
|
|
78
|
+
const domain = value.startsWith("*.") ? value.slice(2) : value;
|
|
79
|
+
return (domain.length <= 253 &&
|
|
80
|
+
/^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.?$/i.test(domain));
|
|
81
|
+
}
|
|
82
|
+
function validCidr(value) {
|
|
83
|
+
const separator = value.lastIndexOf("/");
|
|
84
|
+
if (separator <= 0)
|
|
85
|
+
return false;
|
|
86
|
+
const address = value.slice(0, separator);
|
|
87
|
+
const prefix = Number(value.slice(separator + 1));
|
|
88
|
+
if (!Number.isInteger(prefix))
|
|
89
|
+
return false;
|
|
90
|
+
return address.includes(":")
|
|
91
|
+
? prefix >= 0 && prefix <= 128 && validIpv6(address)
|
|
92
|
+
: prefix >= 0 && prefix <= 32 && validIpv4(address);
|
|
93
|
+
}
|
|
94
|
+
function validIpv4(value) {
|
|
95
|
+
const parts = value.split(".");
|
|
96
|
+
return (parts.length === 4 &&
|
|
97
|
+
parts.every((part) => /^(0|[1-9][0-9]{0,2})$/.test(part) && Number(part) <= 255));
|
|
98
|
+
}
|
|
99
|
+
function validIpv6(value) {
|
|
100
|
+
if ((value.match(/::/g)?.length ?? 0) > 1)
|
|
101
|
+
return false;
|
|
102
|
+
const halves = value.split("::");
|
|
103
|
+
if (halves.length > 2)
|
|
104
|
+
return false;
|
|
105
|
+
const count = (part) => {
|
|
106
|
+
if (part === "")
|
|
107
|
+
return 0;
|
|
108
|
+
const groups = part.split(":");
|
|
109
|
+
let total = 0;
|
|
110
|
+
for (const group of groups) {
|
|
111
|
+
if (/^[0-9a-f]{1,4}$/i.test(group))
|
|
112
|
+
total++;
|
|
113
|
+
else if (validIpv4(group))
|
|
114
|
+
total += 2;
|
|
115
|
+
else
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
return total;
|
|
119
|
+
};
|
|
120
|
+
const left = count(halves[0] ?? "");
|
|
121
|
+
const right = count(halves[1] ?? "");
|
|
122
|
+
return (left !== undefined &&
|
|
123
|
+
right !== undefined &&
|
|
124
|
+
(halves.length === 2 ? left + right < 8 : left === 8));
|
|
125
|
+
}
|
|
126
|
+
function invalid(field, message) {
|
|
127
|
+
fail(ErrorKind.InvalidArgument, field, message);
|
|
128
|
+
}
|
|
129
|
+
function fail(kind, field, message) {
|
|
130
|
+
throw sandboxError({
|
|
131
|
+
kind,
|
|
132
|
+
provider: "daytona",
|
|
133
|
+
operation: "create",
|
|
134
|
+
field,
|
|
135
|
+
message: "sandbox-kit daytona: " + message,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DaytonaConfig as NativeClientConfig } from "@daytona/sdk";
|
|
2
|
+
import { type Config } from "@sandbox-kit/sandbox";
|
|
3
|
+
export type Environment = Readonly<Record<string, string | undefined>>;
|
|
4
|
+
export declare function mapGeneratedClientConfig(config: Config, environment?: Environment): NativeClientConfig;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Client configuration composition for the native SDK constructor.
|
|
2
|
+
// Kept in sync with specs/providers/daytona.yaml client: rules (not emitted).
|
|
3
|
+
import { ErrorKind, sandboxError, validateConfig, ConfigFieldAuth, ConfigFieldScopeAppName, ConfigFieldScopeEnvironment, ConfigFieldScopeProjectId } from "@sandbox-kit/sandbox";
|
|
4
|
+
import { mapAPIKeyCredentials, mapBearerAuth, mapClientSettings, mapScope, } from "#mappings/provider_mappings.js";
|
|
5
|
+
export function mapGeneratedClientConfig(config, environment = environmentVariables()) {
|
|
6
|
+
let source = config;
|
|
7
|
+
if (source.endpoint === undefined)
|
|
8
|
+
source = {
|
|
9
|
+
...source,
|
|
10
|
+
endpoint: environment.DAYTONA_API_URL ??
|
|
11
|
+
environment.DAYTONA_SERVER_URL ??
|
|
12
|
+
"https://app.daytona.io/api",
|
|
13
|
+
};
|
|
14
|
+
validateConfig(source, "daytona", "initialize");
|
|
15
|
+
const target = mapClientSettings(source, "initialize");
|
|
16
|
+
if (source.scope !== undefined) {
|
|
17
|
+
const mapped = mapScope(source.scope, "initialize");
|
|
18
|
+
Object.assign(target, mapped);
|
|
19
|
+
if (source.scope.appName !== undefined)
|
|
20
|
+
unsupported(ConfigFieldScopeAppName, "unsupported client configuration field");
|
|
21
|
+
if (source.scope.environment !== undefined)
|
|
22
|
+
unsupported(ConfigFieldScopeEnvironment, "unsupported client configuration field");
|
|
23
|
+
if (source.scope.projectId !== undefined)
|
|
24
|
+
unsupported(ConfigFieldScopeProjectId, "unsupported client configuration field");
|
|
25
|
+
}
|
|
26
|
+
if (source.auth?.apiKey !== undefined) {
|
|
27
|
+
Object.assign(target, mapAPIKeyCredentials(source.auth.apiKey, "initialize"));
|
|
28
|
+
}
|
|
29
|
+
else if (source.auth?.bearerToken !== undefined) {
|
|
30
|
+
Object.assign(target, mapBearerAuth(source.auth.bearerToken, "initialize"));
|
|
31
|
+
}
|
|
32
|
+
else if (source.auth !== undefined) {
|
|
33
|
+
unsupported(ConfigFieldAuth, "unsupported authentication mode");
|
|
34
|
+
}
|
|
35
|
+
return target;
|
|
36
|
+
}
|
|
37
|
+
function environmentVariables() {
|
|
38
|
+
return (globalThis
|
|
39
|
+
.process?.env ?? {});
|
|
40
|
+
}
|
|
41
|
+
function unsupported(field, message) {
|
|
42
|
+
throw sandboxError({
|
|
43
|
+
kind: ErrorKind.Unsupported,
|
|
44
|
+
provider: "daytona",
|
|
45
|
+
operation: "initialize",
|
|
46
|
+
field,
|
|
47
|
+
message: "sandbox-kit daytona: " + message,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type DaytonaConfig, type Sandbox as DaytonaSandbox } from "@daytona/sdk";
|
|
2
|
+
import { type Provider } from "@sandbox-kit/sandbox";
|
|
3
|
+
import type { Backend, Config } from "@sandbox-kit/sandbox";
|
|
4
|
+
import { mapCreateRequest } from "#mappings/mappings.js";
|
|
5
|
+
import { ProviderBase } from "./provider.js";
|
|
6
|
+
interface NativeDaytona {
|
|
7
|
+
create(params: ReturnType<typeof mapCreateRequest>, options?: {
|
|
8
|
+
readonly timeout?: number;
|
|
9
|
+
}): Promise<DaytonaSandbox>;
|
|
10
|
+
get(id: string): Promise<DaytonaSandbox>;
|
|
11
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
type NativeFactory = (config: DaytonaConfig) => NativeDaytona;
|
|
14
|
+
/** @internal Exported from this module for boundary testing, but not from the package root. */
|
|
15
|
+
export declare class DaytonaProvider extends ProviderBase {
|
|
16
|
+
private readonly nativeFactory;
|
|
17
|
+
constructor(nativeFactory?: NativeFactory);
|
|
18
|
+
initialize(config: Config): Backend;
|
|
19
|
+
}
|
|
20
|
+
/** Selects Daytona as the provider for the shared Sandbox Kit client. */
|
|
21
|
+
export declare function daytona(): Provider;
|
|
22
|
+
export {};
|
package/dist/daytona.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Daytona, } from "@daytona/sdk";
|
|
2
|
+
import { durationMs } from "@bufbuild/protobuf/wkt";
|
|
3
|
+
import { IsolationKind, LifecycleCapability, metadataObjectAsMap } from "@sandbox-kit/sandbox";
|
|
4
|
+
import { mapClientConfig, mapCreateRequest, mapSandboxInfo, } from "#mappings/mappings.js";
|
|
5
|
+
import { mapDaytonaError } from "./errors.js";
|
|
6
|
+
import { BackendBase, ProviderBase } from "./provider.js";
|
|
7
|
+
/** @internal Exported from this module for boundary testing, but not from the package root. */
|
|
8
|
+
export class DaytonaProvider extends ProviderBase {
|
|
9
|
+
nativeFactory;
|
|
10
|
+
constructor(nativeFactory = (config) => new Daytona(config)) {
|
|
11
|
+
super();
|
|
12
|
+
this.nativeFactory = nativeFactory;
|
|
13
|
+
}
|
|
14
|
+
initialize(config) {
|
|
15
|
+
try {
|
|
16
|
+
return new DaytonaBackend(this.nativeFactory(mapClientConfig(config)));
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw mapDaytonaError(error, "initialize");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
class DaytonaBackend extends BackendBase {
|
|
24
|
+
native;
|
|
25
|
+
constructor(native) {
|
|
26
|
+
super();
|
|
27
|
+
this.native = native;
|
|
28
|
+
}
|
|
29
|
+
async create(request, options) {
|
|
30
|
+
try {
|
|
31
|
+
options.signal?.throwIfAborted();
|
|
32
|
+
const params = mapCreateRequest(request);
|
|
33
|
+
const timeout = options.timeout === undefined ? undefined : options.timeout / 1_000;
|
|
34
|
+
const sandbox = await this.native.create(params, timeout === undefined ? undefined : { timeout });
|
|
35
|
+
return { sandbox: mapSandboxInfo(sandbox, "create") };
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw mapDaytonaError(error, "create");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
capabilities(info) {
|
|
42
|
+
if (info.terminal)
|
|
43
|
+
return [];
|
|
44
|
+
const result = [
|
|
45
|
+
LifecycleCapability.Refresh,
|
|
46
|
+
LifecycleCapability.Start,
|
|
47
|
+
LifecycleCapability.Stop,
|
|
48
|
+
LifecycleCapability.Delete,
|
|
49
|
+
];
|
|
50
|
+
const metadata = metadataObjectAsMap(info.providerMetadata);
|
|
51
|
+
const gpuCount = metadata?.gpu_count;
|
|
52
|
+
const hasGpu = (typeof gpuCount === "number" && gpuCount > 0) ||
|
|
53
|
+
(typeof gpuCount === "bigint" && gpuCount > 0n);
|
|
54
|
+
if (!hasGpu &&
|
|
55
|
+
(info.isolation?.kind === IsolationKind.LinuxVm ||
|
|
56
|
+
info.isolation?.providerKind === "windows"))
|
|
57
|
+
result.push(LifecycleCapability.Pause);
|
|
58
|
+
if (!hasGpu && info.isolation?.kind === IsolationKind.Container)
|
|
59
|
+
result.push(LifecycleCapability.Archive);
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
async refresh(id) {
|
|
63
|
+
return this.withSandbox(id, "refresh", async (value) => {
|
|
64
|
+
await value.refreshData();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async start(id, request) {
|
|
68
|
+
return this.withSandbox(id, "start", (value) => value.start(seconds(request.timeout)));
|
|
69
|
+
}
|
|
70
|
+
async stop(id, request) {
|
|
71
|
+
return this.withSandbox(id, "stop", (value) => value.stop(seconds(request.timeout), request.force));
|
|
72
|
+
}
|
|
73
|
+
async pause(id, request) {
|
|
74
|
+
return this.withSandbox(id, "pause", (value) => value.pause(seconds(request.timeout)));
|
|
75
|
+
}
|
|
76
|
+
async archive(id, _request) {
|
|
77
|
+
return this.withSandbox(id, "archive", (value) => value.archive());
|
|
78
|
+
}
|
|
79
|
+
async delete(id, request) {
|
|
80
|
+
return this.withSandbox(id, "delete", (value) => value.delete(seconds(request.timeout), request.wait));
|
|
81
|
+
}
|
|
82
|
+
async closeSandbox(_id) { }
|
|
83
|
+
async withSandbox(id, operation, action) {
|
|
84
|
+
try {
|
|
85
|
+
const sandbox = await this.native.get(id);
|
|
86
|
+
await action(sandbox);
|
|
87
|
+
return mapSandboxInfo(sandbox, operation);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw mapDaytonaError(error, operation);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async close(_options) {
|
|
94
|
+
try {
|
|
95
|
+
await this.native[Symbol.asyncDispose]();
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
throw mapDaytonaError(error, "close");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function seconds(value) {
|
|
103
|
+
return value === undefined ? undefined : durationMs(value) / 1_000;
|
|
104
|
+
}
|
|
105
|
+
/** Selects Daytona as the provider for the shared Sandbox Kit client. */
|
|
106
|
+
export function daytona() {
|
|
107
|
+
return new DaytonaProvider();
|
|
108
|
+
}
|
package/dist/errors.d.ts
ADDED
package/dist/errors.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Native Daytona error translation is handwritten.
|
|
2
|
+
// Classification order: existing SandboxError, abort/timeout DOMException,
|
|
3
|
+
// then DaytonaError code/status maps, then unknown. Cause stays on SandboxError.cause.
|
|
4
|
+
import { DaytonaError } from "@daytona/sdk";
|
|
5
|
+
import { ErrorKind, SandboxError, sandboxError } from "@sandbox-kit/sandbox";
|
|
6
|
+
export function mapDaytonaError(error, operation) {
|
|
7
|
+
if (error instanceof SandboxError)
|
|
8
|
+
return error;
|
|
9
|
+
if (error instanceof DOMException && error.name === "AbortError")
|
|
10
|
+
return create(ErrorKind.Canceled, error, operation);
|
|
11
|
+
if (error instanceof DOMException && error.name === "TimeoutError")
|
|
12
|
+
return create(ErrorKind.Timeout, error, operation);
|
|
13
|
+
let kind = ErrorKind.Unknown;
|
|
14
|
+
let statusCode;
|
|
15
|
+
let providerCode;
|
|
16
|
+
let providerSource;
|
|
17
|
+
if (error instanceof DaytonaError) {
|
|
18
|
+
statusCode = error.statusCode;
|
|
19
|
+
providerCode = error.code;
|
|
20
|
+
providerSource = error.source;
|
|
21
|
+
if (kind === ErrorKind.Unknown)
|
|
22
|
+
switch (error.code) {
|
|
23
|
+
case "SANDBOX_SPOT_EVICTED":
|
|
24
|
+
kind = ErrorKind.Unavailable;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
if (kind === ErrorKind.Unknown)
|
|
28
|
+
switch (error.statusCode) {
|
|
29
|
+
case 400:
|
|
30
|
+
kind = ErrorKind.InvalidArgument;
|
|
31
|
+
break;
|
|
32
|
+
case 401:
|
|
33
|
+
kind = ErrorKind.Authentication;
|
|
34
|
+
break;
|
|
35
|
+
case 403:
|
|
36
|
+
kind = ErrorKind.PermissionDenied;
|
|
37
|
+
break;
|
|
38
|
+
case 404:
|
|
39
|
+
kind = ErrorKind.NotFound;
|
|
40
|
+
break;
|
|
41
|
+
case 408:
|
|
42
|
+
kind = ErrorKind.Timeout;
|
|
43
|
+
break;
|
|
44
|
+
case 409:
|
|
45
|
+
kind = ErrorKind.Conflict;
|
|
46
|
+
break;
|
|
47
|
+
case 410:
|
|
48
|
+
kind = ErrorKind.NotFound;
|
|
49
|
+
break;
|
|
50
|
+
case 412:
|
|
51
|
+
kind = ErrorKind.FailedPrecondition;
|
|
52
|
+
break;
|
|
53
|
+
case 422:
|
|
54
|
+
kind = ErrorKind.InvalidArgument;
|
|
55
|
+
break;
|
|
56
|
+
case 429:
|
|
57
|
+
kind = ErrorKind.RateLimited;
|
|
58
|
+
break;
|
|
59
|
+
case 500:
|
|
60
|
+
kind = ErrorKind.Internal;
|
|
61
|
+
break;
|
|
62
|
+
case 502:
|
|
63
|
+
kind = ErrorKind.Unavailable;
|
|
64
|
+
break;
|
|
65
|
+
case 503:
|
|
66
|
+
kind = ErrorKind.Unavailable;
|
|
67
|
+
break;
|
|
68
|
+
case 504:
|
|
69
|
+
kind = ErrorKind.Timeout;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
if (kind === ErrorKind.Unknown && error.statusCode === 0 && !error.code)
|
|
73
|
+
kind = ErrorKind.Unavailable;
|
|
74
|
+
}
|
|
75
|
+
return create(kind, error, operation, statusCode, providerCode, providerSource);
|
|
76
|
+
}
|
|
77
|
+
function create(kind, error, operation, statusCode, providerCode, providerSource) {
|
|
78
|
+
return sandboxError({ kind, provider: "daytona", operation, field: "", message: error instanceof Error ? error.message : "sandbox-kit daytona: provider operation failed", ...(statusCode === undefined ? {} : { statusCode }), ...(providerCode === undefined ? {} : { providerCode }), ...(providerSource === undefined ? {} : { providerSource }) }, error);
|
|
79
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Config, type CreateOptions, type SandboxInfo } from "@sandbox-kit/sandbox";
|
|
2
|
+
import { type CreateSandboxFromImageParams, type CreateSandboxFromSnapshotParams, type DaytonaConfig, type Sandbox as DaytonaSandbox } from "@daytona/sdk";
|
|
3
|
+
import { type Environment } from "#config/provider_config.js";
|
|
4
|
+
export type DaytonaCreateParams = CreateSandboxFromImageParams | CreateSandboxFromSnapshotParams;
|
|
5
|
+
export declare function mapClientConfig(config: Config, environment?: Environment): DaytonaConfig;
|
|
6
|
+
export declare function mapCreateRequest(request: CreateOptions): DaytonaCreateParams;
|
|
7
|
+
export declare function mapSandboxInfo(value: DaytonaSandbox, operation?: string): SandboxInfo;
|