@solarisdk/core 0.3.1 → 0.4.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.
Files changed (58) hide show
  1. package/README.md +4 -0
  2. package/dist/chunked-download.d.ts +0 -1
  3. package/dist/chunked-download.js +0 -11
  4. package/dist/desktop.d.ts +0 -1
  5. package/dist/desktop.js +0 -52
  6. package/dist/errors.d.ts +10 -1
  7. package/dist/errors.js +16 -39
  8. package/dist/handle.d.ts +7 -1
  9. package/dist/handle.js +87 -235
  10. package/dist/http.d.ts +2 -1
  11. package/dist/http.js +1 -49
  12. package/dist/ids.d.ts +0 -1
  13. package/dist/ids.js +0 -6
  14. package/dist/image.d.ts +0 -1
  15. package/dist/image.js +0 -40
  16. package/dist/index.d.ts +3 -4
  17. package/dist/index.js +3 -5
  18. package/dist/sandbox.d.ts +0 -1
  19. package/dist/sandbox.js +0 -6
  20. package/dist/template-client.d.ts +0 -1
  21. package/dist/template-client.js +3 -27
  22. package/dist/transport.d.ts +9 -2
  23. package/dist/transport.js +64 -102
  24. package/dist/types.d.ts +19 -7
  25. package/dist/types.js +0 -7
  26. package/dist/volume-client.d.ts +0 -1
  27. package/dist/volume-client.js +0 -17
  28. package/dist/ws.d.ts +0 -1
  29. package/dist/ws.js +0 -16
  30. package/package.json +4 -3
  31. package/dist/chunked-download.d.ts.map +0 -1
  32. package/dist/chunked-download.js.map +0 -1
  33. package/dist/desktop.d.ts.map +0 -1
  34. package/dist/desktop.js.map +0 -1
  35. package/dist/errors.d.ts.map +0 -1
  36. package/dist/errors.js.map +0 -1
  37. package/dist/handle.d.ts.map +0 -1
  38. package/dist/handle.js.map +0 -1
  39. package/dist/http.d.ts.map +0 -1
  40. package/dist/http.js.map +0 -1
  41. package/dist/ids.d.ts.map +0 -1
  42. package/dist/ids.js.map +0 -1
  43. package/dist/image.d.ts.map +0 -1
  44. package/dist/image.js.map +0 -1
  45. package/dist/index.d.ts.map +0 -1
  46. package/dist/index.js.map +0 -1
  47. package/dist/sandbox.d.ts.map +0 -1
  48. package/dist/sandbox.js.map +0 -1
  49. package/dist/template-client.d.ts.map +0 -1
  50. package/dist/template-client.js.map +0 -1
  51. package/dist/transport.d.ts.map +0 -1
  52. package/dist/transport.js.map +0 -1
  53. package/dist/types.d.ts.map +0 -1
  54. package/dist/types.js.map +0 -1
  55. package/dist/volume-client.d.ts.map +0 -1
  56. package/dist/volume-client.js.map +0 -1
  57. package/dist/ws.d.ts.map +0 -1
  58. 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
@@ -4,4 +4,3 @@
4
4
  * never carries a whole one: the first 8 characters identify it well enough.
5
5
  */
6
6
  export declare function shortId(id: string): string;
7
- //# sourceMappingURL=ids.d.ts.map
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
@@ -95,4 +95,3 @@ export declare class Image {
95
95
  /** Compile to the build-context inputs. Pure + offline. */
96
96
  compile(): CompiledImage;
97
97
  }
98
- //# sourceMappingURL=image.d.ts.map
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
- // @solarisdk/core — shared runtime for @solarisdk/desktop and @solarisdk/sandbox.
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
@@ -5,4 +5,3 @@ export declare class Sandbox extends SessionHandle {
5
5
  get sandboxId(): string;
6
6
  constructor(session: CreateSandboxResponse, config?: SessionConfig);
7
7
  }
8
- //# sourceMappingURL=sandbox.d.ts.map
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
@@ -32,4 +32,3 @@ export declare class TemplateClient {
32
32
  */
33
33
  waitUntilReady(templateId: string, opts: BuildTemplateOptions): Promise<TemplateView>;
34
34
  }
35
- //# sourceMappingURL=template-client.d.ts.map
@@ -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; // 15 min
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; // reserved for future log-stream correlation
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; // relative budget; decremented per poll (clock-free for tests)
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
@@ -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, per CONTRACTS §4). */
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