@celestoai/sdk 0.1.0 → 0.1.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 CHANGED
@@ -1,6 +1,9 @@
1
- # Celesto SDK (Gatekeeper)
1
+ # @celestoai/sdk
2
2
 
3
- Node-only TypeScript SDK for Celesto's Gatekeeper API (`/v1/gatekeeper`).
3
+ Node-only TypeScript SDK for the [Celesto](https://celesto.ai) platform. Covers:
4
+
5
+ - **Computers** (`/v1/computers`) — create, manage, and interact with sandboxed virtual machines
6
+ - **Gatekeeper** (`/v1/gatekeeper`) — delegated access to user resources
4
7
 
5
8
  ## Install
6
9
 
@@ -8,16 +11,71 @@ Node-only TypeScript SDK for Celesto's Gatekeeper API (`/v1/gatekeeper`).
8
11
  npm install @celestoai/sdk
9
12
  ```
10
13
 
11
- ## Usage
14
+ ## Quickstart
12
15
 
13
16
  ```ts
14
- import { GatekeeperClient } from "@celestoai/sdk/gatekeeper";
17
+ import { Celesto } from "@celestoai/sdk";
15
18
 
16
- const client = new GatekeeperClient({
17
- baseUrl: "https://api.celesto.ai",
18
- token: process.env.CELESTO_API_KEY
19
+ const celesto = new Celesto({
20
+ token: process.env.CELESTO_API_KEY,
21
+ // organizationId: "org_123", // optional, for JWTs with multiple orgs
19
22
  });
20
23
 
24
+ // Computers
25
+ const computer = await celesto.computers.create({ cpus: 2, memory: 2048 });
26
+ const result = await celesto.computers.exec(computer.id, "uname -a");
27
+ console.log(result.stdout);
28
+ await celesto.computers.delete(computer.id);
29
+ ```
30
+
31
+ ## Computers
32
+
33
+ ### Lifecycle
34
+
35
+ ```ts
36
+ const computer = await celesto.computers.create({
37
+ cpus: 2,
38
+ memory: 2048,
39
+ image: "ubuntu-desktop-24.04",
40
+ });
41
+
42
+ await celesto.computers.stop(computer.id);
43
+ await celesto.computers.start(computer.id);
44
+ await celesto.computers.delete(computer.id);
45
+
46
+ const { computers, count } = await celesto.computers.list();
47
+ ```
48
+
49
+ ### Running commands
50
+
51
+ ```ts
52
+ const result = await celesto.computers.exec(computer.id, "ls -la", { timeout: 60 });
53
+ console.log(result.exitCode, result.stdout, result.stderr);
54
+ ```
55
+
56
+ ### Terminal connection
57
+
58
+ `getTerminalConnection()` resolves a computer name or ID and returns everything you need
59
+ to open a WebSocket terminal with any library of your choice. No built-in WebSocket
60
+ dependency — bring your own.
61
+
62
+ ```ts
63
+ const conn = await celesto.computers.getTerminalConnection("my-computer");
64
+
65
+ // Use any WebSocket library (ws, Node 22+ built-in, etc.)
66
+ import WebSocket from "ws";
67
+ const ws = new WebSocket(conn.url, { headers: conn.headers });
68
+ ws.on("open", () => ws.send(conn.firstMessage));
69
+ ws.on("message", (data) => process.stdout.write(data));
70
+ ```
71
+
72
+ ## Gatekeeper
73
+
74
+ ```ts
75
+ import { GatekeeperClient } from "@celestoai/sdk/gatekeeper";
76
+
77
+ const client = new GatekeeperClient({ token: process.env.CELESTO_API_KEY });
78
+
21
79
  const connect = await client.connect({
22
80
  subject: "customer_123",
23
81
  provider: "google_drive",
@@ -29,26 +87,14 @@ if (connect.status === "redirect") {
29
87
  }
30
88
  ```
31
89
 
32
- ## Gatekeeper API coverage
33
-
34
- - `connect`
35
- - `listConnections`
36
- - `getConnection`
37
- - `revokeConnection`
38
- - `listDriveFiles`
39
- - `getAccessRules`
40
- - `updateAccessRules`
41
- - `clearAccessRules`
90
+ Full docs: https://docs.celesto.ai/celesto-sdk/gatekeeper
42
91
 
43
92
  ## Notes
44
93
 
45
94
  - `token` accepts either a Celesto API key or a JWT.
46
95
  - `organizationId` adds the `X-Current-Organization` header.
47
- - Requires Node 18+ for built-in `fetch`.
96
+ - Requires Node 18+ for built-in `fetch`. Zero runtime dependencies.
48
97
 
49
98
  ## License
50
99
 
51
- Apache-2.0. The SDK is open source; use of the Celesto platform is governed by the Celesto Terms of Service:
52
- ```
53
- https://celesto.ai/legal/terms
54
- ```
100
+ 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
@@ -0,0 +1,177 @@
1
+ import {
2
+ buildRequestContext,
3
+ request
4
+ } from "./chunk-N3HU6ONW.js";
5
+
6
+ // src/gatekeeper/client.ts
7
+ var toConnectRequest = (payload) => ({
8
+ subject: payload.subject,
9
+ provider: payload.provider ?? "google_drive",
10
+ project_name: payload.projectName,
11
+ redirect_uri: payload.redirectUri
12
+ });
13
+ var toConnectResponse = (payload) => ({
14
+ status: payload.status,
15
+ oauthUrl: payload.oauth_url ?? void 0,
16
+ connectionId: payload.connection_id ?? void 0
17
+ });
18
+ var toConnection = (payload) => ({
19
+ id: payload.id,
20
+ subject: payload.subject,
21
+ provider: payload.provider,
22
+ projectId: payload.project_id,
23
+ accountEmail: payload.account_email ?? null,
24
+ scopes: payload.scopes ?? [],
25
+ status: payload.status,
26
+ createdAt: payload.created_at,
27
+ updatedAt: payload.updated_at,
28
+ lastUsedAt: payload.last_used_at ?? null,
29
+ accessRules: payload.access_rules ? {
30
+ version: payload.access_rules.version ?? "1",
31
+ allowedFolders: payload.access_rules.allowed_folders ?? [],
32
+ allowedFiles: payload.access_rules.allowed_files ?? [],
33
+ unrestricted: false
34
+ } : null
35
+ });
36
+ var toAccessRules = (payload) => ({
37
+ version: payload.version,
38
+ allowedFolders: payload.allowed_folders ?? [],
39
+ allowedFiles: payload.allowed_files ?? [],
40
+ unrestricted: payload.unrestricted
41
+ });
42
+ var toDriveFile = (payload) => ({
43
+ id: payload.id,
44
+ name: payload.name ?? null,
45
+ mimeType: payload.mime_type ?? null,
46
+ size: payload.size ?? null,
47
+ modifiedTime: payload.modified_time ?? null,
48
+ createdTime: payload.created_time ?? null,
49
+ webViewLink: payload.web_view_link ?? null,
50
+ iconLink: payload.icon_link ?? null,
51
+ thumbnailLink: payload.thumbnail_link ?? null,
52
+ parents: payload.parents ?? null,
53
+ driveId: payload.drive_id ?? null,
54
+ shared: payload.shared ?? null,
55
+ ownedByMe: payload.owned_by_me ?? null
56
+ });
57
+ var gatekeeperPath = (path) => `/v1/gatekeeper${path}`;
58
+ var pickOverrides = (options) => ({
59
+ headers: options?.headers,
60
+ signal: options?.signal
61
+ });
62
+ var GatekeeperClient = class {
63
+ constructor(config) {
64
+ this.config = config;
65
+ }
66
+ async connect(payload, options) {
67
+ const ctx = buildRequestContext(this.config);
68
+ const data = await request(ctx, {
69
+ method: "POST",
70
+ path: gatekeeperPath("/connect"),
71
+ body: toConnectRequest(payload),
72
+ ...pickOverrides(options)
73
+ });
74
+ return toConnectResponse(data);
75
+ }
76
+ async listConnections(params, options) {
77
+ const ctx = buildRequestContext(this.config);
78
+ const data = await request(ctx, {
79
+ method: "GET",
80
+ path: gatekeeperPath("/connections"),
81
+ query: {
82
+ project_name: params.projectName,
83
+ status_filter: params.statusFilter
84
+ },
85
+ ...pickOverrides(options)
86
+ });
87
+ return {
88
+ total: data.total,
89
+ data: data.data.map(toConnection)
90
+ };
91
+ }
92
+ async getConnection(connectionId, options) {
93
+ const ctx = buildRequestContext(this.config);
94
+ const data = await request(ctx, {
95
+ method: "GET",
96
+ path: gatekeeperPath(`/connections/${connectionId}`),
97
+ ...pickOverrides(options)
98
+ });
99
+ return toConnection(data);
100
+ }
101
+ async revokeConnection(params, options) {
102
+ const ctx = buildRequestContext(this.config);
103
+ return request(ctx, {
104
+ method: "DELETE",
105
+ path: gatekeeperPath("/connections"),
106
+ query: {
107
+ subject: params.subject,
108
+ project_name: params.projectName,
109
+ provider: params.provider
110
+ },
111
+ ...pickOverrides(options)
112
+ });
113
+ }
114
+ async listDriveFiles(params, options) {
115
+ const ctx = buildRequestContext(this.config);
116
+ const data = await request(ctx, {
117
+ method: "GET",
118
+ path: gatekeeperPath("/connectors/drive/files"),
119
+ query: {
120
+ project_name: params.projectName,
121
+ subject: params.subject,
122
+ page_size: params.pageSize,
123
+ page_token: params.pageToken,
124
+ folder_id: params.folderId,
125
+ query: params.query,
126
+ include_folders: params.includeFolders,
127
+ order_by: params.orderBy
128
+ },
129
+ ...pickOverrides(options)
130
+ });
131
+ return {
132
+ files: data.files.map(toDriveFile),
133
+ nextPageToken: data.next_page_token ?? null
134
+ };
135
+ }
136
+ async getAccessRules(connectionId, options) {
137
+ const ctx = buildRequestContext(this.config);
138
+ const data = await request(ctx, {
139
+ method: "GET",
140
+ path: gatekeeperPath(`/connections/${connectionId}/access-rules`),
141
+ ...pickOverrides(options)
142
+ });
143
+ return toAccessRules(data);
144
+ }
145
+ async updateAccessRules(params, options) {
146
+ const ctx = buildRequestContext(this.config);
147
+ const data = await request(ctx, {
148
+ method: "PUT",
149
+ path: gatekeeperPath("/connections/access-rules"),
150
+ query: {
151
+ subject: params.subject,
152
+ project_name: params.projectName,
153
+ provider: params.provider
154
+ },
155
+ body: {
156
+ allowed_folders: params.accessRules.allowedFolders ?? [],
157
+ allowed_files: params.accessRules.allowedFiles ?? []
158
+ },
159
+ ...pickOverrides(options)
160
+ });
161
+ return toAccessRules(data);
162
+ }
163
+ async clearAccessRules(connectionId, options) {
164
+ const ctx = buildRequestContext(this.config);
165
+ const data = await request(ctx, {
166
+ method: "DELETE",
167
+ path: gatekeeperPath(`/connections/${connectionId}/access-rules`),
168
+ ...pickOverrides(options)
169
+ });
170
+ return toAccessRules(data);
171
+ }
172
+ };
173
+
174
+ export {
175
+ GatekeeperClient
176
+ };
177
+ //# sourceMappingURL=chunk-4KVRJSVJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/gatekeeper/client.ts"],"sourcesContent":["import { buildRequestContext, ClientConfig, RequestOverrides } from \"../core/config\";\nimport { request } from \"../core/http\";\nimport {\n GatekeeperAccessRules,\n GatekeeperAccessRulesParams,\n GatekeeperConnectRequest,\n GatekeeperConnectResponse,\n GatekeeperConnection,\n GatekeeperDriveFile,\n GatekeeperDriveListParams,\n GatekeeperDriveListResponse,\n GatekeeperListConnectionsParams,\n GatekeeperListConnectionsResponse,\n GatekeeperRevokeParams,\n GatekeeperRevokeResponse,\n} from \"./types\";\n\ninterface GatekeeperConnectRequestWire {\n subject: string;\n provider: string;\n project_name: string;\n redirect_uri?: string;\n}\n\ninterface GatekeeperConnectResponseWire {\n status: string;\n oauth_url?: string | null;\n connection_id?: string | null;\n}\n\ninterface GatekeeperConnectionWire {\n id: string;\n subject: string;\n provider: string;\n project_id: string;\n account_email?: string | null;\n scopes?: string[];\n status: string;\n created_at: string;\n updated_at: string;\n last_used_at?: string | null;\n access_rules?: {\n allowed_folders?: string[];\n allowed_files?: string[];\n version?: string;\n } | null;\n}\n\ninterface GatekeeperListConnectionsResponseWire {\n data: GatekeeperConnectionWire[];\n total: number;\n}\n\ninterface GatekeeperDriveFileWire {\n id: string;\n name?: string | null;\n mime_type?: string | null;\n size?: number | null;\n modified_time?: string | null;\n created_time?: string | null;\n web_view_link?: string | null;\n icon_link?: string | null;\n thumbnail_link?: string | null;\n parents?: string[] | null;\n drive_id?: string | null;\n shared?: boolean | null;\n owned_by_me?: boolean | null;\n}\n\ninterface GatekeeperDriveListResponseWire {\n files: GatekeeperDriveFileWire[];\n next_page_token?: string | null;\n}\n\ninterface GatekeeperAccessRulesResponseWire {\n version: string;\n allowed_folders: string[];\n allowed_files: string[];\n unrestricted: boolean;\n}\n\nconst toConnectRequest = (payload: GatekeeperConnectRequest): GatekeeperConnectRequestWire => ({\n subject: payload.subject,\n provider: payload.provider ?? \"google_drive\",\n project_name: payload.projectName,\n redirect_uri: payload.redirectUri,\n});\n\nconst toConnectResponse = (payload: GatekeeperConnectResponseWire): GatekeeperConnectResponse => ({\n status: payload.status,\n oauthUrl: payload.oauth_url ?? undefined,\n connectionId: payload.connection_id ?? undefined,\n});\n\nconst toConnection = (payload: GatekeeperConnectionWire): GatekeeperConnection => ({\n id: payload.id,\n subject: payload.subject,\n provider: payload.provider,\n projectId: payload.project_id,\n accountEmail: payload.account_email ?? null,\n scopes: payload.scopes ?? [],\n status: payload.status,\n createdAt: payload.created_at,\n updatedAt: payload.updated_at,\n lastUsedAt: payload.last_used_at ?? null,\n accessRules: payload.access_rules\n ? {\n version: payload.access_rules.version ?? \"1\",\n allowedFolders: payload.access_rules.allowed_folders ?? [],\n allowedFiles: payload.access_rules.allowed_files ?? [],\n unrestricted: false,\n }\n : null,\n});\n\nconst toAccessRules = (payload: GatekeeperAccessRulesResponseWire): GatekeeperAccessRules => ({\n version: payload.version,\n allowedFolders: payload.allowed_folders ?? [],\n allowedFiles: payload.allowed_files ?? [],\n unrestricted: payload.unrestricted,\n});\n\nconst toDriveFile = (payload: GatekeeperDriveFileWire): GatekeeperDriveFile => ({\n id: payload.id,\n name: payload.name ?? null,\n mimeType: payload.mime_type ?? null,\n size: payload.size ?? null,\n modifiedTime: payload.modified_time ?? null,\n createdTime: payload.created_time ?? null,\n webViewLink: payload.web_view_link ?? null,\n iconLink: payload.icon_link ?? null,\n thumbnailLink: payload.thumbnail_link ?? null,\n parents: payload.parents ?? null,\n driveId: payload.drive_id ?? null,\n shared: payload.shared ?? null,\n ownedByMe: payload.owned_by_me ?? null,\n});\n\nconst gatekeeperPath = (path: string): string => `/v1/gatekeeper${path}`;\n\nconst pickOverrides = (options?: RequestOverrides): RequestOverrides => ({\n headers: options?.headers,\n signal: options?.signal,\n});\n\nexport class GatekeeperClient {\n private readonly config: ClientConfig;\n\n constructor(config: ClientConfig) {\n this.config = config;\n }\n\n async connect(payload: GatekeeperConnectRequest, options?: RequestOverrides): Promise<GatekeeperConnectResponse> {\n const ctx = buildRequestContext(this.config);\n const data = await request<GatekeeperConnectResponseWire>(ctx, {\n method: \"POST\",\n path: gatekeeperPath(\"/connect\"),\n body: toConnectRequest(payload),\n ...pickOverrides(options),\n });\n return toConnectResponse(data);\n }\n\n async listConnections(params: GatekeeperListConnectionsParams, options?: RequestOverrides): Promise<GatekeeperListConnectionsResponse> {\n const ctx = buildRequestContext(this.config);\n const data = await request<GatekeeperListConnectionsResponseWire>(ctx, {\n method: \"GET\",\n path: gatekeeperPath(\"/connections\"),\n query: {\n project_name: params.projectName,\n status_filter: params.statusFilter,\n },\n ...pickOverrides(options),\n });\n\n return {\n total: data.total,\n data: data.data.map(toConnection),\n };\n }\n\n async getConnection(connectionId: string, options?: RequestOverrides): Promise<GatekeeperConnection> {\n const ctx = buildRequestContext(this.config);\n const data = await request<GatekeeperConnectionWire>(ctx, {\n method: \"GET\",\n path: gatekeeperPath(`/connections/${connectionId}`),\n ...pickOverrides(options),\n });\n return toConnection(data);\n }\n\n async revokeConnection(params: GatekeeperRevokeParams, options?: RequestOverrides): Promise<GatekeeperRevokeResponse> {\n const ctx = buildRequestContext(this.config);\n return request<GatekeeperRevokeResponse>(ctx, {\n method: \"DELETE\",\n path: gatekeeperPath(\"/connections\"),\n query: {\n subject: params.subject,\n project_name: params.projectName,\n provider: params.provider,\n },\n ...pickOverrides(options),\n });\n }\n\n async listDriveFiles(params: GatekeeperDriveListParams, options?: RequestOverrides): Promise<GatekeeperDriveListResponse> {\n const ctx = buildRequestContext(this.config);\n const data = await request<GatekeeperDriveListResponseWire>(ctx, {\n method: \"GET\",\n path: gatekeeperPath(\"/connectors/drive/files\"),\n query: {\n project_name: params.projectName,\n subject: params.subject,\n page_size: params.pageSize,\n page_token: params.pageToken,\n folder_id: params.folderId,\n query: params.query,\n include_folders: params.includeFolders,\n order_by: params.orderBy,\n },\n ...pickOverrides(options),\n });\n\n return {\n files: data.files.map(toDriveFile),\n nextPageToken: data.next_page_token ?? null,\n };\n }\n\n async getAccessRules(connectionId: string, options?: RequestOverrides): Promise<GatekeeperAccessRules> {\n const ctx = buildRequestContext(this.config);\n const data = await request<GatekeeperAccessRulesResponseWire>(ctx, {\n method: \"GET\",\n path: gatekeeperPath(`/connections/${connectionId}/access-rules`),\n ...pickOverrides(options),\n });\n return toAccessRules(data);\n }\n\n async updateAccessRules(params: GatekeeperAccessRulesParams, options?: RequestOverrides): Promise<GatekeeperAccessRules> {\n const ctx = buildRequestContext(this.config);\n const data = await request<GatekeeperAccessRulesResponseWire>(ctx, {\n method: \"PUT\",\n path: gatekeeperPath(\"/connections/access-rules\"),\n query: {\n subject: params.subject,\n project_name: params.projectName,\n provider: params.provider,\n },\n body: {\n allowed_folders: params.accessRules.allowedFolders ?? [],\n allowed_files: params.accessRules.allowedFiles ?? [],\n },\n ...pickOverrides(options),\n });\n return toAccessRules(data);\n }\n\n async clearAccessRules(connectionId: string, options?: RequestOverrides): Promise<GatekeeperAccessRules> {\n const ctx = buildRequestContext(this.config);\n const data = await request<GatekeeperAccessRulesResponseWire>(ctx, {\n method: \"DELETE\",\n path: gatekeeperPath(`/connections/${connectionId}/access-rules`),\n ...pickOverrides(options),\n });\n return toAccessRules(data);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,148 @@
1
+ // src/core/errors.ts
2
+ var CelestoError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "CelestoError";
6
+ }
7
+ };
8
+ var CelestoApiError = class extends CelestoError {
9
+ constructor(message, status, data, requestId) {
10
+ super(message);
11
+ this.name = "CelestoApiError";
12
+ this.status = status;
13
+ this.data = data;
14
+ this.requestId = requestId;
15
+ }
16
+ };
17
+ var CelestoNetworkError = class extends CelestoError {
18
+ constructor(message, cause) {
19
+ super(message);
20
+ this.name = "CelestoNetworkError";
21
+ this.cause = cause;
22
+ }
23
+ };
24
+
25
+ // src/core/config.ts
26
+ var DEFAULT_BASE_URL = "https://api.celesto.ai";
27
+ var buildRequestContext = (config) => ({
28
+ fetch: config.fetch ?? fetch,
29
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
30
+ token: config.token ?? config.apiKey,
31
+ organizationId: config.organizationId,
32
+ userAgent: config.userAgent,
33
+ timeoutMs: config.timeoutMs,
34
+ headers: config.headers
35
+ });
36
+
37
+ // src/core/http.ts
38
+ var joinUrl = (baseUrl, path) => {
39
+ const trimmedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
40
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
41
+ return `${trimmedBase}${normalizedPath}`;
42
+ };
43
+ var buildQuery = (query) => {
44
+ if (!query) {
45
+ return "";
46
+ }
47
+ const params = new URLSearchParams();
48
+ for (const [key, value] of Object.entries(query)) {
49
+ if (value === void 0 || value === null) {
50
+ continue;
51
+ }
52
+ if (Array.isArray(value)) {
53
+ for (const item of value) {
54
+ params.append(key, String(item));
55
+ }
56
+ continue;
57
+ }
58
+ params.set(key, String(value));
59
+ }
60
+ const serialized = params.toString();
61
+ return serialized ? `?${serialized}` : "";
62
+ };
63
+ var parseResponseBody = async (response) => {
64
+ if (response.status === 204) {
65
+ return void 0;
66
+ }
67
+ const contentType = response.headers.get("content-type") ?? "";
68
+ if (contentType.includes("application/json")) {
69
+ return response.json();
70
+ }
71
+ return response.text();
72
+ };
73
+ var extractErrorMessage = (data, status) => {
74
+ if (data && typeof data === "object") {
75
+ const record = data;
76
+ if (typeof record.detail === "string") {
77
+ return record.detail;
78
+ }
79
+ if (typeof record.message === "string") {
80
+ return record.message;
81
+ }
82
+ if (typeof record.error === "string") {
83
+ return record.error;
84
+ }
85
+ }
86
+ return `Request failed with status ${status}`;
87
+ };
88
+ var request = async (ctx, options) => {
89
+ const url = `${joinUrl(ctx.baseUrl, options.path)}${buildQuery(options.query)}`;
90
+ const headers = {
91
+ ...ctx.headers ?? {},
92
+ ...options.headers ?? {}
93
+ };
94
+ if (ctx.token) {
95
+ headers.Authorization = `Bearer ${ctx.token}`;
96
+ }
97
+ if (ctx.organizationId) {
98
+ headers["X-Current-Organization"] = ctx.organizationId;
99
+ }
100
+ if (ctx.userAgent && !headers["User-Agent"]) {
101
+ headers["User-Agent"] = ctx.userAgent;
102
+ }
103
+ const init = {
104
+ method: options.method,
105
+ headers,
106
+ body: void 0,
107
+ signal: options.signal
108
+ };
109
+ if (options.body !== void 0) {
110
+ headers["Content-Type"] = headers["Content-Type"] ?? "application/json";
111
+ init.body = headers["Content-Type"].includes("application/json") ? JSON.stringify(options.body) : options.body;
112
+ }
113
+ let timeoutId;
114
+ let controller;
115
+ if (!options.signal && ctx.timeoutMs && ctx.timeoutMs > 0) {
116
+ controller = new AbortController();
117
+ timeoutId = setTimeout(() => controller?.abort(), ctx.timeoutMs);
118
+ init.signal = controller.signal;
119
+ }
120
+ try {
121
+ const response = await ctx.fetch(url, init);
122
+ const data = await parseResponseBody(response);
123
+ if (!response.ok) {
124
+ const message = extractErrorMessage(data, response.status);
125
+ throw new CelestoApiError(message, response.status, data, response.headers.get("x-request-id") ?? void 0);
126
+ }
127
+ return data;
128
+ } catch (err) {
129
+ if (err instanceof CelestoApiError) {
130
+ throw err;
131
+ }
132
+ const error = err instanceof Error ? err : new Error(String(err));
133
+ throw new CelestoNetworkError(error.message, error);
134
+ } finally {
135
+ if (timeoutId) {
136
+ clearTimeout(timeoutId);
137
+ }
138
+ }
139
+ };
140
+
141
+ export {
142
+ buildRequestContext,
143
+ CelestoError,
144
+ CelestoApiError,
145
+ CelestoNetworkError,
146
+ request
147
+ };
148
+ //# sourceMappingURL=chunk-N3HU6ONW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/errors.ts","../src/core/config.ts","../src/core/http.ts"],"sourcesContent":["/** Base error for all Celesto SDK errors. */\nexport class CelestoError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CelestoError\";\n }\n}\n\n/** Thrown when an API request returns a non-2xx HTTP status. */\nexport class CelestoApiError extends CelestoError {\n readonly status: number;\n readonly data: unknown;\n readonly requestId?: string;\n\n constructor(message: string, status: number, data: unknown, requestId?: string) {\n super(message);\n this.name = \"CelestoApiError\";\n this.status = status;\n this.data = data;\n this.requestId = requestId;\n }\n}\n\n/** Thrown when fetch() itself fails — DNS, network, timeout, abort. */\nexport class CelestoNetworkError extends CelestoError {\n readonly cause?: Error;\n\n constructor(message: string, cause?: Error) {\n super(message);\n this.name = \"CelestoNetworkError\";\n this.cause = cause;\n }\n}\n","export type FetchLike = typeof fetch;\n\nexport interface ClientConfig {\n /** Base API URL, e.g. https://api.celesto.ai */\n baseUrl?: string;\n /** Bearer token (API key or JWT). */\n token?: string;\n /** Alias for token. */\n apiKey?: string;\n /** Organization ID to send as X-Current-Organization. */\n organizationId?: string;\n /** Optional user agent for server-side requests. */\n userAgent?: string;\n /** Default request timeout in milliseconds. */\n timeoutMs?: number;\n /** Override fetch implementation (useful for testing). */\n fetch?: FetchLike;\n /** Default headers to include in every request. */\n headers?: Record<string, string>;\n}\n\nexport interface RequestOptions {\n method: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n path: string;\n query?: Record<string, string | number | boolean | undefined | null | (string | number | boolean)[]>;\n body?: unknown;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n}\n\nexport interface RequestOverrides {\n headers?: Record<string, string>;\n signal?: AbortSignal;\n}\n\nexport interface RequestContext {\n fetch: FetchLike;\n baseUrl: string;\n token?: string;\n organizationId?: string;\n userAgent?: string;\n timeoutMs?: number;\n headers?: Record<string, string>;\n}\n\nexport const DEFAULT_BASE_URL = \"https://api.celesto.ai\";\n\nexport const buildRequestContext = (config: ClientConfig): RequestContext => ({\n fetch: config.fetch ?? fetch,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n token: config.token ?? config.apiKey,\n organizationId: config.organizationId,\n userAgent: config.userAgent,\n timeoutMs: config.timeoutMs,\n headers: config.headers,\n});\n","import { CelestoApiError, CelestoNetworkError } from \"./errors\";\nimport { RequestContext, RequestOptions } from \"./config\";\n\nconst joinUrl = (baseUrl: string, path: string): string => {\n const trimmedBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${trimmedBase}${normalizedPath}`;\n};\n\nconst buildQuery = (\n query?: RequestOptions[\"query\"],\n): string => {\n if (!query) {\n return \"\";\n }\n\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n params.append(key, String(item));\n }\n continue;\n }\n params.set(key, String(value));\n }\n\n const serialized = params.toString();\n return serialized ? `?${serialized}` : \"\";\n};\n\nconst parseResponseBody = async (response: Response): Promise<unknown> => {\n if (response.status === 204) {\n return undefined;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return response.json();\n }\n\n return response.text();\n};\n\nconst extractErrorMessage = (data: unknown, status: number): string => {\n if (data && typeof data === \"object\") {\n const record = data as Record<string, unknown>;\n if (typeof record.detail === \"string\") {\n return record.detail;\n }\n if (typeof record.message === \"string\") {\n return record.message;\n }\n if (typeof record.error === \"string\") {\n return record.error;\n }\n }\n return `Request failed with status ${status}`;\n};\n\nexport const request = async <T>(ctx: RequestContext, options: RequestOptions): Promise<T> => {\n const url = `${joinUrl(ctx.baseUrl, options.path)}${buildQuery(options.query)}`;\n\n const headers: Record<string, string> = {\n ...(ctx.headers ?? {}),\n ...(options.headers ?? {}),\n };\n\n if (ctx.token) {\n headers.Authorization = `Bearer ${ctx.token}`;\n }\n\n if (ctx.organizationId) {\n headers[\"X-Current-Organization\"] = ctx.organizationId;\n }\n\n if (ctx.userAgent && !headers[\"User-Agent\"]) {\n headers[\"User-Agent\"] = ctx.userAgent;\n }\n\n const init: RequestInit = {\n method: options.method,\n headers,\n body: undefined,\n signal: options.signal,\n };\n\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = headers[\"Content-Type\"] ?? \"application/json\";\n init.body = headers[\"Content-Type\"].includes(\"application/json\")\n ? JSON.stringify(options.body)\n : (options.body as BodyInit);\n }\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let controller: AbortController | undefined;\n\n if (!options.signal && ctx.timeoutMs && ctx.timeoutMs > 0) {\n controller = new AbortController();\n timeoutId = setTimeout(() => controller?.abort(), ctx.timeoutMs);\n init.signal = controller.signal;\n }\n\n try {\n const response = await ctx.fetch(url, init);\n const data = await parseResponseBody(response);\n\n if (!response.ok) {\n const message = extractErrorMessage(data, response.status);\n throw new CelestoApiError(message, response.status, data, response.headers.get(\"x-request-id\") ?? undefined);\n }\n\n return data as T;\n } catch (err) {\n if (err instanceof CelestoApiError) {\n throw err;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n throw new CelestoNetworkError(error.message, error);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n};\n"],"mappings":"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","names":[]}
@@ -0,0 +1,164 @@
1
+ import {
2
+ buildRequestContext,
3
+ request
4
+ } from "./chunk-N3HU6ONW.js";
5
+
6
+ // src/computers/client.ts
7
+ var toConnection = (payload) => {
8
+ if (!payload) {
9
+ return void 0;
10
+ }
11
+ const out = {};
12
+ if (payload.ssh != null) {
13
+ out.ssh = payload.ssh;
14
+ }
15
+ if (payload.access_url != null) {
16
+ out.accessUrl = payload.access_url;
17
+ }
18
+ return out;
19
+ };
20
+ var toComputerInfo = (payload) => ({
21
+ id: payload.id,
22
+ name: payload.name,
23
+ status: payload.status,
24
+ vcpus: payload.vcpus,
25
+ ramMb: payload.ram_mb,
26
+ image: payload.image,
27
+ connection: toConnection(payload.connection),
28
+ lastError: payload.last_error ?? null,
29
+ createdAt: payload.created_at,
30
+ stoppedAt: payload.stopped_at ?? null
31
+ });
32
+ var toExecResponse = (payload) => ({
33
+ exitCode: payload.exit_code,
34
+ stdout: payload.stdout,
35
+ stderr: payload.stderr
36
+ });
37
+ var computersPath = (path) => `/v1/computers${path}`;
38
+ var pickOverrides = (options) => ({
39
+ headers: options?.headers,
40
+ signal: options?.signal
41
+ });
42
+ var ComputersClient = class {
43
+ constructor(config) {
44
+ this.config = config;
45
+ }
46
+ async create(params = {}, options) {
47
+ const ctx = buildRequestContext(this.config);
48
+ const data = await request(ctx, {
49
+ method: "POST",
50
+ path: computersPath(""),
51
+ body: {
52
+ vcpus: params.cpus ?? 1,
53
+ ram_mb: params.memory ?? 1024,
54
+ image: params.image ?? "ubuntu-desktop-24.04"
55
+ },
56
+ ...pickOverrides(options)
57
+ });
58
+ return toComputerInfo(data);
59
+ }
60
+ async list(options) {
61
+ const ctx = buildRequestContext(this.config);
62
+ const data = await request(ctx, {
63
+ method: "GET",
64
+ path: computersPath(""),
65
+ ...pickOverrides(options)
66
+ });
67
+ return {
68
+ computers: data.computers.map(toComputerInfo),
69
+ count: data.count
70
+ };
71
+ }
72
+ async get(computerId, options) {
73
+ const ctx = buildRequestContext(this.config);
74
+ const data = await request(ctx, {
75
+ method: "GET",
76
+ path: computersPath(`/${encodeURIComponent(computerId)}`),
77
+ ...pickOverrides(options)
78
+ });
79
+ return toComputerInfo(data);
80
+ }
81
+ async exec(computerId, command, params = {}, options) {
82
+ const ctx = buildRequestContext(this.config);
83
+ const data = await request(ctx, {
84
+ method: "POST",
85
+ path: computersPath(`/${encodeURIComponent(computerId)}/exec`),
86
+ body: {
87
+ command,
88
+ timeout: params.timeout ?? 30
89
+ },
90
+ ...pickOverrides(options)
91
+ });
92
+ return toExecResponse(data);
93
+ }
94
+ async stop(computerId, options) {
95
+ const ctx = buildRequestContext(this.config);
96
+ const data = await request(ctx, {
97
+ method: "POST",
98
+ path: computersPath(`/${encodeURIComponent(computerId)}/stop`),
99
+ ...pickOverrides(options)
100
+ });
101
+ return toComputerInfo(data);
102
+ }
103
+ async start(computerId, options) {
104
+ const ctx = buildRequestContext(this.config);
105
+ const data = await request(ctx, {
106
+ method: "POST",
107
+ path: computersPath(`/${encodeURIComponent(computerId)}/start`),
108
+ ...pickOverrides(options)
109
+ });
110
+ return toComputerInfo(data);
111
+ }
112
+ async delete(computerId, options) {
113
+ const ctx = buildRequestContext(this.config);
114
+ const data = await request(ctx, {
115
+ method: "DELETE",
116
+ path: computersPath(`/${encodeURIComponent(computerId)}`),
117
+ ...pickOverrides(options)
118
+ });
119
+ return toComputerInfo(data);
120
+ }
121
+ /**
122
+ * Get connection info for opening a WebSocket terminal session.
123
+ *
124
+ * Accepts either a computer ID (e.g. `cmp_xxx`) or a human-readable name.
125
+ * The name is resolved to the canonical ID via a GET call — the backend's
126
+ * WebSocket endpoint does not resolve names on its own.
127
+ *
128
+ * Returns the URL, headers, and first message needed to open the connection
129
+ * with any WebSocket library of your choice.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * const conn = await celesto.computers.getTerminalConnection("my-computer");
134
+ * const ws = new WebSocket(conn.url, { headers: conn.headers });
135
+ * ws.on("open", () => ws.send(conn.firstMessage));
136
+ * ws.on("message", (data) => process.stdout.write(data));
137
+ * ```
138
+ */
139
+ async getTerminalConnection(computerIdOrName) {
140
+ const info = await this.get(computerIdOrName);
141
+ const ctx = buildRequestContext(this.config);
142
+ if (!ctx.token) {
143
+ throw new Error("A token is required for terminal connections");
144
+ }
145
+ const wsBase = ctx.baseUrl.replace(/^https:/i, "wss:").replace(/^http:/i, "ws:");
146
+ const url = `${wsBase}/v1/computers/${encodeURIComponent(info.id)}/terminal`;
147
+ const headers = {
148
+ Authorization: `Bearer ${ctx.token}`
149
+ };
150
+ if (ctx.organizationId) {
151
+ headers["X-Current-Organization"] = ctx.organizationId;
152
+ }
153
+ return {
154
+ url,
155
+ headers,
156
+ firstMessage: JSON.stringify({ token: ctx.token })
157
+ };
158
+ }
159
+ };
160
+
161
+ export {
162
+ ComputersClient
163
+ };
164
+ //# sourceMappingURL=chunk-OGMV3NFZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/computers/client.ts"],"sourcesContent":["import { buildRequestContext, ClientConfig, RequestOverrides } from \"../core/config\";\nimport { request } from \"../core/http\";\nimport {\n ComputerConnectionInfo,\n ComputerExecResponse,\n ComputerInfo,\n ComputerListResponse,\n ComputerStatus,\n CreateComputerParams,\n ExecParams,\n TerminalConnectionInfo,\n} from \"./types\";\n\ninterface ComputerConnectionInfoWire {\n ssh?: string | null;\n access_url?: string | null;\n}\n\ninterface ComputerInfoWire {\n id: string;\n name: string;\n status: ComputerStatus;\n vcpus: number;\n ram_mb: number;\n image: string;\n connection?: ComputerConnectionInfoWire | null;\n last_error?: string | null;\n created_at: string;\n stopped_at?: string | null;\n}\n\ninterface ComputerListResponseWire {\n computers: ComputerInfoWire[];\n count: number;\n}\n\ninterface ComputerExecResponseWire {\n exit_code: number;\n stdout: string;\n stderr: string;\n}\n\nconst toConnection = (\n payload: ComputerConnectionInfoWire | null | undefined,\n): ComputerConnectionInfo | undefined => {\n if (!payload) {\n return undefined;\n }\n const out: ComputerConnectionInfo = {};\n if (payload.ssh != null) {\n out.ssh = payload.ssh;\n }\n if (payload.access_url != null) {\n out.accessUrl = payload.access_url;\n }\n return out;\n};\n\nconst toComputerInfo = (payload: ComputerInfoWire): ComputerInfo => ({\n id: payload.id,\n name: payload.name,\n status: payload.status,\n vcpus: payload.vcpus,\n ramMb: payload.ram_mb,\n image: payload.image,\n connection: toConnection(payload.connection),\n lastError: payload.last_error ?? null,\n createdAt: payload.created_at,\n stoppedAt: payload.stopped_at ?? null,\n});\n\nconst toExecResponse = (payload: ComputerExecResponseWire): ComputerExecResponse => ({\n exitCode: payload.exit_code,\n stdout: payload.stdout,\n stderr: payload.stderr,\n});\n\nconst computersPath = (path: string): string => `/v1/computers${path}`;\n\nconst pickOverrides = (options?: RequestOverrides): RequestOverrides => ({\n headers: options?.headers,\n signal: options?.signal,\n});\n\n/**\n * Client for managing sandboxed computers (AI sandboxes).\n *\n * Provides create/list/get/exec/stop/start/delete over HTTP, plus\n * `getTerminalConnection()` which returns the URL and headers needed\n * to open a WebSocket terminal with any WS library of your choice.\n *\n * @example\n * ```ts\n * const celesto = new Celesto({ token: process.env.CELESTO_API_KEY });\n * const computer = await celesto.computers.create({ cpus: 2, memory: 2048 });\n * const result = await celesto.computers.exec(computer.id, \"uname -a\");\n * console.log(result.stdout);\n * await celesto.computers.delete(computer.id);\n * ```\n */\nexport class ComputersClient {\n private readonly config: ClientConfig;\n\n constructor(config: ClientConfig) {\n this.config = config;\n }\n\n async create(params: CreateComputerParams = {}, options?: RequestOverrides): Promise<ComputerInfo> {\n const ctx = buildRequestContext(this.config);\n const data = await request<ComputerInfoWire>(ctx, {\n method: \"POST\",\n path: computersPath(\"\"),\n body: {\n vcpus: params.cpus ?? 1,\n ram_mb: params.memory ?? 1024,\n image: params.image ?? \"ubuntu-desktop-24.04\",\n },\n ...pickOverrides(options),\n });\n return toComputerInfo(data);\n }\n\n async list(options?: RequestOverrides): Promise<ComputerListResponse> {\n const ctx = buildRequestContext(this.config);\n const data = await request<ComputerListResponseWire>(ctx, {\n method: \"GET\",\n path: computersPath(\"\"),\n ...pickOverrides(options),\n });\n return {\n computers: data.computers.map(toComputerInfo),\n count: data.count,\n };\n }\n\n async get(computerId: string, options?: RequestOverrides): Promise<ComputerInfo> {\n const ctx = buildRequestContext(this.config);\n const data = await request<ComputerInfoWire>(ctx, {\n method: \"GET\",\n path: computersPath(`/${encodeURIComponent(computerId)}`),\n ...pickOverrides(options),\n });\n return toComputerInfo(data);\n }\n\n async exec(\n computerId: string,\n command: string,\n params: ExecParams = {},\n options?: RequestOverrides,\n ): Promise<ComputerExecResponse> {\n const ctx = buildRequestContext(this.config);\n const data = await request<ComputerExecResponseWire>(ctx, {\n method: \"POST\",\n path: computersPath(`/${encodeURIComponent(computerId)}/exec`),\n body: {\n command,\n timeout: params.timeout ?? 30,\n },\n ...pickOverrides(options),\n });\n return toExecResponse(data);\n }\n\n async stop(computerId: string, options?: RequestOverrides): Promise<ComputerInfo> {\n const ctx = buildRequestContext(this.config);\n const data = await request<ComputerInfoWire>(ctx, {\n method: \"POST\",\n path: computersPath(`/${encodeURIComponent(computerId)}/stop`),\n ...pickOverrides(options),\n });\n return toComputerInfo(data);\n }\n\n async start(computerId: string, options?: RequestOverrides): Promise<ComputerInfo> {\n const ctx = buildRequestContext(this.config);\n const data = await request<ComputerInfoWire>(ctx, {\n method: \"POST\",\n path: computersPath(`/${encodeURIComponent(computerId)}/start`),\n ...pickOverrides(options),\n });\n return toComputerInfo(data);\n }\n\n async delete(computerId: string, options?: RequestOverrides): Promise<ComputerInfo> {\n const ctx = buildRequestContext(this.config);\n const data = await request<ComputerInfoWire>(ctx, {\n method: \"DELETE\",\n path: computersPath(`/${encodeURIComponent(computerId)}`),\n ...pickOverrides(options),\n });\n return toComputerInfo(data);\n }\n\n /**\n * Get connection info for opening a WebSocket terminal session.\n *\n * Accepts either a computer ID (e.g. `cmp_xxx`) or a human-readable name.\n * The name is resolved to the canonical ID via a GET call — the backend's\n * WebSocket endpoint does not resolve names on its own.\n *\n * Returns the URL, headers, and first message needed to open the connection\n * with any WebSocket library of your choice.\n *\n * @example\n * ```ts\n * const conn = await celesto.computers.getTerminalConnection(\"my-computer\");\n * const ws = new WebSocket(conn.url, { headers: conn.headers });\n * ws.on(\"open\", () => ws.send(conn.firstMessage));\n * ws.on(\"message\", (data) => process.stdout.write(data));\n * ```\n */\n async getTerminalConnection(computerIdOrName: string): Promise<TerminalConnectionInfo> {\n const info = await this.get(computerIdOrName);\n const ctx = buildRequestContext(this.config);\n\n if (!ctx.token) {\n throw new Error(\"A token is required for terminal connections\");\n }\n\n const wsBase = ctx.baseUrl.replace(/^https:/i, \"wss:\").replace(/^http:/i, \"ws:\");\n const url = `${wsBase}/v1/computers/${encodeURIComponent(info.id)}/terminal`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${ctx.token}`,\n };\n if (ctx.organizationId) {\n headers[\"X-Current-Organization\"] = ctx.organizationId;\n }\n\n return {\n url,\n headers,\n firstMessage: JSON.stringify({ token: ctx.token }),\n };\n }\n}\n"],"mappings":"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","names":[]}