@butterbase/cli 0.2.1 → 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/README.md +118 -0
- package/dist/bin/butterbase.js +474 -2
- package/dist/bin/butterbase.js.map +1 -1
- package/dist/src/commands/ai.d.ts +36 -0
- package/dist/src/commands/ai.d.ts.map +1 -0
- package/dist/src/commands/ai.js +131 -0
- package/dist/src/commands/ai.js.map +1 -0
- package/dist/src/commands/app-billing.d.ts +62 -0
- package/dist/src/commands/app-billing.d.ts.map +1 -0
- package/dist/src/commands/app-billing.js +220 -0
- package/dist/src/commands/app-billing.js.map +1 -0
- package/dist/src/commands/app-config.d.ts +37 -0
- package/dist/src/commands/app-config.d.ts.map +1 -0
- package/dist/src/commands/app-config.js +152 -0
- package/dist/src/commands/app-config.js.map +1 -0
- package/dist/src/commands/audit.d.ts +15 -0
- package/dist/src/commands/audit.d.ts.map +1 -0
- package/dist/src/commands/audit.js +49 -0
- package/dist/src/commands/audit.js.map +1 -0
- package/dist/src/commands/billing.d.ts +26 -0
- package/dist/src/commands/billing.d.ts.map +1 -0
- package/dist/src/commands/billing.js +183 -0
- package/dist/src/commands/billing.js.map +1 -0
- package/dist/src/commands/do.js +1 -1
- package/dist/src/commands/do.js.map +1 -1
- package/dist/src/commands/functions.d.ts +16 -0
- package/dist/src/commands/functions.d.ts.map +1 -1
- package/dist/src/commands/functions.js +135 -2
- package/dist/src/commands/functions.js.map +1 -1
- package/dist/src/commands/integrations.d.ts +2 -0
- package/dist/src/commands/integrations.d.ts.map +1 -1
- package/dist/src/commands/integrations.js +2 -2
- package/dist/src/commands/integrations.js.map +1 -1
- package/dist/src/commands/keys.d.ts +1 -0
- package/dist/src/commands/keys.d.ts.map +1 -1
- package/dist/src/commands/keys.js +1 -1
- package/dist/src/commands/keys.js.map +1 -1
- package/dist/src/commands/move.d.ts +25 -0
- package/dist/src/commands/move.d.ts.map +1 -0
- package/dist/src/commands/move.js +157 -0
- package/dist/src/commands/move.js.map +1 -0
- package/dist/src/commands/oauth.d.ts +33 -0
- package/dist/src/commands/oauth.d.ts.map +1 -0
- package/dist/src/commands/oauth.js +122 -0
- package/dist/src/commands/oauth.js.map +1 -0
- package/dist/src/commands/rag.d.ts +44 -0
- package/dist/src/commands/rag.d.ts.map +1 -0
- package/dist/src/commands/rag.js +271 -0
- package/dist/src/commands/rag.js.map +1 -0
- package/dist/src/commands/regions.d.ts +4 -0
- package/dist/src/commands/regions.d.ts.map +1 -0
- package/dist/src/commands/regions.js +16 -0
- package/dist/src/commands/regions.js.map +1 -0
- package/dist/src/commands/rls.d.ts +26 -0
- package/dist/src/commands/rls.d.ts.map +1 -0
- package/dist/src/commands/rls.js +128 -0
- package/dist/src/commands/rls.js.map +1 -0
- package/dist/src/lib/api-client.d.ts +86 -3
- package/dist/src/lib/api-client.d.ts.map +1 -1
- package/dist/src/lib/api-client.js +229 -9
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/errors.d.ts +8 -0
- package/dist/src/lib/errors.d.ts.map +1 -0
- package/dist/src/lib/errors.js +24 -0
- package/dist/src/lib/errors.js.map +1 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -139,6 +139,108 @@ butterbase storage upload ./image.png
|
|
|
139
139
|
butterbase storage delete obj_abc123
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
+
### AI
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
butterbase ai chat "Summarize this" --model openai/gpt-4o-mini
|
|
146
|
+
butterbase ai chat "Explain RAG" --system "You're a concise teacher." --temperature 0.2
|
|
147
|
+
butterbase ai embed "hello world" "another doc"
|
|
148
|
+
butterbase ai models
|
|
149
|
+
butterbase ai config get
|
|
150
|
+
butterbase ai config set --default-model openai/gpt-4o-mini --max-tokens-per-request 4000
|
|
151
|
+
butterbase ai config set --byok-key sk-or-... # rotate BYOK key; "" to clear
|
|
152
|
+
butterbase ai usage --start-date 2026-05-01 --end-date 2026-05-31
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### OAuth (admin)
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
butterbase oauth configure google \
|
|
159
|
+
--client-id ... --client-secret ... \
|
|
160
|
+
--redirect-uri https://app.example/cb \
|
|
161
|
+
--scope openid --scope email
|
|
162
|
+
butterbase oauth list
|
|
163
|
+
butterbase oauth get google
|
|
164
|
+
butterbase oauth update google --enabled false
|
|
165
|
+
butterbase oauth delete google
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Audit logs
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
butterbase audit query --category auth --event-type login --limit 50
|
|
172
|
+
butterbase audit query --from 2026-05-01 --to 2026-05-31 --action create --resource-type user
|
|
173
|
+
butterbase audit query --actor-id user_123 --json
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### App config (server-side)
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
butterbase apps config get
|
|
180
|
+
butterbase apps config cors --allowed-origin https://app.example --allow-credentials true
|
|
181
|
+
butterbase apps config jwt --access-token-ttl 15m --refresh-token-ttl-days 30
|
|
182
|
+
butterbase apps config storage --public-read true --max-file-size-mb 25 --allowed-content-type image/png --allowed-content-type image/jpeg
|
|
183
|
+
butterbase apps config access-mode authenticated
|
|
184
|
+
butterbase apps config secure --table posts --table comments --user-column author_id --access-mode authenticated
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Regions + multi-region moves
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
butterbase regions list
|
|
191
|
+
butterbase apps move app_abc us-west-2 --follow
|
|
192
|
+
butterbase apps migrations active # current app
|
|
193
|
+
butterbase apps migrations status app_abc m_xyz
|
|
194
|
+
butterbase apps migrations abort app_abc m_xyz # before cutover
|
|
195
|
+
butterbase apps migrations reverse app_abc m_xyz # after cutover
|
|
196
|
+
butterbase apps replicas list
|
|
197
|
+
butterbase apps replicas teardown m_xyz
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### App-level billing (Stripe Connect)
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
butterbase app-billing plans list
|
|
204
|
+
butterbase app-billing plans create --name pro --price-cents 1999 --interval month
|
|
205
|
+
butterbase app-billing plans update plan_abc --price-cents 2499
|
|
206
|
+
butterbase app-billing products list
|
|
207
|
+
butterbase app-billing products create --name "Lifetime access" --price-cents 9900
|
|
208
|
+
butterbase app-billing subscribe plan_abc
|
|
209
|
+
butterbase app-billing subscription
|
|
210
|
+
butterbase app-billing cancel
|
|
211
|
+
butterbase app-billing purchase prod_xyz
|
|
212
|
+
butterbase app-billing orders list
|
|
213
|
+
butterbase app-billing orders get order_abc
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Scoped API keys + integrations
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
butterbase keys generate ci-key --scope schema:read --scope functions:invoke
|
|
220
|
+
butterbase integrations configure github --scope repo --scope read:user
|
|
221
|
+
butterbase integrations connect github --redirect-url https://app.example/cb --scope repo
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Functions deploy (full options)
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
butterbase functions deploy fn.ts \
|
|
228
|
+
--name my-fn \
|
|
229
|
+
--trigger cron --trigger-config '{"schedule":"*/5 * * * *"}' \
|
|
230
|
+
--env API_KEY=sk_... --env DEBUG=true \
|
|
231
|
+
--timeout-ms 9000 --memory-mb 256
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### RLS
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
butterbase rls create --table posts --policy-name posts_own \
|
|
238
|
+
--command SELECT --using "author_id = auth.uid()" \
|
|
239
|
+
--role user --restrictive
|
|
240
|
+
butterbase rls delete posts # delete all policies on table
|
|
241
|
+
butterbase rls delete posts --policy posts_own
|
|
242
|
+
```
|
|
243
|
+
|
|
142
244
|
## Global Options
|
|
143
245
|
|
|
144
246
|
Most commands support the `--app` flag to specify an app ID:
|
|
@@ -284,6 +386,22 @@ butterbase integrations tools gmail --app app_abc123
|
|
|
284
386
|
butterbase integrations execute GMAIL_SEND_EMAIL --data '{"to":"x@y.com","subject":"Hi","body":"Hello"}' --app app_abc123
|
|
285
387
|
```
|
|
286
388
|
|
|
389
|
+
## Error output
|
|
390
|
+
|
|
391
|
+
The CLI throws typed `ButterbaseError`s from `@butterbase/sdk`. The top-level
|
|
392
|
+
handler renders the class name, message, and the structured fields the backend
|
|
393
|
+
returned (`code`, `status`, `remediation`). Example for an unauthenticated call:
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
AuthError: Invalid API key
|
|
397
|
+
code: AUTH_INVALID_API_KEY
|
|
398
|
+
status: 401
|
|
399
|
+
remediation: Rotate the key with `butterbase keys generate` and update ~/.butterbase/config.json.
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
The error codes come from `@butterbase/shared`'s `ErrorCodes` namespace — see
|
|
403
|
+
the SDK README for the full list.
|
|
404
|
+
|
|
287
405
|
## License
|
|
288
406
|
|
|
289
407
|
MIT
|
package/dist/bin/butterbase.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
+
import { renderError } from '../src/lib/errors.js';
|
|
3
4
|
import { initCommand } from '../src/commands/init.js';
|
|
4
5
|
import { loginCommand, logoutCommand, configGetCommand, configSetCommand } from '../src/commands/config.js';
|
|
5
6
|
import { appsListCommand, appsCreateCommand, appsUseCommand, appsDeleteCommand, appsPauseCommand, appsResumeCommand } from '../src/commands/apps.js';
|
|
6
7
|
import { schemaGetCommand, schemaApplyCommand } from '../src/commands/schema.js';
|
|
7
|
-
import { functionsListCommand, functionsDeployCommand, functionsLogsCommand, functionsDeleteCommand } from '../src/commands/functions.js';
|
|
8
|
+
import { functionsListCommand, functionsDeployCommand, functionsLogsCommand, functionsDeleteCommand, functionsInvokeCommand, functionsEnvSetCommand, functionsEnvListCommand } from '../src/commands/functions.js';
|
|
8
9
|
import { storageListCommand, storageUploadCommand, storageDeleteCommand, storageConfigCommand } from '../src/commands/storage.js';
|
|
9
10
|
import { realtimeEnableCommand, realtimeConfigCommand, realtimeDisableCommand } from '../src/commands/realtime.js';
|
|
10
11
|
import { deployCommand } from '../src/commands/deploy.js';
|
|
@@ -20,7 +21,17 @@ import { pluginSetupCommand } from '../src/commands/plugin.js';
|
|
|
20
21
|
import { integrationsListCommand, integrationsConfigCommand, integrationsConfigureCommand, integrationsDisableCommand, integrationsConnectCommand, integrationsConnectionsCommand, integrationsDisconnectCommand, integrationsToolsCommand, integrationsExecuteCommand, } from '../src/commands/integrations.js';
|
|
21
22
|
import { domainsListCommand, domainsAddCommand, domainsStatusCommand, domainsVerifyCommand, domainsDeleteCommand, } from '../src/commands/domains.js';
|
|
22
23
|
import { partnersListCommand, partnersCurlCommand } from '../src/commands/partners.js';
|
|
24
|
+
import { rlsListCommand, rlsCreateCommand, rlsEnableCommand, rlsDeleteCommand } from '../src/commands/rls.js';
|
|
25
|
+
import { billingStatusCommand, billingPortalCommand, billingTopupCommand, billingCapGetCommand, billingCapRaiseCommand, billingPlansCommand, billingUsageCommand, } from '../src/commands/billing.js';
|
|
26
|
+
import { ragCollectionsListCommand, ragCollectionsCreateCommand, ragCollectionsGetCommand, ragCollectionsDeleteCommand, ragIngestCommand, ragDocsListCommand, ragDocsDeleteCommand, ragQueryCommand, } from '../src/commands/rag.js';
|
|
23
27
|
import { doDeployCommand, doListCommand, doGetCommand, doDeleteCommand, doUsageCommand, doEnvListCommand, doEnvSetCommand, doEnvUnsetCommand, } from '../src/commands/do.js';
|
|
28
|
+
import { aiChatCommand, aiEmbedCommand, aiModelsCommand, aiConfigGetCommand, aiConfigSetCommand, aiUsageCommand, } from '../src/commands/ai.js';
|
|
29
|
+
import { oauthConfigureCommand, oauthListCommand, oauthGetCommand, oauthUpdateCommand, oauthDeleteCommand, } from '../src/commands/oauth.js';
|
|
30
|
+
import { auditQueryCommand } from '../src/commands/audit.js';
|
|
31
|
+
import { appConfigGetCommand, appCorsCommand, appJwtCommand, appStorageCommand, appAccessModeCommand, appSecureCommand, } from '../src/commands/app-config.js';
|
|
32
|
+
import { regionsListCommand } from '../src/commands/regions.js';
|
|
33
|
+
import { moveCommand, migrationStatusCommand, migrationActiveCommand, migrationAbortCommand, migrationReverseCommand, replicasListCommand, replicaTeardownCommand, } from '../src/commands/move.js';
|
|
34
|
+
import { plansListCommand, plansCreateCommand, plansUpdateCommand, productsListCommand, productsCreateCommand, productsUpdateCommand, subscribeCommand, subscriptionCommand, cancelCommand, purchaseCommand, ordersListCommand, ordersGetCommand, } from '../src/commands/app-billing.js';
|
|
24
35
|
const program = new Command();
|
|
25
36
|
program
|
|
26
37
|
.name('butterbase')
|
|
@@ -77,6 +88,94 @@ apps
|
|
|
77
88
|
.command('resume [app-id]')
|
|
78
89
|
.description('Resume a paused app — restore data-plane traffic')
|
|
79
90
|
.action(appsResumeCommand);
|
|
91
|
+
const appsConfig = apps.command('config').description('Read or update the app\'s server-side config');
|
|
92
|
+
appsConfig
|
|
93
|
+
.command('get')
|
|
94
|
+
.description('Show the app\'s full config')
|
|
95
|
+
.option('--app <appId>', 'Override current app')
|
|
96
|
+
.option('--json', 'Output raw JSON')
|
|
97
|
+
.action((opts) => appConfigGetCommand(opts));
|
|
98
|
+
appsConfig
|
|
99
|
+
.command('cors')
|
|
100
|
+
.description('Update CORS config')
|
|
101
|
+
.option('--app <appId>', 'Override current app')
|
|
102
|
+
.option('--allowed-origin <origin>', 'Allowed origin (repeatable)', (v, prev) => prev.concat(v), [])
|
|
103
|
+
.option('--allowed-method <method>', 'Allowed method (repeatable)', (v, prev) => prev.concat(v), [])
|
|
104
|
+
.option('--allowed-header <header>', 'Allowed header (repeatable)', (v, prev) => prev.concat(v), [])
|
|
105
|
+
.option('--allow-credentials <bool>', '(true|false)', (v) => v === 'true')
|
|
106
|
+
.option('--json', 'Output raw JSON')
|
|
107
|
+
.action((opts) => appCorsCommand(opts));
|
|
108
|
+
appsConfig
|
|
109
|
+
.command('jwt')
|
|
110
|
+
.description('Update JWT TTLs')
|
|
111
|
+
.option('--app <appId>', 'Override current app')
|
|
112
|
+
.option('--access-token-ttl <duration>', 'e.g. "15m", "1h"')
|
|
113
|
+
.option('--refresh-token-ttl-days <n>', 'Refresh token lifetime in days', parseInt)
|
|
114
|
+
.option('--json', 'Output raw JSON')
|
|
115
|
+
.action((opts) => appJwtCommand(opts));
|
|
116
|
+
appsConfig
|
|
117
|
+
.command('storage')
|
|
118
|
+
.description('Update storage config')
|
|
119
|
+
.option('--app <appId>', 'Override current app')
|
|
120
|
+
.option('--public-read <bool>', 'Public-read default (true|false)', (v) => v === 'true')
|
|
121
|
+
.option('--max-file-size-mb <n>', 'Per-file size cap in MB', parseInt)
|
|
122
|
+
.option('--allowed-content-type <ct>', 'Allowed content-type (repeatable)', (v, prev) => prev.concat(v), [])
|
|
123
|
+
.option('--json', 'Output raw JSON')
|
|
124
|
+
.action((opts) => appStorageCommand(opts));
|
|
125
|
+
appsConfig
|
|
126
|
+
.command('access-mode <mode>')
|
|
127
|
+
.description('Set access mode: public | authenticated')
|
|
128
|
+
.option('--app <appId>', 'Override current app')
|
|
129
|
+
.option('--json', 'Output raw JSON')
|
|
130
|
+
.action((mode, opts) => appAccessModeCommand(mode, opts));
|
|
131
|
+
appsConfig
|
|
132
|
+
.command('secure')
|
|
133
|
+
.description('Enable RLS + access-mode in one shot')
|
|
134
|
+
.option('--app <appId>', 'Override current app')
|
|
135
|
+
.option('--table <name>', 'Table to secure (repeatable)', (v, prev) => prev.concat(v), [])
|
|
136
|
+
.option('--user-column <col>', 'User-id column name (default: user_id)')
|
|
137
|
+
.option('--access-mode <mode>', 'public | authenticated')
|
|
138
|
+
.option('--json', 'Output raw JSON')
|
|
139
|
+
.action((opts) => appSecureCommand(opts));
|
|
140
|
+
apps
|
|
141
|
+
.command('move <appId> <destRegion>')
|
|
142
|
+
.description('Migrate an app to another region')
|
|
143
|
+
.option('--follow', 'Poll status until terminal')
|
|
144
|
+
.option('--json', 'Output raw JSON')
|
|
145
|
+
.action((appId, destRegion, opts) => moveCommand(appId, destRegion, opts));
|
|
146
|
+
const appsMigrations = apps.command('migrations').description('Read or control in-flight migrations');
|
|
147
|
+
appsMigrations
|
|
148
|
+
.command('status <appId> <migrationId>')
|
|
149
|
+
.description('Get status of a specific migration')
|
|
150
|
+
.option('--json', 'Output raw JSON')
|
|
151
|
+
.action((appId, migrationId, opts) => migrationStatusCommand(appId, migrationId, opts));
|
|
152
|
+
appsMigrations
|
|
153
|
+
.command('active [appId]')
|
|
154
|
+
.description('Show the currently-active migration for an app')
|
|
155
|
+
.option('--app <appId>', 'Override current app')
|
|
156
|
+
.option('--json', 'Output raw JSON')
|
|
157
|
+
.action((appId, opts) => migrationActiveCommand(appId, opts));
|
|
158
|
+
appsMigrations
|
|
159
|
+
.command('abort <appId> <migrationId>')
|
|
160
|
+
.description('Cancel a migration that has not yet reached cutover')
|
|
161
|
+
.option('--json', 'Output raw JSON')
|
|
162
|
+
.action((appId, migrationId, opts) => migrationAbortCommand(appId, migrationId, opts));
|
|
163
|
+
appsMigrations
|
|
164
|
+
.command('reverse <appId> <migrationId>')
|
|
165
|
+
.description('Roll a completed migration back to source')
|
|
166
|
+
.option('--json', 'Output raw JSON')
|
|
167
|
+
.action((appId, migrationId, opts) => migrationReverseCommand(appId, migrationId, opts));
|
|
168
|
+
const appsReplicas = apps.command('replicas').description('Manage retained source replicas after a move');
|
|
169
|
+
appsReplicas
|
|
170
|
+
.command('list')
|
|
171
|
+
.description('List active retained source replicas')
|
|
172
|
+
.option('--json', 'Output raw JSON')
|
|
173
|
+
.action((opts) => replicasListCommand(opts));
|
|
174
|
+
appsReplicas
|
|
175
|
+
.command('teardown <migrationId>')
|
|
176
|
+
.description('Decommission a retained source replica')
|
|
177
|
+
.option('--json', 'Output raw JSON')
|
|
178
|
+
.action((migrationId, opts) => replicaTeardownCommand(migrationId, opts));
|
|
80
179
|
// Schema
|
|
81
180
|
const schema = program.command('schema').description('Manage database schema');
|
|
82
181
|
schema
|
|
@@ -104,8 +203,12 @@ functions
|
|
|
104
203
|
.description('Deploy a function')
|
|
105
204
|
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
106
205
|
.option('--name <name>', 'Function name (defaults to filename)')
|
|
107
|
-
.option('--trigger <type>', 'Trigger type (http, cron)', 'http')
|
|
206
|
+
.option('--trigger <type>', 'Trigger type (http, cron, s3_upload, webhook, websocket)', 'http')
|
|
207
|
+
.option('--trigger-config <json>', 'Trigger config as JSON (e.g. \'{"schedule":"*/5 * * * *"}\')')
|
|
108
208
|
.option('--description <desc>', 'Function description')
|
|
209
|
+
.option('--env <kv>', 'Env var as KEY=value (repeatable)', (v, prev) => prev.concat(v), [])
|
|
210
|
+
.option('--timeout-ms <n>', 'Per-invocation timeout (ms)', parseInt)
|
|
211
|
+
.option('--memory-mb <n>', 'Memory limit (MB)', parseInt)
|
|
109
212
|
.action(functionsDeployCommand);
|
|
110
213
|
functions
|
|
111
214
|
.command('logs <function-name>')
|
|
@@ -120,6 +223,25 @@ functions
|
|
|
120
223
|
.description('Delete a function')
|
|
121
224
|
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
122
225
|
.action(functionsDeleteCommand);
|
|
226
|
+
functions
|
|
227
|
+
.command('invoke <function-name>')
|
|
228
|
+
.description('Invoke a deployed function')
|
|
229
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
230
|
+
.option('--data <json>', 'Request body as JSON string')
|
|
231
|
+
.option('--json', 'Output as JSON')
|
|
232
|
+
.action(functionsInvokeCommand);
|
|
233
|
+
const functionsEnvCmd = functions.command('env').description('Manage function environment variables');
|
|
234
|
+
functionsEnvCmd
|
|
235
|
+
.command('set <function-name> <vars...>')
|
|
236
|
+
.description('Set env vars (KEY=VALUE pairs)')
|
|
237
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
238
|
+
.action(functionsEnvSetCommand);
|
|
239
|
+
functionsEnvCmd
|
|
240
|
+
.command('list <function-name>')
|
|
241
|
+
.description('List env var keys (values are write-only)')
|
|
242
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
243
|
+
.option('--json', 'Output as JSON')
|
|
244
|
+
.action(functionsEnvListCommand);
|
|
123
245
|
// Storage
|
|
124
246
|
const storage = program.command('storage').description('Manage file storage');
|
|
125
247
|
storage
|
|
@@ -265,6 +387,7 @@ const keys = program.command('keys').description('Manage API keys');
|
|
|
265
387
|
keys
|
|
266
388
|
.command('generate [name]')
|
|
267
389
|
.description('Generate a new API key')
|
|
390
|
+
.option('--scope <scope>', 'Add a scope (repeatable)', (v, prev) => prev.concat(v), [])
|
|
268
391
|
.option('--json', 'Output as JSON')
|
|
269
392
|
.action(keysGenerateCommand);
|
|
270
393
|
keys
|
|
@@ -300,6 +423,7 @@ integrations
|
|
|
300
423
|
.description('Enable a toolkit for the app')
|
|
301
424
|
.option('--app <app-id>', 'App ID')
|
|
302
425
|
.option('--display-name <name>', 'Human-readable display name')
|
|
426
|
+
.option('--scope <scope>', 'Add a scope (repeatable)', (v, prev) => prev.concat(v), [])
|
|
303
427
|
.action(integrationsConfigureCommand);
|
|
304
428
|
integrations
|
|
305
429
|
.command('disable <toolkit>')
|
|
@@ -312,6 +436,7 @@ integrations
|
|
|
312
436
|
.option('--app <app-id>', 'App ID')
|
|
313
437
|
.option('--redirect-url <url>', 'URL to redirect after OAuth')
|
|
314
438
|
.option('--user-id <uuid>', 'User ID (for API key auth)')
|
|
439
|
+
.option('--scope <scope>', 'Add a scope (repeatable)', (v, prev) => prev.concat(v), [])
|
|
315
440
|
.action(integrationsConnectCommand);
|
|
316
441
|
integrations
|
|
317
442
|
.command('connections')
|
|
@@ -431,6 +556,353 @@ partners
|
|
|
431
556
|
.option('-d, --data <body>', 'Request JSON body')
|
|
432
557
|
.option('-x, --execute', 'Execute the curl instead of just printing it')
|
|
433
558
|
.action((slug, path, opts) => partnersCurlCommand(slug, path, opts));
|
|
559
|
+
// RLS
|
|
560
|
+
const rls = program.command('rls').description('Manage Row-Level Security policies');
|
|
561
|
+
rls
|
|
562
|
+
.command('list')
|
|
563
|
+
.description('List RLS policies')
|
|
564
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
565
|
+
.option('--json', 'Output as JSON')
|
|
566
|
+
.action(rlsListCommand);
|
|
567
|
+
rls
|
|
568
|
+
.command('create')
|
|
569
|
+
.description('Create an RLS policy (user-isolation or custom)')
|
|
570
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
571
|
+
.option('--table <table>', 'Target table name')
|
|
572
|
+
.option('--user-isolation', 'Enable user-isolation mode (uses --table, --user-column, --public-read-column)')
|
|
573
|
+
.option('--user-column <col>', 'Column containing the user ID')
|
|
574
|
+
.option('--public-read-column <col>', 'Boolean column enabling public read override')
|
|
575
|
+
.option('--policy-name <name>', 'Policy name (custom mode)')
|
|
576
|
+
.option('--command <cmd>', 'SQL command (SELECT, INSERT, UPDATE, DELETE, ALL)')
|
|
577
|
+
.option('--using <expr>', 'USING expression')
|
|
578
|
+
.option('--with-check <expr>', 'WITH CHECK expression')
|
|
579
|
+
.option('--restrictive', 'Create as RESTRICTIVE policy')
|
|
580
|
+
.option('--role <role>', 'Restrict to a Postgres role (anon | user)')
|
|
581
|
+
.option('--json', 'Output as JSON')
|
|
582
|
+
.action(rlsCreateCommand);
|
|
583
|
+
rls
|
|
584
|
+
.command('enable <table>')
|
|
585
|
+
.description('Enable RLS on a table')
|
|
586
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
587
|
+
.action(rlsEnableCommand);
|
|
588
|
+
rls
|
|
589
|
+
.command('delete <table>')
|
|
590
|
+
.description('Delete RLS policies on a table (all by default, or named with --policy)')
|
|
591
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
592
|
+
.option('--policy <name>', 'Delete only this named policy')
|
|
593
|
+
.action(rlsDeleteCommand);
|
|
594
|
+
// Billing
|
|
595
|
+
const billing = program.command('billing').description('Manage billing, plans, and spending');
|
|
596
|
+
billing
|
|
597
|
+
.command('status')
|
|
598
|
+
.description('Show current plan and billing status')
|
|
599
|
+
.option('--json', 'Output as JSON')
|
|
600
|
+
.action(billingStatusCommand);
|
|
601
|
+
billing
|
|
602
|
+
.command('portal')
|
|
603
|
+
.description('Print the billing portal URL')
|
|
604
|
+
.option('--json', 'Output as JSON')
|
|
605
|
+
.action(billingPortalCommand);
|
|
606
|
+
billing
|
|
607
|
+
.command('topup <amount>')
|
|
608
|
+
.description('Add credit balance (amount in USD)')
|
|
609
|
+
.option('--json', 'Output as JSON')
|
|
610
|
+
.action(billingTopupCommand);
|
|
611
|
+
billing
|
|
612
|
+
.command('cap')
|
|
613
|
+
.description('Show current spending cap')
|
|
614
|
+
.option('--json', 'Output as JSON')
|
|
615
|
+
.action(billingCapGetCommand);
|
|
616
|
+
billing
|
|
617
|
+
.command('cap:raise')
|
|
618
|
+
.description('Raise the spending cap')
|
|
619
|
+
.option('--raise-by <amount>', 'Amount in USD to raise the cap by')
|
|
620
|
+
.option('--json', 'Output as JSON')
|
|
621
|
+
.action(billingCapRaiseCommand);
|
|
622
|
+
billing
|
|
623
|
+
.command('plans')
|
|
624
|
+
.description('List available plans')
|
|
625
|
+
.option('--json', 'Output as JSON')
|
|
626
|
+
.action(billingPlansCommand);
|
|
627
|
+
billing
|
|
628
|
+
.command('usage')
|
|
629
|
+
.description('Show usage metrics')
|
|
630
|
+
.option('--start <date>', 'Start date (ISO 8601)')
|
|
631
|
+
.option('--end <date>', 'End date (ISO 8601)')
|
|
632
|
+
.option('--meter <type>', 'Filter by meter type')
|
|
633
|
+
.option('--json', 'Output as JSON')
|
|
634
|
+
.action(billingUsageCommand);
|
|
635
|
+
// RAG
|
|
636
|
+
const rag = program.command('rag').description('Manage RAG collections and documents');
|
|
637
|
+
const ragCollections = rag.command('collections').description('Manage RAG collections');
|
|
638
|
+
ragCollections
|
|
639
|
+
.command('list')
|
|
640
|
+
.description('List RAG collections')
|
|
641
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
642
|
+
.option('--json', 'Output as JSON')
|
|
643
|
+
.action(ragCollectionsListCommand);
|
|
644
|
+
ragCollections
|
|
645
|
+
.command('create <name>')
|
|
646
|
+
.description('Create a RAG collection')
|
|
647
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
648
|
+
.option('--description <text>', 'Collection description')
|
|
649
|
+
.option('--access-mode <mode>', 'Access mode (public, authenticated, service_key)')
|
|
650
|
+
.option('--chunk-size <n>', 'Chunk size in tokens')
|
|
651
|
+
.option('--chunk-overlap <n>', 'Chunk overlap in tokens')
|
|
652
|
+
.option('--json', 'Output as JSON')
|
|
653
|
+
.action(ragCollectionsCreateCommand);
|
|
654
|
+
ragCollections
|
|
655
|
+
.command('get <name>')
|
|
656
|
+
.description('Get a RAG collection')
|
|
657
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
658
|
+
.option('--json', 'Output as JSON')
|
|
659
|
+
.action(ragCollectionsGetCommand);
|
|
660
|
+
ragCollections
|
|
661
|
+
.command('delete <name>')
|
|
662
|
+
.description('Delete a RAG collection')
|
|
663
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
664
|
+
.action(ragCollectionsDeleteCommand);
|
|
665
|
+
rag
|
|
666
|
+
.command('ingest <file-or-text>')
|
|
667
|
+
.description('Ingest a document or text into a RAG collection')
|
|
668
|
+
.requiredOption('--collection <name>', 'Target collection name')
|
|
669
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
670
|
+
.option('--text', 'Treat the argument as raw text instead of a file path')
|
|
671
|
+
.option('--filename <name>', 'Override the filename stored with the document')
|
|
672
|
+
.option('--metadata <json>', 'Document metadata as JSON string')
|
|
673
|
+
.option('--json', 'Output as JSON')
|
|
674
|
+
.action(ragIngestCommand);
|
|
675
|
+
const ragDocs = rag.command('docs').description('Manage RAG documents');
|
|
676
|
+
ragDocs
|
|
677
|
+
.command('list <collection>')
|
|
678
|
+
.description('List documents in a RAG collection')
|
|
679
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
680
|
+
.option('--json', 'Output as JSON')
|
|
681
|
+
.action(ragDocsListCommand);
|
|
682
|
+
ragDocs
|
|
683
|
+
.command('delete <collection> <doc-id>')
|
|
684
|
+
.description('Delete a document from a RAG collection')
|
|
685
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
686
|
+
.action(ragDocsDeleteCommand);
|
|
687
|
+
rag
|
|
688
|
+
.command('query <collection>')
|
|
689
|
+
.description('Query a RAG collection')
|
|
690
|
+
.option('--app <app-id>', 'App ID (uses current app if not specified)')
|
|
691
|
+
.requiredOption('-q, --query <text>', 'Query string')
|
|
692
|
+
.option('--top-k <n>', 'Number of results to return')
|
|
693
|
+
.option('--threshold <n>', 'Minimum similarity threshold')
|
|
694
|
+
.option('--synthesize', 'Synthesize an answer from retrieved chunks')
|
|
695
|
+
.option('--model <model>', 'LLM model to use for synthesis')
|
|
696
|
+
.option('--json', 'Output as JSON')
|
|
697
|
+
.action(ragQueryCommand);
|
|
698
|
+
// AI Gateway
|
|
699
|
+
const ai = program.command('ai').description('Use the app\'s AI gateway (chat, embeddings, models, BYOK, usage)');
|
|
700
|
+
ai
|
|
701
|
+
.command('chat <prompt>')
|
|
702
|
+
.description('Send a single-turn chat completion')
|
|
703
|
+
.option('--app <appId>', 'Override current app')
|
|
704
|
+
.option('--model <model>', 'Model id (default: app default)')
|
|
705
|
+
.option('--temperature <n>', 'Sampling temperature', parseFloat)
|
|
706
|
+
.option('--max-tokens <n>', 'Max output tokens', parseInt)
|
|
707
|
+
.option('--system <message>', 'Prepend a system message')
|
|
708
|
+
.option('--json', 'Output raw JSON')
|
|
709
|
+
.action((prompt, opts) => aiChatCommand(prompt, opts));
|
|
710
|
+
ai
|
|
711
|
+
.command('embed <input...>')
|
|
712
|
+
.description('Embed text(s) into vectors')
|
|
713
|
+
.option('--app <appId>', 'Override current app')
|
|
714
|
+
.option('--model <model>', 'Embedding model')
|
|
715
|
+
.option('--json', 'Output raw JSON')
|
|
716
|
+
.action((input, opts) => aiEmbedCommand(input, opts));
|
|
717
|
+
ai
|
|
718
|
+
.command('models')
|
|
719
|
+
.description('List available AI models')
|
|
720
|
+
.option('--app <appId>', 'Override current app')
|
|
721
|
+
.option('--json', 'Output raw JSON')
|
|
722
|
+
.action((opts) => aiModelsCommand(opts));
|
|
723
|
+
const aiConfig = ai.command('config').description('Read or update AI config');
|
|
724
|
+
aiConfig
|
|
725
|
+
.command('get')
|
|
726
|
+
.option('--app <appId>', 'Override current app')
|
|
727
|
+
.option('--json', 'Output raw JSON')
|
|
728
|
+
.action((opts) => aiConfigGetCommand(opts));
|
|
729
|
+
aiConfig
|
|
730
|
+
.command('set')
|
|
731
|
+
.option('--app <appId>', 'Override current app')
|
|
732
|
+
.option('--default-model <model>')
|
|
733
|
+
.option('--allowed-models <models...>')
|
|
734
|
+
.option('--max-tokens-per-request <n>', 'Cap on tokens per request', parseInt)
|
|
735
|
+
.option('--byok-key <key>', 'Set or clear BYOK key (empty string clears)')
|
|
736
|
+
.option('--json', 'Output raw JSON')
|
|
737
|
+
.action((opts) => aiConfigSetCommand(opts));
|
|
738
|
+
ai
|
|
739
|
+
.command('usage')
|
|
740
|
+
.description('AI token + cost usage over a window')
|
|
741
|
+
.option('--app <appId>', 'Override current app')
|
|
742
|
+
.option('--start-date <date>', 'ISO date')
|
|
743
|
+
.option('--end-date <date>', 'ISO date')
|
|
744
|
+
.option('--json', 'Output raw JSON')
|
|
745
|
+
.action((opts) => aiUsageCommand({
|
|
746
|
+
app: opts.app, startDate: opts.startDate, endDate: opts.endDate, json: opts.json,
|
|
747
|
+
}));
|
|
748
|
+
// OAuth
|
|
749
|
+
const oauth = program.command('oauth').description('Manage OAuth providers for end-user auth');
|
|
750
|
+
oauth
|
|
751
|
+
.command('configure <provider>')
|
|
752
|
+
.description('Configure an OAuth provider (e.g. google, github, apple)')
|
|
753
|
+
.requiredOption('--client-id <id>')
|
|
754
|
+
.requiredOption('--client-secret <secret>')
|
|
755
|
+
.option('--app <appId>', 'Override current app')
|
|
756
|
+
.option('--redirect-uri <uri>', 'Add a redirect URI (repeatable)', (v, prev) => prev.concat(v), [])
|
|
757
|
+
.option('--scope <scope>', 'Add a scope (repeatable)', (v, prev) => prev.concat(v), [])
|
|
758
|
+
.option('--authorization-url <url>')
|
|
759
|
+
.option('--token-url <url>')
|
|
760
|
+
.option('--userinfo-url <url>')
|
|
761
|
+
.option('--json', 'Output raw JSON')
|
|
762
|
+
.action((provider, opts) => oauthConfigureCommand(provider, opts));
|
|
763
|
+
oauth
|
|
764
|
+
.command('list')
|
|
765
|
+
.description('List configured OAuth providers')
|
|
766
|
+
.option('--app <appId>', 'Override current app')
|
|
767
|
+
.option('--json', 'Output raw JSON')
|
|
768
|
+
.action((opts) => oauthListCommand(opts));
|
|
769
|
+
oauth
|
|
770
|
+
.command('get <provider>')
|
|
771
|
+
.description('Show config for a provider')
|
|
772
|
+
.option('--app <appId>', 'Override current app')
|
|
773
|
+
.option('--json', 'Output raw JSON')
|
|
774
|
+
.action((provider, opts) => oauthGetCommand(provider, opts));
|
|
775
|
+
oauth
|
|
776
|
+
.command('update <provider>')
|
|
777
|
+
.description('Update provider config (any field optional)')
|
|
778
|
+
.option('--app <appId>', 'Override current app')
|
|
779
|
+
.option('--client-id <id>')
|
|
780
|
+
.option('--client-secret <secret>')
|
|
781
|
+
.option('--redirect-uri <uri>', 'Replace redirect URIs', (v, prev) => prev.concat(v), [])
|
|
782
|
+
.option('--scope <scope>', 'Replace scopes', (v, prev) => prev.concat(v), [])
|
|
783
|
+
.option('--enabled <bool>', 'Enable/disable (true|false)', (v) => v === 'true')
|
|
784
|
+
.option('--json', 'Output raw JSON')
|
|
785
|
+
.action((provider, opts) => oauthUpdateCommand(provider, opts));
|
|
786
|
+
oauth
|
|
787
|
+
.command('delete <provider>')
|
|
788
|
+
.description('Delete an OAuth provider configuration')
|
|
789
|
+
.option('--app <appId>', 'Override current app')
|
|
790
|
+
.option('--json', 'Output raw JSON')
|
|
791
|
+
.action((provider, opts) => oauthDeleteCommand(provider, opts));
|
|
792
|
+
// Audit
|
|
793
|
+
const audit = program.command('audit').description('Query the app\'s audit log');
|
|
794
|
+
audit
|
|
795
|
+
.command('query')
|
|
796
|
+
.description('Query audit log entries with optional filters')
|
|
797
|
+
.option('--app <appId>', 'Override current app')
|
|
798
|
+
.option('--category <c>')
|
|
799
|
+
.option('--event-type <e>')
|
|
800
|
+
.option('--action <a>')
|
|
801
|
+
.option('--resource-type <t>')
|
|
802
|
+
.option('--resource-id <id>')
|
|
803
|
+
.option('--actor-id <id>')
|
|
804
|
+
.option('--from <iso>', 'Start of window (ISO date)')
|
|
805
|
+
.option('--to <iso>', 'End of window (ISO date)')
|
|
806
|
+
.option('--limit <n>', 'Max rows', parseInt)
|
|
807
|
+
.option('--offset <n>', 'Pagination offset', parseInt)
|
|
808
|
+
.option('--json', 'Output raw JSON')
|
|
809
|
+
.action((opts) => auditQueryCommand(opts));
|
|
810
|
+
// Regions
|
|
811
|
+
const regions = program.command('regions').description('Multi-region operations');
|
|
812
|
+
regions
|
|
813
|
+
.command('list')
|
|
814
|
+
.description('List supported regions')
|
|
815
|
+
.option('--json', 'Output raw JSON')
|
|
816
|
+
.action((opts) => regionsListCommand(opts));
|
|
817
|
+
// App Billing (Stripe Connect — plans/products/subscriptions/orders)
|
|
818
|
+
const appBilling = program.command('app-billing').description('Manage app-level Stripe Connect billing (plans/products/subscriptions/orders)');
|
|
819
|
+
const abPlans = appBilling.command('plans').description('Subscription plans');
|
|
820
|
+
abPlans
|
|
821
|
+
.command('list')
|
|
822
|
+
.option('--app <appId>', 'Override current app')
|
|
823
|
+
.option('--json', 'Output raw JSON')
|
|
824
|
+
.action((opts) => plansListCommand(opts));
|
|
825
|
+
abPlans
|
|
826
|
+
.command('create')
|
|
827
|
+
.requiredOption('--name <name>')
|
|
828
|
+
.requiredOption('--price-cents <n>', 'Price in cents', parseInt)
|
|
829
|
+
.requiredOption('--interval <month|year>')
|
|
830
|
+
.option('--description <desc>')
|
|
831
|
+
.option('--app <appId>', 'Override current app')
|
|
832
|
+
.option('--json', 'Output raw JSON')
|
|
833
|
+
.action((opts) => plansCreateCommand(opts));
|
|
834
|
+
abPlans
|
|
835
|
+
.command('update <planId>')
|
|
836
|
+
.option('--name <name>')
|
|
837
|
+
.option('--price-cents <n>', 'Price in cents', parseInt)
|
|
838
|
+
.option('--description <desc>')
|
|
839
|
+
.option('--app <appId>', 'Override current app')
|
|
840
|
+
.option('--json', 'Output raw JSON')
|
|
841
|
+
.action((planId, opts) => plansUpdateCommand(planId, opts));
|
|
842
|
+
const abProducts = appBilling.command('products').description('One-time products');
|
|
843
|
+
abProducts
|
|
844
|
+
.command('list')
|
|
845
|
+
.option('--app <appId>', 'Override current app')
|
|
846
|
+
.option('--json', 'Output raw JSON')
|
|
847
|
+
.action((opts) => productsListCommand(opts));
|
|
848
|
+
abProducts
|
|
849
|
+
.command('create')
|
|
850
|
+
.requiredOption('--name <name>')
|
|
851
|
+
.requiredOption('--price-cents <n>', 'Price in cents', parseInt)
|
|
852
|
+
.option('--description <desc>')
|
|
853
|
+
.option('--app <appId>', 'Override current app')
|
|
854
|
+
.option('--json', 'Output raw JSON')
|
|
855
|
+
.action((opts) => productsCreateCommand(opts));
|
|
856
|
+
abProducts
|
|
857
|
+
.command('update <productId>')
|
|
858
|
+
.option('--name <name>')
|
|
859
|
+
.option('--price-cents <n>', 'Price in cents', parseInt)
|
|
860
|
+
.option('--description <desc>')
|
|
861
|
+
.option('--app <appId>', 'Override current app')
|
|
862
|
+
.option('--json', 'Output raw JSON')
|
|
863
|
+
.action((productId, opts) => productsUpdateCommand(productId, opts));
|
|
864
|
+
appBilling
|
|
865
|
+
.command('subscribe <planId>')
|
|
866
|
+
.option('--app <appId>', 'Override current app')
|
|
867
|
+
.option('--json', 'Output raw JSON')
|
|
868
|
+
.action((planId, opts) => subscribeCommand(planId, opts));
|
|
869
|
+
appBilling
|
|
870
|
+
.command('subscription')
|
|
871
|
+
.description('Show the current subscription')
|
|
872
|
+
.option('--app <appId>', 'Override current app')
|
|
873
|
+
.option('--json', 'Output raw JSON')
|
|
874
|
+
.action((opts) => subscriptionCommand(opts));
|
|
875
|
+
appBilling
|
|
876
|
+
.command('cancel')
|
|
877
|
+
.description('Cancel the current subscription')
|
|
878
|
+
.option('--app <appId>', 'Override current app')
|
|
879
|
+
.option('--json', 'Output raw JSON')
|
|
880
|
+
.action((opts) => cancelCommand(opts));
|
|
881
|
+
appBilling
|
|
882
|
+
.command('purchase <productId>')
|
|
883
|
+
.option('--app <appId>', 'Override current app')
|
|
884
|
+
.option('--json', 'Output raw JSON')
|
|
885
|
+
.action((productId, opts) => purchaseCommand(productId, opts));
|
|
886
|
+
const abOrders = appBilling.command('orders').description('Order history');
|
|
887
|
+
abOrders
|
|
888
|
+
.command('list')
|
|
889
|
+
.option('--app <appId>', 'Override current app')
|
|
890
|
+
.option('--json', 'Output raw JSON')
|
|
891
|
+
.action((opts) => ordersListCommand(opts));
|
|
892
|
+
abOrders
|
|
893
|
+
.command('get <orderId>')
|
|
894
|
+
.option('--app <appId>', 'Override current app')
|
|
895
|
+
.option('--json', 'Output raw JSON')
|
|
896
|
+
.action((orderId, opts) => ordersGetCommand(orderId, opts));
|
|
897
|
+
// Top-level error handlers for unhandled exceptions / rejections
|
|
898
|
+
process.on('uncaughtException', (err) => {
|
|
899
|
+
console.error(renderError(err));
|
|
900
|
+
process.exit(1);
|
|
901
|
+
});
|
|
902
|
+
process.on('unhandledRejection', (err) => {
|
|
903
|
+
console.error(renderError(err));
|
|
904
|
+
process.exit(1);
|
|
905
|
+
});
|
|
434
906
|
// Parse arguments
|
|
435
907
|
program.parse();
|
|
436
908
|
//# sourceMappingURL=butterbase.js.map
|