Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions .github/workflows/js-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ name: JS Tests
on:
push:
branches: ["main"]
paths:
- "js/**"
- ".github/workflows/js-test.yml"
pull_request:
paths:
- "js/**"
- ".github/workflows/js-test.yml"

jobs:
test:
Expand Down Expand Up @@ -37,3 +31,6 @@ jobs:

- name: Build
run: npm run build

- name: Unit tests
run: npm test
14 changes: 0 additions & 14 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,7 @@ name: Tests
on:
push:
branches: ["main"]
paths:
- "src/**"
- "tests/**"
- "benchmarks/**"
- "pyproject.toml"
- "uv.lock"
- ".github/workflows/test.yml"
pull_request:
paths:
- "src/**"
- "tests/**"
- "benchmarks/**"
- "pyproject.toml"
- "uv.lock"
- ".github/workflows/test.yml"

jobs:
test:
Expand Down
12 changes: 10 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,18 @@ celesto-sdk/

- Location: [js/](js/)
- Package name: `@celestoai/sdk` (published to npm with public access)
- Scope: **Gatekeeper only** today — not feature-parity with the Python SDK
- Scope: **Gatekeeper** + **Computers**. `CelestoClient` composes both: `celesto.gatekeeper.*` and `celesto.computers.*`. Individual clients are also importable via subpath exports (`@celestoai/sdk/gatekeeper`, `@celestoai/sdk/computers`).
- Computers parity with Python: all 7 HTTP methods (`create`, `list`, `get`, `exec`, `stop`, `start`, `delete`) plus `openTerminal()` which returns an `EventEmitter`-based `Terminal` handle. Terminal uses the `ws` package — the only runtime dependency.
- Terminal rules (mirror [src/celesto/computer.py](src/celesto/computer.py)):
- Always resolve name → ID via `get()` before the WebSocket handshake — the WS endpoint does not resolve names. `openTerminal()` does this internally.
- WebSocket handshake sends `Authorization: Bearer` header; the legacy first-message `{"token": ...}` JSON is also sent after connect for backend compat.
- Resize frames are `{"type": "resize", "cols": N, "rows": N}`.
- Does **not** auto-resume stopped computers — that's application logic, not SDK default.
- Public API is camelCase; wire DTOs are snake_case (`vcpus`, `ram_mb`, `exit_code`, etc.) mapped in the client file. Same pattern as Gatekeeper.
- Build: `cd js && npm install && npm run build` (tsup → ESM + CJS + DTS under `js/dist/`)
- Lint / typecheck: `cd js && npm run lint` (runs `tsc --noEmit`)
- Smoke test: `cd js && node test.mjs` (requires `CELESTO_API_KEY` and hits the live API)
- Unit tests: `cd js && npm test`. Uses Node's built-in `node:test` runner via `tsx`. Tests live in `js/tests/`. HTTP tests mock `fetch` via `ClientConfig.fetch`; terminal tests start a real in-process `WebSocketServer` from the `ws` package on `127.0.0.1:0` to avoid mocking the library.
- Smoke test (manual, needs live API key): `cd js && node test.mjs`
- No workspace plumbing, no `package.json` at the repo root — treat `js/` as a self-contained project.
- Publish process is manual and independent from the Python release: bump `js/package.json` version, `npm run build`, `npm publish` from inside `js/`.

Expand Down
99 changes: 82 additions & 17 deletions js/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Celesto SDK (Gatekeeper)
# @celestoai/sdk

