@code-harness/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/dist/browser.d.ts +2 -2
- package/dist/browser.js.map +1 -1
- package/dist/cjs/browser.d.ts +65 -0
- package/dist/cjs/core/client.d.ts +27 -0
- package/dist/cjs/core/index.d.ts +4 -0
- package/dist/cjs/core/index.js +304 -0
- package/dist/cjs/core/sandbox.d.ts +63 -0
- package/dist/cjs/errors.d.ts +8 -0
- package/dist/cjs/package.json +1 -0
- package/dist/client.d.ts +5 -22
- package/dist/client.js +2 -49
- package/dist/client.js.map +1 -1
- package/dist/core/client.d.ts +27 -0
- package/dist/core/client.js +66 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/sandbox.d.ts +63 -0
- package/dist/core/sandbox.js +117 -0
- package/dist/core/sandbox.js.map +1 -0
- package/dist/errors.d.ts +2 -3
- package/dist/errors.js +7 -4
- package/dist/errors.js.map +1 -1
- package/dist/sandbox.d.ts +7 -25
- package/dist/sandbox.js +27 -100
- package/dist/sandbox.js.map +1 -1
- package/package.json +28 -3
package/dist/browser.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BaseClient } from './core/client.js';
|
|
2
2
|
export interface WaitFor {
|
|
3
3
|
selector?: string;
|
|
4
4
|
text?: string;
|
|
@@ -32,7 +32,7 @@ export declare class Browser {
|
|
|
32
32
|
#private;
|
|
33
33
|
readonly sandboxId: string | null;
|
|
34
34
|
readonly record: boolean;
|
|
35
|
-
constructor(client:
|
|
35
|
+
constructor(client: BaseClient, { id, sandboxId, record }: {
|
|
36
36
|
id: string | null;
|
|
37
37
|
sandboxId: string | null;
|
|
38
38
|
record: boolean;
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAoC9C,MAAM,OAAO,OAAO;IACT,SAAS,CAAe;IACxB,MAAM,CAAS;IACf,OAAO,
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { BaseClient } from './core/client.js';
|
|
2
|
+
export interface WaitFor {
|
|
3
|
+
selector?: string;
|
|
4
|
+
text?: string;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface PageRef {
|
|
8
|
+
ref: number;
|
|
9
|
+
tag: string;
|
|
10
|
+
role: string | null;
|
|
11
|
+
name: string;
|
|
12
|
+
value: string;
|
|
13
|
+
placeholder: string;
|
|
14
|
+
href: string;
|
|
15
|
+
}
|
|
16
|
+
export interface Page {
|
|
17
|
+
title: string;
|
|
18
|
+
url: string;
|
|
19
|
+
text: string;
|
|
20
|
+
refs: PageRef[];
|
|
21
|
+
}
|
|
22
|
+
export interface NavigatedPage extends Page {
|
|
23
|
+
status: number | null;
|
|
24
|
+
error: string | null;
|
|
25
|
+
}
|
|
26
|
+
export interface RunResult {
|
|
27
|
+
result: unknown;
|
|
28
|
+
error: string | null;
|
|
29
|
+
durationMs: number;
|
|
30
|
+
}
|
|
31
|
+
export declare class Browser {
|
|
32
|
+
#private;
|
|
33
|
+
readonly sandboxId: string | null;
|
|
34
|
+
readonly record: boolean;
|
|
35
|
+
constructor(client: BaseClient, { id, sandboxId, record }: {
|
|
36
|
+
id: string | null;
|
|
37
|
+
sandboxId: string | null;
|
|
38
|
+
record: boolean;
|
|
39
|
+
});
|
|
40
|
+
get id(): string | null;
|
|
41
|
+
navigate(url: string, options?: {
|
|
42
|
+
until?: WaitFor;
|
|
43
|
+
}): Promise<NavigatedPage>;
|
|
44
|
+
read(options?: {
|
|
45
|
+
maxChars?: number;
|
|
46
|
+
waitFor?: WaitFor;
|
|
47
|
+
}): Promise<Page>;
|
|
48
|
+
click(ref: number, options?: {
|
|
49
|
+
waitFor?: WaitFor;
|
|
50
|
+
}): Promise<Page>;
|
|
51
|
+
type(ref: number, text: string, options?: {
|
|
52
|
+
submit?: boolean;
|
|
53
|
+
waitFor?: WaitFor;
|
|
54
|
+
}): Promise<Page>;
|
|
55
|
+
screenshot(options?: {
|
|
56
|
+
fullPage?: boolean;
|
|
57
|
+
waitFor?: WaitFor;
|
|
58
|
+
}): Promise<{
|
|
59
|
+
path: string;
|
|
60
|
+
}>;
|
|
61
|
+
run(code: string, options?: {
|
|
62
|
+
timeoutMs?: number;
|
|
63
|
+
}): Promise<RunResult>;
|
|
64
|
+
close(): Promise<void>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Browser } from '../browser.js';
|
|
2
|
+
import { Sandbox, type SandboxOptions } from './sandbox.js';
|
|
3
|
+
export interface ClientOptions {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
token?: string;
|
|
6
|
+
fetch?: typeof fetch;
|
|
7
|
+
}
|
|
8
|
+
export interface CreateSandboxOptions extends SandboxOptions {
|
|
9
|
+
name?: string;
|
|
10
|
+
env?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
export declare class BaseClient {
|
|
13
|
+
#private;
|
|
14
|
+
readonly baseUrl: string;
|
|
15
|
+
constructor(options?: ClientOptions);
|
|
16
|
+
me(): Promise<{
|
|
17
|
+
id: string;
|
|
18
|
+
email: string;
|
|
19
|
+
}>;
|
|
20
|
+
createBrowser(): Promise<Browser>;
|
|
21
|
+
getBrowser(id: string): Browser;
|
|
22
|
+
request(method: string, path: string, body?: unknown): Promise<Response>;
|
|
23
|
+
}
|
|
24
|
+
export declare class Client extends BaseClient {
|
|
25
|
+
createSandbox({ name, env, ...options }?: CreateSandboxOptions): Promise<Sandbox>;
|
|
26
|
+
getSandbox(id: string, options?: SandboxOptions): Promise<Sandbox>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { Browser, type NavigatedPage, type Page, type PageRef, type RunResult, type WaitFor } from '../browser.js';
|
|
2
|
+
export { CodeHarnessError, type CodeHarnessErrorCode } from '../errors.js';
|
|
3
|
+
export { Client, type ClientOptions, type CreateSandboxOptions } from './client.js';
|
|
4
|
+
export { Sandbox, type ExecuteResponse, type FileDownloadResponse, type FileOperationError, type FileUploadResponse, type LaunchOptions, type SandboxOptions, } from './sandbox.js';
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
8
|
+
var __toCommonJS = (from) => {
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
10
|
+
if (entry)
|
|
11
|
+
return entry;
|
|
12
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
__moduleCache.set(from, entry);
|
|
22
|
+
return entry;
|
|
23
|
+
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
29
|
+
var __export = (target, all) => {
|
|
30
|
+
for (var name in all)
|
|
31
|
+
__defProp(target, name, {
|
|
32
|
+
get: all[name],
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/core/index.ts
|
|
40
|
+
var exports_core = {};
|
|
41
|
+
__export(exports_core, {
|
|
42
|
+
Browser: () => Browser,
|
|
43
|
+
Client: () => Client,
|
|
44
|
+
CodeHarnessError: () => CodeHarnessError,
|
|
45
|
+
Sandbox: () => Sandbox
|
|
46
|
+
});
|
|
47
|
+
module.exports = __toCommonJS(exports_core);
|
|
48
|
+
|
|
49
|
+
// src/errors.ts
|
|
50
|
+
var CODES = {
|
|
51
|
+
400: "INVALID_REQUEST",
|
|
52
|
+
401: "AUTHENTICATION_FAILED",
|
|
53
|
+
404: "NOT_FOUND",
|
|
54
|
+
409: "CONFLICT",
|
|
55
|
+
413: "TOO_LARGE",
|
|
56
|
+
429: "RATE_LIMITED",
|
|
57
|
+
502: "UPSTREAM_FAILED",
|
|
58
|
+
504: "TIMEOUT"
|
|
59
|
+
};
|
|
60
|
+
var SANDBOX_ERROR = Symbol.for("sandbox.error");
|
|
61
|
+
|
|
62
|
+
class CodeHarnessError extends Error {
|
|
63
|
+
code;
|
|
64
|
+
status;
|
|
65
|
+
name = "CodeHarnessError";
|
|
66
|
+
constructor(message, code, status = null, cause) {
|
|
67
|
+
super(message, { cause });
|
|
68
|
+
this.code = code;
|
|
69
|
+
this.status = status;
|
|
70
|
+
Object.defineProperty(this, SANDBOX_ERROR, { value: true });
|
|
71
|
+
}
|
|
72
|
+
static async fromResponse(response) {
|
|
73
|
+
const body = await response.json().catch(() => null);
|
|
74
|
+
const message = body?.message ?? body?.error ?? response.statusText;
|
|
75
|
+
return new CodeHarnessError(message, CODES[response.status] ?? "UNKNOWN", response.status);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/browser.ts
|
|
80
|
+
class Browser {
|
|
81
|
+
sandboxId;
|
|
82
|
+
record;
|
|
83
|
+
#client;
|
|
84
|
+
#id;
|
|
85
|
+
#creating = null;
|
|
86
|
+
constructor(client, { id, sandboxId, record }) {
|
|
87
|
+
this.#client = client;
|
|
88
|
+
this.#id = id;
|
|
89
|
+
this.sandboxId = sandboxId;
|
|
90
|
+
this.record = record;
|
|
91
|
+
}
|
|
92
|
+
get id() {
|
|
93
|
+
return this.#id;
|
|
94
|
+
}
|
|
95
|
+
navigate(url, options = {}) {
|
|
96
|
+
return this.#call("navigate", { url, ...options });
|
|
97
|
+
}
|
|
98
|
+
read(options = {}) {
|
|
99
|
+
return this.#call("read", options);
|
|
100
|
+
}
|
|
101
|
+
click(ref, options = {}) {
|
|
102
|
+
return this.#call("click", { ref, ...options });
|
|
103
|
+
}
|
|
104
|
+
type(ref, text, options = {}) {
|
|
105
|
+
return this.#call("type", { ref, text, ...options });
|
|
106
|
+
}
|
|
107
|
+
screenshot(options = {}) {
|
|
108
|
+
return this.#call("screenshot", options);
|
|
109
|
+
}
|
|
110
|
+
run(code, options = {}) {
|
|
111
|
+
return this.#call("run", { code, ...options });
|
|
112
|
+
}
|
|
113
|
+
async close() {
|
|
114
|
+
if (!this.#id)
|
|
115
|
+
return;
|
|
116
|
+
await this.#client.request("DELETE", `/browser/${this.#id}`).catch((err) => {
|
|
117
|
+
if (!(err instanceof CodeHarnessError && err.code === "NOT_FOUND"))
|
|
118
|
+
throw err;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async#call(action, body) {
|
|
122
|
+
const id = await this.#sessionId();
|
|
123
|
+
return (await this.#client.request("POST", `/browser/${id}/${action}`, body)).json();
|
|
124
|
+
}
|
|
125
|
+
async#sessionId() {
|
|
126
|
+
if (this.#id)
|
|
127
|
+
return this.#id;
|
|
128
|
+
this.#creating ??= this.#client.request("POST", "/browser", { workspaceId: this.sandboxId, record: this.record }).then((response) => response.json()).then((session) => this.#id = session.id).finally(() => this.#creating = null);
|
|
129
|
+
return this.#creating;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// src/core/sandbox.ts
|
|
133
|
+
var ROOT = "/workspace";
|
|
134
|
+
var DEFAULT_TIMEOUT_MS = 120000;
|
|
135
|
+
var UTF8 = new TextDecoder("utf-8", { fatal: true });
|
|
136
|
+
var relativePath = (path) => {
|
|
137
|
+
if (path === ROOT)
|
|
138
|
+
return "";
|
|
139
|
+
return path.startsWith(`${ROOT}/`) ? path.slice(ROOT.length + 1) : path.startsWith("/") ? null : path;
|
|
140
|
+
};
|
|
141
|
+
var encodePath = (relative) => relative.split("/").map(encodeURIComponent).join("/");
|
|
142
|
+
var fileError = (err) => {
|
|
143
|
+
if (err instanceof CodeHarnessError && err.code === "NOT_FOUND")
|
|
144
|
+
return "file_not_found";
|
|
145
|
+
if (err instanceof CodeHarnessError && err.code === "INVALID_REQUEST")
|
|
146
|
+
return "invalid_path";
|
|
147
|
+
throw err;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
class Sandbox {
|
|
151
|
+
id;
|
|
152
|
+
name;
|
|
153
|
+
envKeys;
|
|
154
|
+
createdAt;
|
|
155
|
+
browser;
|
|
156
|
+
#client;
|
|
157
|
+
#timeoutMs;
|
|
158
|
+
constructor(client, workspace, { timeoutMs = DEFAULT_TIMEOUT_MS, record = false } = {}) {
|
|
159
|
+
this.#client = client;
|
|
160
|
+
this.#timeoutMs = timeoutMs;
|
|
161
|
+
this.id = workspace.id;
|
|
162
|
+
this.name = workspace.name;
|
|
163
|
+
this.envKeys = workspace.defaultEnvKeys;
|
|
164
|
+
this.createdAt = new Date(workspace.createdAt);
|
|
165
|
+
this.browser = new Browser(client, { id: null, sandboxId: workspace.id, record });
|
|
166
|
+
}
|
|
167
|
+
async execute(command) {
|
|
168
|
+
const response = await this.#client.request("POST", `/workspaces/${this.id}/sandbox/exec`, {
|
|
169
|
+
command,
|
|
170
|
+
timeoutMs: this.#timeoutMs
|
|
171
|
+
});
|
|
172
|
+
const result = await response.json();
|
|
173
|
+
return {
|
|
174
|
+
output: result.timedOut ? `${result.output}
|
|
175
|
+
timed out after ${this.#timeoutMs} ms` : result.output,
|
|
176
|
+
exitCode: result.exitCode,
|
|
177
|
+
truncated: false
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
async uploadFiles(files) {
|
|
181
|
+
const results = [];
|
|
182
|
+
for (const [path, bytes] of files) {
|
|
183
|
+
const relative = relativePath(path);
|
|
184
|
+
if (!relative) {
|
|
185
|
+
results.push({ path, error: "invalid_path" });
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
let content;
|
|
189
|
+
try {
|
|
190
|
+
content = UTF8.decode(bytes);
|
|
191
|
+
} catch {
|
|
192
|
+
results.push({ path, error: "invalid_path" });
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
const error = await this.#client.request("PUT", `/workspaces/${this.id}/files/${encodePath(relative)}`, { content }).then(() => null, fileError);
|
|
196
|
+
results.push({ path, error });
|
|
197
|
+
}
|
|
198
|
+
return results;
|
|
199
|
+
}
|
|
200
|
+
async downloadFiles(paths) {
|
|
201
|
+
const results = [];
|
|
202
|
+
for (const path of paths) {
|
|
203
|
+
const relative = relativePath(path);
|
|
204
|
+
if (!relative) {
|
|
205
|
+
results.push({ path, content: null, error: "invalid_path" });
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
const response = await this.#client.request("GET", `/workspaces/${this.id}/files/${encodePath(relative)}?raw=true`);
|
|
210
|
+
results.push({ path, content: new Uint8Array(await response.arrayBuffer()), error: null });
|
|
211
|
+
} catch (err) {
|
|
212
|
+
results.push({ path, content: null, error: fileError(err) });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return results;
|
|
216
|
+
}
|
|
217
|
+
async uploadAsZip(zip, { path = "" } = {}) {
|
|
218
|
+
const relative = relativePath(path);
|
|
219
|
+
if (relative === null)
|
|
220
|
+
throw new CodeHarnessError(`${path} is outside ${ROOT}`, "INVALID_REQUEST");
|
|
221
|
+
const form = new FormData;
|
|
222
|
+
form.append("path", relative);
|
|
223
|
+
form.append("file", zip instanceof Blob ? zip : new Blob([zip]), "upload.zip");
|
|
224
|
+
return (await this.#client.request("PUT", `/workspaces/${this.id}/upload`, form)).json();
|
|
225
|
+
}
|
|
226
|
+
async launch(options) {
|
|
227
|
+
return (await this.#client.request("POST", `/workspaces/${this.id}/sandbox/launch`, options)).json();
|
|
228
|
+
}
|
|
229
|
+
async logs({ tail } = {}) {
|
|
230
|
+
const query = tail === undefined ? "" : `?tail=${tail}`;
|
|
231
|
+
const response = await this.#client.request("GET", `/workspaces/${this.id}/sandbox/logs${query}`);
|
|
232
|
+
return (await response.json()).lines;
|
|
233
|
+
}
|
|
234
|
+
async stop() {
|
|
235
|
+
await this.#client.request("POST", `/workspaces/${this.id}/sandbox/stop`);
|
|
236
|
+
}
|
|
237
|
+
async close() {
|
|
238
|
+
await this.browser.close();
|
|
239
|
+
await this.#client.request("DELETE", `/workspaces/${this.id}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/core/client.ts
|
|
244
|
+
var API_PREFIX = "/api/v1";
|
|
245
|
+
|
|
246
|
+
class BaseClient {
|
|
247
|
+
baseUrl;
|
|
248
|
+
#token;
|
|
249
|
+
#fetch;
|
|
250
|
+
constructor(options = {}) {
|
|
251
|
+
const env = typeof process === "undefined" ? {} : process.env;
|
|
252
|
+
const baseUrl = options.baseUrl ?? env.CODE_HARNESS_BASE_URL;
|
|
253
|
+
const token = options.token ?? env.CODE_HARNESS_TOKEN;
|
|
254
|
+
if (!baseUrl || !token)
|
|
255
|
+
throw new CodeHarnessError("Pass baseUrl and token, or set CODE_HARNESS_BASE_URL and CODE_HARNESS_TOKEN", "AUTHENTICATION_FAILED");
|
|
256
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
257
|
+
this.#token = token;
|
|
258
|
+
this.#fetch = options.fetch ?? fetch;
|
|
259
|
+
}
|
|
260
|
+
async me() {
|
|
261
|
+
return (await this.request("GET", "/me")).json();
|
|
262
|
+
}
|
|
263
|
+
async createBrowser() {
|
|
264
|
+
const session = await (await this.request("POST", "/browser", {})).json();
|
|
265
|
+
return new Browser(this, { id: session.id, sandboxId: null, record: false });
|
|
266
|
+
}
|
|
267
|
+
getBrowser(id) {
|
|
268
|
+
return new Browser(this, { id, sandboxId: null, record: false });
|
|
269
|
+
}
|
|
270
|
+
async request(method, path, body) {
|
|
271
|
+
const headers = { authorization: `Bearer ${this.#token}` };
|
|
272
|
+
const isJson = body !== undefined && !(body instanceof FormData);
|
|
273
|
+
if (isJson)
|
|
274
|
+
headers["content-type"] = "application/json";
|
|
275
|
+
let response;
|
|
276
|
+
try {
|
|
277
|
+
response = await this.#fetch(`${this.baseUrl}${API_PREFIX}${path}`, {
|
|
278
|
+
method,
|
|
279
|
+
headers,
|
|
280
|
+
body: isJson ? JSON.stringify(body) : body
|
|
281
|
+
});
|
|
282
|
+
} catch (err) {
|
|
283
|
+
const cause = err instanceof Error ? err : new Error(String(err));
|
|
284
|
+
throw new CodeHarnessError(`Can't reach ${this.baseUrl}: ${cause.message}`, "NETWORK_ERROR", null, cause);
|
|
285
|
+
}
|
|
286
|
+
if (!response.ok)
|
|
287
|
+
throw await CodeHarnessError.fromResponse(response);
|
|
288
|
+
return response;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
class Client extends BaseClient {
|
|
293
|
+
async createSandbox({ name, env, ...options } = {}) {
|
|
294
|
+
const response = await this.request("POST", "/workspaces", {
|
|
295
|
+
name: name ?? `sandbox-${Date.now()}`,
|
|
296
|
+
defaultEnv: env
|
|
297
|
+
});
|
|
298
|
+
return new Sandbox(this, await response.json(), options);
|
|
299
|
+
}
|
|
300
|
+
async getSandbox(id, options = {}) {
|
|
301
|
+
const response = await this.request("GET", `/workspaces/${encodeURIComponent(id)}`);
|
|
302
|
+
return new Sandbox(this, await response.json(), options);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Browser } from '../browser.js';
|
|
2
|
+
import type { BaseClient } from './client.js';
|
|
3
|
+
export declare const ROOT = "/workspace";
|
|
4
|
+
export type FileOperationError = 'file_not_found' | 'permission_denied' | 'is_directory' | 'invalid_path';
|
|
5
|
+
export interface ExecuteResponse {
|
|
6
|
+
output: string;
|
|
7
|
+
exitCode: number | null;
|
|
8
|
+
truncated: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface FileUploadResponse {
|
|
11
|
+
path: string;
|
|
12
|
+
error: FileOperationError | null;
|
|
13
|
+
}
|
|
14
|
+
export interface FileDownloadResponse {
|
|
15
|
+
path: string;
|
|
16
|
+
content: Uint8Array | null;
|
|
17
|
+
error: FileOperationError | null;
|
|
18
|
+
}
|
|
19
|
+
export interface SandboxOptions {
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
record?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface LaunchOptions {
|
|
24
|
+
command: string;
|
|
25
|
+
port: number;
|
|
26
|
+
env?: Record<string, string>;
|
|
27
|
+
network?: {
|
|
28
|
+
allow?: string[];
|
|
29
|
+
deny?: string[];
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface Workspace {
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
defaultEnvKeys: string[];
|
|
36
|
+
createdAt: string;
|
|
37
|
+
}
|
|
38
|
+
export declare class Sandbox {
|
|
39
|
+
#private;
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly envKeys: string[];
|
|
43
|
+
readonly createdAt: Date;
|
|
44
|
+
readonly browser: Browser;
|
|
45
|
+
constructor(client: BaseClient, workspace: Workspace, { timeoutMs, record }?: SandboxOptions);
|
|
46
|
+
execute(command: string): Promise<ExecuteResponse>;
|
|
47
|
+
uploadFiles(files: Array<[string, Uint8Array]>): Promise<FileUploadResponse[]>;
|
|
48
|
+
downloadFiles(paths: string[]): Promise<FileDownloadResponse[]>;
|
|
49
|
+
uploadAsZip(zip: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer, { path }?: {
|
|
50
|
+
path?: string;
|
|
51
|
+
}): Promise<{
|
|
52
|
+
path: string;
|
|
53
|
+
files: number;
|
|
54
|
+
}>;
|
|
55
|
+
launch(options: LaunchOptions): Promise<{
|
|
56
|
+
url: string;
|
|
57
|
+
}>;
|
|
58
|
+
logs({ tail }?: {
|
|
59
|
+
tail?: number;
|
|
60
|
+
}): Promise<string[]>;
|
|
61
|
+
stop(): Promise<void>;
|
|
62
|
+
close(): Promise<void>;
|
|
63
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type CodeHarnessErrorCode = 'INVALID_REQUEST' | 'AUTHENTICATION_FAILED' | 'NOT_FOUND' | 'CONFLICT' | 'TOO_LARGE' | 'RATE_LIMITED' | 'UPSTREAM_FAILED' | 'TIMEOUT' | 'NETWORK_ERROR' | 'UNKNOWN';
|
|
2
|
+
export declare class CodeHarnessError extends Error {
|
|
3
|
+
readonly code: CodeHarnessErrorCode;
|
|
4
|
+
readonly status: number | null;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
constructor(message: string, code: CodeHarnessErrorCode, status?: number | null, cause?: Error);
|
|
7
|
+
static fromResponse(response: Response): Promise<CodeHarnessError>;
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,25 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
fetch?: typeof fetch;
|
|
7
|
-
}
|
|
8
|
-
export interface CreateSandboxOptions extends SandboxOptions {
|
|
9
|
-
name?: string;
|
|
10
|
-
env?: Record<string, string>;
|
|
11
|
-
}
|
|
12
|
-
export declare class Client {
|
|
13
|
-
#private;
|
|
14
|
-
readonly baseUrl: string;
|
|
15
|
-
constructor(options?: ClientOptions);
|
|
16
|
-
me(): Promise<{
|
|
17
|
-
id: string;
|
|
18
|
-
email: string;
|
|
19
|
-
}>;
|
|
1
|
+
import { BaseClient, type CreateSandboxOptions } from './core/client.js';
|
|
2
|
+
import type { SandboxOptions } from './core/sandbox.js';
|
|
3
|
+
import { Sandbox } from './sandbox.js';
|
|
4
|
+
export type { ClientOptions, CreateSandboxOptions } from './core/client.js';
|
|
5
|
+
export declare class Client extends BaseClient {
|
|
20
6
|
createSandbox({ name, env, ...options }?: CreateSandboxOptions): Promise<Sandbox>;
|
|
21
7
|
getSandbox(id: string, options?: SandboxOptions): Promise<Sandbox>;
|
|
22
|
-
createBrowser(): Promise<Browser>;
|
|
23
|
-
getBrowser(id: string): Browser;
|
|
24
|
-
request(method: string, path: string, body?: unknown): Promise<Response>;
|
|
25
8
|
}
|
package/dist/client.js
CHANGED
|
@@ -1,24 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CodeHarnessError } from './errors.js';
|
|
1
|
+
import { BaseClient } from './core/client.js';
|
|
3
2
|
import { Sandbox } from './sandbox.js';
|
|
4
|
-
|
|
5
|
-
export class Client {
|
|
6
|
-
baseUrl;
|
|
7
|
-
#token;
|
|
8
|
-
#fetch;
|
|
9
|
-
constructor(options = {}) {
|
|
10
|
-
const env = typeof process === 'undefined' ? {} : process.env;
|
|
11
|
-
const baseUrl = options.baseUrl ?? env.CODE_HARNESS_BASE_URL;
|
|
12
|
-
const token = options.token ?? env.CODE_HARNESS_TOKEN;
|
|
13
|
-
if (!baseUrl || !token)
|
|
14
|
-
throw new CodeHarnessError('Pass baseUrl and token, or set CODE_HARNESS_BASE_URL and CODE_HARNESS_TOKEN', 'AUTHENTICATION_FAILED');
|
|
15
|
-
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
|
16
|
-
this.#token = token;
|
|
17
|
-
this.#fetch = options.fetch ?? fetch;
|
|
18
|
-
}
|
|
19
|
-
async me() {
|
|
20
|
-
return (await this.request('GET', '/me')).json();
|
|
21
|
-
}
|
|
3
|
+
export class Client extends BaseClient {
|
|
22
4
|
async createSandbox({ name, env, ...options } = {}) {
|
|
23
5
|
const response = await this.request('POST', '/workspaces', {
|
|
24
6
|
name: name ?? `sandbox-${Date.now()}`,
|
|
@@ -30,34 +12,5 @@ export class Client {
|
|
|
30
12
|
const response = await this.request('GET', `/workspaces/${encodeURIComponent(id)}`);
|
|
31
13
|
return new Sandbox(this, (await response.json()), options);
|
|
32
14
|
}
|
|
33
|
-
async createBrowser() {
|
|
34
|
-
const session = (await (await this.request('POST', '/browser', {})).json());
|
|
35
|
-
return new Browser(this, { id: session.id, sandboxId: null, record: false });
|
|
36
|
-
}
|
|
37
|
-
getBrowser(id) {
|
|
38
|
-
return new Browser(this, { id, sandboxId: null, record: false });
|
|
39
|
-
}
|
|
40
|
-
// Sends one call to /api/v1, a FormData body as multipart and any other as JSON, and throws CodeHarnessError unless it answers 2xx.
|
|
41
|
-
async request(method, path, body) {
|
|
42
|
-
const headers = { authorization: `Bearer ${this.#token}` };
|
|
43
|
-
const isJson = body !== undefined && !(body instanceof FormData);
|
|
44
|
-
if (isJson)
|
|
45
|
-
headers['content-type'] = 'application/json';
|
|
46
|
-
let response;
|
|
47
|
-
try {
|
|
48
|
-
response = await this.#fetch(`${this.baseUrl}${API_PREFIX}${path}`, {
|
|
49
|
-
method,
|
|
50
|
-
headers,
|
|
51
|
-
body: isJson ? JSON.stringify(body) : body,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
catch (err) {
|
|
55
|
-
const cause = err instanceof Error ? err : new Error(String(err));
|
|
56
|
-
throw new CodeHarnessError(`Can't reach ${this.baseUrl}: ${cause.message}`, 'NETWORK_ERROR', null, cause);
|
|
57
|
-
}
|
|
58
|
-
if (!response.ok)
|
|
59
|
-
throw await CodeHarnessError.fromResponse(response);
|
|
60
|
-
return response;
|
|
61
|
-
}
|
|
62
15
|
}
|
|
63
16
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA6B,MAAM,kBAAkB,CAAA;AAExE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAItC,MAAM,OAAO,MAAO,SAAQ,UAAU;IACpC,KAAK,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,GAAyB,EAAE;QACtE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE;YACzD,IAAI,EAAE,IAAI,IAAI,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE;YACrC,UAAU,EAAE,GAAG;SAChB,CAAC,CAAA;QAEF,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAc,EAAE,OAAO,CAAC,CAAA;IACzE,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAAU,EAAE,OAAO,GAAmB,EAAE;QACvD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,eAAe,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QAEnF,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAc,EAAE,OAAO,CAAC,CAAA;IACzE,CAAC;CACF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Browser } from '../browser.js';
|
|
2
|
+
import { Sandbox, type SandboxOptions } from './sandbox.js';
|
|
3
|
+
export interface ClientOptions {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
token?: string;
|
|
6
|
+
fetch?: typeof fetch;
|
|
7
|
+
}
|
|
8
|
+
export interface CreateSandboxOptions extends SandboxOptions {
|
|
9
|
+
name?: string;
|
|
10
|
+
env?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
export declare class BaseClient {
|
|
13
|
+
#private;
|
|
14
|
+
readonly baseUrl: string;
|
|
15
|
+
constructor(options?: ClientOptions);
|
|
16
|
+
me(): Promise<{
|
|
17
|
+
id: string;
|
|
18
|
+
email: string;
|
|
19
|
+
}>;
|
|
20
|
+
createBrowser(): Promise<Browser>;
|
|
21
|
+
getBrowser(id: string): Browser;
|
|
22
|
+
request(method: string, path: string, body?: unknown): Promise<Response>;
|
|
23
|
+
}
|
|
24
|
+
export declare class Client extends BaseClient {
|
|
25
|
+
createSandbox({ name, env, ...options }?: CreateSandboxOptions): Promise<Sandbox>;
|
|
26
|
+
getSandbox(id: string, options?: SandboxOptions): Promise<Sandbox>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Browser } from '../browser.js';
|
|
2
|
+
import { CodeHarnessError } from '../errors.js';
|
|
3
|
+
import { Sandbox } from './sandbox.js';
|
|
4
|
+
const API_PREFIX = '/api/v1';
|
|
5
|
+
// everything but sandboxes, which each entry's Client adds with its own Sandbox
|
|
6
|
+
export class BaseClient {
|
|
7
|
+
baseUrl;
|
|
8
|
+
#token;
|
|
9
|
+
#fetch;
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
const env = typeof process === 'undefined' ? {} : process.env;
|
|
12
|
+
const baseUrl = options.baseUrl ?? env.CODE_HARNESS_BASE_URL;
|
|
13
|
+
const token = options.token ?? env.CODE_HARNESS_TOKEN;
|
|
14
|
+
if (!baseUrl || !token)
|
|
15
|
+
throw new CodeHarnessError('Pass baseUrl and token, or set CODE_HARNESS_BASE_URL and CODE_HARNESS_TOKEN', 'AUTHENTICATION_FAILED');
|
|
16
|
+
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
|
17
|
+
this.#token = token;
|
|
18
|
+
this.#fetch = options.fetch ?? fetch;
|
|
19
|
+
}
|
|
20
|
+
async me() {
|
|
21
|
+
return (await this.request('GET', '/me')).json();
|
|
22
|
+
}
|
|
23
|
+
async createBrowser() {
|
|
24
|
+
const session = (await (await this.request('POST', '/browser', {})).json());
|
|
25
|
+
return new Browser(this, { id: session.id, sandboxId: null, record: false });
|
|
26
|
+
}
|
|
27
|
+
getBrowser(id) {
|
|
28
|
+
return new Browser(this, { id, sandboxId: null, record: false });
|
|
29
|
+
}
|
|
30
|
+
// Sends one call to /api/v1, a FormData body as multipart and any other as JSON, and throws CodeHarnessError unless it answers 2xx.
|
|
31
|
+
async request(method, path, body) {
|
|
32
|
+
const headers = { authorization: `Bearer ${this.#token}` };
|
|
33
|
+
const isJson = body !== undefined && !(body instanceof FormData);
|
|
34
|
+
if (isJson)
|
|
35
|
+
headers['content-type'] = 'application/json';
|
|
36
|
+
let response;
|
|
37
|
+
try {
|
|
38
|
+
response = await this.#fetch(`${this.baseUrl}${API_PREFIX}${path}`, {
|
|
39
|
+
method,
|
|
40
|
+
headers,
|
|
41
|
+
body: isJson ? JSON.stringify(body) : body,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
const cause = err instanceof Error ? err : new Error(String(err));
|
|
46
|
+
throw new CodeHarnessError(`Can't reach ${this.baseUrl}: ${cause.message}`, 'NETWORK_ERROR', null, cause);
|
|
47
|
+
}
|
|
48
|
+
if (!response.ok)
|
|
49
|
+
throw await CodeHarnessError.fromResponse(response);
|
|
50
|
+
return response;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export class Client extends BaseClient {
|
|
54
|
+
async createSandbox({ name, env, ...options } = {}) {
|
|
55
|
+
const response = await this.request('POST', '/workspaces', {
|
|
56
|
+
name: name ?? `sandbox-${Date.now()}`,
|
|
57
|
+
defaultEnv: env,
|
|
58
|
+
});
|
|
59
|
+
return new Sandbox(this, (await response.json()), options);
|
|
60
|
+
}
|
|
61
|
+
async getSandbox(id, options = {}) {
|
|
62
|
+
const response = await this.request('GET', `/workspaces/${encodeURIComponent(id)}`);
|
|
63
|
+
return new Sandbox(this, (await response.json()), options);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { Browser, type NavigatedPage, type Page, type PageRef, type RunResult, type WaitFor } from '../browser.js';
|
|
2
|
+
export { CodeHarnessError, type CodeHarnessErrorCode } from '../errors.js';
|
|
3
|
+
export { Client, type ClientOptions, type CreateSandboxOptions } from './client.js';
|
|
4
|
+
export { Sandbox, type ExecuteResponse, type FileDownloadResponse, type FileOperationError, type FileUploadResponse, type LaunchOptions, type SandboxOptions, } from './sandbox.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA6E,MAAM,eAAe,CAAA;AAClH,OAAO,EAAE,gBAAgB,EAA6B,MAAM,cAAc,CAAA;AAC1E,OAAO,EAAE,MAAM,EAAiD,MAAM,aAAa,CAAA;AACnF,OAAO,EACL,OAAO,GAOR,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Browser } from '../browser.js';
|
|
2
|
+
import type { BaseClient } from './client.js';
|
|
3
|
+
export declare const ROOT = "/workspace";
|
|
4
|
+
export type FileOperationError = 'file_not_found' | 'permission_denied' | 'is_directory' | 'invalid_path';
|
|
5
|
+
export interface ExecuteResponse {
|
|
6
|
+
output: string;
|
|
7
|
+
exitCode: number | null;
|
|
8
|
+
truncated: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface FileUploadResponse {
|
|
11
|
+
path: string;
|
|
12
|
+
error: FileOperationError | null;
|
|
13
|
+
}
|
|
14
|
+
export interface FileDownloadResponse {
|
|
15
|
+
path: string;
|
|
16
|
+
content: Uint8Array | null;
|
|
17
|
+
error: FileOperationError | null;
|
|
18
|
+
}
|
|
19
|
+
export interface SandboxOptions {
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
record?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface LaunchOptions {
|
|
24
|
+
command: string;
|
|
25
|
+
port: number;
|
|
26
|
+
env?: Record<string, string>;
|
|
27
|
+
network?: {
|
|
28
|
+
allow?: string[];
|
|
29
|
+
deny?: string[];
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface Workspace {
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
defaultEnvKeys: string[];
|
|
36
|
+
createdAt: string;
|
|
37
|
+
}
|
|
38
|
+
export declare class Sandbox {
|
|
39
|
+
#private;
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly envKeys: string[];
|
|
43
|
+
readonly createdAt: Date;
|
|
44
|
+
readonly browser: Browser;
|
|
45
|
+
constructor(client: BaseClient, workspace: Workspace, { timeoutMs, record }?: SandboxOptions);
|
|
46
|
+
execute(command: string): Promise<ExecuteResponse>;
|
|
47
|
+
uploadFiles(files: Array<[string, Uint8Array]>): Promise<FileUploadResponse[]>;
|
|
48
|
+
downloadFiles(paths: string[]): Promise<FileDownloadResponse[]>;
|
|
49
|
+
uploadAsZip(zip: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer, { path }?: {
|
|
50
|
+
path?: string;
|
|
51
|
+
}): Promise<{
|
|
52
|
+
path: string;
|
|
53
|
+
files: number;
|
|
54
|
+
}>;
|
|
55
|
+
launch(options: LaunchOptions): Promise<{
|
|
56
|
+
url: string;
|
|
57
|
+
}>;
|
|
58
|
+
logs({ tail }?: {
|
|
59
|
+
tail?: number;
|
|
60
|
+
}): Promise<string[]>;
|
|
61
|
+
stop(): Promise<void>;
|
|
62
|
+
close(): Promise<void>;
|
|
63
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Browser } from '../browser.js';
|
|
2
|
+
import { CodeHarnessError } from '../errors.js';
|
|
3
|
+
export const ROOT = '/workspace';
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
5
|
+
const UTF8 = new TextDecoder('utf-8', { fatal: true });
|
|
6
|
+
// /workspace/src/a.ts or src/a.ts → src/a.ts, /workspace → ''; null for a path outside /workspace
|
|
7
|
+
const relativePath = (path) => {
|
|
8
|
+
if (path === ROOT)
|
|
9
|
+
return '';
|
|
10
|
+
return path.startsWith(`${ROOT}/`) ? path.slice(ROOT.length + 1) : path.startsWith('/') ? null : path;
|
|
11
|
+
};
|
|
12
|
+
const encodePath = (relative) => relative.split('/').map(encodeURIComponent).join('/');
|
|
13
|
+
// a file route's answer for one path; anything else, like a 401, isn't about the path and is thrown
|
|
14
|
+
const fileError = (err) => {
|
|
15
|
+
if (err instanceof CodeHarnessError && err.code === 'NOT_FOUND')
|
|
16
|
+
return 'file_not_found';
|
|
17
|
+
if (err instanceof CodeHarnessError && err.code === 'INVALID_REQUEST')
|
|
18
|
+
return 'invalid_path';
|
|
19
|
+
throw err;
|
|
20
|
+
};
|
|
21
|
+
export class Sandbox {
|
|
22
|
+
id;
|
|
23
|
+
name;
|
|
24
|
+
envKeys;
|
|
25
|
+
createdAt;
|
|
26
|
+
browser;
|
|
27
|
+
#client;
|
|
28
|
+
#timeoutMs;
|
|
29
|
+
constructor(client, workspace, { timeoutMs = DEFAULT_TIMEOUT_MS, record = false } = {}) {
|
|
30
|
+
this.#client = client;
|
|
31
|
+
this.#timeoutMs = timeoutMs;
|
|
32
|
+
this.id = workspace.id;
|
|
33
|
+
this.name = workspace.name;
|
|
34
|
+
this.envKeys = workspace.defaultEnvKeys;
|
|
35
|
+
this.createdAt = new Date(workspace.createdAt);
|
|
36
|
+
this.browser = new Browser(client, { id: null, sandboxId: workspace.id, record });
|
|
37
|
+
}
|
|
38
|
+
async execute(command) {
|
|
39
|
+
const response = await this.#client.request('POST', `/workspaces/${this.id}/sandbox/exec`, {
|
|
40
|
+
command,
|
|
41
|
+
timeoutMs: this.#timeoutMs,
|
|
42
|
+
});
|
|
43
|
+
const result = (await response.json());
|
|
44
|
+
return {
|
|
45
|
+
output: result.timedOut ? `${result.output}\ntimed out after ${this.#timeoutMs} ms` : result.output,
|
|
46
|
+
exitCode: result.exitCode,
|
|
47
|
+
truncated: false,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async uploadFiles(files) {
|
|
51
|
+
const results = [];
|
|
52
|
+
for (const [path, bytes] of files) {
|
|
53
|
+
const relative = relativePath(path);
|
|
54
|
+
if (!relative) {
|
|
55
|
+
results.push({ path, error: 'invalid_path' });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
let content;
|
|
59
|
+
try {
|
|
60
|
+
content = UTF8.decode(bytes);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// the files route takes text only
|
|
64
|
+
results.push({ path, error: 'invalid_path' });
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const error = await this.#client
|
|
68
|
+
.request('PUT', `/workspaces/${this.id}/files/${encodePath(relative)}`, { content })
|
|
69
|
+
.then(() => null, fileError);
|
|
70
|
+
results.push({ path, error });
|
|
71
|
+
}
|
|
72
|
+
return results;
|
|
73
|
+
}
|
|
74
|
+
async downloadFiles(paths) {
|
|
75
|
+
const results = [];
|
|
76
|
+
for (const path of paths) {
|
|
77
|
+
const relative = relativePath(path);
|
|
78
|
+
if (!relative) {
|
|
79
|
+
results.push({ path, content: null, error: 'invalid_path' });
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const response = await this.#client.request('GET', `/workspaces/${this.id}/files/${encodePath(relative)}?raw=true`);
|
|
84
|
+
results.push({ path, content: new Uint8Array(await response.arrayBuffer()), error: null });
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
results.push({ path, content: null, error: fileError(err) });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return results;
|
|
91
|
+
}
|
|
92
|
+
async uploadAsZip(zip, { path = '' } = {}) {
|
|
93
|
+
const relative = relativePath(path);
|
|
94
|
+
if (relative === null)
|
|
95
|
+
throw new CodeHarnessError(`${path} is outside ${ROOT}`, 'INVALID_REQUEST');
|
|
96
|
+
const form = new FormData();
|
|
97
|
+
form.append('path', relative);
|
|
98
|
+
form.append('file', zip instanceof Blob ? zip : new Blob([zip]), 'upload.zip');
|
|
99
|
+
return (await this.#client.request('PUT', `/workspaces/${this.id}/upload`, form)).json();
|
|
100
|
+
}
|
|
101
|
+
async launch(options) {
|
|
102
|
+
return (await this.#client.request('POST', `/workspaces/${this.id}/sandbox/launch`, options)).json();
|
|
103
|
+
}
|
|
104
|
+
async logs({ tail } = {}) {
|
|
105
|
+
const query = tail === undefined ? '' : `?tail=${tail}`;
|
|
106
|
+
const response = await this.#client.request('GET', `/workspaces/${this.id}/sandbox/logs${query}`);
|
|
107
|
+
return (await response.json()).lines;
|
|
108
|
+
}
|
|
109
|
+
async stop() {
|
|
110
|
+
await this.#client.request('POST', `/workspaces/${this.id}/sandbox/stop`);
|
|
111
|
+
}
|
|
112
|
+
async close() {
|
|
113
|
+
await this.browser.close();
|
|
114
|
+
await this.#client.request('DELETE', `/workspaces/${this.id}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/core/sandbox.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { SandboxError } from 'deepagents';
|
|
2
1
|
export type CodeHarnessErrorCode = 'INVALID_REQUEST' | 'AUTHENTICATION_FAILED' | 'NOT_FOUND' | 'CONFLICT' | 'TOO_LARGE' | 'RATE_LIMITED' | 'UPSTREAM_FAILED' | 'TIMEOUT' | 'NETWORK_ERROR' | 'UNKNOWN';
|
|
3
|
-
export declare class CodeHarnessError extends
|
|
2
|
+
export declare class CodeHarnessError extends Error {
|
|
3
|
+
readonly code: CodeHarnessErrorCode;
|
|
4
4
|
readonly status: number | null;
|
|
5
5
|
readonly name: string;
|
|
6
|
-
readonly code: CodeHarnessErrorCode;
|
|
7
6
|
constructor(message: string, code: CodeHarnessErrorCode, status?: number | null, cause?: Error);
|
|
8
7
|
static fromResponse(response: Response): Promise<CodeHarnessError>;
|
|
9
8
|
}
|
package/dist/errors.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { SandboxError } from 'deepagents';
|
|
2
1
|
const CODES = {
|
|
3
2
|
400: 'INVALID_REQUEST',
|
|
4
3
|
401: 'AUTHENTICATION_FAILED',
|
|
@@ -9,13 +8,17 @@ const CODES = {
|
|
|
9
8
|
502: 'UPSTREAM_FAILED',
|
|
10
9
|
504: 'TIMEOUT',
|
|
11
10
|
};
|
|
12
|
-
|
|
11
|
+
// deepagents' SandboxError.isInstance checks this symbol, so the client entry needn't load deepagents
|
|
12
|
+
const SANDBOX_ERROR = Symbol.for('sandbox.error');
|
|
13
|
+
export class CodeHarnessError extends Error {
|
|
14
|
+
code;
|
|
13
15
|
status;
|
|
14
16
|
name = 'CodeHarnessError';
|
|
15
17
|
constructor(message, code, status = null, cause) {
|
|
16
|
-
super(message,
|
|
18
|
+
super(message, { cause });
|
|
19
|
+
this.code = code;
|
|
17
20
|
this.status = status;
|
|
18
|
-
Object.
|
|
21
|
+
Object.defineProperty(this, SANDBOX_ERROR, { value: true });
|
|
19
22
|
}
|
|
20
23
|
static async fromResponse(response) {
|
|
21
24
|
const body = (await response.json().catch(() => null));
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,KAAK,GAAyC;IAClD,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,uBAAuB;IAC5B,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,UAAU;IACf,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,SAAS;CACf,CAAA;AAcD,sGAAsG;AACtG,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;AAEjD,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAK9B,IAAI;IACJ,MAAM;IALC,IAAI,GAAW,kBAAkB,CAAA;IAEnD,YACE,OAAe,EACN,IAA0B,EAC1B,MAAM,GAAkB,IAAI,EACrC,KAAa;QAEb,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;oBAJhB,IAAI;sBACJ,MAAM;QAIf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7D,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,QAAkB;QAC1C,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAgD,CAAA;QACrG,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,IAAI,EAAE,KAAK,IAAI,QAAQ,CAAC,UAAU,CAAA;QAEnE,OAAO,IAAI,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC5F,CAAC;CACF"}
|
package/dist/sandbox.d.ts
CHANGED
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
import { BaseSandbox, type ExecuteResponse, type FileDownloadResponse, type FileUploadResponse } from 'deepagents';
|
|
2
|
-
import { Browser } from './browser.js';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
timeoutMs?: number;
|
|
7
|
-
record?: boolean;
|
|
8
|
-
}
|
|
9
|
-
export interface LaunchOptions {
|
|
10
|
-
command: string;
|
|
11
|
-
port: number;
|
|
12
|
-
env?: Record<string, string>;
|
|
13
|
-
network?: {
|
|
14
|
-
allow?: string[];
|
|
15
|
-
deny?: string[];
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
export interface Workspace {
|
|
19
|
-
id: string;
|
|
20
|
-
name: string;
|
|
21
|
-
defaultEnvKeys: string[];
|
|
22
|
-
createdAt: string;
|
|
23
|
-
}
|
|
2
|
+
import type { Browser } from './browser.js';
|
|
3
|
+
import type { BaseClient } from './core/client.js';
|
|
4
|
+
import { type LaunchOptions, type SandboxOptions, type Workspace } from './core/sandbox.js';
|
|
5
|
+
export { ROOT, type LaunchOptions, type SandboxOptions, type Workspace } from './core/sandbox.js';
|
|
24
6
|
export declare class Sandbox extends BaseSandbox {
|
|
25
7
|
#private;
|
|
26
8
|
readonly id: string;
|
|
@@ -28,11 +10,11 @@ export declare class Sandbox extends BaseSandbox {
|
|
|
28
10
|
readonly envKeys: string[];
|
|
29
11
|
readonly createdAt: Date;
|
|
30
12
|
readonly browser: Browser;
|
|
31
|
-
constructor(client:
|
|
13
|
+
constructor(client: BaseClient, workspace: Workspace, options?: SandboxOptions);
|
|
32
14
|
execute(command: string): Promise<ExecuteResponse>;
|
|
33
15
|
uploadFiles(files: Array<[string, Uint8Array]>): Promise<FileUploadResponse[]>;
|
|
34
16
|
downloadFiles(paths: string[]): Promise<FileDownloadResponse[]>;
|
|
35
|
-
uploadAsZip(zip: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer,
|
|
17
|
+
uploadAsZip(zip: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer, options?: {
|
|
36
18
|
path?: string;
|
|
37
19
|
}): Promise<{
|
|
38
20
|
path: string;
|
|
@@ -41,7 +23,7 @@ export declare class Sandbox extends BaseSandbox {
|
|
|
41
23
|
launch(options: LaunchOptions): Promise<{
|
|
42
24
|
url: string;
|
|
43
25
|
}>;
|
|
44
|
-
logs(
|
|
26
|
+
logs(options?: {
|
|
45
27
|
tail?: number;
|
|
46
28
|
}): Promise<string[]>;
|
|
47
29
|
stop(): Promise<void>;
|
package/dist/sandbox.js
CHANGED
|
@@ -1,119 +1,46 @@
|
|
|
1
1
|
import { BaseSandbox, } from 'deepagents';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
6
|
-
const UTF8 = new TextDecoder('utf-8', { fatal: true });
|
|
7
|
-
// /workspace/src/a.ts or src/a.ts → src/a.ts, /workspace → ''; null for a path outside /workspace
|
|
8
|
-
const relativePath = (path) => {
|
|
9
|
-
if (path === ROOT)
|
|
10
|
-
return '';
|
|
11
|
-
return path.startsWith(`${ROOT}/`) ? path.slice(ROOT.length + 1) : path.startsWith('/') ? null : path;
|
|
12
|
-
};
|
|
13
|
-
const encodePath = (relative) => relative.split('/').map(encodeURIComponent).join('/');
|
|
14
|
-
// a file route's answer for one path; anything else, like a 401, isn't about the path and is thrown
|
|
15
|
-
const fileError = (err) => {
|
|
16
|
-
if (err instanceof CodeHarnessError && err.code === 'NOT_FOUND')
|
|
17
|
-
return 'file_not_found';
|
|
18
|
-
if (err instanceof CodeHarnessError && err.code === 'INVALID_REQUEST')
|
|
19
|
-
return 'invalid_path';
|
|
20
|
-
throw err;
|
|
21
|
-
};
|
|
2
|
+
import { Sandbox as CoreSandbox } from './core/sandbox.js';
|
|
3
|
+
export { ROOT } from './core/sandbox.js';
|
|
4
|
+
// deepagents' BaseSandbox over the client entry's Sandbox, which holds the calls
|
|
22
5
|
export class Sandbox extends BaseSandbox {
|
|
23
6
|
id;
|
|
24
7
|
name;
|
|
25
8
|
envKeys;
|
|
26
9
|
createdAt;
|
|
27
10
|
browser;
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
constructor(client, workspace, { timeoutMs = DEFAULT_TIMEOUT_MS, record = false } = {}) {
|
|
11
|
+
#sandbox;
|
|
12
|
+
constructor(client, workspace, options = {}) {
|
|
31
13
|
super();
|
|
32
|
-
this.#
|
|
33
|
-
this
|
|
34
|
-
this.
|
|
35
|
-
this.
|
|
36
|
-
this.
|
|
37
|
-
this.
|
|
38
|
-
this.browser = new Browser(client, { id: null, sandboxId: workspace.id, record });
|
|
14
|
+
this.#sandbox = new CoreSandbox(client, workspace, options);
|
|
15
|
+
this.id = this.#sandbox.id;
|
|
16
|
+
this.name = this.#sandbox.name;
|
|
17
|
+
this.envKeys = this.#sandbox.envKeys;
|
|
18
|
+
this.createdAt = this.#sandbox.createdAt;
|
|
19
|
+
this.browser = this.#sandbox.browser;
|
|
39
20
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
command,
|
|
43
|
-
timeoutMs: this.#timeoutMs,
|
|
44
|
-
});
|
|
45
|
-
const result = (await response.json());
|
|
46
|
-
return {
|
|
47
|
-
output: result.timedOut ? `${result.output}\ntimed out after ${this.#timeoutMs} ms` : result.output,
|
|
48
|
-
exitCode: result.exitCode,
|
|
49
|
-
truncated: false,
|
|
50
|
-
};
|
|
21
|
+
execute(command) {
|
|
22
|
+
return this.#sandbox.execute(command);
|
|
51
23
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
for (const [path, bytes] of files) {
|
|
55
|
-
const relative = relativePath(path);
|
|
56
|
-
if (!relative) {
|
|
57
|
-
results.push({ path, error: 'invalid_path' });
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
let content;
|
|
61
|
-
try {
|
|
62
|
-
content = UTF8.decode(bytes);
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
// the files route takes text only
|
|
66
|
-
results.push({ path, error: 'invalid_path' });
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const error = await this.#client
|
|
70
|
-
.request('PUT', `/workspaces/${this.id}/files/${encodePath(relative)}`, { content })
|
|
71
|
-
.then(() => null, fileError);
|
|
72
|
-
results.push({ path, error });
|
|
73
|
-
}
|
|
74
|
-
return results;
|
|
24
|
+
uploadFiles(files) {
|
|
25
|
+
return this.#sandbox.uploadFiles(files);
|
|
75
26
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
for (const path of paths) {
|
|
79
|
-
const relative = relativePath(path);
|
|
80
|
-
if (!relative) {
|
|
81
|
-
results.push({ path, content: null, error: 'invalid_path' });
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
const response = await this.#client.request('GET', `/workspaces/${this.id}/files/${encodePath(relative)}?raw=true`);
|
|
86
|
-
results.push({ path, content: new Uint8Array(await response.arrayBuffer()), error: null });
|
|
87
|
-
}
|
|
88
|
-
catch (err) {
|
|
89
|
-
results.push({ path, content: null, error: fileError(err) });
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return results;
|
|
27
|
+
downloadFiles(paths) {
|
|
28
|
+
return this.#sandbox.downloadFiles(paths);
|
|
93
29
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (relative === null)
|
|
97
|
-
throw new CodeHarnessError(`${path} is outside ${ROOT}`, 'INVALID_REQUEST');
|
|
98
|
-
const form = new FormData();
|
|
99
|
-
form.append('path', relative);
|
|
100
|
-
form.append('file', zip instanceof Blob ? zip : new Blob([zip]), 'upload.zip');
|
|
101
|
-
return (await this.#client.request('PUT', `/workspaces/${this.id}/upload`, form)).json();
|
|
30
|
+
uploadAsZip(zip, options = {}) {
|
|
31
|
+
return this.#sandbox.uploadAsZip(zip, options);
|
|
102
32
|
}
|
|
103
|
-
|
|
104
|
-
return
|
|
33
|
+
launch(options) {
|
|
34
|
+
return this.#sandbox.launch(options);
|
|
105
35
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const response = await this.#client.request('GET', `/workspaces/${this.id}/sandbox/logs${query}`);
|
|
109
|
-
return (await response.json()).lines;
|
|
36
|
+
logs(options = {}) {
|
|
37
|
+
return this.#sandbox.logs(options);
|
|
110
38
|
}
|
|
111
|
-
|
|
112
|
-
|
|
39
|
+
stop() {
|
|
40
|
+
return this.#sandbox.stop();
|
|
113
41
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
await this.#client.request('DELETE', `/workspaces/${this.id}`);
|
|
42
|
+
close() {
|
|
43
|
+
return this.#sandbox.close();
|
|
117
44
|
}
|
|
118
45
|
}
|
|
119
46
|
//# sourceMappingURL=sandbox.js.map
|
package/dist/sandbox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,GAIZ,MAAM,YAAY,CAAA;AAInB,OAAO,EAAE,OAAO,IAAI,WAAW,EAA2D,MAAM,mBAAmB,CAAA;AAEnH,OAAO,EAAE,IAAI,EAA2D,MAAM,mBAAmB,CAAA;AAEjG,iFAAiF;AACjF,MAAM,OAAO,OAAQ,SAAQ,WAAW;IAC7B,EAAE,CAAQ;IACV,IAAI,CAAQ;IACZ,OAAO,CAAU;IACjB,SAAS,CAAM;IACf,OAAO,CAAS;IAChB,QAAQ,CAAa;IAE9B,YAAY,MAAkB,EAAE,SAAoB,EAAE,OAAO,GAAmB,EAAE;QAChF,KAAK,EAAE,CAAA;QACP,IAAI,CAAC,QAAQ,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA;QAC3D,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAA;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAA;QAC9B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAA;QACpC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAA;QACxC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAA;IACtC,CAAC;IAED,OAAO,CAAC,OAAe;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IACvC,CAAC;IAED,WAAW,CAAC,KAAkC;QAC5C,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IACzC,CAAC;IAED,aAAa,CAAC,KAAe;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC3C,CAAC;IAED,WAAW,CACT,GAAiD,EACjD,OAAO,GAAsB,EAAE;QAE/B,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAChD,CAAC;IAED,MAAM,CAAC,OAAsB;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,CAAC,OAAO,GAAsB,EAAE;QAClC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACpC,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC7B,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;IAC9B,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-harness/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "TypeScript client for Code-Harness sandboxes and browsers, with a deepagents backend and LangChain middleware",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -18,6 +18,16 @@
|
|
|
18
18
|
"types": "./dist/index.d.ts",
|
|
19
19
|
"default": "./dist/index.js"
|
|
20
20
|
},
|
|
21
|
+
"./client": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/core/index.d.ts",
|
|
24
|
+
"default": "./dist/core/index.js"
|
|
25
|
+
},
|
|
26
|
+
"require": {
|
|
27
|
+
"types": "./dist/cjs/core/index.d.ts",
|
|
28
|
+
"default": "./dist/cjs/core/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
21
31
|
"./package.json": "./package.json"
|
|
22
32
|
},
|
|
23
33
|
"files": ["dist"],
|
|
@@ -25,9 +35,10 @@
|
|
|
25
35
|
"node": ">=20"
|
|
26
36
|
},
|
|
27
37
|
"scripts": {
|
|
28
|
-
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
38
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && bun run build:cjs",
|
|
29
39
|
"typecheck": "tsc",
|
|
30
|
-
"test": "bun test"
|
|
40
|
+
"test": "bun test",
|
|
41
|
+
"build:cjs": "bun build src/core/index.ts --format=cjs --target=node --outfile dist/cjs/core/index.js && cp dist/browser.d.ts dist/errors.d.ts dist/cjs/ && cp dist/core/*.d.ts dist/cjs/core/ && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json"
|
|
31
42
|
},
|
|
32
43
|
"peerDependencies": {
|
|
33
44
|
"@langchain/core": "^1.3.2",
|
|
@@ -35,6 +46,20 @@
|
|
|
35
46
|
"langchain": "^1.6.0",
|
|
36
47
|
"zod": "^4.0.0"
|
|
37
48
|
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"@langchain/core": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"deepagents": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"langchain": {
|
|
57
|
+
"optional": true
|
|
58
|
+
},
|
|
59
|
+
"zod": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
38
63
|
"devDependencies": {
|
|
39
64
|
"@langchain/core": "^1.3.4",
|
|
40
65
|
"@types/bun": "^1.4.3",
|