@aerol-ai/aerolvm-sdk 0.2.3 → 0.3.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/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { MicroVM } from "./MicroVM.js";
2
2
  export { Sandbox } from "./Sandbox.js";
3
3
  export { Image } from "./Image.js";
4
4
  export type { MicroVMConfig } from "./MicroVM.js";
5
- export type { BinaryLike, BuildImageOptions, BuildImagePushOptions, BuildImageResult, CreateOptions, CreateSessionOptions, ExecRequest, ExecResult, ExecExitInfo, ExposedPort, ExposePortOptions, ExposeProtocol, ExposeResult, Failover, FailoverPolicy, HealthStatus, Lifecycle, MountSpec, MountSpecRedacted, MountType, RegisterSnapshotOptions, RegistryAuth, ResizeOptions, Sandbox as SandboxData, SandboxSnapshot, SandboxStatus, Session, SessionAttachHandle, SessionAttachOptions, SessionStatus, UpdateLifecycleOptions, } from "./types.js";
5
+ export type { BinaryLike, BuildImageOptions, BuildImagePushOptions, BuildImageResult, CreateOptions, CreateSessionOptions, CustomDomain, CustomDomainStatus, ExecRequest, ExecResult, ExecExitInfo, ExposedPort, ExposePortOptions, ExposeProtocol, ExposeResult, Failover, FailoverPolicy, HealthStatus, Lifecycle, MountSpec, MountSpecRedacted, MountType, RegisterSnapshotOptions, RegistryAuth, ResizeOptions, Sandbox as SandboxData, SandboxSnapshot, SandboxStatus, Session, SessionAttachHandle, SessionAttachOptions, SessionStatus, UpdateLifecycleOptions, } from "./types.js";
@@ -1 +1,16 @@
1
1
  export declare const PATH_PREFIX = "/v1";
2
+ /**
3
+ * Collection URL for a sandbox's custom-domain bindings. Used for both POST
4
+ * (add) and GET (list). The DELETE variant lives at
5
+ * {@link sandboxCustomDomainPath}.
6
+ *
7
+ * `id` is interpolated verbatim — sandbox IDs are server-generated opaque
8
+ * tokens and already URL-safe.
9
+ */
10
+ export declare function sandboxCustomDomainsPath(prefix: string, id: string): string;
11
+ /**
12
+ * URL for a single custom-domain binding. The hostname is percent-encoded so
13
+ * IDN punycode (`xn--...`) and wildcard labels round-trip safely through
14
+ * `DELETE /v1/sandboxes/{id}/custom-domains/{hostname}`.
15
+ */
16
+ export declare function sandboxCustomDomainPath(prefix: string, id: string, hostname: string): string;
@@ -5,3 +5,22 @@
5
5
  //
6
6
  // Keep this in sync with pkg/api/v1/dto.go::PathPrefix on the server.
7
7
  export const PATH_PREFIX = "/v1";
8
+ /**
9
+ * Collection URL for a sandbox's custom-domain bindings. Used for both POST
10
+ * (add) and GET (list). The DELETE variant lives at
11
+ * {@link sandboxCustomDomainPath}.
12
+ *
13
+ * `id` is interpolated verbatim — sandbox IDs are server-generated opaque
14
+ * tokens and already URL-safe.
15
+ */
16
+ export function sandboxCustomDomainsPath(prefix, id) {
17
+ return `${prefix}/sandboxes/${id}/custom-domains`;
18
+ }
19
+ /**
20
+ * URL for a single custom-domain binding. The hostname is percent-encoded so
21
+ * IDN punycode (`xn--...`) and wildcard labels round-trip safely through
22
+ * `DELETE /v1/sandboxes/{id}/custom-domains/{hostname}`.
23
+ */
24
+ export function sandboxCustomDomainPath(prefix, id, hostname) {
25
+ return `${prefix}/sandboxes/${id}/custom-domains/${encodeURIComponent(hostname)}`;
26
+ }
@@ -1,5 +1,5 @@
1
1
  import { Image } from "../Image.js";
