@solarisdk/core 0.3.1 → 0.4.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/README.md +4 -0
- package/dist/chunked-download.d.ts +0 -1
- package/dist/chunked-download.js +0 -11
- package/dist/desktop.d.ts +0 -1
- package/dist/desktop.js +0 -52
- package/dist/errors.d.ts +10 -1
- package/dist/errors.js +16 -39
- package/dist/handle.d.ts +7 -1
- package/dist/handle.js +87 -235
- package/dist/http.d.ts +2 -1
- package/dist/http.js +1 -49
- package/dist/ids.d.ts +0 -1
- package/dist/ids.js +0 -6
- package/dist/image.d.ts +0 -1
- package/dist/image.js +0 -40
- package/dist/index.d.ts +3 -4
- package/dist/index.js +3 -5
- package/dist/sandbox.d.ts +0 -1
- package/dist/sandbox.js +0 -6
- package/dist/template-client.d.ts +0 -1
- package/dist/template-client.js +3 -27
- package/dist/transport.d.ts +9 -2
- package/dist/transport.js +64 -102
- package/dist/types.d.ts +34 -7
- package/dist/types.js +0 -7
- package/dist/volume-client.d.ts +0 -1
- package/dist/volume-client.js +0 -17
- package/dist/ws.d.ts +0 -1
- package/dist/ws.js +0 -16
- package/package.json +4 -3
- package/dist/chunked-download.d.ts.map +0 -1
- package/dist/chunked-download.js.map +0 -1
- package/dist/desktop.d.ts.map +0 -1
- package/dist/desktop.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/handle.d.ts.map +0 -1
- package/dist/handle.js.map +0 -1
- package/dist/http.d.ts.map +0 -1
- package/dist/http.js.map +0 -1
- package/dist/ids.d.ts.map +0 -1
- package/dist/ids.js.map +0 -1
- package/dist/image.d.ts.map +0 -1
- package/dist/image.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/sandbox.d.ts.map +0 -1
- package/dist/sandbox.js.map +0 -1
- package/dist/template-client.d.ts.map +0 -1
- package/dist/template-client.js.map +0 -1
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/volume-client.d.ts.map +0 -1
- package/dist/volume-client.js.map +0 -1
- package/dist/ws.d.ts.map +0 -1
- package/dist/ws.js.map +0 -1
package/dist/http.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export interface HttpRequestOptions {
|
|
|
17
17
|
}
|
|
18
18
|
/** A fresh idempotency key (UUID where available). */
|
|
19
19
|
export declare function newIdempotencyKey(): string;
|
|
20
|
+
/** The production gateway. Every client defaults to it when no `baseUrl` is given. */
|
|
21
|
+
export declare const DEFAULT_BASE_URL = "https://api.getsolari.com";
|
|
20
22
|
export declare class HttpTransport {
|
|
21
23
|
readonly apiKey: string;
|
|
22
24
|
readonly baseUrl: string;
|
|
@@ -32,4 +34,3 @@ export declare class HttpTransport {
|
|
|
32
34
|
request<T>(method: string, path: string, body?: unknown, opts?: HttpRequestOptions): Promise<T>;
|
|
33
35
|
private backoffMs;
|
|
34
36
|
}
|
|
35
|
-
//# sourceMappingURL=http.d.ts.map
|
package/dist/http.js
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
|
-
// Shared HTTP transport for the SDK ⇆ Gateway REST API. Both `DesktopClient`
|
|
2
|
-
// and `SandboxClient` delegate here, so there is ONE place that owns auth
|
|
3
|
-
// headers, error mapping, retries/backoff, idempotency keys, and timeouts.
|
|
4
|
-
//
|
|
5
|
-
// Retry policy: idempotent requests (GET, DELETE, or any request carrying an
|
|
6
|
-
// Idempotency-Key) are retried on network errors, HTTP 5xx, 429, and bodies
|
|
7
|
-
// flagged `retryable`, with exponential backoff + jitter. Non-idempotent writes
|
|
8
|
-
// are never silently retried (could double-create) — pass an idempotencyKey to
|
|
9
|
-
// opt a create into safe retries.
|
|
10
1
|
import { ConnectionError, mapGatewayError, SolariError } from "./errors.js";
|
|
11
2
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
12
|
-
/** A fresh idempotency key (UUID where available). */
|
|
13
3
|
export function newIdempotencyKey() {
|
|
14
4
|
const c = globalThis.crypto;
|
|
15
5
|
return c?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2, 12)}`;
|
|
16
6
|
}
|
|
7
|
+
export const DEFAULT_BASE_URL = "https://api.getsolari.com";
|
|
17
8
|
export class HttpTransport {
|
|
18
9
|
apiKey;
|
|
19
10
|
baseUrl;
|
|
@@ -37,11 +28,9 @@ export class HttpTransport {
|
|
|
37
28
|
this.requestTimeoutMs = o.requestTimeoutMs ?? 300_000;
|
|
38
29
|
this.retryDelayMs = o.retryDelayMs;
|
|
39
30
|
}
|
|
40
|
-
/** `Authorization` header for handles + WS upgrades. */
|
|
41
31
|
authHeaders() {
|
|
42
32
|
return { Authorization: `Bearer ${this.apiKey}` };
|
|
43
33
|
}
|
|
44
|
-
/** ws:// (or wss://) origin derived from the gateway base URL. */
|
|
45
34
|
wsOrigin() {
|
|
46
35
|
return this.baseUrl.replace(/^http/, "ws");
|
|
47
36
|
}
|
|
@@ -81,38 +70,6 @@ export class HttpTransport {
|
|
|
81
70
|
catch {
|
|
82
71
|
errBody = undefined;
|
|
83
72
|
}
|
|
84
|
-
// 🚨 AN ALLOWLIST, NOT `>= 500`. A 5xx IS NOT AUTOMATICALLY TRANSIENT.
|
|
85
|
-
//
|
|
86
|
-
// `status >= 500` retried PERMANENT refusals. The gateway has seven 501
|
|
87
|
-
// sites — every /volumes route, refusing because volumes cannot work on
|
|
88
|
-
// GCP at all — and this retried each one five times with backoff before
|
|
89
|
-
// the caller saw anything. Measured on prod 2026-09-22, the backoff curve
|
|
90
|
-
// is visible in the LB logs:
|
|
91
|
-
//
|
|
92
|
-
// 04:47:11 GET /volumes 501
|
|
93
|
-
// 04:47:35 (+24s) 501
|
|
94
|
-
// 04:48:22 (+47s) 501
|
|
95
|
-
//
|
|
96
|
-
// Intervals roughly double, which is what distinguishes a retry loop from
|
|
97
|
-
// a polling client: a poll is evenly spaced. So this was real traffic
|
|
98
|
-
// hammering a "not implemented" on a customer's behalf.
|
|
99
|
-
//
|
|
100
|
-
// 🪤 507 IS IN THE LIST DELIBERATELY, AND NOT VIA THE HINT. The gateway's
|
|
101
|
-
// InsufficientCapacity 507 does carry `retryable: true`, so the hint alone
|
|
102
|
-
// would cover it today — but that makes this SDK's correctness depend on
|
|
103
|
-
// which gateway build the caller is talking to. A rollback, or an older
|
|
104
|
-
// self-hosted gateway, would silently stop retrying a refusal that IS
|
|
105
|
-
// transient by construction (every admissible size fits an empty host;
|
|
106
|
-
// the 507 reports the host's residual budget at that instant). Naming it
|
|
107
|
-
// here removes the deploy-order dependency entirely.
|
|
108
|
-
//
|
|
109
|
-
// 500 is excluded on purpose: an unhandled server error is not
|
|
110
|
-
// known-transient, and the gateway has exactly one such site
|
|
111
|
-
// ("Internal error"). 429 stays excluded as before — that is
|
|
112
|
-
// ConcurrencyLimitError, the org at its cap, and retrying cannot help.
|
|
113
|
-
//
|
|
114
|
-
// The `retryable` hint stays, and is the ONLY route by which a non-5xx
|
|
115
|
-
// can be retried (e.g. a 404 ReplayPending on the browser gateway).
|
|
116
73
|
const RETRYABLE_STATUSES = new Set([502, 503, 504, 507]);
|
|
117
74
|
const retryable = RETRYABLE_STATUSES.has(res.status) || errBody?.retryable === true;
|
|
118
75
|
if (idempotent && retryable && attempt < this.maxRetries) {
|
|
@@ -121,7 +78,6 @@ export class HttpTransport {
|
|
|
121
78
|
}
|
|
122
79
|
throw mapGatewayError(res.status, errBody);
|
|
123
80
|
}
|
|
124
|
-
// DELETE / empty bodies have no JSON.
|
|
125
81
|
const text = await res.text();
|
|
126
82
|
if (text.length === 0)
|
|
127
83
|
return undefined;
|
|
@@ -131,10 +87,6 @@ export class HttpTransport {
|
|
|
131
87
|
backoffMs(attempt) {
|
|
132
88
|
if (this.retryDelayMs !== undefined)
|
|
133
89
|
return this.retryDelayMs;
|
|
134
|
-
// Base 150ms (was 1000): a create bounced by a transient host no_capacity
|
|
135
|
-
// during a burst should re-pick a different host in ~150ms, not idle a full
|
|
136
|
-
// second before its first retry. 150·2^n → 150, 300, 600, 1200, 2400 (cap 8s).
|
|
137
90
|
return Math.min(150 * 2 ** attempt, 8000) + Math.floor(Math.random() * 250);
|
|
138
91
|
}
|
|
139
92
|
}
|
|
140
|
-
//# sourceMappingURL=http.js.map
|
package/dist/ids.d.ts
CHANGED
package/dist/ids.js
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shorten a sandbox/desktop session id for logs and warnings. Session ids are
|
|
3
|
-
* capability tokens (anyone holding one can drive the machine), so SDK output
|
|
4
|
-
* never carries a whole one: the first 8 characters identify it well enough.
|
|
5
|
-
*/
|
|
6
1
|
export function shortId(id) {
|
|
7
2
|
return id.length > 8 ? `${id.slice(0, 8)}…` : id;
|
|
8
3
|
}
|
|
9
|
-
//# sourceMappingURL=ids.js.map
|
package/dist/image.d.ts
CHANGED
package/dist/image.js
CHANGED
|
@@ -1,26 +1,6 @@
|
|
|
1
|
-
// Declarative Image builder (Daytona-style). A fluent chain that compiles to
|
|
2
|
-
// the inputs our golden pipeline (`build-rootfs.sh`) already consumes per
|
|
3
|
-
// template: an apt `packages` list, a `Dockerfile.fragment`, and local files
|
|
4
|
-
// staged into `template-files/` (which the base Dockerfile COPYs to `/`).
|
|
5
|
-
//
|
|
6
|
-
// const img = Image.base("ubuntu:22.04")
|
|
7
|
-
// .aptInstall(["ffmpeg"])
|
|
8
|
-
// .pipInstall(["pandas", "matplotlib"])
|
|
9
|
-
// .runCommands("curl -fsSL https://example.com/i.sh | sh")
|
|
10
|
-
// .addLocalDir("./assets", "/opt/assets")
|
|
11
|
-
// .env({ TZ: "UTC" })
|
|
12
|
-
// .workdir("/work");
|
|
13
|
-
// const tpl = await pt.templates.build(img, { name: "data-sci", kind: "sandbox" });
|
|
14
|
-
//
|
|
15
|
-
// `.compile()` emits a structured `steps[]` (typed ops the snapshot
|
|
16
|
-
// exec-orchestrator runs directly) plus a byte-identical `Dockerfile.fragment`
|
|
17
|
-
// (the Docker rebuild path). NOTE: `.compile()` is pure + offline (unit-tested);
|
|
18
|
-
// actually BUILDING a template (pt.templates.build) requires the gateway
|
|
19
|
-
// `/templates` backend — Phases 2-6 in docs/TEMPLATE-BUILD-PIPELINE.md.
|
|
20
1
|
function envValue(v) {
|
|
21
2
|
return /\s/.test(v) ? JSON.stringify(v) : v;
|
|
22
3
|
}
|
|
23
|
-
/** Render one structured step to its Dockerfile line (approach B). */
|
|
24
4
|
function renderDockerfile(step) {
|
|
25
5
|
switch (step.op) {
|
|
26
6
|
case "pip":
|
|
@@ -46,83 +26,64 @@ export class Image {
|
|
|
46
26
|
_steps = [];
|
|
47
27
|
_localFiles = [];
|
|
48
28
|
constructor() { }
|
|
49
|
-
/** Start from a base OS image (e.g. `"ubuntu:22.04"`). */
|
|
50
29
|
static base(image) {
|
|
51
30
|
const i = new Image();
|
|
52
31
|
i._base = image;
|
|
53
32
|
return i;
|
|
54
33
|
}
|
|
55
|
-
/** Start from an existing Solari template (e.g. `"workstation"`). */
|
|
56
34
|
static fromTemplate(name) {
|
|
57
35
|
const i = new Image();
|
|
58
36
|
i._fromTemplate = name;
|
|
59
37
|
return i;
|
|
60
38
|
}
|
|
61
|
-
/**
|
|
62
|
-
* Start from an OCI image (`"python:3.12-alpine"`, `"ghcr.io/org/app:1.2"`). The image's own
|
|
63
|
-
* filesystem becomes the sandbox's root: exec and file paths are relative to it. Public registries
|
|
64
|
-
* only (docker.io, ghcr.io, public.ecr.aws, gcr.io, quay.io); sandbox templates only; install
|
|
65
|
-
* packages with `runCommands` (not `aptInstall`).
|
|
66
|
-
*/
|
|
67
39
|
static fromImage(ref) {
|
|
68
40
|
const i = new Image();
|
|
69
41
|
i._fromImage = ref;
|
|
70
42
|
return i;
|
|
71
43
|
}
|
|
72
|
-
/** Set the session kind this image is for (`"sandbox"` headless or `"desktop"` GUI). */
|
|
73
44
|
kind(k) {
|
|
74
45
|
this._kind = k;
|
|
75
46
|
return this;
|
|
76
47
|
}
|
|
77
|
-
/** apt packages installed by the pipeline's apt step. */
|
|
78
48
|
aptInstall(pkgs) {
|
|
79
49
|
this._packages.push(...pkgs);
|
|
80
50
|
return this;
|
|
81
51
|
}
|
|
82
|
-
/** `RUN pip3 install …`. */
|
|
83
52
|
pipInstall(pkgs) {
|
|
84
53
|
if (pkgs.length)
|
|
85
54
|
this._steps.push({ op: "pip", packages: [...pkgs] });
|
|
86
55
|
return this;
|
|
87
56
|
}
|
|
88
|
-
/** One `RUN` per command. */
|
|
89
57
|
runCommands(...cmds) {
|
|
90
58
|
for (const c of cmds)
|
|
91
59
|
this._steps.push({ op: "run", command: c });
|
|
92
60
|
return this;
|
|
93
61
|
}
|
|
94
|
-
/** `ENV` vars. */
|
|
95
62
|
env(vars) {
|
|
96
63
|
for (const [k, v] of Object.entries(vars))
|
|
97
64
|
this._steps.push({ op: "env", key: k, value: v });
|
|
98
65
|
return this;
|
|
99
66
|
}
|
|
100
|
-
/** `WORKDIR`. */
|
|
101
67
|
workdir(dir) {
|
|
102
68
|
this._steps.push({ op: "workdir", dir });
|
|
103
69
|
return this;
|
|
104
70
|
}
|
|
105
|
-
/** `ENTRYPOINT` (exec form). */
|
|
106
71
|
entrypoint(cmd) {
|
|
107
72
|
this._steps.push({ op: "entrypoint", command: [...cmd] });
|
|
108
73
|
return this;
|
|
109
74
|
}
|
|
110
|
-
/** `CMD` (exec form). */
|
|
111
75
|
cmd(cmd) {
|
|
112
76
|
this._steps.push({ op: "cmd", command: [...cmd] });
|
|
113
77
|
return this;
|
|
114
78
|
}
|
|
115
|
-
/** Stage a local file into the guest at `dest` (copied via `template-files/`). */
|
|
116
79
|
addLocalFile(src, dest) {
|
|
117
80
|
this._localFiles.push({ src, dest });
|
|
118
81
|
return this;
|
|
119
82
|
}
|
|
120
|
-
/** Stage a local directory into the guest at `dest`. */
|
|
121
83
|
addLocalDir(src, dest) {
|
|
122
84
|
this._localFiles.push({ src, dest });
|
|
123
85
|
return this;
|
|
124
86
|
}
|
|
125
|
-
/** Compile to the build-context inputs. Pure + offline. */
|
|
126
87
|
compile() {
|
|
127
88
|
return {
|
|
128
89
|
kind: this._kind,
|
|
@@ -136,4 +97,3 @@ export class Image {
|
|
|
136
97
|
};
|
|
137
98
|
}
|
|
138
99
|
}
|
|
139
|
-
//# sourceMappingURL=image.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { SessionHandle } from "./handle.js";
|
|
1
|
+
export { DEFAULT_COMMAND_TIMEOUT_MS, SessionHandle } from "./handle.js";
|
|
2
2
|
export { shortId } from "./ids.js";
|
|
3
3
|
export type { SessionConfig, SessionHooks } from "./handle.js";
|
|
4
4
|
export { Desktop } from "./desktop.js";
|
|
@@ -10,7 +10,6 @@ export { TemplateClient } from "./template-client.js";
|
|
|
10
10
|
export type { TemplateClientOptions } from "./template-client.js";
|
|
11
11
|
export { VolumeClient } from "./volume-client.js";
|
|
12
12
|
export type { VolumeClientOptions } from "./volume-client.js";
|
|
13
|
-
export { HttpTransport, newIdempotencyKey } from "./http.js";
|
|
14
|
-
export { ActionError, AuthError, ConcurrencyLimitError, ConnectionError, GatewayError, NoCapacityError, SandboxNotStoppedError, SolariError, PlanError, TimeoutError, } from "./errors.js";
|
|
13
|
+
export { DEFAULT_BASE_URL, HttpTransport, newIdempotencyKey } from "./http.js";
|
|
14
|
+
export { ActionError, AuthError, ConcurrencyLimitError, ConnectionError, GatewayError, NoCapacityError, NotFoundError, SandboxNotStoppedError, SolariError, PlanError, TimeoutError, ValidationError, } from "./errors.js";
|
|
15
15
|
export type * from "./types.js";
|
|
16
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
export { SessionHandle } from "./handle.js";
|
|
1
|
+
export { DEFAULT_COMMAND_TIMEOUT_MS, SessionHandle } from "./handle.js";
|
|
3
2
|
export { shortId } from "./ids.js";
|
|
4
3
|
export { Desktop } from "./desktop.js";
|
|
5
4
|
export { Sandbox } from "./sandbox.js";
|
|
6
5
|
export { Image } from "./image.js";
|
|
7
6
|
export { TemplateClient } from "./template-client.js";
|
|
8
7
|
export { VolumeClient } from "./volume-client.js";
|
|
9
|
-
export { HttpTransport, newIdempotencyKey } from "./http.js";
|
|
10
|
-
export { ActionError, AuthError, ConcurrencyLimitError, ConnectionError, GatewayError, NoCapacityError, SandboxNotStoppedError, SolariError, PlanError, TimeoutError, } from "./errors.js";
|
|
11
|
-
//# sourceMappingURL=index.js.map
|
|
8
|
+
export { DEFAULT_BASE_URL, HttpTransport, newIdempotencyKey } from "./http.js";
|
|
9
|
+
export { ActionError, AuthError, ConcurrencyLimitError, ConnectionError, GatewayError, NoCapacityError, NotFoundError, SandboxNotStoppedError, SolariError, PlanError, TimeoutError, ValidationError, } from "./errors.js";
|
package/dist/sandbox.d.ts
CHANGED
package/dist/sandbox.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
// `Sandbox` — a handle to one live headless session. All of its surface lives
|
|
2
|
-
// on the shared {@link SessionHandle} base (commands, pty, runCode, files,
|
|
3
|
-
// volumes, metrics, snapshot, revert, pause/resume, setTimeout, env,
|
|
4
|
-
// kill). Construct via {@link SandboxClient}.
|
|
5
1
|
import { SessionHandle } from "./handle.js";
|
|
6
2
|
export class Sandbox extends SessionHandle {
|
|
7
|
-
/** The sandbox id (alias of {@link SessionHandle.id}). */
|
|
8
3
|
get sandboxId() {
|
|
9
4
|
return this.id;
|
|
10
5
|
}
|
|
@@ -12,4 +7,3 @@ export class Sandbox extends SessionHandle {
|
|
|
12
7
|
super(session.sandboxId, session.controlUrl, session.expiresAt, config);
|
|
13
8
|
}
|
|
14
9
|
}
|
|
15
|
-
//# sourceMappingURL=sandbox.js.map
|
package/dist/template-client.js
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
// `TemplateClient` — talks the SDK ⇆ Gateway `/templates` HTTP API and turns a
|
|
2
|
-
// declarative {@link Image} into a reusable template a session can launch:
|
|
3
|
-
//
|
|
4
|
-
// const img = Image.base("ubuntu:22.04").aptInstall(["ffmpeg"]).kind("sandbox");
|
|
5
|
-
// const tpl = await pt.templates.build(img, { name: "media" });
|
|
6
|
-
// const sbx = await pt.sandboxes.create({ template: tpl.templateId });
|
|
7
|
-
//
|
|
8
|
-
// `build()` POSTs the compiled recipe (async build on the gateway) and then
|
|
9
|
-
// polls to completion. See docs/TEMPLATE-BUILD-PIPELINE.md.
|
|
10
1
|
import { SolariError } from "./errors.js";
|
|
11
2
|
import { HttpTransport, newIdempotencyKey } from "./http.js";
|
|
12
3
|
import { Image } from "./image.js";
|
|
13
|
-
const DEFAULT_BUILD_TIMEOUT_MS = 900_000;
|
|
4
|
+
const DEFAULT_BUILD_TIMEOUT_MS = 900_000;
|
|
14
5
|
const DEFAULT_POLL_INTERVAL_MS = 3_000;
|
|
15
6
|
const realSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
16
7
|
export class TemplateClient {
|
|
@@ -28,19 +19,13 @@ export class TemplateClient {
|
|
|
28
19
|
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
29
20
|
});
|
|
30
21
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Build a custom template from an {@link Image} (or a pre-{@link CompiledImage}).
|
|
33
|
-
* Kicks off the async gateway build then waits until it is `ready` (or throws
|
|
34
|
-
* on `failed`/timeout). Returns the final template view.
|
|
35
|
-
*/
|
|
36
22
|
async build(image, opts) {
|
|
37
23
|
if (!opts?.name)
|
|
38
24
|
throw new SolariError("templates.build requires a name");
|
|
39
25
|
const { buildId, templateId } = await this.buildRaw(image, opts);
|
|
40
|
-
void buildId;
|
|
26
|
+
void buildId;
|
|
41
27
|
return this.waitUntilReady(templateId, opts);
|
|
42
28
|
}
|
|
43
|
-
/** Start a build without waiting (`POST /templates`). Returns ids immediately. */
|
|
44
29
|
async buildRaw(image, opts) {
|
|
45
30
|
const compiled = image instanceof Image ? image.compile() : image;
|
|
46
31
|
const body = {
|
|
@@ -54,28 +39,20 @@ export class TemplateClient {
|
|
|
54
39
|
idempotencyKey: newIdempotencyKey(),
|
|
55
40
|
});
|
|
56
41
|
}
|
|
57
|
-
/** List templates — built-ins + this org's custom templates (`GET /templates`). */
|
|
58
42
|
async list() {
|
|
59
43
|
const res = await this.http.request("GET", "/templates");
|
|
60
44
|
return res.templates;
|
|
61
45
|
}
|
|
62
|
-
/** Get one template's status/metadata (`GET /templates/:id`). */
|
|
63
46
|
get(templateId) {
|
|
64
47
|
return this.http.request("GET", `/templates/${encodeURIComponent(templateId)}`);
|
|
65
48
|
}
|
|
66
|
-
/** Delete a custom template (`DELETE /templates/:id`; refused while live sessions depend on it). */
|
|
67
49
|
async delete(templateId) {
|
|
68
50
|
await this.http.request("DELETE", `/templates/${encodeURIComponent(templateId)}`);
|
|
69
51
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Poll `GET /templates/:id` until it leaves `building`. Resolves on `ready`,
|
|
72
|
-
* throws on `failed`, throws on timeout. `onLog` is invoked best-effort as the
|
|
73
|
-
* gateway exposes build logs (a no-op until the log stream ships).
|
|
74
|
-
*/
|
|
75
52
|
async waitUntilReady(templateId, opts) {
|
|
76
53
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_BUILD_TIMEOUT_MS;
|
|
77
54
|
const pollMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
78
|
-
const deadline = timeoutMs;
|
|
55
|
+
const deadline = timeoutMs;
|
|
79
56
|
let waited = 0;
|
|
80
57
|
for (;;) {
|
|
81
58
|
const view = await this.get(templateId);
|
|
@@ -92,4 +69,3 @@ export class TemplateClient {
|
|
|
92
69
|
}
|
|
93
70
|
}
|
|
94
71
|
}
|
|
95
|
-
//# sourceMappingURL=template-client.js.map
|
package/dist/transport.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ export interface ControlChannelConfig {
|
|
|
23
23
|
callTimeoutMs?: number;
|
|
24
24
|
/** Extra headers for the control WS upgrade (Node only). */
|
|
25
25
|
headers?: Record<string, string>;
|
|
26
|
+
/**
|
|
27
|
+
* Close the WebSocket after this many milliseconds with nothing using it (no call in flight, no running command,
|
|
28
|
+
* no open PTY); the next call reopens it by itself. Lets a script that ends without `kill()`/`close()` exit instead of
|
|
29
|
+
* hanging on the socket. Default 3000; `0` keeps the connection open for good.
|
|
30
|
+
*/
|
|
31
|
+
idleCloseMs?: number;
|
|
26
32
|
}
|
|
27
33
|
/** The shared control-WS transport. Construct one per live session handle. */
|
|
28
34
|
export declare class ControlChannel {
|
|
@@ -55,6 +61,8 @@ export declare class ControlChannel {
|
|
|
55
61
|
*/
|
|
56
62
|
private readonly streamClosers;
|
|
57
63
|
private readonly callTimeoutMs;
|
|
64
|
+
private readonly idleCloseMs;
|
|
65
|
+
private idleTimer;
|
|
58
66
|
private readonly headers;
|
|
59
67
|
private closed;
|
|
60
68
|
constructor(controlUrl: string, config?: ControlChannelConfig);
|
|
@@ -96,7 +104,7 @@ export declare class ControlChannel {
|
|
|
96
104
|
private onMessage;
|
|
97
105
|
private dispatch;
|
|
98
106
|
private onClose;
|
|
99
|
-
/** Allocate the next opaque request id (string
|
|
107
|
+
/** Allocate the next opaque request id (a string). */
|
|
100
108
|
newId(): string;
|
|
101
109
|
/**
|
|
102
110
|
* Send one JSON-RPC call and await its correlated reply. `onStream` (v1)
|
|
@@ -114,4 +122,3 @@ export declare class ControlChannel {
|
|
|
114
122
|
export declare function base64ToBytes(b64: string): Uint8Array;
|
|
115
123
|
/** Bytes → base64, working in both Node and the browser. */
|
|
116
124
|
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
117
|
-
//# sourceMappingURL=transport.d.ts.map
|