@promigence/sdk 0.1.0-beta.14 → 0.1.0-beta.15

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/pty.d.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  /**
2
2
  * Interactive terminals: `GET /v1/sandboxes/:id/pty` over a WebSocket (RFC 6455).
3
3
  *
4
- * The protocol:
4
+ * The protocol (`promigence.pty.v2`):
5
5
  *
6
- * client → server binary = keystrokes; text = `{"resize":{cols,rows}}` | `{"signal":N}` | `{"eof":true}`
6
+ * client → server first, one text frame `{"start":{"cmd"?,"secrets"?}}`: what to run and the secret
7
+ * names it gets, inside the connection, never in a header or the URL; then
8
+ * binary = keystrokes; text = `{"resize":{cols,rows}}` | `{"signal":N}` | `{"eof":true}`
7
9
  * server → client binary = terminal output; text = `{"event":"open",…}` first and
8
- * `{"event":"exit"|"error"|"closed",…}` last, then a Close frame
10
+ * `{"event":"exit"|"error"|"closed",…}` last, then a Close frame. A terminal that
11
+ * cannot open says so in its first frame: `{"event":"error","status",…}`, then Close.
9
12
  *
10
13
  * Zero dependencies, so this is a small client over `node:http` rather than the global
11
14
  * `WebSocket`: that one cannot send an `Authorization` header, and a key in the query string is
@@ -32,26 +35,20 @@ export interface PtyExit {
32
35
  message: string;
33
36
  };
34
37
  }
35
- /** The header the terminal's command travels in, base64. Never a query parameter. */
36
- export declare const PTY_COMMAND_HEADER = "promigence-pty-command";
37
- /** The header the terminal's secret **names** travel in, base64 JSON. */
38
- export declare const PTY_SECRETS_HEADER = "promigence-pty-secrets";
38
+ /** The WebSocket subprotocol a terminal speaks: its first message is `{"start": {"cmd"?, "secrets"?}}`. */
39
+ export declare const PTY_PROTOCOL = "promigence.pty.v2";
39
40
  export interface PtyConnectOpts {
40
41
  /** `http(s)://host[:port]/v1/sandboxes/<id>/pty?cols=&rows=` — dimensions only. */
41
42
  url: string;
42
43
  apiKey: string;
43
44
  userAgent: string;
44
45
  /**
45
- * The command to run, sent as a header rather than in the URL.
46
- *
47
- * It used to be `?cmd=`, with `envs` composed into it as `export K=v;` — so a terminal opened
48
- * with an API key in its environment wrote that key into the query string of every request,
49
- * and therefore into every access log along the path. Names and values both stay out of the
50
- * URL now.
46
+ * The command to run. Sent in the terminal's first message, inside the connection: never in a
47
+ * header or the URL, where a log on the way could keep it.
51
48
  */
52
49
  command?: string;
53
50
  /** Stored secret names (or `{name, as}` bindings), resolved server-side into the terminal's
54
- * environment. JSON, base64, in a header. */
51
+ * environment. Sent in the first message with the command. */
55
52
  secrets?: unknown[];
56
53
  /** The `promigence-caller` label, when one is set (`setCaller`). */
57
54
  caller?: string;
package/dist/pty.js CHANGED
@@ -5,8 +5,10 @@ export const PTY_INPUT_CHUNK = 64 * 1024;
5
5
  export const PTY_INPUT_KEEP = 256 * 1024;
6
6
  export const PTY_RESUME_HEADER = "promigence-resume";
7
7
  const WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
8
- export const PTY_COMMAND_HEADER = "promigence-pty-command";
9
- export const PTY_SECRETS_HEADER = "promigence-pty-secrets";
8
+ export const PTY_PROTOCOL = "promigence.pty.v2";
9
+ export function ptyStartMessage(command, secrets) {
10
+ return JSON.stringify({ start: { ...(command ? { cmd: command } : {}), ...(secrets?.length ? { secrets } : {}) } });
11
+ }
10
12
  export function wsAccept(key) {
11
13
  return createHash("sha1").update(key + WS_GUID).digest("base64");
12
14
  }
@@ -250,15 +252,7 @@ function openLeg(opts, url, resume) {
250
252
  authorization: `Bearer ${opts.apiKey}`,
251
253
  "user-agent": opts.userAgent,
252
254
  ...(opts.caller ? { [CALLER_HEADER]: opts.caller } : {}),
253
- ...(resume ? { [PTY_RESUME_HEADER]: resume } : {}),
254
- ...(opts.command && !resume
255
- ? { [PTY_COMMAND_HEADER]: Buffer.from(opts.command, "utf8").toString("base64") }
256
- : {}),
257
- ...(opts.secrets?.length && !resume
258
- ? {
259
- [PTY_SECRETS_HEADER]: Buffer.from(JSON.stringify(opts.secrets), "utf8").toString("base64"),
260
- }
261
- : {}),
255
+ ...(resume ? { [PTY_RESUME_HEADER]: resume } : { "sec-websocket-protocol": PTY_PROTOCOL }),
262
256
  },
263
257
  });
264
258
  let resolveEnded;
@@ -291,6 +285,8 @@ function openLeg(opts, url, resume) {
291
285
  return;
292
286
  }
293
287
  socket.setNoDelay(true);
288
+ if (!resume)
289
+ socket.write(encodeFrame(0x1, Buffer.from(ptyStartMessage(opts.command, opts.secrets), "utf8")));
294
290
  const reader = new FrameReader();
295
291
  let exit;
296
292
  let closeCode;
@@ -328,6 +324,12 @@ function openLeg(opts, url, resume) {
328
324
  ...(typeof v["wall_ms"] === "number" ? { wallMs: v["wall_ms"] } : {}),
329
325
  };
330
326
  }
327
+ else if (v["event"] === "error" && !wasOpen && typeof v["status"] === "number") {
328
+ const e = (v["error"] && typeof v["error"] === "object" ? v["error"] : { code: v["code"], message: v["message"] });
329
+ fail(v["status"], JSON.stringify({ error: e }), typeof v["retry_after"] === "string" ? v["retry_after"] : undefined);
330
+ socket.destroy();
331
+ return;
332
+ }
331
333
  else if (v["event"] === "error" || v["event"] === "closed") {
332
334
  exit = {
333
335
  exitCode: null, signal: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promigence/sdk",
3
- "version": "0.1.0-beta.14",
3
+ "version": "0.1.0-beta.15",
4
4
  "description": "The fastest sandboxes for AI agents and code. The Promigence TypeScript SDK: snapshot an environment once, fork it as often as you need, run commands in every copy. A simple Sandbox class and the full PromigenceClient, with zero runtime dependencies.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://www.promigence.ai",