2
- import type { BinaryLike, BuildImageOptions, BuildImageResult, CreateOptions, CreateSessionOptions, ExecRequest, ExecResult, ExecStreamHandle, ExecStreamOptions, ExposedPort, ExposePortOptions, ExposeResult, Failover, HealthStatus, Lifecycle, ListOptions, MountSpecRedacted, NetworkUsage, RegisterSnapshotOptions, SetNetworkLimitsOptions, ResizeOptions, Sandbox, SandboxSnapshot, Session, SessionAttachHandle, SessionAttachOptions } from "../types.js";
2
+ import type { BinaryLike, BuildImageOptions, BuildImageResult, CreateOptions, CreateSessionOptions, CustomDomain, ExecRequest, ExecResult, ExecStreamHandle, ExecStreamOptions, ExposedPort, ExposePortOptions, ExposeResult, Failover, HealthStatus, Lifecycle, ListOptions, MountSpecRedacted, NetworkUsage, RegisterSnapshotOptions, SetNetworkLimitsOptions, ResizeOptions, Sandbox, SandboxSnapshot, Session, SessionAttachHandle, SessionAttachOptions } from "../types.js";
3
3
  type FetchLike = typeof fetch;
4
4
  /**
5
5
  * Wire version of the v1-style sandbox endpoints (`/v1/sandboxes`, etc.) this
@@ -93,6 +93,15 @@ export declare class APIClient {
93
93
  */
94
94
  exposePort(id: string, port: number, options?: ExposePortOptions): Promise<ExposeResult>;
95
95
  unexposePort(id: string, port: number): Promise<void>;
96
+ /**
97
+ * Bind a custom hostname to a sandbox. The server lowercases the hostname
98
+ * and returns the post-add list of bindings (sorted by hostname). Calling
99
+ * with an already-registered hostname is idempotent and returns the
100
+ * existing list.
101
+ */
102
+ addCustomDomain(id: string, hostname: string): Promise<CustomDomain[]>;
103
+ listCustomDomains(id: string): Promise<CustomDomain[]>;
104
+ removeCustomDomain(id: string, hostname: string): Promise<void>;
96
105
  reconcile(): Promise<void>;
97
106
  health(): Promise<HealthStatus>;
98
107
  mounts(id: string): Promise<MountSpecRedacted[]>;
