@browserbasehq/cli 0.0.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 +20 -0
- package/dist/cli.js +54 -0
- package/dist/commands/browse.js +27 -0
- package/dist/commands/contexts.js +42 -0
- package/dist/commands/dashboard.js +11 -0
- package/dist/commands/extensions.js +35 -0
- package/dist/commands/fetch.js +35 -0
- package/dist/commands/functions.js +70 -0
- package/dist/commands/projects.js +28 -0
- package/dist/commands/sessions.js +99 -0
- package/dist/lib/command.js +162 -0
- package/dist/lib/functions/dev.js +331 -0
- package/dist/lib/functions/init.js +102 -0
- package/dist/lib/functions/invoke.js +28 -0
- package/dist/lib/functions/publish.js +131 -0
- package/dist/lib/functions/shared.js +116 -0
- package/dist/lib/open.js +29 -0
- package/dist/lib/process.js +45 -0
- package/dist/main.js +4 -0
- package/package.json +54 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { stat } from "node:fs/promises";
|
|
3
|
+
import { extname, resolve } from "node:path";
|
|
4
|
+
import { fail, outputJson, resolveApiKey, resolveProjectId } from "../command.js";
|
|
5
|
+
const defaultFunctionsApiUrl = "https://api.browserbase.com";
|
|
6
|
+
export function resolveFunctionsApiConfig(args) {
|
|
7
|
+
return {
|
|
8
|
+
apiKey: resolveApiKey(args),
|
|
9
|
+
apiUrl: args.apiUrl ||
|
|
10
|
+
process.env.BROWSERBASE_API_BASE_URL ||
|
|
11
|
+
process.env.BROWSERBASE_BASE_URL ||
|
|
12
|
+
defaultFunctionsApiUrl,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function resolveFunctionsProjectConfig(args) {
|
|
16
|
+
return {
|
|
17
|
+
...resolveFunctionsApiConfig(args),
|
|
18
|
+
projectId: resolveProjectId(args, { required: true }) ||
|
|
19
|
+
fail("Missing Browserbase project ID."),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export async function parseErrorMessage(response) {
|
|
23
|
+
try {
|
|
24
|
+
const data = await response.json();
|
|
25
|
+
if (typeof data === "object" && data !== null) {
|
|
26
|
+
const message = data.message || data.error;
|
|
27
|
+
if (message) {
|
|
28
|
+
return message;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
try {
|
|
34
|
+
const text = await response.text();
|
|
35
|
+
if (text) {
|
|
36
|
+
return text;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return `${response.status} ${response.statusText}`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return `${response.status} ${response.statusText}`;
|
|
44
|
+
}
|
|
45
|
+
export async function functionsGet(config, path) {
|
|
46
|
+
const response = await fetch(`${config.apiUrl}${path}`, {
|
|
47
|
+
headers: {
|
|
48
|
+
"x-bb-api-key": config.apiKey,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
fail(await parseErrorMessage(response));
|
|
53
|
+
}
|
|
54
|
+
return (await response.json());
|
|
55
|
+
}
|
|
56
|
+
export async function functionsPost(config, path, body) {
|
|
57
|
+
const response = await fetch(`${config.apiUrl}${path}`, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: {
|
|
60
|
+
"content-type": "application/json",
|
|
61
|
+
"x-bb-api-key": config.apiKey,
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify(body),
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
fail(await parseErrorMessage(response));
|
|
67
|
+
}
|
|
68
|
+
return (await response.json());
|
|
69
|
+
}
|
|
70
|
+
export async function pollUntil(loader, options) {
|
|
71
|
+
const intervalMs = options.intervalMs ?? 1_000;
|
|
72
|
+
const maxAttempts = options.maxAttempts ?? 120;
|
|
73
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
74
|
+
const result = await loader();
|
|
75
|
+
if (options.done(result)) {
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
79
|
+
}
|
|
80
|
+
fail("Timed out while waiting for the Browserbase Functions operation to complete.");
|
|
81
|
+
}
|
|
82
|
+
export async function resolveEntrypoint(entrypoint) {
|
|
83
|
+
const absolutePath = resolve(entrypoint);
|
|
84
|
+
let stats;
|
|
85
|
+
try {
|
|
86
|
+
stats = await stat(absolutePath);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
fail(`Entrypoint file not found: ${absolutePath}`);
|
|
90
|
+
}
|
|
91
|
+
if (!stats.isFile()) {
|
|
92
|
+
fail(`Entrypoint must be a file: ${absolutePath}`);
|
|
93
|
+
}
|
|
94
|
+
const extension = extname(absolutePath).toLowerCase();
|
|
95
|
+
if (![".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts"].includes(extension)) {
|
|
96
|
+
fail(`Unsupported entrypoint extension: ${extension}`);
|
|
97
|
+
}
|
|
98
|
+
return absolutePath;
|
|
99
|
+
}
|
|
100
|
+
export function ensureCommand(command) {
|
|
101
|
+
const result = spawnSync(command, ["--version"], { stdio: "ignore" });
|
|
102
|
+
if (result.error || result.status !== 0) {
|
|
103
|
+
fail(`${command} is required but was not found on PATH.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function printFunctionsJsonOrMessage(value, options = {}) {
|
|
107
|
+
if (options.json) {
|
|
108
|
+
outputJson(value);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (options.message) {
|
|
112
|
+
console.log(options.message);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
outputJson(value);
|
|
116
|
+
}
|
package/dist/lib/open.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { CommandFailure } from "./command.js";
|
|
3
|
+
export async function openUrl(url) {
|
|
4
|
+
let binary;
|
|
5
|
+
let args;
|
|
6
|
+
if (process.platform === "darwin") {
|
|
7
|
+
binary = "open";
|
|
8
|
+
args = [url];
|
|
9
|
+
}
|
|
10
|
+
else if (process.platform === "win32") {
|
|
11
|
+
binary = "cmd";
|
|
12
|
+
args = ["/c", "start", "", url];
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
binary = "xdg-open";
|
|
16
|
+
args = [url];
|
|
17
|
+
}
|
|
18
|
+
await new Promise((resolve, reject) => {
|
|
19
|
+
const child = spawn(binary, args, {
|
|
20
|
+
detached: true,
|
|
21
|
+
stdio: "ignore",
|
|
22
|
+
});
|
|
23
|
+
child.on("error", (error) => {
|
|
24
|
+
reject(new CommandFailure(`Failed to open ${url}: ${error.message}`));
|
|
25
|
+
});
|
|
26
|
+
child.on("spawn", () => resolve());
|
|
27
|
+
child.unref();
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { access } from "node:fs/promises";
|
|
3
|
+
import { delimiter, join } from "node:path";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
const windowsExtensions = (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM")
|
|
6
|
+
.split(";")
|
|
7
|
+
.filter(Boolean);
|
|
8
|
+
export async function findExecutable(command) {
|
|
9
|
+
const pathEnv = process.env.PATH;
|
|
10
|
+
if (!pathEnv) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const candidates = process.platform === "win32"
|
|
14
|
+
? pathEnv
|
|
15
|
+
.split(delimiter)
|
|
16
|
+
.flatMap((segment) => windowsExtensions.map((extension) => join(segment, `${command}${extension.toLowerCase()}`)))
|
|
17
|
+
: pathEnv.split(delimiter).map((segment) => join(segment, command));
|
|
18
|
+
for (const candidate of candidates) {
|
|
19
|
+
try {
|
|
20
|
+
await access(candidate, constants.X_OK);
|
|
21
|
+
return candidate;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
export async function spawnPassthrough(command, args, options = {}) {
|
|
30
|
+
return await new Promise((resolve, reject) => {
|
|
31
|
+
const child = spawn(command, args, {
|
|
32
|
+
stdio: "inherit",
|
|
33
|
+
env: options.env,
|
|
34
|
+
cwd: options.cwd,
|
|
35
|
+
});
|
|
36
|
+
child.on("error", reject);
|
|
37
|
+
child.on("exit", (code, signal) => {
|
|
38
|
+
if (signal) {
|
|
39
|
+
resolve(1);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
resolve(code ?? 0);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
package/dist/main.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@browserbasehq/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Browserbase CLI for platform APIs, functions, and browse passthrough.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"bin": {
|
|
8
|
+
"bb": "dist/main.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/browserbase/cli.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/browserbase/cli/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/browserbase/cli#readme",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json",
|
|
30
|
+
"check": "tsc --noEmit -p tsconfig.json",
|
|
31
|
+
"cli": "bun run src/main.ts",
|
|
32
|
+
"changeset": "changeset",
|
|
33
|
+
"lint": "bun run check",
|
|
34
|
+
"release": "bun run build && changeset publish",
|
|
35
|
+
"test": "bun run build && vitest run",
|
|
36
|
+
"version": "changeset version",
|
|
37
|
+
"prepublishOnly": "bun run build"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@browserbasehq/sdk": "^2.8.0",
|
|
41
|
+
"archiver": "^7.0.1",
|
|
42
|
+
"commander": "^14.0.1",
|
|
43
|
+
"dotenv": "^16.5.0",
|
|
44
|
+
"ignore": "^7.0.5",
|
|
45
|
+
"tsx": "^4.20.6"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@changesets/cli": "^2.29.8",
|
|
49
|
+
"@types/archiver": "^6.0.3",
|
|
50
|
+
"@types/node": "^24.0.0",
|
|
51
|
+
"typescript": "^5.8.3",
|
|
52
|
+
"vitest": "^3.2.4"
|
|
53
|
+
}
|
|
54
|
+
}
|