@sandbox-kit/modal 0.0.0-stage → 0.1.1

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 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,82 @@
1
- # Temporary Holding Version
1
+ # `@sandbox-kit/modal`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Modal provider for [`@sandbox-kit/sandbox`](https://www.npmjs.com/package/@sandbox-kit/sandbox).
4
+ Use the shared client API; this package supplies the `modal()` provider.
5
+
6
+ ## Install
7
+
8
+ ```sh
9
+ npm install @sandbox-kit/sandbox @sandbox-kit/modal
10
+ ```
11
+
12
+ Requires Node.js 20, 22, or 24.15+, and a Modal token pair.
13
+
14
+ ## Quick start
15
+
16
+ ```ts
17
+ import { modal } from "@sandbox-kit/modal";
18
+ import { Client } from "@sandbox-kit/sandbox";
19
+
20
+ await using client = new Client({
21
+ provider: modal(),
22
+ auth: {
23
+ tokenPair: {
24
+ id: process.env.MODAL_TOKEN_ID!,
25
+ secret: process.env.MODAL_TOKEN_SECRET!,
26
+ },
27
+ },
28
+ scope: {
29
+ appName: process.env.MODAL_APP_NAME!,
30
+ environment: process.env.MODAL_ENVIRONMENT ?? "main",
31
+ },
32
+ timeout: 120_000,
33
+ });
34
+
35
+ const sandbox = await client.create({
36
+ source: { image: { reference: "alpine:3.21" } },
37
+ resources: { cpuCores: 0.5, memoryMib: 512n },
38
+ lifetime: { maximumLifetime: 5 * 60_000 },
39
+ });
40
+ console.log(sandbox.id);
41
+ ```
42
+
43
+ Closing the client releases local SDK resources only. Reclaim sandboxes with
44
+ idle/max lifetime policies or `terminate`.
45
+
46
+ ## Configuration
47
+
48
+ | Setting | Notes |
49
+ | -------------- | ---------------------------------------------------------- |
50
+ | Token pair | `auth: { tokenPair: { id, secret } }` |
51
+ | OAuth refresh | Supported with client ID and exactly one secret or JWT key |
52
+ | Omitted `auth` | Modal SDK environment / profile credentials |
53
+ | App | `scope.appName` — required |
54
+ | Environment | `scope.environment` (default often `main`) |
55
+ | Region | `region` — default placement preference |
56
+ | Endpoint | Not supported |
57
+
58
+ ## What you can do
59
+
60
+ **Create** from a registry image with runtime (command, workdir, PTY), gVisor or
61
+ Linux VM isolation, CPU/memory, placement, network policy and ports, secrets,
62
+ OIDC workload identity, readiness probes, timeouts, labels, and verbose mode.
63
+
64
+ **Lifecycle** on the handle: `attach`, `terminate`, and local `close`.
65
+ Provider-verified `get` / `refresh`, start, stop, pause, archive, and delete are
66
+ unsupported.
67
+
68
+ When you set resources, Modal requires at least 0.125 CPU cores and 128 MiB
69
+ memory. Omitted values keep Modal defaults. Disk size cannot be raised at create.
70
+
71
+ ## Examples
72
+
73
+ | Example | Project |
74
+ | ---------- | --------------------------------------------------------------------------------------------------------------------------------- |
75
+ | Creation | [create-modal-sandbox](https://github.com/sandbox-kit/kit/tree/main/examples/typescript/modal/create-modal-sandbox) |
76
+ | Resources | [create-modal-with-resources](https://github.com/sandbox-kit/kit/tree/main/examples/typescript/modal/create-modal-with-resources) |
77
+ | Attach | [attach-modal-sandbox](https://github.com/sandbox-kit/kit/tree/main/examples/typescript/modal/attach-modal-sandbox) |
78
+ | Full index | [TypeScript examples](https://github.com/sandbox-kit/kit/tree/main/examples/typescript) |
79
+
80
+ ## License
81
+
82
+ MIT
@@ -0,0 +1,2 @@
1
+ import type { CreateOptions } from "@sandbox-kit/sandbox";
2
+ export declare function validateProviderCreate(request: CreateOptions): void;
@@ -0,0 +1,86 @@
1
+ import { ErrorKind, CreateFieldEnvironment, CreateFieldNetworkInboundCidrsEntries, CreateFieldNetworkOutboundCidrsEntries, CreateFieldNetworkOutboundDomainsEntries, CreateFieldPlacementCloud, CreateFieldResourcesCpuCores, CreateFieldResourcesMemoryMib, CreateFieldRuntimeWorkingDirectory, validCidr, validDomain, validEnvName, } from "@sandbox-kit/sandbox";
2
+ import { providerError } from "#errors.js";
3
+ // validateProviderCreate rejects creation settings this provider cannot honor.
4
+ // Rules are inventoried in specs/providers/modal.yaml checks.
5
+ export function validateProviderCreate(request) {
6
+ const cpuCores = request.resources?.cpuCores;
7
+ if (cpuCores !== undefined && cpuCores < 0.125) {
8
+ providerError({
9
+ kind: ErrorKind.InvalidArgument,
10
+ operation: "create",
11
+ field: CreateFieldResourcesCpuCores,
12
+ message: "resources.cpu_cores is outside supported values",
13
+ });
14
+ }
15
+ const memoryMib = request.resources?.memoryMib;
16
+ if (memoryMib !== undefined && memoryMib < BigInt("128")) {
17
+ providerError({
18
+ kind: ErrorKind.InvalidArgument,
19
+ operation: "create",
20
+ field: CreateFieldResourcesMemoryMib,
21
+ message: "resources.memory_mib is outside supported values",
22
+ });
23
+ }
24
+ const workingDirectory = request.runtime?.workingDirectory;
25
+ if (workingDirectory !== undefined && !workingDirectory.startsWith("/")) {
26
+ providerError({
27
+ kind: ErrorKind.InvalidArgument,
28
+ operation: "create",
29
+ field: CreateFieldRuntimeWorkingDirectory,
30
+ message: "runtime.working_directory is outside supported values",
31
+ });
32
+ }
33
+ const cloud = request.placement?.cloud;
34
+ if (cloud !== undefined &&
35
+ cloud !== "aws" &&
36
+ cloud !== "gcp" &&
37
+ cloud !== "oci" &&
38
+ cloud !== "auto") {
39
+ providerError({
40
+ kind: ErrorKind.Unsupported,
41
+ operation: "create",
42
+ field: CreateFieldPlacementCloud,
43
+ message: "placement.cloud is outside supported values",
44
+ });
45
+ }
46
+ for (const value of request.network?.outboundCidrs ?? []) {
47
+ if (value !== "" && !validCidr(value)) {
48
+ providerError({
49
+ kind: ErrorKind.InvalidArgument,
50
+ operation: "create",
51
+ field: CreateFieldNetworkOutboundCidrsEntries,
52
+ message: "network.outbound_cidrs.entries is outside supported values",
53
+ });
54
+ }
55
+ }
56
+ for (const value of request.network?.inboundCidrs ?? []) {
57
+ if (!validCidr(value)) {
58
+ providerError({
59
+ kind: ErrorKind.InvalidArgument,
60
+ operation: "create",
61
+ field: CreateFieldNetworkInboundCidrsEntries,
62
+ message: "network.inbound_cidrs.entries is outside supported values",
63
+ });
64
+ }
65
+ }
66
+ for (const value of request.network?.outboundDomains ?? []) {
67
+ if (value !== "" && !validDomain(value)) {
68
+ providerError({
69
+ kind: ErrorKind.InvalidArgument,
70
+ operation: "create",
71
+ field: CreateFieldNetworkOutboundDomainsEntries,
72
+ message: "network.outbound_domains.entries is outside supported values",
73
+ });
74
+ }
75
+ }
76
+ for (const value of Object.keys(request.environment ?? {})) {
77
+ if (!validEnvName(value)) {
78
+ providerError({
79
+ kind: ErrorKind.InvalidArgument,
80
+ operation: "create",
81
+ field: CreateFieldEnvironment,
82
+ message: "environment is outside supported values",
83
+ });
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,8 @@
1
+ import type { ModalClientParams as NativeClientConfig } from "modal";
2
+ import { type Config, type Scope } from "@sandbox-kit/sandbox";
3
+ export declare function mapGeneratedClientConfig(config: Config): NativeClientConfig;
4
+ export interface ProviderState {
5
+ readonly scope?: Scope;
6
+ readonly region?: string;
7
+ }
8
+ export declare function captureProviderState(config: Config): ProviderState;
@@ -0,0 +1,45 @@
1
+ // Client configuration composition for the native SDK constructor.
2
+ // Kept in sync with specs/providers/modal.yaml client: rules (not emitted).
3
+ import { ErrorKind, ConfigFieldAuth, ConfigFieldEndpoint, ConfigFieldScopeProjectId, } from "@sandbox-kit/sandbox";
4
+ import { mapClientScope, mapOAuthAuth, mapTokenPairCredentials, } from "#mappings/provider_mappings.js";
5
+ import { providerError } from "#errors.js";
6
+ export function mapGeneratedClientConfig(config) {
7
+ const source = config;
8
+ const target = {};
9
+ if (source.endpoint !== undefined)
10
+ unsupported(ConfigFieldEndpoint, "Endpoint cannot be configured through this SDK's public client constructor");
11
+ if (source.scope !== undefined) {
12
+ const mapped = mapClientScope(source.scope, "initialize");
13
+ Object.assign(target, mapped);
14
+ if (source.scope.organizationId !== undefined)
15
+ unsupported("scope.organizationId", "unsupported client configuration field");
16
+ if (source.scope.projectId !== undefined)
17
+ unsupported(ConfigFieldScopeProjectId, "unsupported client configuration field");
18
+ }
19
+ if (source.auth?.tokenPair !== undefined) {
20
+ Object.assign(target, mapTokenPairCredentials(source.auth.tokenPair, "initialize"));
21
+ }
22
+ else if (source.auth?.oauthRefresh !== undefined) {
23
+ Object.assign(target, mapOAuthAuth(source.auth.oauthRefresh, "initialize"));
24
+ }
25
+ else if (source.auth !== undefined) {
26
+ unsupported(ConfigFieldAuth, "unsupported authentication mode");
27
+ }
28
+ return target;
29
+ }
30
+ export function captureProviderState(config) {
31
+ return {
32
+ ...(config.scope === undefined
33
+ ? {}
34
+ : { scope: structuredClone(config.scope) }),
35
+ ...(config.region === undefined ? {} : { region: config.region }),
36
+ };
37
+ }
38
+ function unsupported(field, message) {
39
+ providerError({
40
+ kind: ErrorKind.Unsupported,
41
+ operation: "initialize",
42
+ field,
43
+ message,
44
+ });
45
+ }
@@ -0,0 +1,11 @@
1
+ import { SandboxError, type ErrorInfo } from "@sandbox-kit/sandbox";
2
+ /** Inputs for throwing a Modal-scoped validation or mapping error. */
3
+ export interface ProviderErrorInput {
4
+ kind: ErrorInfo["kind"];
5
+ operation: string;
6
+ field: string;
7
+ message: string;
8
+ }
9
+ export declare function mapModalError(error: unknown, operation: string): SandboxError;
10
+ /** Local throw helper for mappings, checks, and config. */
11
+ export declare function providerError(input: ProviderErrorInput): never;
package/dist/errors.js ADDED
@@ -0,0 +1,56 @@
1
+ // Native Modal error translation is handwritten.
2
+ // Classification order: existing SandboxError, abort/timeout DOMException,
3
+ // then native Modal types, then unknown. Cause stays on SandboxError.cause.
4
+ import { AlreadyExistsError, ClientClosedError, ConflictError, InvalidError, NotFoundError, ResourceExhaustedError, SandboxTimeoutError, TimeoutError, } from "modal";
5
+ import { ErrorKind, SandboxError, sandboxError, } from "@sandbox-kit/sandbox";
6
+ export function mapModalError(error, operation) {
7
+ if (error instanceof SandboxError)
8
+ return error;
9
+ if (error instanceof DOMException && error.name === "AbortError")
10
+ return create({ kind: ErrorKind.Canceled, error, operation });
11
+ if (error instanceof DOMException && error.name === "TimeoutError")
12
+ return create({ kind: ErrorKind.Timeout, error, operation });
13
+ let kind = ErrorKind.Unknown;
14
+ if (kind === ErrorKind.Unknown && error instanceof InvalidError)
15
+ kind = ErrorKind.InvalidArgument;
16
+ if (kind === ErrorKind.Unknown && error instanceof NotFoundError)
17
+ kind = ErrorKind.NotFound;
18
+ if (kind === ErrorKind.Unknown && error instanceof AlreadyExistsError)
19
+ kind = ErrorKind.AlreadyExists;
20
+ if (kind === ErrorKind.Unknown && error instanceof ConflictError)
21
+ kind = ErrorKind.Conflict;
22
+ if (kind === ErrorKind.Unknown && error instanceof ResourceExhaustedError)
23
+ kind = ErrorKind.ResourceExhausted;
24
+ if (kind === ErrorKind.Unknown && error instanceof TimeoutError)
25
+ kind = ErrorKind.Timeout;
26
+ if (kind === ErrorKind.Unknown && error instanceof SandboxTimeoutError)
27
+ kind = ErrorKind.Timeout;
28
+ if (kind === ErrorKind.Unknown && error instanceof ClientClosedError)
29
+ kind = ErrorKind.FailedPrecondition;
30
+ return create({ kind, error, operation });
31
+ }
32
+ function create(input) {
33
+ const { kind, error, operation, statusCode, providerCode, providerSource } = input;
34
+ return sandboxError({
35
+ kind,
36
+ provider: "modal",
37
+ operation,
38
+ field: "",
39
+ message: error instanceof Error
40
+ ? error.message
41
+ : "sandbox-kit modal: provider operation failed",
42
+ ...(statusCode === undefined ? {} : { statusCode }),
43
+ ...(providerCode === undefined ? {} : { providerCode }),
44
+ ...(providerSource === undefined ? {} : { providerSource }),
45
+ }, error);
46
+ }
47
+ /** Local throw helper for mappings, checks, and config. */
48
+ export function providerError(input) {
49
+ throw sandboxError({
50
+ kind: input.kind,
51
+ provider: "modal",
52
+ operation: input.operation,
53
+ field: input.field,
54
+ message: "sandbox-kit modal: " + input.message,
55
+ });
56
+ }
@@ -0,0 +1,2 @@
1
+ export { providerName } from "./provider.js";
2
+ export { modal } from "./modal.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { providerName } from "./provider.js";
2
+ export { modal } from "./modal.js";
@@ -0,0 +1,16 @@
1
+ import { type ModalClientParams, type Sandbox, type SandboxCreateParams } from "modal";
2
+ import { type Config, type CreateOptions, type SandboxInfo } from "@sandbox-kit/sandbox";
3
+ import type { ProviderState } from "#config/provider_config.js";
4
+ export interface ModalCreatePlan {
5
+ readonly app: string;
6
+ readonly environment?: string;
7
+ readonly image: string;
8
+ readonly params: SandboxCreateParams;
9
+ readonly secretNames: readonly string[];
10
+ readonly proxyName?: string;
11
+ readonly waitUntilReady: boolean;
12
+ readonly readyTimeoutMs?: number;
13
+ }
14
+ export declare function mapClientConfig(config: Config): ModalClientParams;
15
+ export declare function mapCreateRequest(request: CreateOptions, config: ProviderState): ModalCreatePlan;
16
+ export declare function mapSandboxInfo(value: Sandbox, request?: CreateOptions): SandboxInfo;
@@ -0,0 +1,315 @@
1
+ // Provider-specific orchestration around generated portable field mappings.
2
+ import { Probe, } from "modal";
3
+ import { EgressMode, ErrorKind, IsolationKind, PolicyMode, PortTransport, SecretInjection, SandboxState, ValueOrigin, WaitCondition, CreateFieldIsolation, CreateFieldIsolationKind, CreateFieldLifetime, CreateFieldLifetimeIdleTerminateAfter, CreateFieldLifetimeIdleTerminateMode, CreateFieldNetwork, CreateFieldNetworkEgress, CreateFieldNetworkPortsPort, CreateFieldNetworkPortsTransport, CreateFieldPlacementTarget, CreateFieldProvisioningTimeout, CreateFieldProvisioningWaitFor, CreateFieldReadiness, CreateFieldRuntime, CreateFieldSecuritySecretsEnvironmentVariable, CreateFieldSecuritySecretsInjection, CreateFieldSource, ConfigFieldScopeAppName, CreateFieldName, CreateFieldNetworkInboundCidrs, CreateFieldNetworkProxyReference, CreateFieldProvisioningQueueTimeout, CreateFieldResourcesCpuLimitCores, CreateFieldResourcesDiskMib, CreateFieldResourcesMemoryLimitMib, CreateFieldResourcesMemoryMib, CreateFieldSecurityPublicAccess, CreateFieldSecuritySecretsReference, CreateFieldSourceImageReference, } from "@sandbox-kit/sandbox";
4
+ import { mapCommonCreateFields as generatedMapCommonCreateFields, mapIdleDuration as generatedMapIdleDuration, mapLifetimeDuration as generatedMapLifetimeDuration, mapResources as generatedMapResources, mapSandboxIdentity as generatedMapSandboxIdentity, } from "./provider_mappings.js";
5
+ import { validateProviderCreate } from "#checks/provider_checks.js";
6
+ import { mapGeneratedClientConfig } from "#config/provider_config.js";
7
+ import { providerError } from "#errors.js";
8
+ export function mapClientConfig(config) {
9
+ const result = mapGeneratedClientConfig(config);
10
+ if (config.timeout !== undefined)
11
+ result.timeoutMs = finiteDurationMs(config.timeout, "timeout", true);
12
+ return result;
13
+ }
14
+ export function mapCreateRequest(request, config) {
15
+ validateProviderCreate(request);
16
+ const app = config.scope?.appName === undefined
17
+ ? invalid(ConfigFieldScopeAppName, "Modal app name is required")
18
+ : nonblank(config.scope.appName, ConfigFieldScopeAppName);
19
+ if (request.source?.image === undefined)
20
+ unsupported(CreateFieldSource, "Modal requires an explicit image source");
21
+ const params = generatedMapCommonCreateFields(request);
22
+ if (request.name !== undefined)
23
+ params.name = nonblank(request.name, CreateFieldName);
24
+ if (config.region !== undefined)
25
+ params.regions = [nonblankConfig(config.region, "region")];
26
+ mapRuntime(request, params);
27
+ mapIsolation(request, params);
28
+ mapResources(request, params);
29
+ mapPlacement(request, params);
30
+ mapNetwork(request, params);
31
+ const secretNames = mapSecurity(request, params);
32
+ mapLifetime(request, params);
33
+ mapReadiness(request, params);
34
+ const wait = mapProvisioning(request, params);
35
+ mapObservability(request, params);
36
+ if (request.providerOptions !== undefined)
37
+ unsupported("providerOptions", "Modal provider options are not mapped");
38
+ return {
39
+ app,
40
+ ...(config.scope?.environment === undefined
41
+ ? {}
42
+ : { environment: config.scope.environment }),
43
+ image: nonblank(request.source.image.reference, CreateFieldSourceImageReference),
44
+ params,
45
+ secretNames,
46
+ ...(request.network?.proxyReference === undefined
47
+ ? {}
48
+ : {
49
+ proxyName: nonblank(request.network.proxyReference, CreateFieldNetworkProxyReference),
50
+ }),
51
+ ...wait,
52
+ };
53
+ }
54
+ function mapRuntime(r, p) {
55
+ const v = r.runtime;
56
+ if (!v)
57
+ return;
58
+ if (v.workingDirectory !== undefined)
59
+ p.workdir = v.workingDirectory;
60
+ if (v.entrypoint !== undefined)
61
+ p.command = [...v.entrypoint];
62
+ if (v.pty !== undefined)
63
+ p.pty = v.pty;
64
+ if (v.language !== undefined ||
65
+ v.version !== undefined ||
66
+ v.user !== undefined)
67
+ unsupported(CreateFieldRuntime, "language, version, and user must come from the Modal image");
68
+ }
69
+ function mapIsolation(r, p) {
70
+ const v = r.isolation;
71
+ if (!v)
72
+ return;
73
+ const kind = v.kind ?? IsolationKind.Default;
74
+ if (kind === IsolationKind.LinuxVm)
75
+ p.runtime = "vm";
76
+ else if (kind === IsolationKind.Container)
77
+ p.runtime = "gvisor";
78
+ else if (kind !== IsolationKind.Default)
79
+ unsupported(CreateFieldIsolationKind, "requested Modal isolation is unsupported");
80
+ if (v.providerKind !== undefined || v.nestedVirtualization !== undefined)
81
+ unsupported(CreateFieldIsolation, "provider kind and nested virtualization are unsupported");
82
+ }
83
+ function mapResources(r, p) {
84
+ const v = r.resources;
85
+ if (!v)
86
+ return;
87
+ if (v.cpuLimitCores !== undefined)
88
+ positive(v.cpuLimitCores, CreateFieldResourcesCpuLimitCores);
89
+ if (v.memoryMib !== undefined)
90
+ integer(v.memoryMib, CreateFieldResourcesMemoryMib, 128);
91
+ if (v.memoryLimitMib !== undefined)
92
+ integer(v.memoryLimitMib, CreateFieldResourcesMemoryLimitMib, 1);
93
+ if (v.diskMib !== undefined)
94
+ unsupported(CreateFieldResourcesDiskMib, "Modal disk override is unsupported");
95
+ Object.assign(p, generatedMapResources(v));
96
+ }
97
+ function mapPlacement(r, p) {
98
+ const v = r.placement;
99
+ if (!v)
100
+ return;
101
+ if (v.cloud !== undefined)
102
+ p.cloud = v.cloud;
103
+ if (v.regions !== undefined)
104
+ p.regions = [...v.regions];
105
+ if (v.target !== undefined)
106
+ unsupported(CreateFieldPlacementTarget, "Modal placement target is unsupported");
107
+ }
108
+ function mapNetwork(r, p) {
109
+ const v = r.network;
110
+ if (!v)
111
+ return;
112
+ const egress = v.egress ?? EgressMode.Default;
113
+ if (egress === EgressMode.BlockAll)
114
+ p.blockNetwork = true;
115
+ else if (egress !== EgressMode.Default &&
116
+ egress !== EgressMode.AllowAll &&
117
+ egress !== EgressMode.Restricted)
118
+ invalid(CreateFieldNetworkEgress, "unknown egress mode");
119
+ if (v.outboundCidrs !== undefined)
120
+ p.outboundCidrAllowlist = [...v.outboundCidrs];
121
+ if (v.outboundDomains !== undefined)
122
+ p.outboundDomainAllowlist = [...v.outboundDomains];
123
+ if (v.inboundCidrs !== undefined) {
124
+ if (!v.inboundCidrs.length)
125
+ unsupported(CreateFieldNetworkInboundCidrs, "empty inbound deny-all is not representable");
126
+ p.inboundCidrAllowlist = [...v.inboundCidrs];
127
+ }
128
+ if (v.privateNetwork !== undefined)
129
+ p.i6pn = v.privateNetwork;
130
+ if (v.customDomain !== undefined)
131
+ p.customDomain = v.customDomain;
132
+ if (v.ports) {
133
+ p.encryptedPorts = [];
134
+ p.h2Ports = [];
135
+ p.unencryptedPorts = [];
136
+ for (const x of v.ports) {
137
+ const port = x.port;
138
+ if (port === undefined)
139
+ invalid(CreateFieldNetworkPortsPort, "port is required");
140
+ const transport = x.transport ?? PortTransport.Default;
141
+ if (transport === PortTransport.Tls)
142
+ p.encryptedPorts.push(port);
143
+ else if (transport === PortTransport.Http2Tls)
144
+ p.h2Ports.push(port);
145
+ else if (transport === PortTransport.Plain)
146
+ p.unencryptedPorts.push(port);
147
+ else
148
+ invalid(CreateFieldNetworkPortsTransport, "explicit transport is required");
149
+ }
150
+ }
151
+ if (v.linkedSandbox !== undefined || v.outboundProxyUrl !== undefined)
152
+ unsupported(CreateFieldNetwork, "linked sandbox and outbound proxy URL mappings are unsupported");
153
+ }
154
+ function mapSecurity(r, p) {
155
+ const v = r.security;
156
+ if (!v)
157
+ return [];
158
+ if (v.workloadIdentity !== undefined)
159
+ p.includeOidcIdentityToken = v.workloadIdentity;
160
+ if (v.publicAccess !== undefined)
161
+ unsupported(CreateFieldSecurityPublicAccess, "Modal public access is represented by ports");
162
+ const names = [];
163
+ for (const s of v.secrets ?? []) {
164
+ if (s.environmentVariable !== undefined)
165
+ unsupported(CreateFieldSecuritySecretsEnvironmentVariable, "per-variable secret renaming is unsupported");
166
+ const injection = s.injection ?? SecretInjection.Default;
167
+ if (injection !== SecretInjection.Default &&
168
+ injection !== SecretInjection.Environment)
169
+ unsupported(CreateFieldSecuritySecretsInjection, "egress-placeholder injection is unsupported");
170
+ names.push(nonblank(s.reference, CreateFieldSecuritySecretsReference));
171
+ }
172
+ return names;
173
+ }
174
+ function mapLifetime(r, p) {
175
+ const v = r.lifetime;
176
+ if (!v)
177
+ return;
178
+ if (v.maximumLifetime !== undefined)
179
+ finiteDurationMs(v.maximumLifetime, "lifetime.maximumLifetime", false);
180
+ Object.assign(p, generatedMapLifetimeDuration(v));
181
+ if (v.idleTerminate) {
182
+ const mode = v.idleTerminate.mode ?? PolicyMode.Default;
183
+ if (mode === PolicyMode.Disabled)
184
+ p.idleTimeoutMs = 0;
185
+ else if (mode === PolicyMode.After) {
186
+ if (v.idleTerminate.after === undefined)
187
+ invalid(CreateFieldLifetimeIdleTerminateAfter, "duration is required");
188
+ finiteDurationMs(v.idleTerminate.after, "lifetime.idleTerminate.after", false);
189
+ Object.assign(p, generatedMapIdleDuration(v.idleTerminate));
190
+ }
191
+ else if (mode !== PolicyMode.Default)
192
+ invalid(CreateFieldLifetimeIdleTerminateMode, "unknown policy mode");
193
+ }
194
+ if (v.ephemeral !== undefined ||
195
+ v.idleStop !== undefined ||
196
+ v.idlePause !== undefined ||
197
+ v.stoppedArchive !== undefined ||
198
+ v.stoppedDelete !== undefined)
199
+ unsupported(CreateFieldLifetime, "requested lifecycle policy is unsupported by Modal");
200
+ }
201
+ function mapReadiness(r, p) {
202
+ const v = r.readiness;
203
+ if (!v)
204
+ return;
205
+ if (v.tcpPort !== undefined) {
206
+ p.readinessProbe = Probe.withTcp(v.tcpPort);
207
+ }
208
+ else if (v.command !== undefined)
209
+ p.readinessProbe = Probe.withExec([...(v.command.argv ?? [])]);
210
+ else
211
+ invalid(CreateFieldReadiness, "probe is required");
212
+ }
213
+ function mapProvisioning(r, _p) {
214
+ const v = r.provisioning;
215
+ if (!v)
216
+ return { waitUntilReady: false };
217
+ if (v.queueTimeout !== undefined)
218
+ unsupported(CreateFieldProvisioningQueueTimeout, "Modal queue timeout is unsupported");
219
+ const waitFor = v.waitFor ?? WaitCondition.Default;
220
+ if (waitFor === WaitCondition.Default || waitFor === WaitCondition.Scheduled)
221
+ return { waitUntilReady: false };
222
+ if (waitFor === WaitCondition.Ready) {
223
+ if (v.timeout === undefined || v.timeout <= 0)
224
+ invalid(CreateFieldProvisioningTimeout, "ready wait requires a positive timeout");
225
+ if (!r.readiness)
226
+ invalid(CreateFieldReadiness, "ready wait requires a probe");
227
+ return { waitUntilReady: true, readyTimeoutMs: v.timeout };
228
+ }
229
+ unsupported(CreateFieldProvisioningWaitFor, "requested wait condition is unsupported");
230
+ }
231
+ function mapObservability(r, p) {
232
+ const v = r.observability;
233
+ if (!v)
234
+ return;
235
+ if (v.verbose !== undefined)
236
+ p.verbose = v.verbose;
237
+ if (v.telemetryEndpoint !== undefined)
238
+ unsupported("observability.telemetryEndpoint", "per-sandbox telemetry endpoint is unsupported");
239
+ }
240
+ export function mapSandboxInfo(value, request) {
241
+ const mapped = generatedMapSandboxIdentity(value);
242
+ const origins = { ...(mapped.origins ?? {}) };
243
+ const result = {
244
+ id: mapped.id ?? value.sandboxId,
245
+ provider: "modal",
246
+ state: SandboxState.Running,
247
+ labels: {},
248
+ origins,
249
+ };
250
+ if (request?.name !== undefined) {
251
+ mutable(result).name = request.name;
252
+ origins.name = ValueOrigin.Request;
253
+ }
254
+ if (request?.labels !== undefined) {
255
+ mutable(result).labels = { ...request.labels };
256
+ origins.labels = ValueOrigin.Request;
257
+ }
258
+ if (request?.isolation !== undefined) {
259
+ mutable(result).isolation = { ...request.isolation };
260
+ origins.isolation = ValueOrigin.Request;
261
+ }
262
+ return result;
263
+ }
264
+ function mutable(v) {
265
+ return v;
266
+ }
267
+ function nonblank(v, f) {
268
+ if (!v.trim())
269
+ invalid(f, "must not be blank");
270
+ return v;
271
+ }
272
+ function nonblankConfig(v, f) {
273
+ if (!v.trim())
274
+ configInvalid(f, "must not be blank");
275
+ return v;
276
+ }
277
+ function positive(v, f) {
278
+ if (!Number.isFinite(v) || v <= 0)
279
+ invalid(f, "must be positive");
280
+ return v;
281
+ }
282
+ function integer(v, f, min) {
283
+ if (v < BigInt(min) || v > 2147483647n)
284
+ invalid(f, "is outside the supported range");
285
+ return Number(v);
286
+ }
287
+ function finiteDurationMs(v, f, zero) {
288
+ if (!Number.isFinite(v) || v < 0 || (!zero && v === 0))
289
+ invalid(f, "must be a finite positive duration");
290
+ return v;
291
+ }
292
+ function invalid(field, message) {
293
+ providerError({
294
+ kind: ErrorKind.InvalidArgument,
295
+ operation: "create",
296
+ field,
297
+ message,
298
+ });
299
+ }
300
+ function unsupported(field, message) {
301
+ providerError({
302
+ kind: ErrorKind.Unsupported,
303
+ operation: "create",
304
+ field,
305
+ message,
306
+ });
307
+ }
308
+ function configInvalid(field, message) {
309
+ providerError({
310
+ kind: ErrorKind.InvalidArgument,
311
+ operation: "initialize",
312
+ field,
313
+ message,
314
+ });
315
+ }