@sealant/sdk 0.22.0 → 0.23.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.
@@ -3,18 +3,19 @@ import { closeSessionOp, getSessionOp, getSessionOutputOp, resizeSessionOp, send
3
3
  * Open the held-WebSocket terminal attachment (the data plane). One socket:
4
4
  * binary frames are PTY bytes in both directions, text frames are control
5
5
  * JSON (`{"t":"resize",...}` up, `{"t":"end"}` down). Auth rides the connect —
6
- * `?token=` for apiKey clients (WebSocket cannot set headers), `?ownerUserId=`
7
- * for host-local and never repeats per event.
6
+ * `?ownerUserId=` always, plus `?token=` for apiKey clients (WebSocket cannot
7
+ * set headers; a service principal needs the owner assertion *and* its key)
8
+ * and never repeats per event.
8
9
  */
9
10
  const openAttachment = (ctx, sessionId, options) => {
10
11
  const config = ctx.config;
11
12
  const url = new URL(`/v1/sessions/${sessionId}/attach`, config.baseUrl);
12
13
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
13
14
  url.searchParams.set("from", (options?.from ?? 0n).toString());
14
- if (config.apiKey === undefined) {
15
- url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
16
- }
17
- else {
15
+ // The owner assertion always rides the URL; a service principal needs it *alongside* its key,
16
+ // and WebSocket cannot carry headers, so the key rides the URL too.
17
+ url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
18
+ if (config.apiKey !== undefined) {
18
19
  url.searchParams.set("token", config.apiKey);
19
20
  }
20
21
  return new Promise((resolve, reject) => {
@@ -126,9 +127,7 @@ async function* streamOverSse(ctx, sessionId, from, signal) {
126
127
  const fetchImpl = config.fetch ?? fetch;
127
128
  const url = new URL(`/v1/sessions/${sessionId}/output/stream`, config.baseUrl);
128
129
  url.searchParams.set("from", from.toString());
129
- if (config.apiKey === undefined) {
130
- url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
131
- }
130
+ url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
132
131
  const response = await fetchImpl(url, {
133
132
  headers: {
134
133
  accept: "text/event-stream",
@@ -214,10 +214,10 @@ const openForward = (ctx, workspaceId, port, options) => {
214
214
  if (options?.protocol === "udp") {
215
215
  url.searchParams.set("protocol", "udp");
216
216
  }
217
- if (config.apiKey === undefined) {
218
- url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
219
- }
220
- else {
217
+ // The owner assertion always rides the URL (a service principal needs it alongside its
218
+ // key, and WebSocket cannot carry headers — same contract as the session attach).
219
+ url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
220
+ if (config.apiKey !== undefined) {
221
221
  url.searchParams.set("token", config.apiKey);
222
222
  }
223
223
  return new Promise((resolve, reject) => {
@@ -4,7 +4,8 @@
4
4
  * no contract change. The public `repository` is the SOURCE git repo (it becomes
5
5
  * `spec.sources.workspace.url`); the contract's `repository`/`tag` are the OCI push coordinates, which
6
6
  * we derive. `customization.enableSealantd` is forced on (it bakes + launches the daemon the run path
7
- * connects to), the runtime target is pinned to docker (the only bridgeable adapter today), and the
7
+ * connects to), the runtime target is `auto` (the deployment's default adapter — Docker on self-host, Kubernetes
8
+ * when the worker is configured for a cluster), and the
8
9
  * foreground is a keepalive so the workspace idles with the daemon up and the harness is exec'd on
9
10
  * demand by `run()` rather than launched at boot. `options.credentials`, if present, is lowered via
10
11
  * `mapWorkspaceCredentials` (see `./credentials.js`) and folded into `spec.credentials`; the control
@@ -182,7 +183,9 @@ export const buildCreateWorkspaceRequest = (options, config) => {
182
183
  os: options.baseImage !== undefined
183
184
  ? { family: "custom", mode: "require", baseImage: options.baseImage }
184
185
  : { family: options.os ?? "fedora", mode: "prefer" },
185
- runtime: { family: "docker", mode: "require" },
186
+ // `auto` = the deployment's DEFAULT_RUNTIME_ADAPTER. SDK callers don't know (and must not
187
+ // care) whether the control plane runs workspaces as containers or Pods.
188
+ runtime: { family: "auto", mode: "prefer" },
186
189
  },
187
190
  lifecycle: {
188
191
  startup: { foreground: { kind: "command", run: "sleep infinity", shell: "bash" } },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealant/sdk",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "The fluent public SDK for Sealant — create a workspace, run a harness, replay the record.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -26,7 +26,7 @@
26
26
  "access": "public"
27
27
  },
28
28
  "dependencies": {
29
- "@sealant/api-contracts": "^0.22.0"
29
+ "@sealant/api-contracts": "^0.23.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@effect/vitest": "4.0.0-beta.85",