@polardbx/pxbaas 0.0.0-stage → 0.1.0-beta.10
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 +223 -2
- package/bin/pxbaas.js +13 -0
- package/dist/app/local-index.d.ts +70 -0
- package/dist/app/local-index.d.ts.map +1 -0
- package/dist/app/local-index.js +140 -0
- package/dist/app/local-index.js.map +1 -0
- package/dist/app/preflight.d.ts +61 -0
- package/dist/app/preflight.d.ts.map +1 -0
- package/dist/app/preflight.js +115 -0
- package/dist/app/preflight.js.map +1 -0
- package/dist/app/spec-lint.d.ts +45 -0
- package/dist/app/spec-lint.d.ts.map +1 -0
- package/dist/app/spec-lint.js +423 -0
- package/dist/app/spec-lint.js.map +1 -0
- package/dist/app/templates.d.ts +167 -0
- package/dist/app/templates.d.ts.map +1 -0
- package/dist/app/templates.js +151 -0
- package/dist/app/templates.js.map +1 -0
- package/dist/cli/help-guides.d.ts +17 -0
- package/dist/cli/help-guides.d.ts.map +1 -0
- package/dist/cli/help-guides.js +132 -0
- package/dist/cli/help-guides.js.map +1 -0
- package/dist/cli/root.d.ts +3 -0
- package/dist/cli/root.d.ts.map +1 -0
- package/dist/cli/root.js +75 -0
- package/dist/cli/root.js.map +1 -0
- package/dist/commands/app/index.d.ts +8 -0
- package/dist/commands/app/index.d.ts.map +1 -0
- package/dist/commands/app/index.js +1907 -0
- package/dist/commands/app/index.js.map +1 -0
- package/dist/commands/auth/index.d.ts +3 -0
- package/dist/commands/auth/index.d.ts.map +1 -0
- package/dist/commands/auth/index.js +198 -0
- package/dist/commands/auth/index.js.map +1 -0
- package/dist/commands/completion/index.d.ts +3 -0
- package/dist/commands/completion/index.d.ts.map +1 -0
- package/dist/commands/completion/index.js +14 -0
- package/dist/commands/completion/index.js.map +1 -0
- package/dist/commands/data/index.d.ts +55 -0
- package/dist/commands/data/index.d.ts.map +1 -0
- package/dist/commands/data/index.js +407 -0
- package/dist/commands/data/index.js.map +1 -0
- package/dist/commands/db/index.d.ts +29 -0
- package/dist/commands/db/index.d.ts.map +1 -0
- package/dist/commands/db/index.js +500 -0
- package/dist/commands/db/index.js.map +1 -0
- package/dist/commands/doctor/index.d.ts +3 -0
- package/dist/commands/doctor/index.d.ts.map +1 -0
- package/dist/commands/doctor/index.js +305 -0
- package/dist/commands/doctor/index.js.map +1 -0
- package/dist/commands/functions/delete.d.ts +3 -0
- package/dist/commands/functions/delete.d.ts.map +1 -0
- package/dist/commands/functions/delete.js +55 -0
- package/dist/commands/functions/delete.js.map +1 -0
- package/dist/commands/functions/deploy.d.ts +3 -0
- package/dist/commands/functions/deploy.d.ts.map +1 -0
- package/dist/commands/functions/deploy.js +118 -0
- package/dist/commands/functions/deploy.js.map +1 -0
- package/dist/commands/functions/index.d.ts +3 -0
- package/dist/commands/functions/index.d.ts.map +1 -0
- package/dist/commands/functions/index.js +15 -0
- package/dist/commands/functions/index.js.map +1 -0
- package/dist/commands/functions/list.d.ts +6 -0
- package/dist/commands/functions/list.d.ts.map +1 -0
- package/dist/commands/functions/list.js +63 -0
- package/dist/commands/functions/list.js.map +1 -0
- package/dist/commands/functions/new.d.ts +7 -0
- package/dist/commands/functions/new.d.ts.map +1 -0
- package/dist/commands/functions/new.js +72 -0
- package/dist/commands/functions/new.js.map +1 -0
- package/dist/commands/gen/index.d.ts +3 -0
- package/dist/commands/gen/index.d.ts.map +1 -0
- package/dist/commands/gen/index.js +323 -0
- package/dist/commands/gen/index.js.map +1 -0
- package/dist/commands/guide/index.d.ts +8 -0
- package/dist/commands/guide/index.d.ts.map +1 -0
- package/dist/commands/guide/index.js +20 -0
- package/dist/commands/guide/index.js.map +1 -0
- package/dist/commands/instance/index.d.ts +8 -0
- package/dist/commands/instance/index.d.ts.map +1 -0
- package/dist/commands/instance/index.js +481 -0
- package/dist/commands/instance/index.js.map +1 -0
- package/dist/commands/login/index.d.ts +3 -0
- package/dist/commands/login/index.d.ts.map +1 -0
- package/dist/commands/login/index.js +145 -0
- package/dist/commands/login/index.js.map +1 -0
- package/dist/commands/logout/index.d.ts +3 -0
- package/dist/commands/logout/index.d.ts.map +1 -0
- package/dist/commands/logout/index.js +41 -0
- package/dist/commands/logout/index.js.map +1 -0
- package/dist/commands/profile/import-env.d.ts +18 -0
- package/dist/commands/profile/import-env.d.ts.map +1 -0
- package/dist/commands/profile/import-env.js +206 -0
- package/dist/commands/profile/import-env.js.map +1 -0
- package/dist/commands/profile/index.d.ts +3 -0
- package/dist/commands/profile/index.d.ts.map +1 -0
- package/dist/commands/profile/index.js +124 -0
- package/dist/commands/profile/index.js.map +1 -0
- package/dist/commands/rest/index.d.ts +3 -0
- package/dist/commands/rest/index.d.ts.map +1 -0
- package/dist/commands/rest/index.js +102 -0
- package/dist/commands/rest/index.js.map +1 -0
- package/dist/commands/skill/index.d.ts +11 -0
- package/dist/commands/skill/index.d.ts.map +1 -0
- package/dist/commands/skill/index.js +228 -0
- package/dist/commands/skill/index.js.map +1 -0
- package/dist/commands/status/index.d.ts +3 -0
- package/dist/commands/status/index.d.ts.map +1 -0
- package/dist/commands/status/index.js +59 -0
- package/dist/commands/status/index.js.map +1 -0
- package/dist/commands/storage/index.d.ts +3 -0
- package/dist/commands/storage/index.d.ts.map +1 -0
- package/dist/commands/storage/index.js +400 -0
- package/dist/commands/storage/index.js.map +1 -0
- package/dist/commands/tenant/index.d.ts +19 -0
- package/dist/commands/tenant/index.d.ts.map +1 -0
- package/dist/commands/tenant/index.js +667 -0
- package/dist/commands/tenant/index.js.map +1 -0
- package/dist/commands/whoami/index.d.ts +3 -0
- package/dist/commands/whoami/index.d.ts.map +1 -0
- package/dist/commands/whoami/index.js +101 -0
- package/dist/commands/whoami/index.js.map +1 -0
- package/dist/credentials/commit.d.ts +38 -0
- package/dist/credentials/commit.d.ts.map +1 -0
- package/dist/credentials/commit.js +57 -0
- package/dist/credentials/commit.js.map +1 -0
- package/dist/credentials/credential-store.d.ts +86 -0
- package/dist/credentials/credential-store.d.ts.map +1 -0
- package/dist/credentials/credential-store.js +282 -0
- package/dist/credentials/credential-store.js.map +1 -0
- package/dist/credentials/env-file.d.ts +85 -0
- package/dist/credentials/env-file.d.ts.map +1 -0
- package/dist/credentials/env-file.js +193 -0
- package/dist/credentials/env-file.js.map +1 -0
- package/dist/credentials/formatter.d.ts +39 -0
- package/dist/credentials/formatter.d.ts.map +1 -0
- package/dist/credentials/formatter.js +79 -0
- package/dist/credentials/formatter.js.map +1 -0
- package/dist/credentials/index.d.ts +13 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +13 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/jwt-introspect.d.ts +39 -0
- package/dist/credentials/jwt-introspect.d.ts.map +1 -0
- package/dist/credentials/jwt-introspect.js +64 -0
- package/dist/credentials/jwt-introspect.js.map +1 -0
- package/dist/credentials/masker.d.ts +23 -0
- package/dist/credentials/masker.d.ts.map +1 -0
- package/dist/credentials/masker.js +40 -0
- package/dist/credentials/masker.js.map +1 -0
- package/dist/credentials/profile.d.ts +95 -0
- package/dist/credentials/profile.d.ts.map +1 -0
- package/dist/credentials/profile.js +207 -0
- package/dist/credentials/profile.js.map +1 -0
- package/dist/credentials/tenant-guard.d.ts +16 -0
- package/dist/credentials/tenant-guard.d.ts.map +1 -0
- package/dist/credentials/tenant-guard.js +53 -0
- package/dist/credentials/tenant-guard.js.map +1 -0
- package/dist/credentials/tty-guard.d.ts +29 -0
- package/dist/credentials/tty-guard.d.ts.map +1 -0
- package/dist/credentials/tty-guard.js +79 -0
- package/dist/credentials/tty-guard.js.map +1 -0
- package/dist/db/apply-schema.d.ts +144 -0
- package/dist/db/apply-schema.d.ts.map +1 -0
- package/dist/db/apply-schema.js +359 -0
- package/dist/db/apply-schema.js.map +1 -0
- package/dist/db/introspect.d.ts +54 -0
- package/dist/db/introspect.d.ts.map +1 -0
- package/dist/db/introspect.js +140 -0
- package/dist/db/introspect.js.map +1 -0
- package/dist/db/sql-file.d.ts +104 -0
- package/dist/db/sql-file.d.ts.map +1 -0
- package/dist/db/sql-file.js +584 -0
- package/dist/db/sql-file.js.map +1 -0
- package/dist/instance/provision.d.ts +89 -0
- package/dist/instance/provision.d.ts.map +1 -0
- package/dist/instance/provision.js +139 -0
- package/dist/instance/provision.js.map +1 -0
- package/dist/instance/zero-store.d.ts +47 -0
- package/dist/instance/zero-store.d.ts.map +1 -0
- package/dist/instance/zero-store.js +91 -0
- package/dist/instance/zero-store.js.map +1 -0
- package/dist/instance/zero-whitelist.d.ts +39 -0
- package/dist/instance/zero-whitelist.d.ts.map +1 -0
- package/dist/instance/zero-whitelist.js +67 -0
- package/dist/instance/zero-whitelist.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +69 -0
- package/dist/main.js.map +1 -0
- package/dist/skill/agents-md.d.ts +25 -0
- package/dist/skill/agents-md.d.ts.map +1 -0
- package/dist/skill/agents-md.js +62 -0
- package/dist/skill/agents-md.js.map +1 -0
- package/dist/skill/assets.d.ts +38 -0
- package/dist/skill/assets.d.ts.map +1 -0
- package/dist/skill/assets.js +111 -0
- package/dist/skill/assets.js.map +1 -0
- package/dist/skill/hint.d.ts +39 -0
- package/dist/skill/hint.d.ts.map +1 -0
- package/dist/skill/hint.js +109 -0
- package/dist/skill/hint.js.map +1 -0
- package/dist/skill/hosts.d.ts +45 -0
- package/dist/skill/hosts.d.ts.map +1 -0
- package/dist/skill/hosts.js +96 -0
- package/dist/skill/hosts.js.map +1 -0
- package/dist/skill/installer.d.ts +100 -0
- package/dist/skill/installer.d.ts.map +1 -0
- package/dist/skill/installer.js +241 -0
- package/dist/skill/installer.js.map +1 -0
- package/dist/skill/ownership.d.ts +35 -0
- package/dist/skill/ownership.d.ts.map +1 -0
- package/dist/skill/ownership.js +52 -0
- package/dist/skill/ownership.js.map +1 -0
- package/dist/tenant/bundle.d.ts +66 -0
- package/dist/tenant/bundle.d.ts.map +1 -0
- package/dist/tenant/bundle.js +132 -0
- package/dist/tenant/bundle.js.map +1 -0
- package/dist/tenant/guide.d.ts +50 -0
- package/dist/tenant/guide.d.ts.map +1 -0
- package/dist/tenant/guide.js +152 -0
- package/dist/tenant/guide.js.map +1 -0
- package/dist/tenant/probe.d.ts +65 -0
- package/dist/tenant/probe.d.ts.map +1 -0
- package/dist/tenant/probe.js +159 -0
- package/dist/tenant/probe.js.map +1 -0
- package/dist/tenant/verify.d.ts +37 -0
- package/dist/tenant/verify.d.ts.map +1 -0
- package/dist/tenant/verify.js +132 -0
- package/dist/tenant/verify.js.map +1 -0
- package/dist/version.d.ts +29 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +65 -0
- package/dist/version.js.map +1 -0
- package/package.json +63 -3
- package/skills/pxbaas-app-spec/SKILL.md +165 -0
- package/skills/pxbaas-app-spec/references/deploy-options.md +158 -0
- package/skills/pxbaas-app-spec/references/guardrails-pitfalls.md +89 -0
- package/skills/pxbaas-app-spec/references/runtime-contract.md +151 -0
- package/skills/pxbaas-app-spec/references/ssr-session.md +121 -0
- package/skills/pxbaas-app-spec/references/templates-examples.md +311 -0
- package/skills/pxbaas-cli/SKILL.md +186 -0
- package/skills/pxbaas-cli/references/api-reference.md +68 -0
- package/skills/pxbaas-cli/references/app-deploy.md +186 -0
- package/skills/pxbaas-cli/references/auth-and-credentials.md +116 -0
- package/skills/pxbaas-cli/references/data-postgrest.md +101 -0
- package/skills/pxbaas-cli/references/db-and-meta.md +102 -0
- package/skills/pxbaas-cli/references/edge-functions.md +71 -0
- package/skills/pxbaas-cli/references/multi-tenant-apps.md +138 -0
- package/skills/pxbaas-cli/references/provision.md +101 -0
- package/skills/pxbaas-cli/references/safety-and-two-phase.md +78 -0
- package/skills/pxbaas-cli/references/storage.md +61 -0
- package/skills/pxbaas-cli/references/tenant-admin.md +122 -0
- package/skills/pxbaas-cli/references/troubleshooting.md +76 -0
- package/templates/webapp/api/index.ts +55 -0
- package/templates/webapp/csr-bff/README.md +81 -0
- package/templates/webapp/csr-bff/backend/index.ts +168 -0
- package/templates/webapp/csr-bff/db/rls.json +13 -0
- package/templates/webapp/csr-bff/db/schema.sql +49 -0
- package/templates/webapp/csr-bff/frontend/dist/admin.html +101 -0
- package/templates/webapp/csr-bff/frontend/dist/article.html +44 -0
- package/templates/webapp/csr-bff/frontend/dist/blog.js +206 -0
- package/templates/webapp/csr-bff/frontend/dist/blogger.html +53 -0
- package/templates/webapp/csr-bff/frontend/dist/index.html +70 -0
- package/templates/webapp/csr-bff/frontend/dist/login.html +56 -0
- package/templates/webapp/csr-bff/frontend/dist/profile.html +59 -0
- package/templates/webapp/csr-bff/frontend/dist/signup.html +78 -0
- package/templates/webapp/csr-bff/frontend/dist/style.css +27 -0
- package/templates/webapp/manifest.json +419 -0
- package/templates/webapp/mpa/about.html +29 -0
- package/templates/webapp/mpa/app.js +42 -0
- package/templates/webapp/mpa/index.html +42 -0
- package/templates/webapp/mpa/index.ts +60 -0
- package/templates/webapp/mpa/style.css +42 -0
- package/templates/webapp/react-vite/frontend/index.html +12 -0
- package/templates/webapp/react-vite/frontend/package-lock.json +1826 -0
- package/templates/webapp/react-vite/frontend/package.json +23 -0
- package/templates/webapp/react-vite/frontend/src/App.tsx +34 -0
- package/templates/webapp/react-vite/frontend/src/main.tsx +13 -0
- package/templates/webapp/react-vite/frontend/src/style.css +46 -0
- package/templates/webapp/react-vite/frontend/tsconfig.json +20 -0
- package/templates/webapp/react-vite/frontend/vite.config.ts +10 -0
- package/templates/webapp/react-vite-hono/backend/index.ts +38 -0
- package/templates/webapp/react-vite-hono/frontend/index.html +12 -0
- package/templates/webapp/react-vite-hono/frontend/package-lock.json +1826 -0
- package/templates/webapp/react-vite-hono/frontend/package.json +23 -0
- package/templates/webapp/react-vite-hono/frontend/src/App.tsx +47 -0
- package/templates/webapp/react-vite-hono/frontend/src/main.tsx +13 -0
- package/templates/webapp/react-vite-hono/frontend/src/style.css +66 -0
- package/templates/webapp/react-vite-hono/frontend/tsconfig.json +20 -0
- package/templates/webapp/react-vite-hono/frontend/vite.config.ts +10 -0
- package/templates/webapp/spa/index.ts +119 -0
- package/templates/webapp/ssr-auth/backend/index.ts +133 -0
- package/templates/webapp/ssr-auth/frontend/dist/index.html +15 -0
- package/templates/webapp/ssr-blog/README.md +111 -0
- package/templates/webapp/ssr-blog/backend/index.ts +764 -0
- package/templates/webapp/ssr-blog/db/rls.json +13 -0
- package/templates/webapp/ssr-blog/db/schema.sql +51 -0
- package/templates/webapp/ssr-blog/frontend/dist/index.html +39 -0
- package/templates/webapp/ssr-frameworks/README.md +64 -0
- package/templates/webapp/ssr-frameworks/backend/index.ts +241 -0
- package/templates/webapp/ssr-frameworks/frontend/dist/index.html +31 -0
- package/templates/webapp/ssr-hono/backend/index.ts +111 -0
- package/templates/webapp/ssr-hono/frontend/dist/index.html +12 -0
- package/templates/webapp/ssr-shop/README.md +80 -0
- package/templates/webapp/ssr-shop/backend/index.ts +491 -0
- package/templates/webapp/ssr-shop/db/rls.json +16 -0
- package/templates/webapp/ssr-shop/db/schema.sql +90 -0
- package/templates/webapp/ssr-shop/frontend/dist/index.html +12 -0
- package/templates/webapp/vanilla-static/frontend/dist/app.js +6 -0
- package/templates/webapp/vanilla-static/frontend/dist/index.html +19 -0
- package/templates/webapp/vanilla-static/frontend/dist/style.css +43 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Data Operations & REST Passthrough (data / rest)
|
|
2
|
+
|
|
3
|
+
Covers: `data select` · `data insert` · `data update` · `data delete` · `rest`.
|
|
4
|
+
Backed by the PostgREST-style endpoint `/rest/v1/*` (capability `rest`). The current implementation uses the profile's **anon** key (RLS-constrained).
|
|
5
|
+
|
|
6
|
+
## PostgREST filter syntax (`--filter`)
|
|
7
|
+
|
|
8
|
+
Format: `column=operator.value`
|
|
9
|
+
|
|
10
|
+
| Meaning | filter |
|
|
11
|
+
|---|---|
|
|
12
|
+
| equal | `id=eq.1` |
|
|
13
|
+
| not equal | `status=neq.deleted` |
|
|
14
|
+
| greater / less | `age=gt.18` / `age=lt.60` |
|
|
15
|
+
| range | `price=gte.100` / `price=lte.200` |
|
|
16
|
+
| IN | `id=in.(1,2,3)` |
|
|
17
|
+
| like | `name=like.*an*` |
|
|
18
|
+
| is null | `deleted_at=is.null` |
|
|
19
|
+
|
|
20
|
+
## data select — read rows (safe, read-only)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pxbaas data select <table> --filter "id=eq.1" --columns "*" --limit 100 --order created_at --ascending --json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **Flags:** `--filter <f>` · `--columns <list>` (default `*`) · `--limit <n>` (default 100) · `--order <column>` · `--ascending` (default descending) · `--json`
|
|
27
|
+
- **Output (`--json`):** the raw PostgREST array of row objects:
|
|
28
|
+
```json
|
|
29
|
+
[ { "id": 1, "title": "Buy milk", "is_complete": false } ]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## data insert — insert rows (write)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pxbaas data insert <table> --values '{"title":"hello","done":false}' --json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- **Flags:** `--values <json>` (**required**; single object or array) · `--json`
|
|
39
|
+
- **Output (`--json`):** array of inserted rows (return=representation).
|
|
40
|
+
- ⚠️ write — confirm the target table and payload with the user first.
|
|
41
|
+
|
|
42
|
+
## data update — update rows (write)
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pxbaas data update <table> --values '{"done":true}' --filter "id=eq.1" --json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- **Flags:** `--values <json>` (**required**) · `--filter <f>` (**required**) · `--json`
|
|
49
|
+
- **Output (`--json`):** array of updated rows.
|
|
50
|
+
- ⚠️ `--filter` is mandatory, but still verify how many rows it matches to avoid collateral updates.
|
|
51
|
+
|
|
52
|
+
## data delete — delete rows (destructive)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pxbaas data delete <table> --filter "id=eq.1" --json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- **Flags:** `--filter <f>` (**required**, repeatable to combine) · `--yes` · `--json`
|
|
59
|
+
- **Output (`--json`):** array of deleted rows.
|
|
60
|
+
- **Gated in the CLI:** it first runs a read-only preview of the affected row count and prints the exact request URL, then requires authorization — an interactive confirm, or `--yes` for non-interactive use. Nothing is deleted without it, and a refused run still carries a `preview` object in `--json` so an audit consumer can see what was declined. A failed preview also blocks the delete.
|
|
61
|
+
- `--filter` is mandatory because an unfiltered delete would take the whole table.
|
|
62
|
+
- Still preview the target yourself first (`data select` with the SAME filter) and get the user's explicit consent before passing `--yes`.
|
|
63
|
+
|
|
64
|
+
## rest — raw HTTP passthrough (debugging)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pxbaas rest GET "/todos?select=*&limit=5" --role anon --json
|
|
68
|
+
pxbaas rest POST "/todos" --data '{"title":"x"}' --role anon --json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- **Signature:** `rest <method> <path>`
|
|
72
|
+
- **Flags:** `--data <json>` (request body) · `--role <anon|service_role>` (default anon) · `--json`
|
|
73
|
+
- `<path>` is relative to `/rest/v1/`. Use for cases the `data` shortcuts don't cover (custom headers, upsert, RPC via `/rpc/<fn>`).
|
|
74
|
+
- Write/delete methods are destructive — confirm first.
|
|
75
|
+
|
|
76
|
+
## Workflow — safe write/delete
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
1) data select <table> --filter "<same filter>" # preview the affected rows
|
|
80
|
+
2) restate to user: table + filter + row count + operation
|
|
81
|
+
3) get explicit consent
|
|
82
|
+
4) run insert/update/delete --json
|
|
83
|
+
5) data select again to verify the result
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> REST endpoint details, embedding/RPC constraints: fetch `${endpoint}/docs` — see api-reference.md.
|
|
87
|
+
|
|
88
|
+
## Schema cache after DDL
|
|
89
|
+
|
|
90
|
+
The REST layer (`/rest/v1`) caches each table's column list. After a DDL change
|
|
91
|
+
(`ALTER TABLE ... ADD/DROP/MODIFY COLUMN`, or `CREATE`/`DROP TABLE`) the cache
|
|
92
|
+
re-introspects automatically: immediately where the platform wires DDL to a
|
|
93
|
+
cache reload, otherwise within one refresh interval (~30s). Until then:
|
|
94
|
+
|
|
95
|
+
- `select=*` (and `Prefer: return=representation` bodies) may still omit a
|
|
96
|
+
just-added column. This is a stale column list, not an error — the row is
|
|
97
|
+
returned, only the new field is missing.
|
|
98
|
+
- Workaround: enumerate columns explicitly (`?select=id,room_id,board`) instead
|
|
99
|
+
of `*`, or retry after a few seconds.
|
|
100
|
+
|
|
101
|
+
`pxbaas db add-column` / `db create-table` print a reminder about this.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Database & Metadata (db / gen)
|
|
2
|
+
|
|
3
|
+
Covers: `db query` · `db tables` · `db schema` · `db create-table` · `db add-column` · `gen types`.
|
|
4
|
+
Backed by the Meta API (mysql-meta / PG-Meta-compatible, capability `meta` → `${endpoint}/pg`).
|
|
5
|
+
|
|
6
|
+
> ⚠️ **The backend is MySQL / PolarDB-X, not PostgreSQL.** Write MySQL-dialect SQL. See api-reference.md for the full dialect/limitation table.
|
|
7
|
+
|
|
8
|
+
## db query — run arbitrary SQL
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pxbaas db query "SELECT count(*) FROM users" --role anon --json
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- **Signature:** `db query <sql>`
|
|
15
|
+
- **Flags:** `--role <anon|service_role>` (default **anon**) · `--json`
|
|
16
|
+
- **Role:** default `anon` (RLS-constrained). Use `service_role` for cross-user/admin reads and explain to the user that it bypasses RLS.
|
|
17
|
+
- **Output (`--json`):**
|
|
18
|
+
```json
|
|
19
|
+
{ "rows": [ { "count(*)": 42 } ], "rowCount": 1, "fields": [ { "name": "count(*)", "dataType": "BIGINT" } ] }
|
|
20
|
+
```
|
|
21
|
+
- **Gotchas:** `db query` can also run write/DDL SQL. If the statement contains INSERT/UPDATE/DELETE/DROP/ALTER/CREATE, treat it as destructive and confirm with the user first.
|
|
22
|
+
- **Multi-tenant:** with an MT profile (`--tenant-id`), `db query` routes through `/api/tenant-ddl/query` using the per-tenant service_role key and runs on the tenant's OWN database (`/pg/query` is platform-admin only and rejects per-tenant keys). `--role anon` is not applicable there — the tenant-ddl endpoint is service_role-only, so the query always runs as the tenant service_role. For batch DDL + RLS use `db push <file>` or `app db-init <name>` (see app-deploy.md); both are MT-aware.
|
|
23
|
+
|
|
24
|
+
## db push — apply a SQL file (DDL + RLS + seed)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pxbaas db push ./db/schema.sql --schema public --dry-run # preview the plan
|
|
28
|
+
pxbaas db push ./db/schema.sql --yes # apply (stop-on-first-error, no rollback)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- **Flags:** `--schema <name>` (single-tenant `__SCHEMA__` target, default `public`) · `--rls <file>` (declarative `db/rls.json`) · `--role` (default service_role) · `--dry-run` · `--yes` · `--json`
|
|
32
|
+
- Mode-aware: single-tenant runs through `/pg/query`; multi-tenant through `/api/tenant-ddl` (de-qualifies `__SCHEMA__`, diverts RLS to the structured endpoints). Shows the full plan and requires authorization; never rolls back.
|
|
33
|
+
- `app db-init <name>` is the app-bundled convenience wrapper (reads `<appDir>/db/schema.sql` + `db/rls.json`).
|
|
34
|
+
|
|
35
|
+
## db tables — list tables
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pxbaas db tables --schema public --role service_role --json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- **Flags:** `--schema <name>` (default `public`) · `--role` (default **service_role**) · `--json`
|
|
42
|
+
- Listing all tables needs the admin view, hence the service_role default.
|
|
43
|
+
- **Multi-tenant:** works — introspection routes through `/api/tenant-ddl` (`information_schema`) with the per-tenant service_role key, so `--schema` is bound to the tenant database. The `schema` field in `--json` reports the database actually queried.
|
|
44
|
+
|
|
45
|
+
## db schema — inspect a table (columns + indexes)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pxbaas db schema <table> --schema public --role service_role --json
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- **Flags:** `--schema` (default `public`) · `--role` (default **service_role**) · `--json`
|
|
52
|
+
- Returns columns (name / type / nullable / default / primary key / comment) and indexes (columns / unique / primary / type).
|
|
53
|
+
|
|
54
|
+
## db create-table — create a table (destructive DDL)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pxbaas db create-table <name> \
|
|
58
|
+
--columns '[{"name":"id","type":"bigint","primaryKey":true},{"name":"title","type":"text"}]' \
|
|
59
|
+
--schema public --role service_role --json
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- **Flags:** `--columns <json>` (array of `{name,type,nullable?,primaryKey?}`; omit → default `id bigint PK` + `created_at timestamp`) · `--schema` (default `public`) · `--role` (default service_role) · `--json`
|
|
63
|
+
- ⚠️ **Destructive DDL, no built-in gate:** restate the table name, schema, and column definitions and get explicit user consent before running (see safety-and-two-phase.md).
|
|
64
|
+
- **Multi-tenant:** works on an MT profile — the DDL runs through `/api/tenant-ddl` against the tenant's own database, always as the tenant service_role. `--schema` is ignored (warning prints the effective tenant db) and `--role anon` is ignored.
|
|
65
|
+
- Prints a REST schema-cache reminder: `/rest/v1` caches column lists, so `select=*` may not show the new column for up to ~30s. Enumerate columns explicitly or retry.
|
|
66
|
+
|
|
67
|
+
## db add-column — add a column (destructive DDL)
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pxbaas db add-column <table> <column> --type text --nullable --default <value> \
|
|
71
|
+
--schema public --role service_role --json
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- **Flags:** `--type <t>` (default `text`) · `--nullable` (default true) · `--default <value>` · `--schema` (default `public`) · `--role` (default service_role) · `--json`
|
|
75
|
+
- ⚠️ **Destructive DDL, no built-in gate:** confirm with the user first.
|
|
76
|
+
- **Multi-tenant:** same as `db create-table` — tenant's own database, `--schema`/`--role anon` ignored with a warning.
|
|
77
|
+
- Restarts apply after the schema cache refreshes; see the cache note under `db create-table`.
|
|
78
|
+
|
|
79
|
+
## gen types — generate type definitions
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pxbaas gen types --lang typescript --schema public --output types.ts --json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- **Flags:** `--lang <typescript|go|swift|python>` (default `typescript`) · `--output <file>` (default stdout) · `--schema` (default `public`)
|
|
86
|
+
- Read-only, safe.
|
|
87
|
+
|
|
88
|
+
## Default-role cheat sheet
|
|
89
|
+
|
|
90
|
+
| Command | Default role |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `db query` | anon |
|
|
93
|
+
| `db tables` / `db schema` | service_role |
|
|
94
|
+
| `db create-table` / `db add-column` | service_role |
|
|
95
|
+
|
|
96
|
+
## Workflow — inspect before you query
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pxbaas db tables --json # what tables exist
|
|
100
|
+
pxbaas db schema orders --json # columns + indexes of one table
|
|
101
|
+
pxbaas db query "SELECT * FROM orders LIMIT 5" --role anon --json # sample rows
|
|
102
|
+
```
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Edge Functions Management (functions)
|
|
2
|
+
|
|
3
|
+
Covers: `functions new` · `functions deploy` · `functions list` · `functions delete`.
|
|
4
|
+
Backed by the Management API (capability `functions`); deploy/delete need `service_role`.
|
|
5
|
+
|
|
6
|
+
## Directory convention
|
|
7
|
+
|
|
8
|
+
Functions live in `./functions/<slug>/` with entrypoint `index.ts` by default; override with `--dir` / `--entrypoint`.
|
|
9
|
+
`slug` must match `^[a-z0-9-]+$` (lowercase letters, numbers, hyphens) or the command errors.
|
|
10
|
+
|
|
11
|
+
## functions new — scaffold (safe, local files only)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pxbaas functions new <slug> --dir ./functions --entrypoint index.ts
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- **Flags:** `--dir <directory>` (default `./functions`) · `--entrypoint <path>` (default `index.ts`)
|
|
18
|
+
- Generates an entrypoint template under `<dir>/<slug>/`; no remote interaction.
|
|
19
|
+
|
|
20
|
+
## functions list — list deployed functions (read-only)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pxbaas functions list --json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **Output (`--json`):**
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"count": 1,
|
|
30
|
+
"functions": [
|
|
31
|
+
{ "slug": "hello", "name": "hello", "status": "ACTIVE", "version": 3,
|
|
32
|
+
"entrypoint_path": "index.ts", "verify_jwt": true,
|
|
33
|
+
"created_at": "2026-09-01T00:00:00Z", "updated_at": "2026-09-15T00:00:00Z" }
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
- `status` is one of `ACTIVE | INACTIVE | DEPLOYING | ERROR`.
|
|
38
|
+
|
|
39
|
+
## functions deploy — deploy (write/publish, confirm first)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pxbaas functions deploy <slug> --dir ./functions --entrypoint index.ts --json
|
|
43
|
+
# disable JWT verification (not recommended): add --no-verify-jwt
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- **Flags:** `--dir` (default `./functions`) · `--entrypoint` (default `index.ts`) · `--no-verify-jwt` · `--json`
|
|
47
|
+
- Pre-checks: function dir exists, entrypoint exists, dir has ≥1 file.
|
|
48
|
+
- Recursively collects files, **skipping** `node_modules`, hidden files/dirs (`.`-prefixed), and `.lock` files.
|
|
49
|
+
- Returns `status / version / entrypoint_path / verify_jwt / updated_at`.
|
|
50
|
+
- ⚠️ **Publish operation, no built-in gate:** restate slug, dir, entrypoint, and verify_jwt to the user and get consent first.
|
|
51
|
+
- ⚠️ `--no-verify-jwt` disables auth on the function (useful for third-party webhooks like Stripe/WeChat, but lowers security) — flag the risk to the user.
|
|
52
|
+
- ⚠️ **Known platform pitfall (multi-tenant deploy):** the Management API deploy is a multipart request whose `metadata` must be a **plain form field without a filename**; if sent as a file part, the server fails to parse it. This is handled in the SDK/driver layer — if deploy returns an odd 400/parse error, see troubleshooting.md and this point.
|
|
53
|
+
|
|
54
|
+
## functions delete — delete (destructive, confirm first)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pxbaas functions delete <slug> --json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- ⚠️ **Irreversible, no built-in gate:** run `functions list` to confirm the slug exists → restate what will be deleted → get explicit consent → then delete.
|
|
61
|
+
|
|
62
|
+
## Workflow — author → deploy → verify
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pxbaas functions new hello --json # 1. scaffold (local)
|
|
66
|
+
# 2. edit ./functions/hello/index.ts
|
|
67
|
+
pxbaas functions deploy hello --json # 3. deploy (confirm with user first)
|
|
68
|
+
pxbaas functions list --json # 4. verify it is live (status ACTIVE)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> Invocation endpoint (`/functions/v1/<slug>`) and per-function `verify_jwt` semantics: fetch `${endpoint}/docs` — see api-reference.md.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Multi-Tenant App Deployment & Acceptance
|
|
2
|
+
|
|
3
|
+
Use this when the instance runs `MULTI_TENANT_MODE=true` and you must provision tenants,
|
|
4
|
+
give an app its own tenant database, or prove tenant isolation. Everything below was
|
|
5
|
+
verified against a live multi-tenant instance; the credential split in §1 is the single
|
|
6
|
+
most common source of 401/403 confusion.
|
|
7
|
+
|
|
8
|
+
## 1. Credential tiers (three-way split — do not mix)
|
|
9
|
+
|
|
10
|
+
| Endpoint family | Credential that works | Rejected credential → error |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `/api/platform/*` (Studio: tenants CRUD) | **dashboard Basic Auth** (`DASHBOARD_USERNAME`/`DASHBOARD_PASSWORD`) | global service key → `401 Unauthorized` |
|
|
13
|
+
| `/pg/query` (ad-hoc SQL) | **global service_role key**, sent as BOTH `Authorization: Bearer` and `apikey` | Basic Auth → 401 "apikey or Bearer required"; per-tenant key → `401` |
|
|
14
|
+
| Data plane `/rest/v1`, `/auth/v1`; Management API `/v1/projects/default/*` (apps create/publish, functions deploy) | **per-tenant key** (Management API also needs `X-Tenant-Id`) | global key + `X-Tenant-Id` → `403 Global credentials cannot access tenant resources` |
|
|
15
|
+
| `/api/tenant-ddl/*` (tenant self-service DDL + RLS) | **per-tenant service_role key** — send only `Authorization: Bearer`; Kong verifies the JWT and injects the trusted `X-Tenant-Id` (never send it yourself) | global key → `403 GLOBAL_KEY_NOT_ALLOWED`; per-tenant anon → `403 ROLE_NOT_ALLOWED`; suspended tenant → `403 TENANT_NOT_ACTIVE` |
|
|
16
|
+
|
|
17
|
+
> RLS registry management is symmetric: `rls/tables` and `rls/policies` both support POST/GET/DELETE
|
|
18
|
+
> (DELETE on `rls/tables` does not require the table to still exist, so it cleans up after a DROP).
|
|
19
|
+
|
|
20
|
+
- A per-tenant anon/service key carries a `tenant_id` claim, so **REST and Auth route from the
|
|
21
|
+
key alone** — `X-Tenant-Id` is optional there. Issued user JWTs carry `aud=<tenant_id>`.
|
|
22
|
+
- Using tenant X's key with `X-Tenant-Id: Y` → `403 Token tenant mismatch` (gateway guardrail).
|
|
23
|
+
- CLI: `pxbaas login --endpoint <url> --tenant-id <id>` with the tenant's per-tenant keys gives a
|
|
24
|
+
working MT profile. As of the tenant self-service DDL capability, **`pxbaas db query`, `db push`,
|
|
25
|
+
and `app db-init` all work in MT** — they route through `/api/tenant-ddl` with the per-tenant
|
|
26
|
+
service_role key (DDL runs on the tenant's own db; the tenant MySQL account's `GRANT ALL ON
|
|
27
|
+
tenant_<id>.*` is the hard isolation boundary). The old "`db query` 401s in MT, use the global key
|
|
28
|
+
on `/pg/query`" guidance is obsolete; `/pg/query` remains platform-admin only.
|
|
29
|
+
|
|
30
|
+
## 2. Provisioning a tenant
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
curl -sS -X POST -u "$DASHBOARD_USERNAME:$DASHBOARD_PASSWORD" \
|
|
34
|
+
-H 'Content-Type: application/json' \
|
|
35
|
+
-d '{"tenant_id":"acme","plan":"free"}' \
|
|
36
|
+
"$ENDPOINT/api/platform/tenants"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`201` returns the tenant row **including `jwt_secret`, `anon_key`, `service_role_key`,
|
|
40
|
+
`db_name`** — no need to sign JWTs yourself. It also provisions: `CREATE DATABASE
|
|
41
|
+
tenant_<id>`, `CREATE USER` + `GRANT`, a `tenant_db_accounts` row, a private Storage bucket,
|
|
42
|
+
Realtime registration (`realtime_provisioned:false` is non-fatal), and two `_mysqlrest_rls_*`
|
|
43
|
+
tables inside the tenant DB (see §3 — nothing reads them).
|
|
44
|
+
|
|
45
|
+
- `409` → the tenant exists; `GET /api/platform/tenants` (same Basic Auth) returns its keys.
|
|
46
|
+
- `DEFAULT_TENANT_ID` in the instance env is a convention only: `_platform.tenants` may be
|
|
47
|
+
empty and no `default` tenant is implied.
|
|
48
|
+
|
|
49
|
+
## 3. Data layer & RLS placement (silent-failure trap)
|
|
50
|
+
|
|
51
|
+
| What | Where |
|
|
52
|
+
|---|---|
|
|
53
|
+
| Business tables | the tenant DB: `tenant_<id>.<table>` |
|
|
54
|
+
| RLS metadata (authoritative) | the **central** `supabase._mysqlrest_rls_tables` / `supabase._mysqlrest_rls_policies` |
|
|
55
|
+
| `table_schema` column value | **`tenant_<id>`** (single-tenant instances use `public`) |
|
|
56
|
+
| `_mysqlrest_rls_*` copies inside the tenant DB | created by provisioning, **read by no service** — writing here silently leaves RLS off |
|
|
57
|
+
|
|
58
|
+
MysqlREST loads policies with `schemas = [<tenant db name>]` against the central RLS database
|
|
59
|
+
(`MYSQLREST_RLS_DATABASE`, default `supabase`). A wrong `table_schema` produces **no error and
|
|
60
|
+
no effect**, so always verify behaviourally after registering policies:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# anon sees only what the anon policy allows
|
|
64
|
+
curl -sS "$ENDPOINT/rest/v1/posts?select=id,status" -H "apikey: $TENANT_ANON"
|
|
65
|
+
# owner-scoped write with a forged owner must be refused
|
|
66
|
+
curl -sS -o /dev/null -w '%{http_code}\n' -X POST "$ENDPOINT/rest/v1/posts" \
|
|
67
|
+
-H "apikey: $TENANT_ANON" -H "Authorization: Bearer $USER_TOKEN" \
|
|
68
|
+
-H 'Content-Type: application/json' \
|
|
69
|
+
-d '{"title":"x","author_id":"someone-else","status":"draft"}' # expect 403 PGRST302
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 3b. Tenant self-service DDL / db-init as a normal tenant
|
|
73
|
+
|
|
74
|
+
A normal tenant (holding only its per-tenant service_role key — no platform admin credential) can
|
|
75
|
+
initialize and tear down its own app database through the CLI:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pxbaas login --endpoint <url> --tenant-id <id> # paste the tenant's per-tenant anon + service keys
|
|
79
|
+
pxbaas app db-init <name> --dir ./apps --dry-run # preview the plan (DDL + seed + RLS)
|
|
80
|
+
pxbaas app db-init <name> --dir ./apps --yes # apply (stop-on-first-error, no rollback)
|
|
81
|
+
pxbaas db query "SELECT count(*) FROM posts" --json
|
|
82
|
+
pxbaas app destroy <name> --confirm --purge-db # optional: also drop the app's tables + RLS rows
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- `db-init`/`db push` read `db/schema.sql` (DDL + seed) and the declarative `db/rls.json` (RLS).
|
|
86
|
+
In MT the `__SCHEMA__` qualifier is dropped (the connection is already bound to the tenant db) and
|
|
87
|
+
cross-schema names are refused by GRANT.
|
|
88
|
+
- **RLS is registered through the structured `/api/tenant-ddl/rls/*` endpoints**, not raw central
|
|
89
|
+
INSERTs (the tenant account has no GRANT on the shared `supabase` db). `table_schema` is bound
|
|
90
|
+
server-side to the verified tenant db — the CLI never sends it, so a tenant cannot touch another's
|
|
91
|
+
policies. If `db/rls.json` is absent, RLS INSERTs embedded in `schema.sql` are parsed and routed
|
|
92
|
+
the same way.
|
|
93
|
+
- `--purge-db` DROPs the app's tables and DELETEs its RLS registry rows — both the policies and the
|
|
94
|
+
central `_mysqlrest_rls_tables` toggle (via `DELETE /api/tenant-ddl/rls/tables`). On instances that
|
|
95
|
+
predate that endpoint the toggle row is left (harmless; re-created on the next `db-init`).
|
|
96
|
+
|
|
97
|
+
## 4. Deploying a webapp into a tenant
|
|
98
|
+
|
|
99
|
+
- Every Management API call needs `Authorization: Bearer <tenant service_role_key>` **and**
|
|
100
|
+
`X-Tenant-Id: <tenant>`.
|
|
101
|
+
- Manifest: `schemaVersion: 2`, and `name` **must equal** the mount's `appName` (mismatch →
|
|
102
|
+
`409 APP_MANIFEST_INVALID`). Candidate slug shape: `app_<mount-uuid>_r_<rev>`; publish with
|
|
103
|
+
`expectedGeneration` (CAS).
|
|
104
|
+
- Upload statics/backend with explicit nested `filename=frontend/dist/<name>` and
|
|
105
|
+
`filename=backend/index.ts` (multipart flattening otherwise loses the nesting).
|
|
106
|
+
- Idempotency: mount create `409` → look the mount up in `_platform.app_mounts` by
|
|
107
|
+
(`app_name`, `tenant_id`) and reuse; publish `409 APP_ARTIFACT_INVALID: Candidate is already
|
|
108
|
+
active` → treat as success.
|
|
109
|
+
- `APP_SSR_PROBE_FAILED` on publish is a **cold-sandbox budget** issue, not an app defect:
|
|
110
|
+
warm that tenant's sandbox (deploy the same worker as a legacy function and hit it until
|
|
111
|
+
200), then retry publish 3–5×. See pxbaas-app-spec `references/deploy-options.md`.
|
|
112
|
+
- Workers on `/apps` candidates receive **no platform env**, so any baked-in base URL/anon key
|
|
113
|
+
must be the **target instance's** base and the **target tenant's** anon key. Reusing another
|
|
114
|
+
tenant's or another instance's values silently reads the wrong data.
|
|
115
|
+
|
|
116
|
+
## 5. Cross-tenant acceptance checklist
|
|
117
|
+
|
|
118
|
+
Run all of these before calling a multi-tenant deployment done:
|
|
119
|
+
|
|
120
|
+
| # | Check | Expected |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| 1 | List business tables per tenant DB | each tenant holds only its own app's tables |
|
|
123
|
+
| 2 | Insert a distinct marker row per tenant, read through each app's public surface | each app shows only its own marker |
|
|
124
|
+
| 3 | Login in tenant X, then send that cookie (explicit `Cookie:` header, bypassing path scoping) to tenant Y's mount | anonymous — the proxy validates the cookie's tenant **and** mount binding, not just `Path` |
|
|
125
|
+
| 4 | Client sends `X-App-User-Id`/`X-App-User-Email` itself | stripped; the worker sees no identity |
|
|
126
|
+
| 5 | Tenant X's user JWT against tenant Y's REST | never returns Y's data (observed: routed by the JWT's own tenant → `404 PGRST200` table not found) |
|
|
127
|
+
| 6 | Tenant X's anon/service key + `X-Tenant-Id: Y` | `403 Token tenant mismatch` |
|
|
128
|
+
| 7 | Two users alternating on the same mount | each always sees their own identity (no shared-jar bleed) |
|
|
129
|
+
|
|
130
|
+
## 6. Known platform-side issues (report, don't code around them silently)
|
|
131
|
+
|
|
132
|
+
- Publish-time SSR probe has a fixed budget shorter than a cold sandbox's npm module
|
|
133
|
+
resolution (≈60 s with four SSR renderers).
|
|
134
|
+
- `capabilities.ssrLibs` reflects a build-time allow-list and may **under-report** what the
|
|
135
|
+
sandbox can actually resolve — verify by running the worker, not by reading the capability.
|
|
136
|
+
- `APP_MANIFEST_INVALID` does not name the offending manifest field.
|
|
137
|
+
- Tenant DBs contain unread `_mysqlrest_rls_*` copies that invite writing policies to the
|
|
138
|
+
wrong place.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Provisioning & Managing Zero Instances (provision / instance)
|
|
2
|
+
|
|
3
|
+
Covers: `provision` (alias `instance claim`) · `instance list` · `instance release` · `instance credentials` · `instance current` · `instance whitelist get|add`.
|
|
4
|
+
|
|
5
|
+
When a customer has no BaaS instance yet, `pxbaas provision` claims a **disposable, Supabase-compatible instance** from PolarDB-X Zero and binds it to a profile — fully automatic, no human TTY login.
|
|
6
|
+
|
|
7
|
+
## Why agents MAY run this (unlike `pxbaas login`)
|
|
8
|
+
|
|
9
|
+
`pxbaas login` is human-only because it would require handling user-typed plaintext keys. `pxbaas provision` is different: the keys come from the **first-party Zero endpoint over TLS**, the CLI ingests them straight into the keyring, and **only fingerprints are ever shown**. So an agent can run it end-to-end without ever seeing a plaintext key. Zero instances are short-lived (15 days) and low-sensitivity.
|
|
10
|
+
|
|
11
|
+
## pxbaas provision — claim an instance
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pxbaas provision [--name <profile>] [--whitelist-ip <ip,cidr>] [--reuse] [--no-switch] [--force] [--json]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- **Flags:** `--name` (profile to create; default `zero-<id suffix>`) · `--whitelist-ip` (extra allowed IPs; defaults to your egress IP) · `--reuse` (bind an existing active instance instead of claiming) · `--no-switch` (create profile but keep the current one) · `--force` (overwrite a same-named profile) · `--json`
|
|
18
|
+
- **What it does:** `POST https://zero.polardbx.com/api/v1/supabase/instances` → stores anon/service keys in the keyring, writes `~/.baas/zero.json` (token + binding, 0600), creates a `single-tenant` profile, and (by default) switches the current profile to it.
|
|
19
|
+
- **Output (`--json`)** never contains plaintext keys — only `endpoint`, `dashboardUrl`, key **fingerprints**, `expiresAt`, `whitelistIp`:
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"status": "provisioned",
|
|
23
|
+
"profile": "zero-d4e5f6",
|
|
24
|
+
"switchedFrom": "default",
|
|
25
|
+
"instance": { "id": "sbx_a1b2...", "endpoint": "http://pxsp-xxx:8000", "dashboardUrl": "http://pxsp-xxx:8000", "expiresAt": "2026-09-05T10:30:00.000Z", "mode": "single-tenant", "whitelistIp": "203.0.113.7" },
|
|
26
|
+
"keys": { "anon": { "fingerprint": "sha256:ab12cd34…wxyz", "role": "anon" }, "serviceRole": { "fingerprint": "sha256:ef56gh78…wxyz", "role": "service_role" } },
|
|
27
|
+
"dashboard": { "username": "supabase", "passwordRevealed": false },
|
|
28
|
+
"nextSteps": ["pxbaas status --json", "pxbaas db tables --json", "pxbaas skill install --host <host>"]
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Gotchas**
|
|
33
|
+
- **15-day TTL, no renewal.** When it expires, data-plane calls fail; claim a fresh one (`pxbaas provision`). `pxbaas doctor` warns as expiry approaches.
|
|
34
|
+
- **Keys are returned ONLY at claim time** (Zero has no credentials re-read endpoint). They are persisted locally; if lost, `release` + `provision` again.
|
|
35
|
+
- **Whitelist IP:** the instance only accepts requests from the whitelisted IP (your egress IP by default). If the machine running `pxbaas` differs from the one that claimed, pass `--whitelist-ip` or requests get rejected at the gateway.
|
|
36
|
+
|
|
37
|
+
## Multiple instances — how the CLI knows which one
|
|
38
|
+
|
|
39
|
+
**One instance = one profile.** Your own instance (`pxbaas login`) and any Zero instances (`pxbaas provision`) are separate profiles; nothing is overwritten.
|
|
40
|
+
|
|
41
|
+
- The instance a command targets = the **current profile** (`pxbaas profile use <name>`) or an explicit **`--profile <name>`**.
|
|
42
|
+
- Zero profiles carry `source: "zero"` + `zeroInstanceId` + `expiresAt`; `pxbaas profile ls` shows the source and which is current.
|
|
43
|
+
- `pxbaas whoami` / `pxbaas status` / `pxbaas instance current` always tell you which instance you are pointed at.
|
|
44
|
+
- Default profile name is `zero-<id suffix>`; provision refuses to clobber an existing name unless `--force`.
|
|
45
|
+
|
|
46
|
+
## pxbaas instance list / current
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pxbaas instance list --json # Zero instances bound locally (reconciled with Zero when a token exists)
|
|
50
|
+
pxbaas instance current --json # the Zero instance behind the current profile (or "not a zero instance")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## pxbaas instance credentials — reveal dashboard login
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pxbaas instance credentials <id> [--reveal] [--json]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- Default: endpoint, dashboardUrl, dashboard user (`supabase`), key **fingerprints**, expiry.
|
|
60
|
+
- `--reveal`: additionally prints the **Dashboard password** (for browser login). Handle with care — do not paste into shared logs. The anon/service keys are **never** revealed (they live in the keyring; just use the commands).
|
|
61
|
+
|
|
62
|
+
## pxbaas instance release — destructive, two-phase
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pxbaas instance release <id> # preview only
|
|
66
|
+
pxbaas instance release <id> --confirm # actually release (destroys cloud resources)
|
|
67
|
+
pxbaas instance release <id> --confirm --keep-profile # release remotely, keep local profile
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- Without `--confirm` it only previews. Release removes the local profile/credentials too (unless `--keep-profile`).
|
|
71
|
+
- If the released instance was the **current** profile, no profile is active afterwards — switch with `pxbaas profile use <name>` or `pxbaas provision`.
|
|
72
|
+
|
|
73
|
+
## pxbaas instance whitelist — query / append IP allow-list (Zero instances only)
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pxbaas instance whitelist get [--id <zeroId>] [--json] # show effective whitelist
|
|
77
|
+
pxbaas instance whitelist add <ips> [--id <zeroId>] [--dry-run] [--json] # append IPv4/CIDR
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- **Zero instances only.** Targets the current profile when it is `source: zero`, or an explicit `--id <sbx_*>`. On a non-Zero (login) profile it refuses with a clear error — the whitelist self-service API exists only for Zero-provisioned instances.
|
|
81
|
+
- **Auth**: derived locally from the stored dashboard password as `sha256hex("supabase:"+password)` and sent as `X-Studio-User` / `X-Studio-Hash`. The password and hash are never printed or persisted. Requires the instance to have been claimed on this machine (the password is stored at claim time; Zero has no credential re-read).
|
|
82
|
+
- **`add` is append-only and idempotent**: existing entries are kept, duplicates are not re-added, and there is no delete/replace — by design, so you can never accidentally clear the list and lock yourself out (the API also requires the request to come from an already-allowed IP). To shrink the list, contact the platform admin. `--dry-run` previews the parsed IPs without calling Zero.
|
|
83
|
+
- **`ips`** is a comma-separated IPv4/CIDR list (e.g. `9.9.9.9,10.0.0.0/24`); single request ≤ 50 entries, merged total ≤ 50. IPv6 is not supported.
|
|
84
|
+
- **IP gate (`IP_MISMATCH`, 403)**: the call must originate from the claiming IP or an already-whitelisted IP. If your egress IP changed since claim, you cannot self-add the new one from it — re-provision with `--whitelist-ip`, or run from an allowed IP. Tip: claim with a CIDR (e.g. `--whitelist-ip <your-egress>/24`) if your egress rotates within a range.
|
|
85
|
+
- Other codes: `ASSIGNMENT_EXPIRED` (403, past 15-day TTL → re-provision), `STUDIO_CREDENTIALS_INVALID` (403), `INSTANCE_NOT_ACCESSIBLE` (404), `INSTANCE_BUSY` / `CONCURRENT_UPDATE` (409, retry / re-`get` to reconcile), `WHITELIST_MODIFY_FAILED` (502, report the `cloudRequestId`), `RATE_LIMIT_EXCEEDED` (429).
|
|
86
|
+
- `get` output: `instanceId`, `groupName`, `whitelist` (effective entries; excludes the system `127.0.0.1` baseline), `source`, `expiresAt`, `updatedAt`.
|
|
87
|
+
|
|
88
|
+
## Capacity / rate limits — stop and inform (do NOT loop)
|
|
89
|
+
|
|
90
|
+
Zero is a shared pre-warmed pool with per-caller limits. On these errors, **stop, report, and let the user decide** — never retry in a loop:
|
|
91
|
+
|
|
92
|
+
| Error code | Meaning | Action |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `SUPABASE_LIMIT_REACHED` (429) | you hold the max concurrent instances | `pxbaas instance list` → `pxbaas instance release <id> --confirm` |
|
|
95
|
+
| `RATE_LIMIT_EXCEEDED` (429) | too many requests from this IP | wait, do not loop |
|
|
96
|
+
| `SUPABASE_POOL_EXHAUSTED` (503) | pool empty right now | retry ONCE after 1–2 min, else report |
|
|
97
|
+
| `SUPABASE_DISABLED` (503) | service disabled | report; do not retry |
|
|
98
|
+
| `INVALID_WHITELIST_IP` (400) | bad `--whitelist-ip` | use comma-separated IPv4/CIDR |
|
|
99
|
+
| `INSTANCE_NOT_FOUND` (404) | not found / not yours / already released | check `pxbaas instance list` |
|
|
100
|
+
|
|
101
|
+
> After provisioning, the instance also serves its own live API reference at `GET {endpoint}/docs` — see api-reference.md.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Safety Model & Destructive Operations (must read)
|
|
2
|
+
|
|
3
|
+
This is the safety baseline for using `pxbaas`. **The CLI currently has NO built-in confirmation gate**, so the responsibility to confirm falls on YOU (the agent).
|
|
4
|
+
|
|
5
|
+
## Which commands actually gate themselves
|
|
6
|
+
|
|
7
|
+
Gating landed after this page was first written, so it is now a per-command fact rather
|
|
8
|
+
than a global one. Verified against `--help` output:
|
|
9
|
+
|
|
10
|
+
| Command | Gate |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| `db push <file>`, `app db-init <name>` | shows the full plan, then TTY confirm or `--yes`; without authorization **no statement runs** |
|
|
13
|
+
| `data delete <table>` | read-only preview of affected rows + exact request URL, then TTY confirm or `--yes`; `--json` keeps a `preview` field even when refused |
|
|
14
|
+
| `app remove`, `app destroy`, `app share revoke`, `instance release`, `skill remove` | require `--confirm`; without them the command returns a `dry-run` preview |
|
|
15
|
+
| `tenant create` | `--dry-run` plan, then TTY confirm or `--yes`; refuses a colliding tenant id unless `--reactivate` |
|
|
16
|
+
| `tenant repair-keys` | requires `--confirm` |
|
|
17
|
+
|
|
18
|
+
**No gate at all** — you are the confirmation layer for these:
|
|
19
|
+
|
|
20
|
+
| Command | Risk |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `db create-table`, `db add-column` | DDL, executes immediately (help text says so) |
|
|
23
|
+
| `db query "<write/DDL>"` | executes whatever the SQL says |
|
|
24
|
+
| `data insert`, `data update` | writes; `update` requires `--filter` but may still hit many rows |
|
|
25
|
+
| `rest` with POST/PATCH/PUT/DELETE | whatever the method does |
|
|
26
|
+
| `functions deploy`, `functions delete` | publishes/overwrites or deletes a live function, irreversible |
|
|
27
|
+
| `app deploy` | publishes live (preflight + spec lint run, but no interactive confirm) |
|
|
28
|
+
| `storage rm` / `mv` / `cp` overwrite | deletes, moves, or silently overwrites objects |
|
|
29
|
+
| `auth users create` / `delete` / `invite` | mutates users; `invite` sends real email |
|
|
30
|
+
| `profile rm`, `logout`, `tenant logout` | removes local credentials (config, not instance data) |
|
|
31
|
+
|
|
32
|
+
Read-only and always safe: `whoami` `status` `doctor` `profile ls` `tenant probe` `tenant ls`
|
|
33
|
+
`tenant handoffs` `db tables` `db schema` `gen types` `data select` `functions list` `storage ls`
|
|
34
|
+
`auth users list/get` `app list` `app url` `app capabilities` `app templates` `instance list/current`.
|
|
35
|
+
|
|
36
|
+
## Risk classification (what impact to expect)
|
|
37
|
+
|
|
38
|
+
| Command | Risk |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `data delete <table> --filter ...` | deletes rows, irreversible (gated: preview + `--yes`) |
|
|
41
|
+
| `data insert` / `data update` | writes / mutates data |
|
|
42
|
+
| `db create-table` / `db add-column` | schema change (DDL), executes immediately |
|
|
43
|
+
| `db query "<write or DDL SQL>"` | depends on the SQL |
|
|
44
|
+
| `db push` / `app db-init` | DDL + RLS + seed; sequential, stops on first error, **never rolls back** |
|
|
45
|
+
| `functions deploy` | publishes / overwrites a live function |
|
|
46
|
+
| `functions delete <slug>` | deletes a live function, irreversible; also revokes its share links |
|
|
47
|
+
| `app deploy` / `publish` / `rollback` / `unpublish` | changes what is live for users |
|
|
48
|
+
| `app remove` / `app destroy [--purge-db]` | deletes functions + mount; `--purge-db` also drops tables and RLS rows |
|
|
49
|
+
| `storage rm` / `mv` / `cp` (overwrite) | deletes / moves / overwrites objects; remote→remote `cp` is a **move** (source is removed) |
|
|
50
|
+
| `auth users delete` / `create` / `invite` | deletes / creates users; `invite` sends real email |
|
|
51
|
+
| `rest` POST/PATCH/DELETE/PUT | depends on method and path |
|
|
52
|
+
| `profile rm` / `logout` / `tenant logout` | removes local credentials (also the stored keys, so re-login is required) |
|
|
53
|
+
| `tenant create` | provisions a database, a MySQL account + GRANTs, a storage bucket, RLS tables, Realtime registration; consumes quota |
|
|
54
|
+
| `tenant repair-keys` | re-signs NULL-keyed tenants from the existing `jwt_secret`; idempotent, **not** a rotation |
|
|
55
|
+
| `instance release` | destroys cloud resources and the local profile |
|
|
56
|
+
|
|
57
|
+
## Agent confirmation protocol (for destructive ops)
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
1) PREVIEW with a read-only command to determine the impact:
|
|
61
|
+
- data delete/update → data select with the same filter
|
|
62
|
+
- storage rm → storage ls with the same prefix
|
|
63
|
+
- functions delete → functions list
|
|
64
|
+
- auth users delete → auth users get
|
|
65
|
+
2) RESTATE to the user: operation + target (table/function/path/user) + estimated affected rows/objects + reversibility
|
|
66
|
+
3) WAIT for explicit consent ("yes", "go ahead", "confirm"); ambiguous or no consent → do NOT execute
|
|
67
|
+
4) EXECUTE the command (with --json)
|
|
68
|
+
5) VERIFY with a read-only command and report the result
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Other safety rules
|
|
72
|
+
|
|
73
|
+
- **NEVER run `pxbaas login`** — it needs an interactive TTY; agents cannot complete it. If not logged in, ask the user to log in (see auth-and-credentials.md).
|
|
74
|
+
- **NEVER handle plaintext keys** — output is fingerprint-only (sha256 first 8 + last 4); do not request, echo, or reconstruct a plaintext anon/service key.
|
|
75
|
+
- **Least-privilege role** — prefer `anon` for reads; use `service_role` only when you truly need to bypass RLS, and explain its meaning to the user.
|
|
76
|
+
- **Tenant isolation** — the CLI validates the key's `tenant_id` against the profile; do not mix credentials across profiles or target another tenant's resources.
|
|
77
|
+
- **`--no-verify-jwt`** — `functions deploy --no-verify-jwt` disables JWT verification on the function and lowers security; avoid unless necessary and always tell the user.
|
|
78
|
+
- **Admin scope** — `/docs` lists admin APIs (PG-Meta `/pg/`, Management API `/v1/projects/*`) that the customer CLI does not expose; do not attempt them via `pxbaas`.
|