@browserbasehq/cli 0.3.0 → 0.3.2
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/LICENSE +21 -0
- package/README.md +170 -9
- package/dist/cli.js +2 -2
- package/dist/commands/b.js +19 -0
- package/dist/commands/browse.js +49 -6
- package/dist/commands/contexts.js +2 -2
- package/dist/commands/fetch.js +8 -13
- package/dist/commands/search.js +8 -23
- package/dist/commands/sessions.js +5 -5
- package/dist/lib/command.js +1 -10
- package/dist/lib/functions/init.js +2 -1
- package/dist/lib/functions/publish.js +33 -12
- package/dist/lib/functions/shared.js +1 -12
- package/package.json +1 -1
- package/dist/commands/dashboard.js +0 -11
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Browserbase, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,20 +1,181 @@
|
|
|
1
1
|
# Browserbase CLI
|
|
2
2
|
|
|
3
|
-
Browserbase
|
|
3
|
+
The official CLI for [Browserbase](https://browserbase.com). Manage sessions, deploy serverless functions, browse the web, and interact with the full Browserbase platform from your terminal.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
npm install -g @browserbasehq/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js 18+.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Set your API key
|
|
17
|
+
export BROWSERBASE_API_KEY=bb_live_...
|
|
18
|
+
|
|
19
|
+
# Fetch a webpage
|
|
20
|
+
bb fetch https://example.com
|
|
21
|
+
|
|
22
|
+
# Search the web
|
|
23
|
+
bb search "browserbase documentation"
|
|
24
|
+
|
|
25
|
+
# Browse interactively
|
|
26
|
+
bb browse https://example.com
|
|
27
|
+
|
|
28
|
+
# List your sessions
|
|
29
|
+
bb sessions list
|
|
11
30
|
```
|
|
12
31
|
|
|
13
|
-
##
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
### `bb fetch <url>`
|
|
35
|
+
|
|
36
|
+
Retrieve webpage content without a full browser session.
|
|
14
37
|
|
|
15
38
|
```bash
|
|
16
|
-
|
|
39
|
+
bb fetch https://example.com
|
|
40
|
+
bb fetch https://example.com --output page.json
|
|
41
|
+
bb fetch https://example.com --proxies --allow-redirects
|
|
17
42
|
```
|
|
18
43
|
|
|
19
|
-
|
|
20
|
-
|
|
44
|
+
| Flag | Description |
|
|
45
|
+
|------|-------------|
|
|
46
|
+
| `--output <path>` | Write response to file |
|
|
47
|
+
| `--proxies` | Enable Browserbase proxy support |
|
|
48
|
+
| `--allow-redirects` | Follow HTTP redirects |
|
|
49
|
+
| `--allow-insecure-ssl` | Bypass TLS certificate verification |
|
|
50
|
+
|
|
51
|
+
### `bb search <query>`
|
|
52
|
+
|
|
53
|
+
Search the web using the Browserbase Search API.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bb search "web automation tools"
|
|
57
|
+
bb search "browserbase" --num-results 5
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
| Flag | Description |
|
|
61
|
+
|------|-------------|
|
|
62
|
+
| `--num-results <n>` | Number of results (1-25, default 10) |
|
|
63
|
+
| `--output <path>` | Write results to file |
|
|
64
|
+
|
|
65
|
+
### `bb browse [args...]`
|
|
66
|
+
|
|
67
|
+
Launch a browser session. Forwards to the `@browserbasehq/browse-cli` package (auto-installs on first use).
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
bb browse https://example.com
|
|
71
|
+
bb browse --yes # skip install prompt
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### `bb sessions`
|
|
75
|
+
|
|
76
|
+
Manage remote browser sessions.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
bb sessions list # List all sessions
|
|
80
|
+
bb sessions list --q "status=RUNNING" # Filter by metadata
|
|
81
|
+
bb sessions get <session-id> # Get session details
|
|
82
|
+
bb sessions create --body '{"projectId":"..."}'
|
|
83
|
+
bb sessions update <id> --status REQUEST_RELEASE
|
|
84
|
+
bb sessions debug <id> # Get debugger connection URLs
|
|
85
|
+
bb sessions logs <id> # View session logs
|
|
86
|
+
bb sessions recording <id> # Get rrweb recording events
|
|
87
|
+
bb sessions downloads get <id> # Download session artifacts (ZIP)
|
|
88
|
+
bb sessions uploads create <id> <file> # Upload a file to a session
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `bb functions`
|
|
92
|
+
|
|
93
|
+
Write and deploy serverless browser automation to the cloud.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Scaffold a new project
|
|
97
|
+
bb functions init my-function
|
|
98
|
+
|
|
99
|
+
# Run locally
|
|
100
|
+
bb functions dev handler.ts --port 3000
|
|
101
|
+
|
|
102
|
+
# Deploy to Browserbase
|
|
103
|
+
bb functions publish handler.ts
|
|
104
|
+
bb functions publish handler.ts --dry-run # preview without deploying
|
|
105
|
+
|
|
106
|
+
# Invoke a deployed function
|
|
107
|
+
bb functions invoke <function-id> --params '{"url":"https://example.com"}'
|
|
108
|
+
bb functions invoke --check-status <invocation-id>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
| Subcommand | Description |
|
|
112
|
+
|------------|-------------|
|
|
113
|
+
| `init [name]` | Scaffold a Functions project (`--package-manager npm\|pnpm`) |
|
|
114
|
+
| `dev <entry>` | Start local dev server (`--port`, `--host`, `--verbose`) |
|
|
115
|
+
| `publish <entry>` | Deploy function (`--dry-run`) |
|
|
116
|
+
| `invoke [id]` | Invoke a function (`--params`, `--no-wait`, `--check-status`) |
|
|
117
|
+
|
|
118
|
+
### `bb projects`
|
|
119
|
+
|
|
120
|
+
Manage Browserbase projects.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
bb projects list
|
|
124
|
+
bb projects get <project-id>
|
|
125
|
+
bb projects usage <project-id>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `bb contexts`
|
|
129
|
+
|
|
130
|
+
Persist browser state (cookies, localStorage) across sessions.
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
bb contexts create --body '{"projectId":"..."}'
|
|
134
|
+
bb contexts get <context-id>
|
|
135
|
+
bb contexts update <context-id> # Refresh upload URL
|
|
136
|
+
bb contexts delete <context-id>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `bb extensions`
|
|
140
|
+
|
|
141
|
+
Manage Chrome extensions for remote sessions.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
bb extensions upload extension.zip
|
|
145
|
+
bb extensions get <extension-id>
|
|
146
|
+
bb extensions delete <extension-id>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### `bb skills`
|
|
150
|
+
|
|
151
|
+
Install Browserbase agent skills for Claude Code.
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
bb skills # Interactive install
|
|
155
|
+
bb skills install # Non-interactive install
|
|
156
|
+
bb skills --yes # Auto-accept prompts
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Configuration
|
|
160
|
+
|
|
161
|
+
| Environment Variable | Description |
|
|
162
|
+
|---------------------|-------------|
|
|
163
|
+
| `BROWSERBASE_API_KEY` | Your Browserbase API key (required) |
|
|
164
|
+
| `BROWSERBASE_PROJECT_ID` | Default project ID for Functions |
|
|
165
|
+
| `BROWSERBASE_BASE_URL` | Custom API base URL |
|
|
166
|
+
|
|
167
|
+
All environment variables can be overridden per-command with `--api-key`, `--project-id`, or `--base-url` flags.
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
bun install
|
|
173
|
+
bun run cli -- --help # Run locally
|
|
174
|
+
bun run check # Type-check
|
|
175
|
+
bun run build # Build to dist/
|
|
176
|
+
bun run test # Build + run tests
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,6 @@ import { attachBrowseCommand } from "./commands/browse.js";
|
|
|
4
4
|
const require = createRequire(import.meta.url);
|
|
5
5
|
const { version } = require("../package.json");
|
|
6
6
|
import { attachContextsCommand } from "./commands/contexts.js";
|
|
7
|
-
import { attachDashboardCommand } from "./commands/dashboard.js";
|
|
8
7
|
import { attachExtensionsCommand } from "./commands/extensions.js";
|
|
9
8
|
import { attachFetchCommand } from "./commands/fetch.js";
|
|
10
9
|
import { attachFunctionsCommand } from "./commands/functions.js";
|
|
@@ -12,6 +11,7 @@ import { attachSearchCommand } from "./commands/search.js";
|
|
|
12
11
|
import { attachProjectsCommand } from "./commands/projects.js";
|
|
13
12
|
import { attachSessionsCommand } from "./commands/sessions.js";
|
|
14
13
|
import { attachSkillsCommand } from "./commands/skills.js";
|
|
14
|
+
import { attachBCommand } from "./commands/b.js";
|
|
15
15
|
export function buildProgram() {
|
|
16
16
|
const program = new Command();
|
|
17
17
|
program
|
|
@@ -27,12 +27,12 @@ export function buildProgram() {
|
|
|
27
27
|
attachFetchCommand(program);
|
|
28
28
|
attachSearchCommand(program);
|
|
29
29
|
attachSessionsCommand(program);
|
|
30
|
-
attachDashboardCommand(program);
|
|
31
30
|
attachFunctionsCommand(program);
|
|
32
31
|
attachProjectsCommand(program);
|
|
33
32
|
attachContextsCommand(program);
|
|
34
33
|
attachExtensionsCommand(program);
|
|
35
34
|
attachSkillsCommand(program);
|
|
35
|
+
attachBCommand(program);
|
|
36
36
|
return program;
|
|
37
37
|
}
|
|
38
38
|
export async function run(argv) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const B_LINES = [
|
|
2
|
+
"██████╗ ",
|
|
3
|
+
"██╔══██╗",
|
|
4
|
+
"██████╔╝",
|
|
5
|
+
"██╔══██╗",
|
|
6
|
+
"██████╔╝",
|
|
7
|
+
"╚═════╝ ",
|
|
8
|
+
];
|
|
9
|
+
export function attachBCommand(program) {
|
|
10
|
+
program
|
|
11
|
+
.command("b [extra]", { hidden: true })
|
|
12
|
+
.description("🅱️")
|
|
13
|
+
.action((extra) => {
|
|
14
|
+
const count = 1 + (extra ? extra.length : 0);
|
|
15
|
+
for (const line of B_LINES) {
|
|
16
|
+
console.log(Array(count).fill(line).join(" "));
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
package/dist/commands/browse.js
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
|
+
import * as readline from "node:readline/promises";
|
|
1
2
|
import { fail } from "../lib/command.js";
|
|
2
3
|
import { findExecutable, spawnPassthrough } from "../lib/process.js";
|
|
4
|
+
async function installBrowseCli() {
|
|
5
|
+
const npmPath = await findExecutable("npm");
|
|
6
|
+
if (!npmPath) {
|
|
7
|
+
fail([
|
|
8
|
+
"`npm` is not installed.",
|
|
9
|
+
"Install Node.js from https://nodejs.org to get npm,",
|
|
10
|
+
"then rerun `bb browse`.",
|
|
11
|
+
].join("\n"));
|
|
12
|
+
}
|
|
13
|
+
const exitCode = await spawnPassthrough(npmPath, [
|
|
14
|
+
"install",
|
|
15
|
+
"-g",
|
|
16
|
+
"@browserbasehq/browse-cli",
|
|
17
|
+
]);
|
|
18
|
+
if (exitCode !== 0) {
|
|
19
|
+
process.exitCode = exitCode;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
3
22
|
export function attachBrowseCommand(program) {
|
|
4
23
|
program
|
|
5
24
|
.command("browse")
|
|
@@ -8,18 +27,42 @@ export function attachBrowseCommand(program) {
|
|
|
8
27
|
.allowUnknownOption(true)
|
|
9
28
|
.allowExcessArguments(true)
|
|
10
29
|
.passThroughOptions()
|
|
30
|
+
.helpOption(false)
|
|
11
31
|
.action(async (args) => {
|
|
12
|
-
|
|
32
|
+
let browsePath = await findExecutable("browse");
|
|
13
33
|
if (!browsePath) {
|
|
14
|
-
|
|
34
|
+
console.log([
|
|
35
|
+
"",
|
|
15
36
|
"`browse` is not installed.",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
37
|
+
"Automate web browser interactions using natural language via CLI commands.",
|
|
38
|
+
"",
|
|
39
|
+
" npm install -g @browserbasehq/browse-cli",
|
|
18
40
|
"",
|
|
19
|
-
"Then rerun your `bb browse ...` command.",
|
|
20
41
|
].join("\n"));
|
|
42
|
+
const rl = readline.createInterface({
|
|
43
|
+
input: process.stdin,
|
|
44
|
+
output: process.stdout,
|
|
45
|
+
});
|
|
46
|
+
try {
|
|
47
|
+
const answer = await rl.question("Install now? [Y/n] ");
|
|
48
|
+
if (answer.trim().toLowerCase() === "n") {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
rl.close();
|
|
54
|
+
}
|
|
55
|
+
await installBrowseCli();
|
|
56
|
+
browsePath = await findExecutable("browse");
|
|
57
|
+
if (!browsePath) {
|
|
58
|
+
fail([
|
|
59
|
+
"Installation succeeded but `browse` was not found on PATH.",
|
|
60
|
+
"You may need to restart your shell, then rerun your command.",
|
|
61
|
+
].join("\n"));
|
|
62
|
+
}
|
|
21
63
|
}
|
|
22
|
-
const
|
|
64
|
+
const forwardArgs = args && args.length > 0 ? args : ["--help"];
|
|
65
|
+
const exitCode = await spawnPassthrough(browsePath, forwardArgs);
|
|
23
66
|
if (exitCode !== 0) {
|
|
24
67
|
process.exitCode = exitCode;
|
|
25
68
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addCommonApiOptions, createBrowserbaseClient,
|
|
1
|
+
import { addCommonApiOptions, createBrowserbaseClient, outputJson, parseOptionalJsonObjectArg, requestBrowserbase, requestBrowserbaseJson, } from "../lib/command.js";
|
|
2
2
|
export function attachContextsCommand(program) {
|
|
3
3
|
const contexts = program
|
|
4
4
|
.command("contexts")
|
|
@@ -12,7 +12,7 @@ export function attachContextsCommand(program) {
|
|
|
12
12
|
.description("Create a context.")
|
|
13
13
|
.option("--body <body>", "Optional JSON request body.")).action(async (options) => {
|
|
14
14
|
const client = createBrowserbaseClient(options);
|
|
15
|
-
const body =
|
|
15
|
+
const body = parseOptionalJsonObjectArg(options.body, "body");
|
|
16
16
|
outputJson(await client.contexts.create(body));
|
|
17
17
|
});
|
|
18
18
|
addCommonApiOptions(contexts
|
package/dist/commands/fetch.js
CHANGED
|
@@ -16,20 +16,15 @@ export function attachFetchCommand(program) {
|
|
|
16
16
|
});
|
|
17
17
|
if (options.output) {
|
|
18
18
|
await writeOutputFile(options.output, result.content);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
outputJson({
|
|
20
|
+
ok: true,
|
|
21
|
+
outputPath: options.output,
|
|
22
|
+
contentType: result.contentType,
|
|
23
|
+
statusCode: result.statusCode,
|
|
24
|
+
sizeBytes: Buffer.byteLength(result.content, "utf8"),
|
|
25
|
+
});
|
|
24
26
|
return;
|
|
25
27
|
}
|
|
26
|
-
|
|
27
|
-
outputJson(result);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
process.stdout.write(result.content);
|
|
31
|
-
if (!result.content.endsWith("\n")) {
|
|
32
|
-
process.stdout.write("\n");
|
|
33
|
-
}
|
|
28
|
+
outputJson(result);
|
|
34
29
|
});
|
|
35
30
|
}
|
package/dist/commands/search.js
CHANGED
|
@@ -13,30 +13,15 @@ export function attachSearchCommand(program) {
|
|
|
13
13
|
});
|
|
14
14
|
if (options.output) {
|
|
15
15
|
await writeOutputFile(options.output, JSON.stringify(result, null, 2));
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
outputJson({
|
|
17
|
+
ok: true,
|
|
18
|
+
outputPath: options.output,
|
|
19
|
+
requestId: result.requestId,
|
|
20
|
+
query: result.query,
|
|
21
|
+
resultCount: result.results.length,
|
|
22
|
+
});
|
|
21
23
|
return;
|
|
22
24
|
}
|
|
23
|
-
|
|
24
|
-
outputJson(result);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
for (const [i, r] of result.results.entries()) {
|
|
28
|
-
const num = i + 1;
|
|
29
|
-
console.log(`${String(num)}. ${r.title}`);
|
|
30
|
-
console.log(` ${r.url}`);
|
|
31
|
-
const meta = [];
|
|
32
|
-
if (r.author)
|
|
33
|
-
meta.push(r.author);
|
|
34
|
-
if (r.publishedDate)
|
|
35
|
-
meta.push(r.publishedDate);
|
|
36
|
-
if (meta.length > 0) {
|
|
37
|
-
console.log(` ${meta.join(" · ")}`);
|
|
38
|
-
}
|
|
39
|
-
console.log();
|
|
40
|
-
}
|
|
25
|
+
outputJson(result);
|
|
41
26
|
});
|
|
42
27
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Option } from "commander";
|
|
2
|
-
import { addCommonApiOptions, createBrowserbaseClient, fail,
|
|
2
|
+
import { addCommonApiOptions, createBrowserbaseClient, fail, outputJson, parseOptionalJsonObjectArg, resolveUploadableFile, writeBinaryOutput, } from "../lib/command.js";
|
|
3
3
|
export function attachSessionsCommand(program) {
|
|
4
4
|
const sessions = program
|
|
5
5
|
.command("sessions")
|
|
@@ -11,7 +11,7 @@ export function attachSessionsCommand(program) {
|
|
|
11
11
|
addCommonApiOptions(sessions
|
|
12
12
|
.command("list")
|
|
13
13
|
.description("List sessions.")
|
|
14
|
-
.option("--q <q>",
|
|
14
|
+
.option("--q <q>", `Session metadata query (e.g. "user_metadata['env']:'staging'").`)).action(async (options) => {
|
|
15
15
|
const client = createBrowserbaseClient(options);
|
|
16
16
|
outputJson(await client.sessions.list(options.q ? { q: options.q } : {}));
|
|
17
17
|
});
|
|
@@ -26,7 +26,7 @@ export function attachSessionsCommand(program) {
|
|
|
26
26
|
.description("Create a session.")
|
|
27
27
|
.option("--body <body>", "Optional JSON request body.")).action(async (options) => {
|
|
28
28
|
const client = createBrowserbaseClient(options);
|
|
29
|
-
const body =
|
|
29
|
+
const body = parseOptionalJsonObjectArg(options.body, "body");
|
|
30
30
|
outputJson(await client.sessions.create(body));
|
|
31
31
|
});
|
|
32
32
|
addCommonApiOptions(sessions
|
|
@@ -38,10 +38,10 @@ export function attachSessionsCommand(program) {
|
|
|
38
38
|
.option("--body <body>", "Optional JSON request body. Merged with --status when provided.")).action(async (id, options) => {
|
|
39
39
|
const client = createBrowserbaseClient(options);
|
|
40
40
|
const sessionId = id || fail("Session ID is required.");
|
|
41
|
-
const body =
|
|
41
|
+
const body = {
|
|
42
42
|
...parseOptionalJsonObjectArg(options.body, "body"),
|
|
43
43
|
status: options.status ?? "REQUEST_RELEASE",
|
|
44
|
-
}
|
|
44
|
+
};
|
|
45
45
|
outputJson(await client.sessions.update(sessionId, body));
|
|
46
46
|
});
|
|
47
47
|
addCommonApiOptions(sessions
|
package/dist/lib/command.js
CHANGED
|
@@ -17,10 +17,7 @@ export function fail(message, exitCode = 1) {
|
|
|
17
17
|
export function addCommonApiOptions(command) {
|
|
18
18
|
return command
|
|
19
19
|
.option("--api-key <apiKey>", "Override the Browserbase API key.")
|
|
20
|
-
.option("--
|
|
21
|
-
.option("--base-url <baseUrl>", "Override the Browserbase API base URL.")
|
|
22
|
-
.option("--json", "Print JSON output.")
|
|
23
|
-
.option("--verbose", "Enable verbose logging.");
|
|
20
|
+
.option("--base-url <baseUrl>", "Override the Browserbase API base URL.");
|
|
24
21
|
}
|
|
25
22
|
export function addFunctionsApiOptions(command, options = {}) {
|
|
26
23
|
const { includeProjectId = false, includeVerbose = false } = options;
|
|
@@ -91,12 +88,6 @@ export function parseOptionalJsonValueArg(rawValue, label) {
|
|
|
91
88
|
fail(`Invalid JSON for ${label}: ${error.message}`);
|
|
92
89
|
}
|
|
93
90
|
}
|
|
94
|
-
export function mergeProjectIdIntoBody(projectId, body) {
|
|
95
|
-
if (projectId && body.projectId === undefined) {
|
|
96
|
-
return { ...body, projectId };
|
|
97
|
-
}
|
|
98
|
-
return body;
|
|
99
|
-
}
|
|
100
91
|
export function outputJson(value) {
|
|
101
92
|
console.log(JSON.stringify(value, null, 2));
|
|
102
93
|
}
|
|
@@ -64,7 +64,7 @@ export async function initFunctionsProject({ projectName, packageManager, }) {
|
|
|
64
64
|
type: "module",
|
|
65
65
|
scripts: {
|
|
66
66
|
dev: "bb functions dev index.ts",
|
|
67
|
-
|
|
67
|
+
deploy: "bb functions publish index.ts",
|
|
68
68
|
},
|
|
69
69
|
};
|
|
70
70
|
await writeFile(join(projectRoot, "package.json"), JSON.stringify(packageJson, null, 2) + "\n");
|
|
@@ -90,6 +90,7 @@ export async function initFunctionsProject({ projectName, packageManager, }) {
|
|
|
90
90
|
console.log(` cd ${projectName}`);
|
|
91
91
|
console.log(" Edit .env with your Browserbase credentials");
|
|
92
92
|
console.log(` ${packageManager === "pnpm" ? "pnpm" : "npm run"} dev`);
|
|
93
|
+
console.log(` ${packageManager === "pnpm" ? "pnpm run deploy" : "npm run deploy"}`);
|
|
93
94
|
}
|
|
94
95
|
function runPackageManager(packageManager, args, cwd) {
|
|
95
96
|
const result = spawnSync(packageManager, args, {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import archiver from "archiver";
|
|
2
2
|
import ignore from "ignore";
|
|
3
|
-
import { createWriteStream, existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { copyFileSync, createWriteStream, existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
|
4
4
|
import { readFile, readdir, stat } from "node:fs/promises";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
5
6
|
import { tmpdir } from "node:os";
|
|
6
7
|
import { join, relative } from "node:path";
|
|
7
8
|
import { randomUUID } from "node:crypto";
|
|
@@ -25,21 +26,24 @@ const defaultIgnorePatterns = [
|
|
|
25
26
|
export async function publishFunction(options) {
|
|
26
27
|
const entrypoint = await resolveEntrypoint(options.entrypoint);
|
|
27
28
|
const config = resolveFunctionsProjectConfig(options);
|
|
28
|
-
const archivePath = await createArchive(process.cwd(), options.dryRun);
|
|
29
|
-
const metadata = {
|
|
30
|
-
entrypoint: relative(process.cwd(), entrypoint),
|
|
31
|
-
projectId: config.projectId,
|
|
32
|
-
};
|
|
33
29
|
if (options.dryRun) {
|
|
30
|
+
const { archivePath, entries } = await createArchive(process.cwd());
|
|
34
31
|
console.log(JSON.stringify({
|
|
35
32
|
dryRun: true,
|
|
36
33
|
apiUrl: config.apiUrl,
|
|
37
34
|
projectId: config.projectId,
|
|
38
|
-
entrypoint:
|
|
35
|
+
entrypoint: relative(process.cwd(), entrypoint),
|
|
39
36
|
archivePath,
|
|
37
|
+
files: entries,
|
|
40
38
|
}, null, 2));
|
|
41
39
|
return;
|
|
42
40
|
}
|
|
41
|
+
ensureNpmLockfile(process.cwd());
|
|
42
|
+
const { archivePath, entries } = await createArchive(process.cwd());
|
|
43
|
+
const metadata = {
|
|
44
|
+
entrypoint: relative(process.cwd(), entrypoint),
|
|
45
|
+
projectId: config.projectId,
|
|
46
|
+
};
|
|
43
47
|
const formData = new FormData();
|
|
44
48
|
formData.append("metadata", JSON.stringify(metadata));
|
|
45
49
|
formData.append("archive", new Blob([await readFile(archivePath)], {
|
|
@@ -69,13 +73,10 @@ export async function publishFunction(options) {
|
|
|
69
73
|
process.exitCode = 1;
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
|
-
async function createArchive(root
|
|
76
|
+
async function createArchive(root) {
|
|
73
77
|
const archivePath = join(tmpdir(), `browserbase-functions-${randomUUID()}.tar.gz`);
|
|
74
78
|
const ignoreMatcher = await loadIgnoreMatcher(root);
|
|
75
79
|
const entries = await listArchiveEntries(root, root, ignoreMatcher);
|
|
76
|
-
if (dryRun) {
|
|
77
|
-
console.log(JSON.stringify({ files: entries }, null, 2));
|
|
78
|
-
}
|
|
79
80
|
await new Promise((resolve, reject) => {
|
|
80
81
|
const output = createWriteStream(archivePath);
|
|
81
82
|
const archive = archiver("tar", {
|
|
@@ -97,7 +98,27 @@ async function createArchive(root, dryRun) {
|
|
|
97
98
|
}
|
|
98
99
|
archive.finalize().catch(reject);
|
|
99
100
|
});
|
|
100
|
-
return archivePath;
|
|
101
|
+
return { archivePath, entries };
|
|
102
|
+
}
|
|
103
|
+
function ensureNpmLockfile(root) {
|
|
104
|
+
if (existsSync(join(root, "package-lock.json"))) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Generate in a temp directory to avoid conflicts with pnpm's node_modules
|
|
108
|
+
// structure, then copy the lockfile back.
|
|
109
|
+
const tmpDir = join(tmpdir(), `bb-lockgen-${randomUUID()}`);
|
|
110
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
111
|
+
copyFileSync(join(root, "package.json"), join(tmpDir, "package.json"));
|
|
112
|
+
const result = spawnSync("npm", ["install", "--package-lock-only"], {
|
|
113
|
+
cwd: tmpDir,
|
|
114
|
+
stdio: "pipe",
|
|
115
|
+
});
|
|
116
|
+
if (result.status !== 0) {
|
|
117
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
118
|
+
fail("Failed to generate package-lock.json. The build server requires an npm lockfile.");
|
|
119
|
+
}
|
|
120
|
+
copyFileSync(join(tmpDir, "package-lock.json"), join(root, "package-lock.json"));
|
|
121
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
101
122
|
}
|
|
102
123
|
async function loadIgnoreMatcher(root) {
|
|
103
124
|
const matcher = ignore();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { stat } from "node:fs/promises";
|
|
3
3
|
import { extname, resolve } from "node:path";
|
|
4
|
-
import { fail,
|
|
4
|
+
import { fail, resolveApiKey, resolveProjectId } from "../command.js";
|
|
5
5
|
const defaultFunctionsApiUrl = "https://api.browserbase.com";
|
|
6
6
|
export function resolveFunctionsApiConfig(args) {
|
|
7
7
|
return {
|
|
@@ -103,14 +103,3 @@ export function ensureCommand(command) {
|
|
|
103
103
|
fail(`${command} is required but was not found on PATH.`);
|
|
104
104
|
}
|
|
105
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/package.json
CHANGED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { openUrl } from "../lib/open.js";
|
|
2
|
-
export function attachDashboardCommand(program) {
|
|
3
|
-
program
|
|
4
|
-
.command("dashboard")
|
|
5
|
-
.description("Open the Browserbase web dashboard for your project.")
|
|
6
|
-
.action(async () => {
|
|
7
|
-
const url = "http://browserbase.com/overview";
|
|
8
|
-
await openUrl(url);
|
|
9
|
-
console.log(`Opened ${url}`);
|
|
10
|
-
});
|
|
11
|
-
}
|