@castari/sdk 0.1.5 → 0.2.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.
- package/README.md +84 -174
- package/dist/agents.d.ts +76 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +111 -0
- package/dist/agents.js.map +1 -0
- package/dist/auth.d.ts +27 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +33 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +51 -50
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +90 -243
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +108 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +52 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +73 -0
- package/dist/errors.js.map +1 -0
- package/dist/http.d.ts +32 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +117 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +157 -58
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/usage.d.ts +26 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +45 -0
- package/dist/usage.js.map +1 -0
- package/package.json +51 -34
- package/LICENSE +0 -21
- package/dist/const.d.ts +0 -6
- package/dist/const.js +0 -9
- package/dist/message-handler.d.ts +0 -8
- package/dist/message-handler.js +0 -96
- package/dist/server.d.ts +0 -6
- package/dist/server.js +0 -222
package/dist/client.d.ts
CHANGED
|
@@ -1,55 +1,56 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { AgentsAPI } from './agents.js';
|
|
2
|
+
import { UsageAPI } from './usage.js';
|
|
3
|
+
import { AuthAPI } from './auth.js';
|
|
4
|
+
import type { CastariClientOptions } from './types.js';
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
6
|
+
* Main client for interacting with the Castari API
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { CastariClient } from '@castari/sdk';
|
|
11
|
+
*
|
|
12
|
+
* // Uses credentials from ~/.castari or CASTARI_API_KEY env var
|
|
13
|
+
* const client = new CastariClient();
|
|
14
|
+
*
|
|
15
|
+
* // Or provide credentials explicitly
|
|
16
|
+
* const client = new CastariClient({ apiKey: 'cap_xxxxx' });
|
|
17
|
+
*
|
|
18
|
+
* // List agents
|
|
19
|
+
* const agents = await client.agents.list();
|
|
20
|
+
*
|
|
21
|
+
* // Deploy an agent
|
|
22
|
+
* await client.agents.deploy('my-agent');
|
|
23
|
+
*
|
|
24
|
+
* // Invoke an agent
|
|
25
|
+
* const result = await client.agents.invoke('my-agent', { prompt: 'Hello!' });
|
|
26
|
+
* ```
|
|
5
27
|
*/
|
|
6
|
-
export interface ClientOptions extends Partial<QueryConfig> {
|
|
7
|
-
/** Local/custom connection URL (e.g., 'http://localhost:3000'). If omitted, Platform mode is used. */
|
|
8
|
-
connectionUrl?: string;
|
|
9
|
-
/** Anthropic API key (required unless present in process.env.ANTHROPIC_API_KEY) */
|
|
10
|
-
anthropicApiKey?: string;
|
|
11
|
-
/** Castari client ID (required for platform mode; otherwise read from env) */
|
|
12
|
-
clientId?: string;
|
|
13
|
-
/** Castari platform API key (used for auth when contacting the platform) */
|
|
14
|
-
platformApiKey?: string;
|
|
15
|
-
/** Enable debug logging */
|
|
16
|
-
debug?: boolean;
|
|
17
|
-
/** Snapshot name to deploy/start */
|
|
18
|
-
snapshot?: string;
|
|
19
|
-
/** Optional labels to apply to the sandbox (and filter by for reuse) */
|
|
20
|
-
labels?: Record<string, string>;
|
|
21
|
-
/** Optional volume name to mount at /home/castari/agent-workspace */
|
|
22
|
-
volume?: string;
|
|
23
|
-
/** Castari Platform API URL. Defaults to https://api.castari.com (or localhost in dev) */
|
|
24
|
-
platformUrl?: string;
|
|
25
|
-
/** Optional sessionId to resume */
|
|
26
|
-
resume?: string;
|
|
27
|
-
/**
|
|
28
|
-
* Use the platform API as a WebSocket proxy instead of connecting directly to the sandbox.
|
|
29
|
-
* Defaults to true for reliability. Set to false to connect directly to the sandbox.
|
|
30
|
-
*/
|
|
31
|
-
useProxy?: boolean;
|
|
32
|
-
}
|
|
33
28
|
export declare class CastariClient {
|
|
34
|
-
private ws?;
|
|
35
29
|
private options;
|
|
36
|
-
private
|
|
37
|
-
private
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
30
|
+
private httpClient;
|
|
31
|
+
private initialized;
|
|
32
|
+
private initPromise;
|
|
33
|
+
/** API for managing agents */
|
|
34
|
+
readonly agents: AgentsAPI;
|
|
35
|
+
/** API for accessing usage statistics */
|
|
36
|
+
readonly usage: UsageAPI;
|
|
37
|
+
/** API for authentication operations */
|
|
38
|
+
readonly auth: AuthAPI;
|
|
39
|
+
/**
|
|
40
|
+
* Create a new Castari client
|
|
41
|
+
* @param options - Client configuration options
|
|
42
|
+
*/
|
|
43
|
+
constructor(options?: CastariClientOptions);
|
|
44
|
+
/**
|
|
45
|
+
* Initialize the client by loading credentials from config
|
|
46
|
+
* This is called automatically before the first API request
|
|
47
|
+
*/
|
|
48
|
+
private initialize;
|
|
49
|
+
private doInitialize;
|
|
50
|
+
/**
|
|
51
|
+
* Ensure the client is initialized before making requests
|
|
52
|
+
* @throws AuthenticationError if no credentials are available
|
|
53
|
+
*/
|
|
54
|
+
ensureAuthenticated(): Promise<void>;
|
|
55
55
|
}
|
|
56
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,aAAa;IAkBZ,OAAO,CAAC,OAAO;IAjB3B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAA8B;IAEjD,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAE3B,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IAEzB,wCAAwC;IACxC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAEvB;;;OAGG;gBACiB,OAAO,GAAE,oBAAyB;IAqBtD;;;OAGG;YACW,UAAU;YAaV,YAAY;IAY1B;;;OAGG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ3C"}
|
package/dist/client.js
CHANGED
|
@@ -1,255 +1,102 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { HttpClient } from './http.js';
|
|
2
|
+
import { AgentsAPI } from './agents.js';
|
|
3
|
+
import { UsageAPI } from './usage.js';
|
|
4
|
+
import { AuthAPI } from './auth.js';
|
|
5
|
+
import { getAuth } from './config.js';
|
|
6
|
+
import { AuthenticationError } from './errors.js';
|
|
7
|
+
/**
|
|
8
|
+
* Main client for interacting with the Castari API
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { CastariClient } from '@castari/sdk';
|
|
13
|
+
*
|
|
14
|
+
* // Uses credentials from ~/.castari or CASTARI_API_KEY env var
|
|
15
|
+
* const client = new CastariClient();
|
|
16
|
+
*
|
|
17
|
+
* // Or provide credentials explicitly
|
|
18
|
+
* const client = new CastariClient({ apiKey: 'cap_xxxxx' });
|
|
19
|
+
*
|
|
20
|
+
* // List agents
|
|
21
|
+
* const agents = await client.agents.list();
|
|
22
|
+
*
|
|
23
|
+
* // Deploy an agent
|
|
24
|
+
* await client.agents.deploy('my-agent');
|
|
25
|
+
*
|
|
26
|
+
* // Invoke an agent
|
|
27
|
+
* const result = await client.agents.invoke('my-agent', { prompt: 'Hello!' });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
4
30
|
export class CastariClient {
|
|
5
|
-
ws;
|
|
6
31
|
options;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
32
|
+
httpClient;
|
|
33
|
+
initialized = false;
|
|
34
|
+
initPromise = null;
|
|
35
|
+
/** API for managing agents */
|
|
36
|
+
agents;
|
|
37
|
+
/** API for accessing usage statistics */
|
|
38
|
+
usage;
|
|
39
|
+
/** API for authentication operations */
|
|
40
|
+
auth;
|
|
41
|
+
/**
|
|
42
|
+
* Create a new Castari client
|
|
43
|
+
* @param options - Client configuration options
|
|
44
|
+
*/
|
|
12
45
|
constructor(options = {}) {
|
|
13
|
-
this.options =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/** Check if the WebSocket is currently connected */
|
|
18
|
-
isConnected() {
|
|
19
|
-
return this.ws?.readyState === WebSocket.OPEN;
|
|
20
|
-
}
|
|
21
|
-
async start() {
|
|
22
|
-
const anthropicApiKey = this.options.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
|
|
23
|
-
if (!anthropicApiKey) {
|
|
24
|
-
throw new Error('ANTHROPIC_API_KEY is required');
|
|
25
|
-
}
|
|
26
|
-
this.resolvedClientId =
|
|
27
|
-
this.options.clientId || process.env.CASTARI_CLIENT_ID || undefined;
|
|
28
|
-
this.resolvedPlatformApiKey =
|
|
29
|
-
this.options.platformApiKey || process.env.CASTARI_API_KEY || undefined;
|
|
30
|
-
const connection = this.options.connectionUrl
|
|
31
|
-
? await this.setupLocalConnection()
|
|
32
|
-
: await this.setupPlatformConnection();
|
|
33
|
-
if (this.options.debug) {
|
|
34
|
-
console.log(`📡 Configuring server at ${connection.configUrl}...`);
|
|
35
|
-
}
|
|
36
|
-
const configPayload = {
|
|
37
|
-
anthropicApiKey,
|
|
38
|
-
agents: this.options.agents,
|
|
39
|
-
allowedTools: this.options.allowedTools,
|
|
40
|
-
systemPrompt: this.options.systemPrompt,
|
|
41
|
-
model: this.options.model,
|
|
42
|
-
resume: this.options.resume,
|
|
43
|
-
};
|
|
44
|
-
if (this.options.debug) {
|
|
45
|
-
console.log(`📋 Config payload:`, JSON.stringify(configPayload, null, 2));
|
|
46
|
-
}
|
|
47
|
-
const configHeaders = {
|
|
48
|
-
'Content-Type': 'application/json',
|
|
49
|
-
...connection.authHeaders,
|
|
50
|
-
};
|
|
51
|
-
let configResponse = null;
|
|
52
|
-
const maxConfigAttempts = 5;
|
|
53
|
-
for (let attempt = 1; attempt <= maxConfigAttempts; attempt++) {
|
|
54
|
-
configResponse = await fetch(connection.configUrl, {
|
|
55
|
-
method: 'POST',
|
|
56
|
-
headers: configHeaders,
|
|
57
|
-
body: JSON.stringify(configPayload),
|
|
58
|
-
}).catch(err => {
|
|
59
|
-
if (this.options.debug) {
|
|
60
|
-
console.warn(`⚠️ Config request failed on attempt ${attempt}:`, err);
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
});
|
|
64
|
-
if (configResponse && configResponse.ok)
|
|
65
|
-
break;
|
|
66
|
-
if (this.options.debug) {
|
|
67
|
-
console.warn(`⚠️ Config attempt ${attempt} failed (status ${configResponse?.status ?? 'n/a'}).`);
|
|
68
|
-
}
|
|
69
|
-
if (attempt < maxConfigAttempts) {
|
|
70
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (!configResponse || !configResponse.ok) {
|
|
74
|
-
const errorText = configResponse ? await configResponse.text() : 'no response';
|
|
75
|
-
if (connection.cleanup)
|
|
76
|
-
await connection.cleanup();
|
|
77
|
-
throw new Error(`Failed to configure server (status ${configResponse?.status ?? 'n/a'}): ${errorText}`);
|
|
78
|
-
}
|
|
79
|
-
const { connectionToken } = (await configResponse.json());
|
|
80
|
-
if (!connectionToken) {
|
|
81
|
-
if (connection.cleanup)
|
|
82
|
-
await connection.cleanup();
|
|
83
|
-
throw new Error('Server did not return a connectionToken');
|
|
84
|
-
}
|
|
85
|
-
const wsUrlParams = new URLSearchParams();
|
|
86
|
-
wsUrlParams.set('token', connectionToken);
|
|
87
|
-
// Add any auth params from platform (for sandbox proxy auth)
|
|
88
|
-
if (connection.authParams) {
|
|
89
|
-
for (const [key, value] of Object.entries(connection.authParams)) {
|
|
90
|
-
wsUrlParams.set(key, value);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
const wsUrlJoiner = connection.wsUrl.includes('?') ? '&' : '?';
|
|
94
|
-
const wsUrl = `${connection.wsUrl}${wsUrlJoiner}${wsUrlParams.toString()}`;
|
|
95
|
-
if (this.options.debug) {
|
|
96
|
-
console.log(`🔌 Connecting to WebSocket at ${wsUrl}...`);
|
|
97
|
-
}
|
|
98
|
-
return new Promise((resolve, reject) => {
|
|
99
|
-
this.ws = new WebSocket(wsUrl);
|
|
100
|
-
this.ws.onopen = () => {
|
|
101
|
-
if (this.options.debug)
|
|
102
|
-
console.log('✅ Connected to Castari Server');
|
|
103
|
-
resolve();
|
|
104
|
-
};
|
|
105
|
-
this.ws.onmessage = event => {
|
|
106
|
-
try {
|
|
107
|
-
const message = JSON.parse(event.data.toString());
|
|
108
|
-
this.handleMessage(message);
|
|
109
|
-
}
|
|
110
|
-
catch (error) {
|
|
111
|
-
console.error('Failed to parse message:', error);
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
this.ws.onerror = error => {
|
|
115
|
-
console.error('WebSocket error:', error);
|
|
116
|
-
reject(error);
|
|
117
|
-
};
|
|
118
|
-
this.ws.onclose = (event) => {
|
|
119
|
-
if (this.options.debug)
|
|
120
|
-
console.log(`👋 Disconnected (code=${event.code})`);
|
|
121
|
-
this.closeHandlers.forEach(handler => handler(event.code, event.reason));
|
|
122
|
-
};
|
|
46
|
+
this.options = options;
|
|
47
|
+
// Create HTTP client with provided or default base URL
|
|
48
|
+
this.httpClient = new HttpClient({
|
|
49
|
+
baseUrl: options.baseUrl || 'https://web-13239-04c55b73-wp4aqyqk.onporter.run',
|
|
123
50
|
});
|
|
51
|
+
// Set auth if provided directly
|
|
52
|
+
if (options.apiKey) {
|
|
53
|
+
this.httpClient.setAuth('api_key', options.apiKey);
|
|
54
|
+
this.initialized = true;
|
|
55
|
+
}
|
|
56
|
+
else if (options.token) {
|
|
57
|
+
this.httpClient.setAuth('token', options.token);
|
|
58
|
+
this.initialized = true;
|
|
59
|
+
}
|
|
60
|
+
// Initialize API classes
|
|
61
|
+
this.agents = new AgentsAPI(this.httpClient);
|
|
62
|
+
this.usage = new UsageAPI(this.httpClient);
|
|
63
|
+
this.auth = new AuthAPI(this.httpClient);
|
|
124
64
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Initialize the client by loading credentials from config
|
|
67
|
+
* This is called automatically before the first API request
|
|
68
|
+
*/
|
|
69
|
+
async initialize() {
|
|
70
|
+
if (this.initialized)
|
|
71
|
+
return;
|
|
72
|
+
// If already initializing, wait for it
|
|
73
|
+
if (this.initPromise) {
|
|
74
|
+
await this.initPromise;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.initPromise = this.doInitialize();
|
|
78
|
+
await this.initPromise;
|
|
131
79
|
}
|
|
132
|
-
async
|
|
133
|
-
if
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
console.log(`🚀 Requesting sandbox from ${platformUrl}...`);
|
|
139
|
-
}
|
|
140
|
-
const response = await fetch(`${platformUrl}/sandbox/start`, {
|
|
141
|
-
method: 'POST',
|
|
142
|
-
headers: {
|
|
143
|
-
'Content-Type': 'application/json',
|
|
144
|
-
...(this.resolvedPlatformApiKey
|
|
145
|
-
? { Authorization: `Bearer ${this.resolvedPlatformApiKey}` }
|
|
146
|
-
: {}),
|
|
147
|
-
},
|
|
148
|
-
body: JSON.stringify({
|
|
149
|
-
snapshot: this.options.snapshot,
|
|
150
|
-
labels: this.options.labels,
|
|
151
|
-
volume: this.options.volume,
|
|
152
|
-
clientId: this.resolvedClientId
|
|
153
|
-
})
|
|
154
|
-
});
|
|
155
|
-
if (!response.ok) {
|
|
156
|
-
const errorText = await response.text();
|
|
157
|
-
throw new Error(`Failed to start sandbox: ${errorText}`);
|
|
158
|
-
}
|
|
159
|
-
const { id, url, proxyUrl, authHeaders, authParams } = await response.json();
|
|
160
|
-
this.sandboxId = id;
|
|
161
|
-
// Default to proxy mode (true) unless explicitly disabled
|
|
162
|
-
const useProxy = this.options.useProxy ?? (process.env.CASTARI_USE_PROXY !== 'false');
|
|
163
|
-
if (this.options.debug) {
|
|
164
|
-
console.log(`✅ Sandbox started: ${id} at ${url}`);
|
|
165
|
-
if (useProxy && proxyUrl) {
|
|
166
|
-
console.log(`🔀 Using proxy mode via ${proxyUrl}`);
|
|
80
|
+
async doInitialize() {
|
|
81
|
+
// Load auth from config if not provided
|
|
82
|
+
if (!this.options.apiKey && !this.options.token) {
|
|
83
|
+
const auth = await getAuth();
|
|
84
|
+
if (auth) {
|
|
85
|
+
this.httpClient.setAuth(auth.type, auth.value);
|
|
167
86
|
}
|
|
168
87
|
}
|
|
169
|
-
|
|
170
|
-
if (useProxy && proxyUrl) {
|
|
171
|
-
// Proxy mode: connect through platform API
|
|
172
|
-
const proxyConfigUrl = `${platformUrl}/proxy/${id}/config`;
|
|
173
|
-
const proxyWsUrl = proxyUrl;
|
|
174
|
-
return {
|
|
175
|
-
configUrl: proxyConfigUrl,
|
|
176
|
-
wsUrl: proxyWsUrl,
|
|
177
|
-
// No auth headers/params needed - proxy handles sandbox auth
|
|
178
|
-
cleanup: async () => {
|
|
179
|
-
await this.stop({ delete: true });
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
// Direct mode: connect to sandbox directly
|
|
184
|
-
const baseUrl = url.replace(/\/$/, '');
|
|
185
|
-
const configUrl = `${baseUrl.replace('ws://', 'http://').replace('wss://', 'https://')}/config`;
|
|
186
|
-
const wsUrlBase = `${baseUrl.replace('https://', 'wss://').replace('http://', 'ws://')}/ws`;
|
|
187
|
-
return {
|
|
188
|
-
configUrl,
|
|
189
|
-
wsUrl: wsUrlBase,
|
|
190
|
-
authHeaders,
|
|
191
|
-
authParams,
|
|
192
|
-
cleanup: async () => {
|
|
193
|
-
await this.stop({ delete: true });
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
handleMessage(message) {
|
|
198
|
-
if (this.options.debug) {
|
|
199
|
-
console.log('📨 Received message:', JSON.stringify(message, null, 2));
|
|
200
|
-
}
|
|
201
|
-
this.messageHandlers.forEach(handler => handler(message));
|
|
88
|
+
this.initialized = true;
|
|
202
89
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return () => {
|
|
213
|
-
this.closeHandlers = this.closeHandlers.filter(h => h !== handler);
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
send(message) {
|
|
217
|
-
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
218
|
-
throw new Error('WebSocket is not connected');
|
|
219
|
-
}
|
|
220
|
-
this.ws.send(JSON.stringify(message));
|
|
221
|
-
}
|
|
222
|
-
async stop(options = { delete: true }) {
|
|
223
|
-
if (this.ws) {
|
|
224
|
-
this.ws.close();
|
|
225
|
-
}
|
|
226
|
-
if (this.sandboxId) {
|
|
227
|
-
const platformUrl = (this.options.platformUrl || process.env.CASTARI_PLATFORM_URL || DEFAULT_PLATFORM_URL).replace(/\/$/, '');
|
|
228
|
-
try {
|
|
229
|
-
const clientId = this.resolvedClientId || this.options.clientId || process.env.CASTARI_CLIENT_ID;
|
|
230
|
-
const apiKey = this.resolvedPlatformApiKey || this.options.platformApiKey || process.env.CASTARI_API_KEY;
|
|
231
|
-
const response = await fetch(`${platformUrl}/sandbox/stop`, {
|
|
232
|
-
method: 'POST',
|
|
233
|
-
headers: {
|
|
234
|
-
'Content-Type': 'application/json',
|
|
235
|
-
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
236
|
-
},
|
|
237
|
-
body: JSON.stringify({
|
|
238
|
-
sandboxId: this.sandboxId,
|
|
239
|
-
delete: options.delete,
|
|
240
|
-
clientId
|
|
241
|
-
})
|
|
242
|
-
});
|
|
243
|
-
if (!response.ok) {
|
|
244
|
-
console.error(`Failed to stop sandbox: ${await response.text()}`);
|
|
245
|
-
}
|
|
246
|
-
else if (this.options.debug) {
|
|
247
|
-
console.log(`🛑 Sandbox ${options.delete ? 'deleted' : 'stopped'}`);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
catch (err) {
|
|
251
|
-
console.error('Failed to call stop endpoint:', err);
|
|
252
|
-
}
|
|
90
|
+
/**
|
|
91
|
+
* Ensure the client is initialized before making requests
|
|
92
|
+
* @throws AuthenticationError if no credentials are available
|
|
93
|
+
*/
|
|
94
|
+
async ensureAuthenticated() {
|
|
95
|
+
await this.initialize();
|
|
96
|
+
const auth = await getAuth();
|
|
97
|
+
if (!auth && !this.options.apiKey && !this.options.token) {
|
|
98
|
+
throw new AuthenticationError();
|
|
253
99
|
}
|
|
254
100
|
}
|
|
255
101
|
}
|
|
102
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAa,OAAO,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,aAAa;IAkBJ;IAjBZ,UAAU,CAAa;IACvB,WAAW,GAAG,KAAK,CAAC;IACpB,WAAW,GAAyB,IAAI,CAAC;IAEjD,8BAA8B;IACrB,MAAM,CAAY;IAE3B,yCAAyC;IAChC,KAAK,CAAW;IAEzB,wCAAwC;IAC/B,IAAI,CAAU;IAEvB;;;OAGG;IACH,YAAoB,UAAgC,EAAE;QAAlC,YAAO,GAAP,OAAO,CAA2B;QACpD,uDAAuD;QACvD,IAAI,CAAC,UAAU,GAAG,IAAI,UAAU,CAAC;YAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,kDAAkD;SAC/E,CAAC,CAAC;QAEH,gCAAgC;QAChC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACnD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAC1B,CAAC;aAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YAChD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAC1B,CAAC;QAED,yBAAyB;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAE7B,uCAAuC;QACvC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,CAAC,WAAW,CAAC;YACvB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACvC,MAAM,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,wCAAwC;QACxC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAChD,MAAM,IAAI,GAAG,MAAM,OAAO,EAAE,CAAC;YAC7B,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,mBAAmB;QACvB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAExB,MAAM,IAAI,GAAG,MAAM,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACzD,MAAM,IAAI,mBAAmB,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;CACF"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credentials stored in ~/.castari/credentials.yaml
|
|
3
|
+
*/
|
|
4
|
+
export interface Credentials {
|
|
5
|
+
token?: string;
|
|
6
|
+
api_key?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Config stored in ~/.castari/config.yaml
|
|
10
|
+
*/
|
|
11
|
+
export interface Config {
|
|
12
|
+
api_url?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Load credentials from ~/.castari/credentials.yaml
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadCredentials(): Promise<Credentials>;
|
|
18
|
+
/**
|
|
19
|
+
* Save credentials to ~/.castari/credentials.yaml
|
|
20
|
+
* File is created with mode 0600 for security
|
|
21
|
+
*/
|
|
22
|
+
export declare function saveCredentials(credentials: Credentials): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Clear all stored credentials
|
|
25
|
+
*/
|
|
26
|
+
export declare function clearCredentials(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Load config from ~/.castari/config.yaml
|
|
29
|
+
*/
|
|
30
|
+
export declare function loadConfig(): Promise<Config>;
|
|
31
|
+
/**
|
|
32
|
+
* Save config to ~/.castari/config.yaml
|
|
33
|
+
*/
|
|
34
|
+
export declare function saveConfig(config: Config): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Get the API URL from config, env var, or default
|
|
37
|
+
*/
|
|
38
|
+
export declare function getApiUrl(): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Get the auth token or API key from env vars or config
|
|
41
|
+
* Priority: CASTARI_API_KEY env var > credentials file
|
|
42
|
+
*/
|
|
43
|
+
export declare function getAuth(): Promise<{
|
|
44
|
+
type: 'api_key' | 'token';
|
|
45
|
+
value: string;
|
|
46
|
+
} | null>;
|
|
47
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAeA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAWD;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CAO5D;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMtD;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAOlD;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9D;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAcjD;AAED;;;GAGG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC;IAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAiB5F"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { mkdir, readFile, writeFile, rm } from 'node:fs/promises';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
6
|
+
/** Directory for Castari config files */
|
|
7
|
+
const CONFIG_DIR = join(homedir(), '.castari');
|
|
8
|
+
/** Path to credentials file */
|
|
9
|
+
const CREDENTIALS_FILE = join(CONFIG_DIR, 'credentials.yaml');
|
|
10
|
+
/** Path to config file */
|
|
11
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'config.yaml');
|
|
12
|
+
/**
|
|
13
|
+
* Ensure the config directory exists
|
|
14
|
+
*/
|
|
15
|
+
async function ensureConfigDir() {
|
|
16
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
17
|
+
await mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Load credentials from ~/.castari/credentials.yaml
|
|
22
|
+
*/
|
|
23
|
+
export async function loadCredentials() {
|
|
24
|
+
try {
|
|
25
|
+
const content = await readFile(CREDENTIALS_FILE, 'utf-8');
|
|
26
|
+
return parseYaml(content) || {};
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Save credentials to ~/.castari/credentials.yaml
|
|
34
|
+
* File is created with mode 0600 for security
|
|
35
|
+
*/
|
|
36
|
+
export async function saveCredentials(credentials) {
|
|
37
|
+
await ensureConfigDir();
|
|
38
|
+
const content = stringifyYaml(credentials);
|
|
39
|
+
await writeFile(CREDENTIALS_FILE, content, { mode: 0o600 });
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Clear all stored credentials
|
|
43
|
+
*/
|
|
44
|
+
export async function clearCredentials() {
|
|
45
|
+
try {
|
|
46
|
+
await rm(CREDENTIALS_FILE);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// File doesn't exist, that's fine
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Load config from ~/.castari/config.yaml
|
|
54
|
+
*/
|
|
55
|
+
export async function loadConfig() {
|
|
56
|
+
try {
|
|
57
|
+
const content = await readFile(CONFIG_FILE, 'utf-8');
|
|
58
|
+
return parseYaml(content) || {};
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Save config to ~/.castari/config.yaml
|
|
66
|
+
*/
|
|
67
|
+
export async function saveConfig(config) {
|
|
68
|
+
await ensureConfigDir();
|
|
69
|
+
const content = stringifyYaml(config);
|
|
70
|
+
await writeFile(CONFIG_FILE, content, { mode: 0o644 });
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get the API URL from config, env var, or default
|
|
74
|
+
*/
|
|
75
|
+
export async function getApiUrl() {
|
|
76
|
+
// Check env var first
|
|
77
|
+
if (process.env.CASTARI_API_URL) {
|
|
78
|
+
return process.env.CASTARI_API_URL;
|
|
79
|
+
}
|
|
80
|
+
// Check config file
|
|
81
|
+
const config = await loadConfig();
|
|
82
|
+
if (config.api_url) {
|
|
83
|
+
return config.api_url;
|
|
84
|
+
}
|
|
85
|
+
// Default
|
|
86
|
+
return 'https://web-13239-04c55b73-wp4aqyqk.onporter.run';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get the auth token or API key from env vars or config
|
|
90
|
+
* Priority: CASTARI_API_KEY env var > credentials file
|
|
91
|
+
*/
|
|
92
|
+
export async function getAuth() {
|
|
93
|
+
// Check env var first (for CI/CD)
|
|
94
|
+
const apiKey = process.env.CASTARI_API_KEY;
|
|
95
|
+
if (apiKey) {
|
|
96
|
+
return { type: 'api_key', value: apiKey };
|
|
97
|
+
}
|
|
98
|
+
// Check credentials file
|
|
99
|
+
const credentials = await loadCredentials();
|
|
100
|
+
if (credentials.api_key) {
|
|
101
|
+
return { type: 'api_key', value: credentials.api_key };
|
|
102
|
+
}
|
|
103
|
+
if (credentials.token) {
|
|
104
|
+
return { type: 'token', value: credentials.token };
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|