@@ -146,6 +155,19 @@ export declare class SandboxResource implements Sandbox {
146
155
  downloadFile(targetPath: string): Promise<Uint8Array>;
147
156
  exposePort(port: number, options?: ExposePortOptions): Promise<ExposeResult>;
148
157
  unexposePort(port: number): Promise<void>;
158
+ /**
159
+ * Per-sandbox custom-hostname bindings. Exposed as a namespaced accessor
160
+ * (rather than `addCustomDomain`/`removeCustomDomain`/`listCustomDomains`
161
+ * methods on the resource) so call sites read like
162
+ * `sandbox.customDomains.add("api.acme.com")`, mirroring the noun in the
163
+ * `/v1/.../custom-domains` URL space. A fresh object is returned per access
164
+ * so the closures always see the current `id` even after `refresh()`.
165
+ */
166
+ get customDomains(): {
167
+ add(hostname: string): Promise<CustomDomain[]>;
168
+ remove(hostname: string): Promise<void>;
169
+ list(): Promise<CustomDomain[]>;
170
+ };
149
171
  createSnapshot(name: string): Promise<SandboxSnapshot>;
150
172
  start(): Promise<this>;
151
173
  stop(): Promise<this>;
@@ -1,5 +1,5 @@
1
1
  import { basename } from "node:path";
2
- import { PATH_PREFIX as V1_PATH_PREFIX } from "./api/v1/paths.js";
2
+ import { PATH_PREFIX as V1_PATH_PREFIX, sandboxCustomDomainPath as v1SandboxCustomDomainPath, sandboxCustomDomainsPath as v1SandboxCustomDomainsPath, } from "./api/v1/paths.js";
3
3
  import { Image } from "../Image.js";
4
4
  const DEFAULT_API_VERSION = "v1";
5
5
  const PATH_PREFIXES = {
@@ -220,6 +220,23 @@ export class APIClient {
220
220
  async unexposePort(id, port) {
221
221
  await this.doJSON("DELETE", `${this.versionPrefix}/sandboxes/${id}/ports/${port}`);
222
222
  }
223
+ /**
224
+ * Bind a custom hostname to a sandbox. The server lowercases the hostname
225
+ * and returns the post-add list of bindings (sorted by hostname). Calling
226
+ * with an already-registered hostname is idempotent and returns the
227
+ * existing list.
228
+ */
229
+ async addCustomDomain(id, hostname) {
230
+ const response = await this.doJSON("POST", v1SandboxCustomDomainsPath(this.versionPrefix, id), { hostname });
231
+ return response.custom_domains.map(fromApiCustomDomain);
232
+ }
233
+ async listCustomDomains(id) {
234
+ const response = await this.doJSON("GET", v1SandboxCustomDomainsPath(this.versionPrefix, id));
235
+ return response.custom_domains.map(fromApiCustomDomain);
236
+ }
237
+ async removeCustomDomain(id, hostname) {
238
+ await this.doJSON("DELETE", v1SandboxCustomDomainPath(this.versionPrefix, id, hostname));
239
+ }
223
240
  async reconcile() {
224
241
  await this.doJSON("POST", this.versioned("/admin/reconcile"));
225
242
  }
@@ -334,6 +351,23 @@ export class SandboxResource {
334
351
  async unexposePort(port) {
335
352
  await this.client.unexposePort(this.id, port);
336
353
  }
354
+ /**
355
+ * Per-sandbox custom-hostname bindings. Exposed as a namespaced accessor
356
+ * (rather than `addCustomDomain`/`removeCustomDomain`/`listCustomDomains`
357
+ * methods on the resource) so call sites read like
358
+ * `sandbox.customDomains.add("api.acme.com")`, mirroring the noun in the
359
+ * `/v1/.../custom-domains` URL space. A fresh object is returned per access
360
+ * so the closures always see the current `id` even after `refresh()`.
361
+ */
362
+ get customDomains() {
363
+ const client = this.client;
364
+ const id = this.id;
365
+ return {
366
+ add: (hostname) => client.addCustomDomain(id, hostname),
367
+ remove: (hostname) => client.removeCustomDomain(id, hostname),
368
+ list: () => client.listCustomDomains(id),
369
+ };
370
+ }
337
371
  async createSnapshot(name) {
338
372
  return this.client.createSnapshot(this.id, name);
339
373
  }
@@ -390,6 +424,7 @@ function toApiCreateOptions(options) {
390
424
  lifecycle: options.lifecycle ? toApiLifecycle(options.lifecycle) : undefined,
391
425
  failover: options.failover ? toApiFailover(options.failover) : undefined,
392
426
  runtime: options.runtime,
427
+ custom_domains: options.customDomains,
393
428
  };
394
429
  }
395
430
  function toApiRegisterSnapshotOptions(options) {
@@ -522,6 +557,15 @@ function fromApiSession(session) {
522
557
  attached: session.attached,
523
558
  };
524
559
  }
560
+ function fromApiCustomDomain(domain) {
561
+ return {
562
+ hostname: domain.hostname,
563
+ status: domain.status,
564
+ lastError: domain.last_error,
565
+ createdAt: domain.created_at,
566
+ updatedAt: domain.updated_at,
567
+ };
568
+ }
525
569
  function fromApiExposedPort(port) {
526
570
  return {
527
571
  sandboxID: port.sandbox_id,
package/dist/types.d.ts CHANGED
@@ -170,6 +170,13 @@ export interface CreateOptions {
170
170
  * Not compatible with runtime="gvisor".
171
171
  */
172
172
  gpus?: GPUOptions;
173
+ /**
174
+ * Custom hostnames to bind to this sandbox at create-time. Each entry is
175
+ * lowercased server-side and progresses through the standard custom-domain
176
+ * lifecycle (pending_dns → issuing → ready). Equivalent to calling
177
+ * `sandbox.customDomains.add(host)` for each entry after create.
178
+ */
179
+ customDomains?: string[];
173
180
  }
174
181
  export interface ResizeOptions {
175
182
  /** Number of CPU cores. Fractional values supported (e.g. 0.5). */
@@ -219,6 +226,21 @@ export interface ExposedPort {
219
226
  publicURL: string;
220
227
  createdAt: string;
221
228
  }
229
+ /**
230
+ * Lifecycle states for a per-sandbox custom hostname.
231
+ * - "pending_dns": hostname registered; awaiting DNS to point at the daemon.
232
+ * - "issuing": DNS resolves; Caddy is acquiring an ACME certificate.
233
+ * - "ready": certificate issued; traffic served end-to-end on the host.
234
+ * - "failed": ACME or DNS validation failed; see `lastError`.
235
+ */
236
+ export type CustomDomainStatus = "pending_dns" | "issuing" | "ready" | "failed";
237
+ export interface CustomDomain {
238
+ hostname: string;
239
+ status: CustomDomainStatus;
240
+ lastError?: string;
241
+ createdAt: string;
242
+ updatedAt: string;
243
+ }
222
244
  /**
223
245
  * Wire protocol an exposure publishes through:
224
246
  * - "http": Caddy HTTP reverse proxy at https://<id>-<port>.<domain>.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aerol-ai/aerolvm-sdk",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",