@polardbx/pxbaas 0.1.0-beta.1 → 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 +224 -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 +24 -1
- package/dist/app/preflight.d.ts.map +1 -1
- package/dist/app/preflight.js +47 -11
- package/dist/app/preflight.js.map +1 -1
- package/dist/app/spec-lint.d.ts.map +1 -1
- package/dist/app/spec-lint.js +16 -0
- package/dist/app/spec-lint.js.map +1 -1
- package/dist/app/templates.d.ts +24 -0
- package/dist/app/templates.d.ts.map +1 -1
- package/dist/app/templates.js.map +1 -1
- 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.map +1 -1
- package/dist/cli/root.js +6 -0
- package/dist/cli/root.js.map +1 -1
- package/dist/commands/app/index.d.ts.map +1 -1
- package/dist/commands/app/index.js +687 -47
- package/dist/commands/app/index.js.map +1 -1
- package/dist/commands/completion/index.d.ts.map +1 -1
- package/dist/commands/completion/index.js +5 -1
- package/dist/commands/completion/index.js.map +1 -1
- package/dist/commands/data/index.d.ts +52 -0
- package/dist/commands/data/index.d.ts.map +1 -1
- package/dist/commands/data/index.js +201 -39
- package/dist/commands/data/index.js.map +1 -1
- package/dist/commands/db/index.d.ts +15 -0
- package/dist/commands/db/index.d.ts.map +1 -1
- package/dist/commands/db/index.js +200 -55
- package/dist/commands/db/index.js.map +1 -1
- package/dist/commands/functions/new.d.ts +4 -0
- package/dist/commands/functions/new.d.ts.map +1 -1
- package/dist/commands/functions/new.js +24 -9
- package/dist/commands/functions/new.js.map +1 -1
- package/dist/commands/gen/index.d.ts.map +1 -1
- package/dist/commands/gen/index.js +13 -10
- package/dist/commands/gen/index.js.map +1 -1
- 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.map +1 -1
- package/dist/commands/instance/index.js +120 -0
- package/dist/commands/instance/index.js.map +1 -1
- package/dist/commands/login/index.d.ts.map +1 -1
- package/dist/commands/login/index.js +23 -63
- package/dist/commands/login/index.js.map +1 -1
- package/dist/commands/profile/import-env.d.ts +7 -2
- package/dist/commands/profile/import-env.d.ts.map +1 -1
- package/dist/commands/profile/import-env.js +141 -16
- package/dist/commands/profile/import-env.js.map +1 -1
- package/dist/commands/profile/index.d.ts.map +1 -1
- package/dist/commands/profile/index.js +16 -1
- package/dist/commands/profile/index.js.map +1 -1
- package/dist/commands/skill/index.d.ts.map +1 -1
- package/dist/commands/skill/index.js +89 -14
- package/dist/commands/skill/index.js.map +1 -1
- package/dist/commands/storage/index.d.ts.map +1 -1
- package/dist/commands/storage/index.js +209 -7
- package/dist/commands/storage/index.js.map +1 -1
- 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.js +19 -0
- package/dist/commands/whoami/index.js.map +1 -1
- package/dist/credentials/credential-store.d.ts +30 -1
- package/dist/credentials/credential-store.d.ts.map +1 -1
- package/dist/credentials/credential-store.js +114 -12
- package/dist/credentials/credential-store.js.map +1 -1
- package/dist/credentials/env-file.d.ts +48 -7
- package/dist/credentials/env-file.d.ts.map +1 -1
- package/dist/credentials/env-file.js +91 -16
- package/dist/credentials/env-file.js.map +1 -1
- package/dist/credentials/index.d.ts +2 -0
- package/dist/credentials/index.d.ts.map +1 -1
- package/dist/credentials/index.js +2 -0
- package/dist/credentials/index.js.map +1 -1
- package/dist/credentials/jwt-introspect.d.ts +7 -0
- package/dist/credentials/jwt-introspect.d.ts.map +1 -1
- package/dist/credentials/jwt-introspect.js.map +1 -1
- package/dist/credentials/masker.d.ts +3 -0
- package/dist/credentials/masker.d.ts.map +1 -1
- package/dist/credentials/masker.js +3 -0
- package/dist/credentials/masker.js.map +1 -1
- package/dist/credentials/profile.d.ts +12 -0
- package/dist/credentials/profile.d.ts.map +1 -1
- package/dist/credentials/profile.js +23 -0
- package/dist/credentials/profile.js.map +1 -1
- package/dist/credentials/tty-guard.d.ts +10 -0
- package/dist/credentials/tty-guard.d.ts.map +1 -1
- package/dist/credentials/tty-guard.js +32 -0
- package/dist/credentials/tty-guard.js.map +1 -1
- package/dist/db/apply-schema.d.ts +98 -11
- package/dist/db/apply-schema.d.ts.map +1 -1
- package/dist/db/apply-schema.js +247 -80
- package/dist/db/apply-schema.js.map +1 -1
- 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 +55 -0
- package/dist/db/sql-file.d.ts.map +1 -1
- package/dist/db/sql-file.js +417 -0
- package/dist/db/sql-file.js.map +1 -1
- 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.js +26 -3
- package/dist/main.js.map +1 -1
- 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/hosts.d.ts +31 -7
- package/dist/skill/hosts.d.ts.map +1 -1
- package/dist/skill/hosts.js +65 -7
- package/dist/skill/hosts.js.map +1 -1
- package/dist/skill/installer.d.ts +15 -3
- package/dist/skill/installer.d.ts.map +1 -1
- package/dist/skill/installer.js +62 -24
- package/dist/skill/installer.js.map +1 -1
- 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 +3 -3
- package/skills/pxbaas-app-spec/SKILL.md +4 -2
- package/skills/pxbaas-app-spec/references/deploy-options.md +3 -2
- package/skills/pxbaas-app-spec/references/runtime-contract.md +2 -2
- package/skills/pxbaas-app-spec/references/templates-examples.md +7 -4
- package/skills/pxbaas-cli/SKILL.md +26 -8
- package/skills/pxbaas-cli/references/app-deploy.md +46 -3
- package/skills/pxbaas-cli/references/auth-and-credentials.md +30 -2
- package/skills/pxbaas-cli/references/data-postgrest.md +19 -3
- package/skills/pxbaas-cli/references/db-and-meta.md +17 -0
- package/skills/pxbaas-cli/references/multi-tenant-apps.md +35 -4
- package/skills/pxbaas-cli/references/provision.md +16 -1
- package/skills/pxbaas-cli/references/safety-and-two-phase.md +42 -13
- package/skills/pxbaas-cli/references/tenant-admin.md +122 -0
- package/skills/pxbaas-cli/references/troubleshooting.md +4 -1
- package/templates/webapp/csr-bff/db/rls.json +13 -0
- package/templates/webapp/csr-bff/db/schema.sql +8 -28
- package/templates/webapp/manifest.json +131 -8
- package/templates/webapp/react-vite-hono/backend/index.ts +21 -4
- package/templates/webapp/ssr-blog/db/rls.json +13 -0
- package/templates/webapp/ssr-blog/db/schema.sql +8 -28
- package/templates/webapp/ssr-hono/backend/index.ts +50 -31
- package/templates/webapp/ssr-shop/db/rls.json +16 -0
- package/templates/webapp/ssr-shop/db/schema.sql +12 -42
- package/dist/commands/login/login.d.ts +0 -3
- package/dist/commands/login/login.d.ts.map +0 -1
- package/dist/commands/login/login.js +0 -185
- package/dist/commands/login/login.js.map +0 -1
- /package/templates/webapp/vanilla-static/frontend/{app.js → dist/app.js} +0 -0
- /package/templates/webapp/vanilla-static/frontend/{index.html → dist/index.html} +0 -0
- /package/templates/webapp/vanilla-static/frontend/{style.css → dist/style.css} +0 -0
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
-- · 多租户实例:__SCHEMA__ = tenant_<tenant_id>
|
|
7
7
|
-- sed 's/__SCHEMA__/public/g' db/schema.sql
|
|
8
8
|
--
|
|
9
|
-
--
|
|
10
|
-
--
|
|
9
|
+
-- 执行通道(推荐):`pxbaas app db-init <name>` —— 单/多租户通用:
|
|
10
|
+
-- 单租户 __SCHEMA__→public 经 /pg/query;多租户 __SCHEMA__ 去限定经 /api/tenant-ddl
|
|
11
|
+
-- 用 per-tenant service_role key 执行(GRANT 仅本租户库)。本文件只含 DDL + 种子;
|
|
12
|
+
-- RLS 声明在同目录 db/rls.json,由 db-init 一并应用。
|
|
11
13
|
--
|
|
12
|
-
-- ⚠️ RLS 元数据落点(写错静默失效=RLS 关闭):永远写中心库 supabase._mysqlrest_rls_
|
|
13
|
-
--
|
|
14
|
+
-- ⚠️ RLS 元数据落点(写错静默失效=RLS 关闭):永远写中心库 supabase._mysqlrest_rls_*;
|
|
15
|
+
-- db-init 自动绑定 table_schema(单租户=--schema,多租户=服务端强绑),勿手写库名。
|
|
14
16
|
-- =============================================================================
|
|
15
17
|
|
|
16
18
|
CREATE TABLE IF NOT EXISTS `__SCHEMA__`.`posts_ssr` (
|
|
@@ -26,30 +28,8 @@ CREATE TABLE IF NOT EXISTS `__SCHEMA__`.`posts_ssr` (
|
|
|
26
28
|
KEY `idx_posts_ssr_status` (`status`, `created_at`)
|
|
27
29
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
28
30
|
|
|
29
|
-
-- ---- RLS
|
|
30
|
-
|
|
31
|
-
VALUES ('__SCHEMA__','posts_ssr',1,0);
|
|
32
|
-
|
|
33
|
-
-- ---- RLS 策略:anon 只读 published;authenticated 读 published 或本人;写改删限本人 ----
|
|
34
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
35
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
36
|
-
VALUES ('__SCHEMA__','posts_ssr','posts_ssr_select_anon','anon','SELECT','`status` = ''published''',NULL,1);
|
|
37
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
38
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
39
|
-
VALUES ('__SCHEMA__','posts_ssr','posts_ssr_select_auth','authenticated','SELECT',
|
|
40
|
-
'`status` = ''published'' OR author_id = {{request.jwt.claim.sub}}',NULL,1);
|
|
41
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
42
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
43
|
-
VALUES ('__SCHEMA__','posts_ssr','posts_ssr_insert_auth','authenticated','INSERT',NULL,
|
|
44
|
-
'author_id = {{request.jwt.claim.sub}}',1);
|
|
45
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
46
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
47
|
-
VALUES ('__SCHEMA__','posts_ssr','posts_ssr_update_auth','authenticated','UPDATE',
|
|
48
|
-
'author_id = {{request.jwt.claim.sub}}','author_id = {{request.jwt.claim.sub}}',1);
|
|
49
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
50
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
51
|
-
VALUES ('__SCHEMA__','posts_ssr','posts_ssr_delete_auth','authenticated','DELETE',
|
|
52
|
-
'author_id = {{request.jwt.claim.sub}}',NULL,1);
|
|
31
|
+
-- ---- RLS 注册与策略:声明在同目录 db/rls.json,由 `pxbaas app db-init` 应用 ----
|
|
32
|
+
-- anon 只读 published;authenticated 读 published 或本人;写/改/删限本人(author_id = jwt.sub)。
|
|
53
33
|
|
|
54
34
|
-- ---- 种子文章(3 篇 published,幂等)----
|
|
55
35
|
INSERT INTO `__SCHEMA__`.`posts_ssr` (title, content, author_id, author_name, status)
|
|
@@ -37,30 +37,45 @@ function esc(s: string): string {
|
|
|
37
37
|
.split(String.fromCharCode(34)).join(""");
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
40
|
+
// Path contract (APP_WORKER_PATH_REWRITE off = current default): the proxy
|
|
41
|
+
// forwards /apps/{mount}/api/<x> to the worker as /<candidateSlug>/<x> — the
|
|
42
|
+
// candidate slug prefix is NOT stripped at runtime (the stripped path is only
|
|
43
|
+
// delivered via X-Pxbaas-Worker-Path when the rewrite kill-switch is ON, which
|
|
44
|
+
// is disabled by default due to the D18 streamRid regression). Normalize the
|
|
45
|
+
// slug prefix away and match on the logical path, so handlers resolve under ANY
|
|
46
|
+
// prefix shape (/{slug}/x, /api/x, or /x) and still work if the switch flips on.
|
|
47
|
+
// Same convention as the ssr-shop / ssr-blog / csr-bff templates.
|
|
48
|
+
function norm(path: string): string {
|
|
49
|
+
return path.replace(/^\/app_[^/]+/, "") || path;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
app.get("*", async (c) => {
|
|
53
|
+
const p = norm(new URL(c.req.url).pathname);
|
|
54
|
+
|
|
55
|
+
// L3 shape demo: server-side fetch of DB content via the derived internal base
|
|
56
|
+
// (anon key from env; RLS enforced server-side). Degrades gracefully so the
|
|
57
|
+
// shell still renders if the internal entry is ever unreachable.
|
|
58
|
+
if (p === "/ssr-data") {
|
|
59
|
+
let rows: Array<Record<string, unknown>> = [];
|
|
60
|
+
let note = "";
|
|
61
|
+
try {
|
|
62
|
+
const r = await fetch(internalBase() + "/rest/v1/?select=1", {
|
|
63
|
+
headers: { apikey: Deno.env.get("SUPABASE_ANON_KEY") || "" },
|
|
64
|
+
});
|
|
65
|
+
note = `internal base reachable: http-${r.status}`;
|
|
66
|
+
} catch (e) {
|
|
67
|
+
note = `internal base unreachable: ${String(e).slice(0, 60)}`;
|
|
68
|
+
}
|
|
69
|
+
return c.html(`<!DOCTYPE html><html><head><meta charset="utf-8"><title>L3 demo</title></head><body>
|
|
55
70
|
<div id="__ssr" data-ssr="v1"><h1>L3 full-SSR demo</h1><p>${esc(note)}</p><pre>${esc(JSON.stringify(rows))}</pre></div>
|
|
56
71
|
</body></html>`);
|
|
57
|
-
}
|
|
72
|
+
}
|
|
58
73
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
74
|
+
if (p === "/page") {
|
|
75
|
+
const theme = c.req.query("theme") === "dark" ? "dark" : "light";
|
|
76
|
+
const bg = theme === "dark" ? "#111" : "#fafafa";
|
|
77
|
+
const fg = theme === "dark" ? "#eee" : "#222";
|
|
78
|
+
const html = `<!DOCTYPE html><html><head><meta charset="utf-8">
|
|
64
79
|
<title>{{APP_NAME}} SSR</title>
|
|
65
80
|
<style>body{font-family:sans-serif;max-width:720px;margin:40px auto;background:${bg};color:${fg}}</style>
|
|
66
81
|
</head><body>
|
|
@@ -77,16 +92,20 @@ app.get("/page", (c) => {
|
|
|
77
92
|
})();
|
|
78
93
|
</script>
|
|
79
94
|
</body></html>`;
|
|
80
|
-
|
|
81
|
-
}
|
|
95
|
+
return c.html(html);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// JSON API. /apps/{m}/api/data and /api/health normalize to /data and /health
|
|
99
|
+
// after the slug strip; the /api-prefixed shapes are kept as a defensive
|
|
100
|
+
// fallback for deployments that deliver the logical path un-stripped.
|
|
101
|
+
if (p === "/data" || p === "/api/data") {
|
|
102
|
+
return c.json({ ok: true, engine: "hono", now: new Date().toISOString() });
|
|
103
|
+
}
|
|
104
|
+
if (p === "/health" || p === "/api/health") {
|
|
105
|
+
return c.json({ ok: true });
|
|
106
|
+
}
|
|
82
107
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// fallthrough delivers the FULL logical path (/page). Register both shapes so
|
|
86
|
-
// the worker behaves identically when the rewrite kill-switch is flipped back on.
|
|
87
|
-
app.get("/data", (c) => c.json({ ok: true, engine: "hono", now: new Date().toISOString() }));
|
|
88
|
-
app.get("/api/data", (c) => c.json({ ok: true, engine: "hono", now: new Date().toISOString() }));
|
|
89
|
-
app.get("/health", (c) => c.json({ ok: true }));
|
|
90
|
-
app.get("/api/health", (c) => c.json({ ok: true }));
|
|
108
|
+
return c.json({ ok: false, error: "not_found", path: p }, 404);
|
|
109
|
+
});
|
|
91
110
|
|
|
92
111
|
Deno.serve(app.fetch);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Declarative RLS for the shop webapp. Applied by `pxbaas app db-init` (single-tenant AND multi-tenant). table_schema is NEVER declared here: single-tenant binds it to --schema (default public); multi-tenant binds it server-side to the tenant db. using/check expressions may embed {{request.jwt.claim.*}} templates.",
|
|
3
|
+
"tables": [
|
|
4
|
+
{ "table": "products", "rlsEnabled": true, "rlsForced": false },
|
|
5
|
+
{ "table": "orders", "rlsEnabled": true, "rlsForced": false },
|
|
6
|
+
{ "table": "order_items", "rlsEnabled": true, "rlsForced": false }
|
|
7
|
+
],
|
|
8
|
+
"policies": [
|
|
9
|
+
{ "table": "products", "name": "products_select_anon", "role": "anon", "command": "SELECT", "using": "1=1", "check": null, "permissive": true },
|
|
10
|
+
{ "table": "products", "name": "products_select_auth", "role": "authenticated", "command": "SELECT", "using": "1=1", "check": null, "permissive": true },
|
|
11
|
+
{ "table": "orders", "name": "orders_select_auth", "role": "authenticated", "command": "SELECT", "using": "`buyer_email` = {{request.jwt.claim.email}} OR {{request.jwt.claim.email}} = 'admin@shop.demo'", "check": null, "permissive": true },
|
|
12
|
+
{ "table": "orders", "name": "orders_insert_auth", "role": "authenticated", "command": "INSERT", "using": null, "check": "`buyer_email` = {{request.jwt.claim.email}}", "permissive": true },
|
|
13
|
+
{ "table": "order_items", "name": "order_items_select_auth", "role": "authenticated", "command": "SELECT", "using": "`buyer_email` = {{request.jwt.claim.email}} OR {{request.jwt.claim.email}} = 'admin@shop.demo'", "check": null, "permissive": true },
|
|
14
|
+
{ "table": "order_items", "name": "order_items_insert_auth", "role": "authenticated", "command": "INSERT", "using": null, "check": "`buyer_email` = {{request.jwt.claim.email}}", "permissive": true }
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -6,15 +6,16 @@
|
|
|
6
6
|
-- · 多租户实例:__SCHEMA__ = tenant_<tenant_id>(每租户一套库)
|
|
7
7
|
-- sed 's/__SCHEMA__/public/g' db/schema.sql
|
|
8
8
|
--
|
|
9
|
-
--
|
|
10
|
-
-- · 单租户:
|
|
11
|
-
-- · 多租户:
|
|
12
|
-
--
|
|
9
|
+
-- 执行通道(推荐):`pxbaas app db-init <name>` —— 单/多租户通用,自动:
|
|
10
|
+
-- · 单租户:__SCHEMA__ → public,经 /pg/query(全局 admin)执行;
|
|
11
|
+
-- · 多租户:__SCHEMA__ 去限定(连接已锁租户库),经 /api/tenant-ddl 用
|
|
12
|
+
-- per-tenant service_role key 执行;GRANT 仅本租户库,天然隔离。
|
|
13
|
+
-- 本文件只含 DDL + 种子;RLS 声明在同目录 db/rls.json,由 db-init 一并应用。
|
|
13
14
|
--
|
|
14
15
|
-- ⚠️ RLS 元数据的落点(写错静默失效,等价于关闭 RLS):
|
|
15
|
-
-- 永远写中心库 supabase._mysqlrest_rls_tables / _mysqlrest_rls_policies
|
|
16
|
-
--
|
|
17
|
-
--
|
|
16
|
+
-- 永远写中心库 supabase._mysqlrest_rls_tables / _mysqlrest_rls_policies。
|
|
17
|
+
-- db-init 会自动绑定 table_schema(单租户=--schema,多租户=服务端强绑租户库),
|
|
18
|
+
-- 无需也不要手写库名。租户库内同名 _mysqlrest_rls_* 表没有任何服务读取,勿写入。
|
|
18
19
|
-- =============================================================================
|
|
19
20
|
|
|
20
21
|
-- ---- 表结构 ----
|
|
@@ -54,41 +55,10 @@ CREATE TABLE IF NOT EXISTS `__SCHEMA__`.`order_items` (
|
|
|
54
55
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
55
56
|
);
|
|
56
57
|
|
|
57
|
-
-- ---- RLS
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
-- ---- RLS 策略 ----
|
|
62
|
-
-- products:公开目录,anon / authenticated 均可读
|
|
63
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
64
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
65
|
-
VALUES ('__SCHEMA__','products','products_select_anon','anon','SELECT','1=1',NULL,1);
|
|
66
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
67
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
68
|
-
VALUES ('__SCHEMA__','products','products_select_auth','authenticated','SELECT','1=1',NULL,1);
|
|
69
|
-
|
|
70
|
-
-- orders:仅本人(buyer_email = jwt.email)或管理员白名单可读;仅本人可写
|
|
71
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
72
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
73
|
-
VALUES ('__SCHEMA__','orders','orders_select_auth','authenticated','SELECT',
|
|
74
|
-
'`buyer_email` = {{request.jwt.claim.email}} OR {{request.jwt.claim.email}} = ''admin@shop.demo''',
|
|
75
|
-
NULL, 1);
|
|
76
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
77
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
78
|
-
VALUES ('__SCHEMA__','orders','orders_insert_auth','authenticated','INSERT',NULL,
|
|
79
|
-
'`buyer_email` = {{request.jwt.claim.email}}', 1);
|
|
80
|
-
|
|
81
|
-
-- order_items:仅本人(buyer_email = jwt.email)或管理员白名单可读;仅本人可写(owner 门禁落在本表,
|
|
82
|
-
-- 不依赖前端按 order_id 过滤 —— 前端过滤不是安全边界,R2-05)。
|
|
83
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
84
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
85
|
-
VALUES ('__SCHEMA__','order_items','order_items_select_auth','authenticated','SELECT',
|
|
86
|
-
'`buyer_email` = {{request.jwt.claim.email}} OR {{request.jwt.claim.email}} = ''admin@shop.demo''',
|
|
87
|
-
NULL, 1);
|
|
88
|
-
INSERT IGNORE INTO supabase._mysqlrest_rls_policies
|
|
89
|
-
(table_schema, table_name, policy_name, role_name, command, using_expr, check_expr, permissive)
|
|
90
|
-
VALUES ('__SCHEMA__','order_items','order_items_insert_auth','authenticated','INSERT',NULL,
|
|
91
|
-
'`buyer_email` = {{request.jwt.claim.email}}', 1);
|
|
58
|
+
-- ---- RLS 注册与策略:声明在同目录 db/rls.json,由 `pxbaas app db-init` 应用 ----
|
|
59
|
+
-- · products:公开目录,anon / authenticated 均可读;
|
|
60
|
+
-- · orders / order_items:仅本人(buyer_email = jwt.email)或管理员白名单可读,仅本人可写。
|
|
61
|
+
-- (不再内联 INSERT,避免与 rls.json 双源;如需手动注册见 db/rls.json。)
|
|
92
62
|
|
|
93
63
|
-- ---- 种子商品(10 件,幂等)----
|
|
94
64
|
INSERT INTO `__SCHEMA__`.`products` (name, description, price_cents, stock, emoji, category)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/commands/login/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4CpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkB3D"}
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import inquirer from 'inquirer';
|
|
2
|
-
import { CredentialStore, ProfileManager, introspectJwt, validateTenantConsistency, assertTty, assertNoKeyArgs, formatSuccess, formatError, computeFingerprint, } from '../../credentials/index.js';
|
|
3
|
-
/**
|
|
4
|
-
* 从 stdin 读取一行(用于 --anon-key-stdin / --service-key-stdin)
|
|
5
|
-
*/
|
|
6
|
-
async function readFromStdin() {
|
|
7
|
-
return new Promise((resolve, reject) => {
|
|
8
|
-
let data = '';
|
|
9
|
-
process.stdin.setEncoding('utf8');
|
|
10
|
-
process.stdin.on('readable', () => {
|
|
11
|
-
let chunk;
|
|
12
|
-
while ((chunk = process.stdin.read()) !== null) {
|
|
13
|
-
data += chunk;
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
process.stdin.on('end', () => {
|
|
17
|
-
resolve(data.trim());
|
|
18
|
-
});
|
|
19
|
-
process.stdin.on('error', reject);
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
export function registerLoginCommand(program) {
|
|
23
|
-
program
|
|
24
|
-
.command('login')
|
|
25
|
-
.description('Authenticate with PolarDB-X BaaS (interactive TTY only)')
|
|
26
|
-
.option('--endpoint <url>', 'BaaS endpoint URL')
|
|
27
|
-
.option('--tenant-id <id>', 'Tenant ID (for multi-tenant mode)')
|
|
28
|
-
.option('--anon-key-stdin', 'Read anon key from stdin')
|
|
29
|
-
.option('--service-key-stdin', 'Read service role key from stdin')
|
|
30
|
-
.option('--profile <name>', 'Profile name to use')
|
|
31
|
-
.action(async (options) => {
|
|
32
|
-
try {
|
|
33
|
-
await handleLogin(options, program);
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
37
|
-
console.error(formatError(message));
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
async function handleLogin(options, program) {
|
|
43
|
-
// 检查 argv 中是否有密钥参数(安全守卫)
|
|
44
|
-
assertNoKeyArgs(process.argv);
|
|
45
|
-
const isStdinMode = options.anonKeyStdin || options.serviceKeyStdin;
|
|
46
|
-
// 如果不是 stdin 模式,必须是 TTY
|
|
47
|
-
if (!isStdinMode) {
|
|
48
|
-
assertTty();
|
|
49
|
-
}
|
|
50
|
-
let endpoint;
|
|
51
|
-
let tenantId;
|
|
52
|
-
let anonKey;
|
|
53
|
-
let serviceRoleKey;
|
|
54
|
-
if (isStdinMode) {
|
|
55
|
-
// stdin 模式:从命令行参数或 stdin 获取
|
|
56
|
-
endpoint = options.endpoint || '';
|
|
57
|
-
tenantId = options.tenantId;
|
|
58
|
-
if (!endpoint) {
|
|
59
|
-
throw new Error('--endpoint is required when using --anon-key-stdin or --service-key-stdin');
|
|
60
|
-
}
|
|
61
|
-
if (options.anonKeyStdin && options.serviceKeyStdin) {
|
|
62
|
-
// 两个都从 stdin 读取(每行一个)
|
|
63
|
-
const lines = (await readFromStdin()).split('\n');
|
|
64
|
-
if (lines.length < 2) {
|
|
65
|
-
throw new Error('Expected two lines from stdin: anon key on first line, service role key on second line');
|
|
66
|
-
}
|
|
67
|
-
anonKey = lines[0].trim();
|
|
68
|
-
serviceRoleKey = lines[1].trim();
|
|
69
|
-
}
|
|
70
|
-
else if (options.anonKeyStdin) {
|
|
71
|
-
anonKey = (await readFromStdin()).trim();
|
|
72
|
-
throw new Error('--service-key-stdin is required when using --anon-key-stdin');
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
serviceRoleKey = (await readFromStdin()).trim();
|
|
76
|
-
throw new Error('--anon-key-stdin is required when using --service-key-stdin');
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
// TTY 交互模式:使用 inquirer 提示
|
|
81
|
-
const answers = await inquirer.prompt([
|
|
82
|
-
{
|
|
83
|
-
type: 'input',
|
|
84
|
-
name: 'endpoint',
|
|
85
|
-
message: 'BaaS endpoint URL:',
|
|
86
|
-
default: options.endpoint || 'http://localhost:8000',
|
|
87
|
-
validate: (input) => {
|
|
88
|
-
if (!input.trim())
|
|
89
|
-
return 'Endpoint is required';
|
|
90
|
-
if (!input.startsWith('http://') && !input.startsWith('https://')) {
|
|
91
|
-
return 'Endpoint must start with http:// or https://';
|
|
92
|
-
}
|
|
93
|
-
return true;
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
type: 'input',
|
|
98
|
-
name: 'tenantId',
|
|
99
|
-
message: 'Tenant ID (leave empty for single-tenant mode):',
|
|
100
|
-
default: options.tenantId || '',
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
type: 'password',
|
|
104
|
-
name: 'anonKey',
|
|
105
|
-
message: 'Anon Key:',
|
|
106
|
-
mask: '*',
|
|
107
|
-
validate: (input) => {
|
|
108
|
-
if (!input.trim())
|
|
109
|
-
return 'Anon key is required';
|
|
110
|
-
return true;
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
type: 'password',
|
|
115
|
-
name: 'serviceRoleKey',
|
|
116
|
-
message: 'Service Role Key:',
|
|
117
|
-
mask: '*',
|
|
118
|
-
validate: (input) => {
|
|
119
|
-
if (!input.trim())
|
|
120
|
-
return 'Service role key is required';
|
|
121
|
-
return true;
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
]);
|
|
125
|
-
endpoint = answers.endpoint;
|
|
126
|
-
tenantId = answers.tenantId || undefined;
|
|
127
|
-
anonKey = answers.anonKey;
|
|
128
|
-
serviceRoleKey = answers.serviceRoleKey;
|
|
129
|
-
}
|
|
130
|
-
// 解析 JWT
|
|
131
|
-
const anonJwt = await introspectJwt(anonKey);
|
|
132
|
-
const serviceJwt = await introspectJwt(serviceRoleKey);
|
|
133
|
-
// 检查 JWT 是否过期
|
|
134
|
-
if (anonJwt.isExpired) {
|
|
135
|
-
console.warn(formatError('Warning: Anon key is expired'));
|
|
136
|
-
}
|
|
137
|
-
if (serviceJwt.isExpired) {
|
|
138
|
-
console.warn(formatError('Warning: Service role key is expired'));
|
|
139
|
-
}
|
|
140
|
-
// 创建 profile
|
|
141
|
-
const mode = tenantId ? 'multi-tenant' : 'single-tenant';
|
|
142
|
-
const profileName = options.profile || 'default';
|
|
143
|
-
const profile = {
|
|
144
|
-
name: profileName,
|
|
145
|
-
endpoint,
|
|
146
|
-
tenantId,
|
|
147
|
-
mode,
|
|
148
|
-
createdAt: new Date().toISOString(),
|
|
149
|
-
updatedAt: new Date().toISOString(),
|
|
150
|
-
};
|
|
151
|
-
// 验证租户一致性
|
|
152
|
-
validateTenantConsistency(profile, anonJwt, serviceJwt);
|
|
153
|
-
// 保存 profile
|
|
154
|
-
const profileManager = new ProfileManager();
|
|
155
|
-
await profileManager.setProfile(profile);
|
|
156
|
-
await profileManager.useProfile(profileName);
|
|
157
|
-
// 保存凭据
|
|
158
|
-
const credentialStore = new CredentialStore();
|
|
159
|
-
await credentialStore.setCredentials(profileName, {
|
|
160
|
-
anonKey,
|
|
161
|
-
serviceRoleKey,
|
|
162
|
-
storedAt: new Date().toISOString(),
|
|
163
|
-
});
|
|
164
|
-
// 输出成功消息
|
|
165
|
-
const output = {
|
|
166
|
-
profile: profileName,
|
|
167
|
-
endpoint,
|
|
168
|
-
tenantId: tenantId || '(single-tenant)',
|
|
169
|
-
mode,
|
|
170
|
-
anonKeyFingerprint: computeFingerprint(anonKey),
|
|
171
|
-
serviceKeyFingerprint: computeFingerprint(serviceRoleKey),
|
|
172
|
-
};
|
|
173
|
-
if (options.json || program.opts().json) {
|
|
174
|
-
console.log(JSON.stringify(output, null, 2));
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
console.log(formatSuccess(`Login successful for profile: ${profileName}`));
|
|
178
|
-
console.log(` Endpoint: ${endpoint}`);
|
|
179
|
-
console.log(` Tenant ID: ${tenantId || '(single-tenant)'}`);
|
|
180
|
-
console.log(` Mode: ${mode}`);
|
|
181
|
-
console.log(` Anon Key: ${output.anonKeyFingerprint}`);
|
|
182
|
-
console.log(` Service Key: ${output.serviceKeyFingerprint}`);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
//# sourceMappingURL=login.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/commands/login/login.ts"],"names":[],"mappings":"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"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|