Node-only TypeScript SDK for Celesto's Gatekeeper API (`/v1/gatekeeper`).
Node-only TypeScript SDK for the [Celesto](https://celesto.ai) platform. Covers:

- **Gatekeeper** (`/v1/gatekeeper`) — delegated access to user resources
- **Computers** (`/v1/computers`) — create, manage, and interact with sandboxed virtual machines

## Install

Expand All @@ -11,15 +14,84 @@ npm install @celestoai/sdk
## Quickstart

```ts
import { GatekeeperClient } from "@celestoai/sdk/gatekeeper";
import { CelestoClient } from "@celestoai/sdk";

const client = new GatekeeperClient({
baseUrl: "https://api.celesto.ai",
const celesto = new CelestoClient({
token: process.env.CELESTO_API_KEY,
// If using JWT and multiple orgs, set the org context:
// organizationId: "org_123",
// organizationId: "org_123", // optional, for JWTs with multiple orgs
});

// Gatekeeper
const connect = await celesto.gatekeeper.connect({
subject: "customer_123",
provider: "google_drive",
projectName: "Default",
});

// Computers
const computer = await celesto.computers.create({ cpus: 2, memory: 2048 });
const result = await celesto.computers.exec(computer.id, "uname -a");
console.log(result.stdout);
await celesto.computers.delete(computer.id);
```

## Computers

### Lifecycle

```ts
const computer = await celesto.computers.create({
cpus: 2,
memory: 2048,
image: "ubuntu-desktop-24.04",
});

await celesto.computers.stop(computer.id);
await celesto.computers.start(computer.id);
await celesto.computers.delete(computer.id);

const { computers, count } = await celesto.computers.list();
```

### Running commands

```ts
const result = await celesto.computers.exec(computer.id, "ls -la", { timeout: 60 });
console.log(result.exitCode, result.stdout, result.stderr);
```

### Interactive terminal

`openTerminal()` returns an event-driven handle backed by a WebSocket. It accepts either a
computer ID or a human-readable name — the name is resolved to the canonical ID before the
WebSocket handshake. `openTerminal()` does **not** auto-resume stopped computers; call
`start()` yourself and poll for `status === "running"` if you need that.

```ts
const terminal = await celesto.computers.openTerminal(computer.id);

terminal.on("data", (chunk) => process.stdout.write(chunk));
terminal.on("close", (code, reason) => {
console.log(`terminal closed: ${code} ${reason}`);
});
terminal.on("error", (err) => {
console.error(err);
});

terminal.write("ls -la\n");
terminal.resize(120, 40);

// ...later
await terminal.close();
```

## Gatekeeper

```ts
import { GatekeeperClient } from "@celestoai/sdk/gatekeeper";

const client = new GatekeeperClient({ token: process.env.CELESTO_API_KEY });

const connect = await client.connect({
subject: "customer_123",
provider: "google_drive",
Expand All @@ -31,21 +103,14 @@ if (connect.status === "redirect") {
}
```

## Documentation

```
https://docs.celesto.ai/celesto-sdk/gatekeeper
```
Full docs: https://docs.celesto.ai/celesto-sdk/gatekeeper

## Notes

- `token` accepts either a Celesto API key or a JWT.
- `organizationId` adds the `X-Current-Organization` header.
- Requires Node 18+ for built-in `fetch`.
- Requires Node 18+ for built-in `fetch`. The `ws` package is used for WebSocket terminal support.

## License

Apache-2.0. The SDK is open source; use of the Celesto platform is governed by the Celesto Terms of Service:
```
https://celesto.ai/legal/terms
```
Apache-2.0. The SDK is open source; use of the Celesto platform is governed by the Celesto Terms of Service: https://celesto.ai/legal/terms
101 changes: 99 additions & 2 deletions js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 15 additions & 3 deletions js/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@celestoai/sdk",
"version": "0.1.0",
"description": "Celesto SDK (Gatekeeper client)",
"version": "0.2.0",
"description": "Celesto SDK Gatekeeper and Computers clients for Node.js",
"license": "Apache-2.0",
"type": "module",
"main": "./dist/index.cjs",
Expand All @@ -17,6 +17,11 @@
"types": "./dist/gatekeeper/index.d.ts",
"import": "./dist/gatekeeper/index.js",
"require": "./dist/gatekeeper/index.cjs"
},
"./computers": {
"types": "./dist/computers/index.d.ts",
"import": "./dist/computers/index.js",
"require": "./dist/computers/index.cjs"
}
},
"files": [
Expand All @@ -32,10 +37,17 @@
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"lint": "tsc -p tsconfig.json --noEmit"
"lint": "tsc -p tsconfig.json --noEmit",
"test": "tsx --test tests/computers.test.ts tests/terminal.test.ts"
},
"dependencies": {
"ws": "^8.18.0"
},
"devDependencies": {
"@types/node": "^20.14.0",
"@types/ws": "^8.5.12",
"tsup": "^8.0.2",
"tsx": "^4.19.0",
"typescript": "^5.5.4"
}
}
Loading
Loading