@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.
Files changed (312) hide show
  1. package/README.md +223 -2
  2. package/bin/pxbaas.js +13 -0
  3. package/dist/app/local-index.d.ts +70 -0
  4. package/dist/app/local-index.d.ts.map +1 -0
  5. package/dist/app/local-index.js +140 -0
  6. package/dist/app/local-index.js.map +1 -0
  7. package/dist/app/preflight.d.ts +61 -0
  8. package/dist/app/preflight.d.ts.map +1 -0
  9. package/dist/app/preflight.js +115 -0
  10. package/dist/app/preflight.js.map +1 -0
  11. package/dist/app/spec-lint.d.ts +45 -0
  12. package/dist/app/spec-lint.d.ts.map +1 -0
  13. package/dist/app/spec-lint.js +423 -0
  14. package/dist/app/spec-lint.js.map +1 -0
  15. package/dist/app/templates.d.ts +167 -0
  16. package/dist/app/templates.d.ts.map +1 -0
  17. package/dist/app/templates.js +151 -0
  18. package/dist/app/templates.js.map +1 -0
  19. package/dist/cli/help-guides.d.ts +17 -0
  20. package/dist/cli/help-guides.d.ts.map +1 -0
  21. package/dist/cli/help-guides.js +132 -0
  22. package/dist/cli/help-guides.js.map +1 -0
  23. package/dist/cli/root.d.ts +3 -0
  24. package/dist/cli/root.d.ts.map +1 -0
  25. package/dist/cli/root.js +75 -0
  26. package/dist/cli/root.js.map +1 -0
  27. package/dist/commands/app/index.d.ts +8 -0
  28. package/dist/commands/app/index.d.ts.map +1 -0
  29. package/dist/commands/app/index.js +1907 -0
  30. package/dist/commands/app/index.js.map +1 -0
  31. package/dist/commands/auth/index.d.ts +3 -0
  32. package/dist/commands/auth/index.d.ts.map +1 -0
  33. package/dist/commands/auth/index.js +198 -0
  34. package/dist/commands/auth/index.js.map +1 -0
  35. package/dist/commands/completion/index.d.ts +3 -0
  36. package/dist/commands/completion/index.d.ts.map +1 -0
  37. package/dist/commands/completion/index.js +14 -0
  38. package/dist/commands/completion/index.js.map +1 -0
  39. package/dist/commands/data/index.d.ts +55 -0
  40. package/dist/commands/data/index.d.ts.map +1 -0
  41. package/dist/commands/data/index.js +407 -0
  42. package/dist/commands/data/index.js.map +1 -0
  43. package/dist/commands/db/index.d.ts +29 -0
  44. package/dist/commands/db/index.d.ts.map +1 -0
  45. package/dist/commands/db/index.js +500 -0
  46. package/dist/commands/db/index.js.map +1 -0
  47. package/dist/commands/doctor/index.d.ts +3 -0
  48. package/dist/commands/doctor/index.d.ts.map +1 -0
  49. package/dist/commands/doctor/index.js +305 -0
  50. package/dist/commands/doctor/index.js.map +1 -0
  51. package/dist/commands/functions/delete.d.ts +3 -0
  52. package/dist/commands/functions/delete.d.ts.map +1 -0
  53. package/dist/commands/functions/delete.js +55 -0
  54. package/dist/commands/functions/delete.js.map +1 -0
  55. package/dist/commands/functions/deploy.d.ts +3 -0
  56. package/dist/commands/functions/deploy.d.ts.map +1 -0
  57. package/dist/commands/functions/deploy.js +118 -0
  58. package/dist/commands/functions/deploy.js.map +1 -0
  59. package/dist/commands/functions/index.d.ts +3 -0
  60. package/dist/commands/functions/index.d.ts.map +1 -0
  61. package/dist/commands/functions/index.js +15 -0
  62. package/dist/commands/functions/index.js.map +1 -0
  63. package/dist/commands/functions/list.d.ts +6 -0
  64. package/dist/commands/functions/list.d.ts.map +1 -0
  65. package/dist/commands/functions/list.js +63 -0
  66. package/dist/commands/functions/list.js.map +1 -0
  67. package/dist/commands/functions/new.d.ts +7 -0
  68. package/dist/commands/functions/new.d.ts.map +1 -0
  69. package/dist/commands/functions/new.js +72 -0
  70. package/dist/commands/functions/new.js.map +1 -0
  71. package/dist/commands/gen/index.d.ts +3 -0
  72. package/dist/commands/gen/index.d.ts.map +1 -0
  73. package/dist/commands/gen/index.js +323 -0
  74. package/dist/commands/gen/index.js.map +1 -0
  75. package/dist/commands/guide/index.d.ts +8 -0
  76. package/dist/commands/guide/index.d.ts.map +1 -0
  77. package/dist/commands/guide/index.js +20 -0
  78. package/dist/commands/guide/index.js.map +1 -0
  79. package/dist/commands/instance/index.d.ts +8 -0
  80. package/dist/commands/instance/index.d.ts.map +1 -0
  81. package/dist/commands/instance/index.js +481 -0
  82. package/dist/commands/instance/index.js.map +1 -0
  83. package/dist/commands/login/index.d.ts +3 -0
  84. package/dist/commands/login/index.d.ts.map +1 -0
  85. package/dist/commands/login/index.js +145 -0
  86. package/dist/commands/login/index.js.map +1 -0
  87. package/dist/commands/logout/index.d.ts +3 -0
  88. package/dist/commands/logout/index.d.ts.map +1 -0
  89. package/dist/commands/logout/index.js +41 -0
  90. package/dist/commands/logout/index.js.map +1 -0
  91. package/dist/commands/profile/import-env.d.ts +18 -0
  92. package/dist/commands/profile/import-env.d.ts.map +1 -0
  93. package/dist/commands/profile/import-env.js +206 -0
  94. package/dist/commands/profile/import-env.js.map +1 -0
  95. package/dist/commands/profile/index.d.ts +3 -0
  96. package/dist/commands/profile/index.d.ts.map +1 -0
  97. package/dist/commands/profile/index.js +124 -0
  98. package/dist/commands/profile/index.js.map +1 -0
  99. package/dist/commands/rest/index.d.ts +3 -0
  100. package/dist/commands/rest/index.d.ts.map +1 -0
  101. package/dist/commands/rest/index.js +102 -0
  102. package/dist/commands/rest/index.js.map +1 -0
  103. package/dist/commands/skill/index.d.ts +11 -0
  104. package/dist/commands/skill/index.d.ts.map +1 -0
  105. package/dist/commands/skill/index.js +228 -0
  106. package/dist/commands/skill/index.js.map +1 -0
  107. package/dist/commands/status/index.d.ts +3 -0
  108. package/dist/commands/status/index.d.ts.map +1 -0
  109. package/dist/commands/status/index.js +59 -0
  110. package/dist/commands/status/index.js.map +1 -0
  111. package/dist/commands/storage/index.d.ts +3 -0
  112. package/dist/commands/storage/index.d.ts.map +1 -0
  113. package/dist/commands/storage/index.js +400 -0
  114. package/dist/commands/storage/index.js.map +1 -0
  115. package/dist/commands/tenant/index.d.ts +19 -0
  116. package/dist/commands/tenant/index.d.ts.map +1 -0
  117. package/dist/commands/tenant/index.js +667 -0
  118. package/dist/commands/tenant/index.js.map +1 -0
  119. package/dist/commands/whoami/index.d.ts +3 -0
  120. package/dist/commands/whoami/index.d.ts.map +1 -0
  121. package/dist/commands/whoami/index.js +101 -0
  122. package/dist/commands/whoami/index.js.map +1 -0
  123. package/dist/credentials/commit.d.ts +38 -0
  124. package/dist/credentials/commit.d.ts.map +1 -0
  125. package/dist/credentials/commit.js +57 -0
  126. package/dist/credentials/commit.js.map +1 -0
  127. package/dist/credentials/credential-store.d.ts +86 -0
  128. package/dist/credentials/credential-store.d.ts.map +1 -0
  129. package/dist/credentials/credential-store.js +282 -0
  130. package/dist/credentials/credential-store.js.map +1 -0
  131. package/dist/credentials/env-file.d.ts +85 -0
  132. package/dist/credentials/env-file.d.ts.map +1 -0
  133. package/dist/credentials/env-file.js +193 -0
  134. package/dist/credentials/env-file.js.map +1 -0
  135. package/dist/credentials/formatter.d.ts +39 -0
  136. package/dist/credentials/formatter.d.ts.map +1 -0
  137. package/dist/credentials/formatter.js +79 -0
  138. package/dist/credentials/formatter.js.map +1 -0
  139. package/dist/credentials/index.d.ts +13 -0
  140. package/dist/credentials/index.d.ts.map +1 -0
  141. package/dist/credentials/index.js +13 -0
  142. package/dist/credentials/index.js.map +1 -0
  143. package/dist/credentials/jwt-introspect.d.ts +39 -0
  144. package/dist/credentials/jwt-introspect.d.ts.map +1 -0
  145. package/dist/credentials/jwt-introspect.js +64 -0
  146. package/dist/credentials/jwt-introspect.js.map +1 -0
  147. package/dist/credentials/masker.d.ts +23 -0
  148. package/dist/credentials/masker.d.ts.map +1 -0
  149. package/dist/credentials/masker.js +40 -0
  150. package/dist/credentials/masker.js.map +1 -0
  151. package/dist/credentials/profile.d.ts +95 -0
  152. package/dist/credentials/profile.d.ts.map +1 -0
  153. package/dist/credentials/profile.js +207 -0
  154. package/dist/credentials/profile.js.map +1 -0
  155. package/dist/credentials/tenant-guard.d.ts +16 -0
  156. package/dist/credentials/tenant-guard.d.ts.map +1 -0
  157. package/dist/credentials/tenant-guard.js +53 -0
  158. package/dist/credentials/tenant-guard.js.map +1 -0
  159. package/dist/credentials/tty-guard.d.ts +29 -0
  160. package/dist/credentials/tty-guard.d.ts.map +1 -0
  161. package/dist/credentials/tty-guard.js +79 -0
  162. package/dist/credentials/tty-guard.js.map +1 -0
  163. package/dist/db/apply-schema.d.ts +144 -0
  164. package/dist/db/apply-schema.d.ts.map +1 -0
  165. package/dist/db/apply-schema.js +359 -0
  166. package/dist/db/apply-schema.js.map +1 -0
  167. package/dist/db/introspect.d.ts +54 -0
  168. package/dist/db/introspect.d.ts.map +1 -0
  169. package/dist/db/introspect.js +140 -0
  170. package/dist/db/introspect.js.map +1 -0
  171. package/dist/db/sql-file.d.ts +104 -0
  172. package/dist/db/sql-file.d.ts.map +1 -0
  173. package/dist/db/sql-file.js +584 -0
  174. package/dist/db/sql-file.js.map +1 -0
  175. package/dist/instance/provision.d.ts +89 -0
  176. package/dist/instance/provision.d.ts.map +1 -0
  177. package/dist/instance/provision.js +139 -0
  178. package/dist/instance/provision.js.map +1 -0
  179. package/dist/instance/zero-store.d.ts +47 -0
  180. package/dist/instance/zero-store.d.ts.map +1 -0
  181. package/dist/instance/zero-store.js +91 -0
  182. package/dist/instance/zero-store.js.map +1 -0
  183. package/dist/instance/zero-whitelist.d.ts +39 -0
  184. package/dist/instance/zero-whitelist.d.ts.map +1 -0
  185. package/dist/instance/zero-whitelist.js +67 -0
  186. package/dist/instance/zero-whitelist.js.map +1 -0
  187. package/dist/main.d.ts +3 -0
  188. package/dist/main.d.ts.map +1 -0
  189. package/dist/main.js +69 -0
  190. package/dist/main.js.map +1 -0
  191. package/dist/skill/agents-md.d.ts +25 -0
  192. package/dist/skill/agents-md.d.ts.map +1 -0
  193. package/dist/skill/agents-md.js +62 -0
  194. package/dist/skill/agents-md.js.map +1 -0
  195. package/dist/skill/assets.d.ts +38 -0
  196. package/dist/skill/assets.d.ts.map +1 -0
  197. package/dist/skill/assets.js +111 -0
  198. package/dist/skill/assets.js.map +1 -0
  199. package/dist/skill/hint.d.ts +39 -0
  200. package/dist/skill/hint.d.ts.map +1 -0
  201. package/dist/skill/hint.js +109 -0
  202. package/dist/skill/hint.js.map +1 -0
  203. package/dist/skill/hosts.d.ts +45 -0
  204. package/dist/skill/hosts.d.ts.map +1 -0
  205. package/dist/skill/hosts.js +96 -0
  206. package/dist/skill/hosts.js.map +1 -0
  207. package/dist/skill/installer.d.ts +100 -0
  208. package/dist/skill/installer.d.ts.map +1 -0
  209. package/dist/skill/installer.js +241 -0
  210. package/dist/skill/installer.js.map +1 -0
  211. package/dist/skill/ownership.d.ts +35 -0
  212. package/dist/skill/ownership.d.ts.map +1 -0
  213. package/dist/skill/ownership.js +52 -0
  214. package/dist/skill/ownership.js.map +1 -0
  215. package/dist/tenant/bundle.d.ts +66 -0
  216. package/dist/tenant/bundle.d.ts.map +1 -0
  217. package/dist/tenant/bundle.js +132 -0
  218. package/dist/tenant/bundle.js.map +1 -0
  219. package/dist/tenant/guide.d.ts +50 -0
  220. package/dist/tenant/guide.d.ts.map +1 -0
  221. package/dist/tenant/guide.js +152 -0
  222. package/dist/tenant/guide.js.map +1 -0
  223. package/dist/tenant/probe.d.ts +65 -0
  224. package/dist/tenant/probe.d.ts.map +1 -0
  225. package/dist/tenant/probe.js +159 -0
  226. package/dist/tenant/probe.js.map +1 -0
  227. package/dist/tenant/verify.d.ts +37 -0
  228. package/dist/tenant/verify.d.ts.map +1 -0
  229. package/dist/tenant/verify.js +132 -0
  230. package/dist/tenant/verify.js.map +1 -0
  231. package/dist/version.d.ts +29 -0
  232. package/dist/version.d.ts.map +1 -0
  233. package/dist/version.js +65 -0
  234. package/dist/version.js.map +1 -0
  235. package/package.json +63 -3
  236. package/skills/pxbaas-app-spec/SKILL.md +165 -0
  237. package/skills/pxbaas-app-spec/references/deploy-options.md +158 -0
  238. package/skills/pxbaas-app-spec/references/guardrails-pitfalls.md +89 -0
  239. package/skills/pxbaas-app-spec/references/runtime-contract.md +151 -0
  240. package/skills/pxbaas-app-spec/references/ssr-session.md +121 -0
  241. package/skills/pxbaas-app-spec/references/templates-examples.md +311 -0
  242. package/skills/pxbaas-cli/SKILL.md +186 -0
  243. package/skills/pxbaas-cli/references/api-reference.md +68 -0
  244. package/skills/pxbaas-cli/references/app-deploy.md +186 -0
  245. package/skills/pxbaas-cli/references/auth-and-credentials.md +116 -0
  246. package/skills/pxbaas-cli/references/data-postgrest.md +101 -0
  247. package/skills/pxbaas-cli/references/db-and-meta.md +102 -0
  248. package/skills/pxbaas-cli/references/edge-functions.md +71 -0
  249. package/skills/pxbaas-cli/references/multi-tenant-apps.md +138 -0
  250. package/skills/pxbaas-cli/references/provision.md +101 -0
  251. package/skills/pxbaas-cli/references/safety-and-two-phase.md +78 -0
  252. package/skills/pxbaas-cli/references/storage.md +61 -0
  253. package/skills/pxbaas-cli/references/tenant-admin.md +122 -0
  254. package/skills/pxbaas-cli/references/troubleshooting.md +76 -0
  255. package/templates/webapp/api/index.ts +55 -0
  256. package/templates/webapp/csr-bff/README.md +81 -0
  257. package/templates/webapp/csr-bff/backend/index.ts +168 -0
  258. package/templates/webapp/csr-bff/db/rls.json +13 -0
  259. package/templates/webapp/csr-bff/db/schema.sql +49 -0
  260. package/templates/webapp/csr-bff/frontend/dist/admin.html +101 -0
  261. package/templates/webapp/csr-bff/frontend/dist/article.html +44 -0
  262. package/templates/webapp/csr-bff/frontend/dist/blog.js +206 -0
  263. package/templates/webapp/csr-bff/frontend/dist/blogger.html +53 -0
  264. package/templates/webapp/csr-bff/frontend/dist/index.html +70 -0
  265. package/templates/webapp/csr-bff/frontend/dist/login.html +56 -0
  266. package/templates/webapp/csr-bff/frontend/dist/profile.html +59 -0
  267. package/templates/webapp/csr-bff/frontend/dist/signup.html +78 -0
  268. package/templates/webapp/csr-bff/frontend/dist/style.css +27 -0
  269. package/templates/webapp/manifest.json +419 -0
  270. package/templates/webapp/mpa/about.html +29 -0
  271. package/templates/webapp/mpa/app.js +42 -0
  272. package/templates/webapp/mpa/index.html +42 -0
  273. package/templates/webapp/mpa/index.ts +60 -0
  274. package/templates/webapp/mpa/style.css +42 -0
  275. package/templates/webapp/react-vite/frontend/index.html +12 -0
  276. package/templates/webapp/react-vite/frontend/package-lock.json +1826 -0
  277. package/templates/webapp/react-vite/frontend/package.json +23 -0
  278. package/templates/webapp/react-vite/frontend/src/App.tsx +34 -0
  279. package/templates/webapp/react-vite/frontend/src/main.tsx +13 -0
  280. package/templates/webapp/react-vite/frontend/src/style.css +46 -0
  281. package/templates/webapp/react-vite/frontend/tsconfig.json +20 -0
  282. package/templates/webapp/react-vite/frontend/vite.config.ts +10 -0
  283. package/templates/webapp/react-vite-hono/backend/index.ts +38 -0
  284. package/templates/webapp/react-vite-hono/frontend/index.html +12 -0
  285. package/templates/webapp/react-vite-hono/frontend/package-lock.json +1826 -0
  286. package/templates/webapp/react-vite-hono/frontend/package.json +23 -0
  287. package/templates/webapp/react-vite-hono/frontend/src/App.tsx +47 -0
  288. package/templates/webapp/react-vite-hono/frontend/src/main.tsx +13 -0
  289. package/templates/webapp/react-vite-hono/frontend/src/style.css +66 -0
  290. package/templates/webapp/react-vite-hono/frontend/tsconfig.json +20 -0
  291. package/templates/webapp/react-vite-hono/frontend/vite.config.ts +10 -0
  292. package/templates/webapp/spa/index.ts +119 -0
  293. package/templates/webapp/ssr-auth/backend/index.ts +133 -0
  294. package/templates/webapp/ssr-auth/frontend/dist/index.html +15 -0
  295. package/templates/webapp/ssr-blog/README.md +111 -0
  296. package/templates/webapp/ssr-blog/backend/index.ts +764 -0
  297. package/templates/webapp/ssr-blog/db/rls.json +13 -0
  298. package/templates/webapp/ssr-blog/db/schema.sql +51 -0
  299. package/templates/webapp/ssr-blog/frontend/dist/index.html +39 -0
  300. package/templates/webapp/ssr-frameworks/README.md +64 -0
  301. package/templates/webapp/ssr-frameworks/backend/index.ts +241 -0
  302. package/templates/webapp/ssr-frameworks/frontend/dist/index.html +31 -0
  303. package/templates/webapp/ssr-hono/backend/index.ts +111 -0
  304. package/templates/webapp/ssr-hono/frontend/dist/index.html +12 -0
  305. package/templates/webapp/ssr-shop/README.md +80 -0
  306. package/templates/webapp/ssr-shop/backend/index.ts +491 -0
  307. package/templates/webapp/ssr-shop/db/rls.json +16 -0
  308. package/templates/webapp/ssr-shop/db/schema.sql +90 -0
  309. package/templates/webapp/ssr-shop/frontend/dist/index.html +12 -0
  310. package/templates/webapp/vanilla-static/frontend/dist/app.js +6 -0
  311. package/templates/webapp/vanilla-static/frontend/dist/index.html +19 -0
  312. package/templates/webapp/vanilla-static/frontend/dist/style.css +43 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * 多租户接入缺口的诊断与引导(方案文档 §5.4)。
3
+ *
4
+ * 原来 `profile import` 撞到"多租户 env 却没有租户级凭据"时只抛一句拒绝,而它给出的
5
+ * 两个建议("重新生成 client.env"、"用 per-tenant key 登录")**都是使用者自己做不到**
6
+ * 的动作——租户级密钥由平台签发。结果是 CLI 把用户堵在门口,还让他以为是自己的错。
7
+ *
8
+ * 本模块把这一处变成两条明确出口:
9
+ * - 非管理员 → 一份可以直接转给实例管理员的**申请清单**(要哪个租户、哪两把值、
10
+ * 以及怎么判断拿到的到底是不是租户级密钥);
11
+ * - 具备管理面能力 → 指出可以用 `pxbaas tenant ...` 自助开通/取键,并给出命令。
12
+ *
13
+ * 边界:这里**只读、只打印**,绝不在失败分支里创建租户(读路径不携带建库/建账号/
14
+ * 占配额这类写副作用,见方案 N2)。管理凭据也只做**临时**探测,绝不落库(N3)。
15
+ */
16
+ import { computeFingerprint, decodeJwt } from '../credentials/index.js';
17
+ import { resolveAdminFromEnv } from '../credentials/env-file.js';
18
+ import { probeTenantAdmin } from './probe.js';
19
+ /** 判据用的候选变量:先看租户级,再看会被误当租户级的平台全局级。 */
20
+ const KEY_CANDIDATES = [
21
+ 'TENANT_ANON_KEY',
22
+ 'TENANT_SERVICE_ROLE_KEY',
23
+ 'SUPABASE_ANON_KEY',
24
+ 'ANON_KEY',
25
+ 'GLOBAL_ANON_KEY',
26
+ 'SUPABASE_SERVICE_ROLE_KEY',
27
+ 'SERVICE_ROLE_KEY',
28
+ 'GLOBAL_SERVICE_ROLE_KEY',
29
+ ];
30
+ /** 纯本地解析:不联网、不写任何状态。 */
31
+ export function diagnoseTenantCredentialGap(env, options = {}) {
32
+ const keyFindings = [];
33
+ const tenantLevelKeysPresent = [];
34
+ for (const variable of KEY_CANDIDATES) {
35
+ const value = (env[variable] ?? '').trim();
36
+ if (!value)
37
+ continue;
38
+ const parts = value.split('.');
39
+ // 与 whoami / tenant 同一套展示口径:sha256 前 8 + 后 4,前缀只在这一处加。
40
+ const fingerprint = computeFingerprint(value);
41
+ let role;
42
+ let tenantId;
43
+ let expired = false;
44
+ let note = 'Value is not a JWT (three dot-separated parts expected) — cannot be a Supabase-style API key.';
45
+ if (parts.length === 3) {
46
+ try {
47
+ const payload = decodeJwt(value);
48
+ role = payload.role;
49
+ tenantId = payload.tenant_id;
50
+ expired = typeof payload.exp === 'number' && payload.exp * 1000 <= Date.now();
51
+ note = tenantId
52
+ ? `Tenant-level key for tenant "${tenantId}"${expired ? ' (EXPIRED)' : ''}`
53
+ : `Platform-global key (no tenant_id claim)${expired ? ' (EXPIRED)' : ''} — cannot reach tenant resources`;
54
+ }
55
+ catch (error) {
56
+ note = `JWT payload unparsable: ${error instanceof Error ? error.message : String(error)}`;
57
+ }
58
+ }
59
+ if (/^TENANT_/.test(variable))
60
+ tenantLevelKeysPresent.push(variable);
61
+ keyFindings.push({ variable, role, tenantId, expired, fingerprint, note });
62
+ }
63
+ const endpoint = firstNonEmpty([
64
+ env.SUPABASE_URL,
65
+ env.SUPABASE_PUBLIC_URL,
66
+ env.SUPABASE_INTRANET_URL,
67
+ ]);
68
+ return {
69
+ envFile: options.envFile,
70
+ endpoint,
71
+ multiTenantMode: firstNonEmpty([env.MULTI_TENANT_MODE]),
72
+ defaultTenantId: firstNonEmpty([env.DEFAULT_TENANT_ID]),
73
+ tenantLevelKeysPresent,
74
+ keyFindings,
75
+ adminCredentialsPresent: Boolean(resolveAdminFromEnv(env)),
76
+ };
77
+ }
78
+ /** 非管理员出口:一份可原样转给实例管理员的申请清单。 */
79
+ export function renderRequestChecklist(diag) {
80
+ const lines = [
81
+ '你需要的不是新建租户,而是**某个租户的两把 per-tenant 密钥**。请向实例管理员申请:',
82
+ '',
83
+ ` tenant_id: ${diag.defaultTenantId ?? '<要访问的租户 ID>'}`,
84
+ ' anon key: (JWT payload 必须含 tenant_id)',
85
+ ' service role key: (同上)',
86
+ ` 实例端点: ${diag.endpoint ?? '<Kong 网关地址,通常是 :8000>'}`,
87
+ '',
88
+ '拿到后请写成这样一份接入包(变量名必须逐字一致),再导入:',
89
+ '',
90
+ ' MULTI_TENANT_MODE=true',
91
+ ` SUPABASE_URL=${diag.endpoint ?? 'https://<网关地址>'}`,
92
+ ` DEFAULT_TENANT_ID=${diag.defaultTenantId ?? '<租户 ID>'}`,
93
+ ' TENANT_ANON_KEY=<粘贴 anon key>',
94
+ ' TENANT_SERVICE_ROLE_KEY=<粘贴 service role key>',
95
+ '',
96
+ ` pxbaas profile import ./<租户>.pxbaas.env --name <租户> --json`,
97
+ ' pxbaas whoami --json # 期望 mode=multi-tenant 且 tenantId 正确',
98
+ '',
99
+ '自检判据(拿到密钥先解码看一眼,能立刻分辨管理员给的是不是租户级密钥):',
100
+ " printf '%s' \"$TENANT_ANON_KEY\" | cut -d. -f2 | base64 -d",
101
+ ' → payload 里必须出现 "tenant_id":"<租户ID>";没有就是平台全局密钥,用不了。',
102
+ ];
103
+ if (diag.adminCredentialsPresent) {
104
+ lines.push('', '注意:这份 env 里带着 DASHBOARD_USERNAME / DASHBOARD_PASSWORD(实例管理面口令)。', '按安全设计它们不会被导入。若这份文件原本来自管理员,请改由管理员用', '"pxbaas tenant login" + "pxbaas tenant keys <id> --bundle <file>" 正规发放接入包。');
105
+ }
106
+ return lines.join('\n');
107
+ }
108
+ /** 管理员出口:指出可以自助的动作与命令。 */
109
+ export function renderAdminPath(diag, probe) {
110
+ const endpoint = diag.endpoint ?? probe.endpoint;
111
+ const tenant = diag.defaultTenantId;
112
+ const lines = [
113
+ '本机凭据可打开该实例的租户管理面。可以选择自助处理(CLI 不会替你建租户,需显式执行):',
114
+ '',
115
+ ` pxbaas tenant login --endpoint ${endpoint} # 绑定管理凭据(口令走掩码或 stdin,不进 argv)`,
116
+ ' pxbaas tenant ls --json # 看这个实例上到底有哪些租户',
117
+ ];
118
+ if (tenant) {
119
+ lines.push(` pxbaas tenant keys ${tenant} --admin --as-profile # 已有该租户:直接把它的密钥绑进本机钥匙串`, ` pxbaas tenant keys ${tenant} --admin --bundle ./${tenant}.pxbaas.env # 要交给别人:生成规范接入包`, ` pxbaas tenant create ${tenant} --dry-run # 确实需要新租户时先看计划`);
120
+ }
121
+ else {
122
+ lines.push(' pxbaas tenant create <tenant-id> --dry-run # 需要新租户时先看计划');
123
+ }
124
+ lines.push('', ' 提示:先跑 tenant ls 再决定建不建——多数情况该做的是取回已有租户的密钥,', ' 而不是造一个新租户。');
125
+ return lines.join('\n');
126
+ }
127
+ /**
128
+ * 用 env 里的 dashboard 凭据做一次**临时**探测:只在内存里使用,不落库、不写文件。
129
+ * 没有成对凭据时返回 undefined(调用方走非管理员出口)。
130
+ */
131
+ export async function tryProbeFromEnv(env, endpoint) {
132
+ if (!endpoint)
133
+ return undefined;
134
+ const admin = resolveAdminFromEnv(env);
135
+ if (!admin)
136
+ return undefined;
137
+ try {
138
+ return await probeTenantAdmin({ endpoint, username: admin.username, password: admin.password });
139
+ }
140
+ catch {
141
+ // 探测本身失败不该掩盖原始报错:按"不具备管理面"处理即可。
142
+ return undefined;
143
+ }
144
+ }
145
+ function firstNonEmpty(values) {
146
+ for (const value of values) {
147
+ if (typeof value === 'string' && value.trim())
148
+ return value.trim();
149
+ }
150
+ return undefined;
151
+ }
152
+ //# sourceMappingURL=guide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guide.js","sourceRoot":"","sources":["../../src/tenant/guide.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * 平台管理面能力探测(tenant probe)。
3
+ *
4
+ * 为什么要它:`profile import` / `login` 撞墙时,CLI 必须先知道"这个人到底是不是
5
+ * 管理员"才能给出正确的下一步。判据不能用"本机有没有 DASHBOARD_* 凭据"——持有凭据
6
+ * 与被授予权限是两件事(运维把服务端全量 env 发给客户排查问题,客户就"被管理员"了)。
7
+ * 所以这里用一次**只读**调用去问平台,按回答分流。
8
+ *
9
+ * 关键陷阱(方案文档 G3):Studio 的列表接口在「元数据查询失败」时同样返回
10
+ * `200 + { tenants: [], multiTenantMode: true }`(见 pages/api/platform/tenants/index.ts
11
+ * 的三处 200 空返回)。只看 HTTP 状态会把"平台库有问题/存量 schema 漂移"误报成
12
+ * "你没有权限 / 这个实例没有租户"。本模块用详情接口做二次判别:
13
+ * GET /api/platform/tenants/{不存在的 id}
14
+ * → 404 = 查询链路健康 ⇒ 空列表确实是"没有租户"
15
+ * → 500 = 查询本身失败 ⇒ 元数据不可读(多半是 schema 漂移)
16
+ * 这条判据来自 [id].ts 的实现(result.error → 500,未找到 → 404),非猜测。
17
+ */
18
+ import { type RedactedTenant } from '@polardbx/pxbaas-client';
19
+ export type ProbeStatus =
20
+ /** 具备平台管理面能力 */
21
+ 'admin'
22
+ /** 凭据无效/无权限(401/403) */
23
+ | 'not-admin'
24
+ /** 该实例不是多租户实例(multiTenantMode=false) */
25
+ | 'single-tenant'
26
+ /** 元数据不可读:列表为空且详情探测失败(G3/G5) */
27
+ | 'metadata-unreadable'
28
+ /** 网络不可达 / 端点错误 */
29
+ | 'unreachable';
30
+ export interface TenantProbeResult {
31
+ status: ProbeStatus;
32
+ /** 是否可执行租户管理写操作。仅 admin 为 true。 */
33
+ adminCapable: boolean;
34
+ endpoint: string;
35
+ multiTenantMode: boolean;
36
+ /** 仅 admin / metadata-unreadable 时可能有值(后者通常为空)。 */
37
+ tenants?: RedactedTenant[];
38
+ /** 一句话结论,可直接进诊断输出。 */
39
+ detail: string;
40
+ /** 归一化错误码(TENANT_ADMIN_UNAUTHORIZED 等),便于 --json 消费方分支。 */
41
+ errorCode?: string;
42
+ }
43
+ export interface AdminContext {
44
+ endpoint: string;
45
+ username: string;
46
+ password: string;
47
+ profileName: string;
48
+ }
49
+ /**
50
+ * 从当前(或指定)profile 的钥匙串账目里取管理凭据。
51
+ * 缺失时抛可直接展示的错误 —— 调用方不需要再判断"是 CLI 坏了还是没登录"。
52
+ */
53
+ export declare function loadAdminContext(options?: {
54
+ profile?: string;
55
+ }): Promise<AdminContext>;
56
+ export interface ProbeInput {
57
+ endpoint: string;
58
+ username: string;
59
+ password: string;
60
+ /** 探测用租户列表的条数上限无关;此值仅用于详情判别的超时。 */
61
+ timeout?: number;
62
+ }
63
+ /** 用给定凭据探测管理面能力。纯只读:不会发出任何写请求。 */
64
+ export declare function probeTenantAdmin(input: ProbeInput): Promise<TenantProbeResult>;
65
+ //# sourceMappingURL=probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/tenant/probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAMjC,MAAM,MAAM,WAAW;AACrB,gBAAgB;AACd,OAAO;AACT,wBAAwB;GACtB,WAAW;AACb,wCAAwC;GACtC,eAAe;AACjB,gCAAgC;GAC9B,qBAAqB;AACvB,mBAAmB;GACjB,aAAa,CAAC;AAElB,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,mCAAmC;IACnC,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,mDAAmD;IACnD,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CA8BhG;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,kCAAkC;AAClC,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkEpF"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * 平台管理面能力探测(tenant probe)。
3
+ *
4
+ * 为什么要它:`profile import` / `login` 撞墙时,CLI 必须先知道"这个人到底是不是
5
+ * 管理员"才能给出正确的下一步。判据不能用"本机有没有 DASHBOARD_* 凭据"——持有凭据
6
+ * 与被授予权限是两件事(运维把服务端全量 env 发给客户排查问题,客户就"被管理员"了)。
7
+ * 所以这里用一次**只读**调用去问平台,按回答分流。
8
+ *
9
+ * 关键陷阱(方案文档 G3):Studio 的列表接口在「元数据查询失败」时同样返回
10
+ * `200 + { tenants: [], multiTenantMode: true }`(见 pages/api/platform/tenants/index.ts
11
+ * 的三处 200 空返回)。只看 HTTP 状态会把"平台库有问题/存量 schema 漂移"误报成
12
+ * "你没有权限 / 这个实例没有租户"。本模块用详情接口做二次判别:
13
+ * GET /api/platform/tenants/{不存在的 id}
14
+ * → 404 = 查询链路健康 ⇒ 空列表确实是"没有租户"
15
+ * → 500 = 查询本身失败 ⇒ 元数据不可读(多半是 schema 漂移)
16
+ * 这条判据来自 [id].ts 的实现(result.error → 500,未找到 → 404),非猜测。
17
+ */
18
+ import { TenantAdminDriver, TenantAdminError, } from '@polardbx/pxbaas-client';
19
+ import { CredentialStore, ProfileManager } from '../credentials/index.js';
20
+ /** 探测用的哨兵租户 ID:合法字符集内、且按命名规范不可能真实存在。 */
21
+ const METADATA_PROBE_ID = '__pxbaas_probe__';
22
+ /**
23
+ * 从当前(或指定)profile 的钥匙串账目里取管理凭据。
24
+ * 缺失时抛可直接展示的错误 —— 调用方不需要再判断"是 CLI 坏了还是没登录"。
25
+ */
26
+ export async function loadAdminContext(options = {}) {
27
+ const profiles = new ProfileManager();
28
+ const profile = options.profile
29
+ ? await profiles.getProfile(options.profile)
30
+ : await profiles.getCurrentProfile();
31
+ if (!profile) {
32
+ throw new Error(options.profile
33
+ ? `Profile '${options.profile}' not found. Run "pxbaas profile ls" to list profiles.`
34
+ : 'No active profile. Run "pxbaas login" or "pxbaas tenant login --endpoint <url>" first.');
35
+ }
36
+ const store = new CredentialStore();
37
+ const admin = await store.getAdminCredentials(profile.name);
38
+ if (!admin) {
39
+ throw new Error(`Profile '${profile.name}' has no platform admin credentials. ` +
40
+ `Run "pxbaas tenant login --endpoint ${profile.endpoint}" (or add --with-admin to "pxbaas profile import") ` +
41
+ `with the instance dashboard credentials.`);
42
+ }
43
+ return {
44
+ endpoint: profile.endpoint,
45
+ username: admin.username,
46
+ password: admin.password,
47
+ profileName: profile.name,
48
+ };
49
+ }
50
+ /** 用给定凭据探测管理面能力。纯只读:不会发出任何写请求。 */
51
+ export async function probeTenantAdmin(input) {
52
+ const driver = new TenantAdminDriver({
53
+ endpoint: input.endpoint,
54
+ username: input.username,
55
+ password: input.password,
56
+ timeout: input.timeout,
57
+ });
58
+ let tenants;
59
+ let multiTenantMode;
60
+ try {
61
+ const listed = await driver.list();
62
+ tenants = listed.tenants;
63
+ multiTenantMode = listed.multiTenantMode;
64
+ }
65
+ catch (error) {
66
+ return classifyFailure(input.endpoint, error);
67
+ }
68
+ if (!multiTenantMode) {
69
+ return {
70
+ status: 'single-tenant',
71
+ adminCapable: false,
72
+ endpoint: input.endpoint,
73
+ multiTenantMode: false,
74
+ detail: 'This instance is not in multi-tenant mode (multiTenantMode=false). Tenant administration does not apply here.',
75
+ };
76
+ }
77
+ if (tenants.length === 0) {
78
+ // 空列表有两种成因,必须用详情接口判别,否则会把平台故障报成"没有租户"。
79
+ const health = await probeMetadataHealth(driver);
80
+ if (!health.readable) {
81
+ return {
82
+ status: 'metadata-unreadable',
83
+ adminCapable: false,
84
+ endpoint: input.endpoint,
85
+ multiTenantMode: true,
86
+ tenants: [],
87
+ errorCode: health.errorCode,
88
+ detail: 'Credentials are accepted, but the tenant metadata could not be read ' +
89
+ `(${health.errorCode ?? 'unknown error'}). On long-lived instances this usually means schema drift ` +
90
+ '(e.g. a missing column in _platform.tenants) rather than an empty tenant list. ' +
91
+ 'Verify with the platform operator before retrying.',
92
+ };
93
+ }
94
+ return {
95
+ status: 'admin',
96
+ adminCapable: true,
97
+ endpoint: input.endpoint,
98
+ multiTenantMode: true,
99
+ tenants: [],
100
+ detail: 'Admin channel works. This instance has no tenants yet — you can create the first one with "pxbaas tenant create".',
101
+ };
102
+ }
103
+ return {
104
+ status: 'admin',
105
+ adminCapable: true,
106
+ endpoint: input.endpoint,
107
+ multiTenantMode: true,
108
+ tenants,
109
+ detail: `Admin channel works. ${tenants.length} tenant(s) visible on this instance.`,
110
+ };
111
+ }
112
+ async function probeMetadataHealth(driver) {
113
+ try {
114
+ await driver.get(METADATA_PROBE_ID);
115
+ // 哨兵 ID 竟然存在:极不可能,但存在即说明查询链路是通的。
116
+ return { readable: true };
117
+ }
118
+ catch (error) {
119
+ if (error instanceof TenantAdminError) {
120
+ // 404 ⇒ 查询执行成功且没找到 ⇒ 链路健康
121
+ if (error.code === 'TENANT_NOT_FOUND')
122
+ return { readable: true, errorCode: error.code };
123
+ return { readable: false, errorCode: error.code };
124
+ }
125
+ return { readable: false };
126
+ }
127
+ }
128
+ function classifyFailure(endpoint, error) {
129
+ const adminError = error instanceof TenantAdminError
130
+ ? error
131
+ : new TenantAdminError('TENANT_ADMIN_UNKNOWN_ERROR', error instanceof Error ? error.message : String(error));
132
+ if (adminError.code === 'TENANT_ADMIN_UNAUTHORIZED' || adminError.code === 'TENANT_ADMIN_FORBIDDEN') {
133
+ return {
134
+ status: 'not-admin',
135
+ adminCapable: false,
136
+ endpoint,
137
+ multiTenantMode: false,
138
+ errorCode: adminError.code,
139
+ detail: 'These credentials are not accepted by the tenant admin channel ' +
140
+ `(${adminError.code}, HTTP ${adminError.status ?? 'n/a'}). ` +
141
+ 'Tenant administration needs the instance dashboard credentials, not an API key.',
142
+ };
143
+ }
144
+ // 注意:多租户关闭的信号是列表响应里的 `multiTenantMode: false`(GET 集合接口对
145
+ // 非多租户实例返回 200 + 空数组),**不是** HTTP 400 —— 400 只出现在写操作分支
146
+ // ("Multi-tenant mode is not enabled")。所以这里不能把 400 解读成单租户实例,
147
+ // 否则等于凭一个猜测替用户下结论。400 归到"端点没按预期应答"。
148
+ return {
149
+ status: 'unreachable',
150
+ adminCapable: false,
151
+ endpoint,
152
+ multiTenantMode: false,
153
+ errorCode: adminError.code,
154
+ detail: adminError.code === 'TENANT_ADMIN_BAD_REQUEST'
155
+ ? `Tenant admin channel answered 400: ${adminError.message}. This instance did not report multi-tenant mode, so no tenant operation was attempted.`
156
+ : `Tenant admin channel could not be reached: ${adminError.message}`,
157
+ };
158
+ }
159
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../../src/tenant/probe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 建租户后的验证闭环(方案文档 G4)。
3
+ *
4
+ * 平台侧的建租户接口会把「建库 / 建账号 / GRANT / 租户库内 RLS 表 / Realtime 注册」
5
+ * 全部当作**非致命**步骤:任何一步失败只 console.error,HTTP 仍然返回 201
6
+ * (pages/api/platform/tenants/index.ts:265 起)。也就是说"创建成功"并不等于
7
+ * "这个租户可用"。CLI 若在 create 之后直接报成功,管理员就会把平台缺陷当成 CLI 的 bug。
8
+ *
9
+ * 这里用新签发的**租户自己的** service_role key 走一遍租户自助 DDL 通道,逐项确认:
10
+ * 1. SELECT DATABASE() ⇒ 密钥有效、租户处于 active、自助 DDL 通道可用,并拿到真实库名
11
+ * 2. information_schema 计数 ⇒ 租户库确实存在且可内省(0 张表对新租户是正常的)
12
+ * 3. RLS 注册表可读 ⇒ 中心 RLS 元数据对该租户可达(RLS 落库的前置条件)
13
+ * 三条都是只读语句,不改变任何状态。
14
+ */
15
+ export type VerifyStatus = 'pass' | 'fail' | 'skip';
16
+ export interface VerifyStep {
17
+ name: string;
18
+ status: VerifyStatus;
19
+ detail: string;
20
+ /** 失败时给管理员的可执行补救建议。 */
21
+ remediation?: string;
22
+ }
23
+ export interface VerifyTenantResult {
24
+ ok: boolean;
25
+ /** 租户实际生效的库名(来自 SELECT DATABASE(),非拼接推断)。 */
26
+ dbName?: string;
27
+ steps: VerifyStep[];
28
+ }
29
+ export interface VerifyTenantInput {
30
+ endpoint: string;
31
+ serviceRoleKey: string;
32
+ /** create 响应里的 realtime_provisioned;为 false 时记为 warn 级步骤(平台侧非致命)。 */
33
+ realtimeProvisioned?: boolean;
34
+ timeout?: number;
35
+ }
36
+ export declare function verifyTenantUsable(input: VerifyTenantInput): Promise<VerifyTenantResult>;
37
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/tenant/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,OAAO,CAAC;IACZ,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkH9F"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * 建租户后的验证闭环(方案文档 G4)。
3
+ *
4
+ * 平台侧的建租户接口会把「建库 / 建账号 / GRANT / 租户库内 RLS 表 / Realtime 注册」
5
+ * 全部当作**非致命**步骤:任何一步失败只 console.error,HTTP 仍然返回 201
6
+ * (pages/api/platform/tenants/index.ts:265 起)。也就是说"创建成功"并不等于
7
+ * "这个租户可用"。CLI 若在 create 之后直接报成功,管理员就会把平台缺陷当成 CLI 的 bug。
8
+ *
9
+ * 这里用新签发的**租户自己的** service_role key 走一遍租户自助 DDL 通道,逐项确认:
10
+ * 1. SELECT DATABASE() ⇒ 密钥有效、租户处于 active、自助 DDL 通道可用,并拿到真实库名
11
+ * 2. information_schema 计数 ⇒ 租户库确实存在且可内省(0 张表对新租户是正常的)
12
+ * 3. RLS 注册表可读 ⇒ 中心 RLS 元数据对该租户可达(RLS 落库的前置条件)
13
+ * 三条都是只读语句,不改变任何状态。
14
+ */
15
+ import { TenantDdlDriver, TenantDdlError } from '@polardbx/pxbaas-client';
16
+ export async function verifyTenantUsable(input) {
17
+ const driver = new TenantDdlDriver({
18
+ endpoint: input.endpoint,
19
+ serviceRoleKey: input.serviceRoleKey,
20
+ timeout: input.timeout ?? 30_000,
21
+ });
22
+ const steps = [];
23
+ let dbName;
24
+ // 1) 租户自助 DDL 通道 + 密钥有效性
25
+ let channelOk = false;
26
+ try {
27
+ const rows = (await driver.query('SELECT DATABASE() AS db'));
28
+ const value = rows?.[0]?.db;
29
+ dbName = typeof value === 'string' && value ? value : undefined;
30
+ channelOk = Boolean(dbName);
31
+ steps.push({
32
+ name: 'Tenant DDL channel',
33
+ status: channelOk ? 'pass' : 'fail',
34
+ detail: channelOk
35
+ ? `Connected as tenant database "${dbName}"`
36
+ : 'SELECT DATABASE() returned no database name',
37
+ remediation: channelOk
38
+ ? undefined
39
+ : 'Verify the tenant is active and that the key belongs to this tenant (pxbaas doctor --json).',
40
+ });
41
+ }
42
+ catch (error) {
43
+ steps.push({
44
+ name: 'Tenant DDL channel',
45
+ status: 'fail',
46
+ detail: describe(error),
47
+ remediation: 'The tenant database or its account may not have been provisioned. Platform-side tenant creation treats those steps as non-fatal, so a 201 response does not guarantee a usable tenant — ask the operator to check the tenant db, user and GRANT.',
48
+ });
49
+ }
50
+ // 2) 库可内省(存在性代理判据:能查 information_schema 即库已在)
51
+ if (channelOk) {
52
+ try {
53
+ const rows = (await driver.query('SELECT COUNT(*) AS t FROM information_schema.tables WHERE table_schema = DATABASE()'));
54
+ const count = Number(rows?.[0]?.t ?? NaN);
55
+ steps.push({
56
+ name: 'Tenant database introspectable',
57
+ status: Number.isFinite(count) ? 'pass' : 'fail',
58
+ detail: Number.isFinite(count)
59
+ ? `${count} table(s) currently in "${dbName}"`
60
+ : 'Count query returned an unexpected shape',
61
+ });
62
+ }
63
+ catch (error) {
64
+ steps.push({
65
+ name: 'Tenant database introspectable',
66
+ status: 'fail',
67
+ detail: describe(error),
68
+ remediation: 'Create tables with "pxbaas db push <file>" or "pxbaas app db-init <name>".',
69
+ });
70
+ }
71
+ }
72
+ else {
73
+ steps.push({
74
+ name: 'Tenant database introspectable',
75
+ status: 'skip',
76
+ detail: 'Skipped because the DDL channel is not usable.',
77
+ });
78
+ }
79
+ // 3) 中心 RLS 注册表对该租户可达
80
+ if (channelOk) {
81
+ try {
82
+ const tables = await driver.listRlsTables();
83
+ steps.push({
84
+ name: 'RLS registry reachable',
85
+ status: 'pass',
86
+ detail: `${tables.length} RLS-registered table(s) for this tenant`,
87
+ });
88
+ }
89
+ catch (error) {
90
+ steps.push({
91
+ name: 'RLS registry reachable',
92
+ status: 'fail',
93
+ detail: describe(error),
94
+ remediation: 'RLS metadata may not be initialized for this tenant. Register policies through "pxbaas db push --rls db/rls.json" (multi-tenant binds table_schema server-side).',
95
+ });
96
+ }
97
+ }
98
+ else {
99
+ steps.push({ name: 'RLS registry reachable', status: 'skip', detail: 'Skipped (channel unavailable).' });
100
+ }
101
+ // 4) Realtime 注册(平台侧非致命;false 时该租户 WS 握手会 403)
102
+ if (input.realtimeProvisioned === undefined) {
103
+ steps.push({
104
+ name: 'Realtime registration',
105
+ status: 'skip',
106
+ detail: 'Not reported by this endpoint (only the create response carries it).',
107
+ });
108
+ }
109
+ else {
110
+ steps.push({
111
+ name: 'Realtime registration',
112
+ status: input.realtimeProvisioned ? 'pass' : 'fail',
113
+ detail: input.realtimeProvisioned
114
+ ? 'Tenant registered for Realtime'
115
+ : 'Realtime registration failed (platform-side, non-fatal for REST/Auth)',
116
+ remediation: input.realtimeProvisioned
117
+ ? undefined
118
+ : 'WebSocket subscriptions for this tenant will be rejected until it is registered in Realtime; ask the operator to re-run registration.',
119
+ });
120
+ }
121
+ return {
122
+ ok: steps.every((step) => step.status !== 'fail'),
123
+ dbName,
124
+ steps,
125
+ };
126
+ }
127
+ function describe(error) {
128
+ if (error instanceof TenantDdlError)
129
+ return `${error.code}: ${error.message}`;
130
+ return error instanceof Error ? error.message : String(error);
131
+ }
132
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/tenant/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Runtime CLI version resolution.
3
+ *
4
+ * `npm run build` is a plain `tsc --build`, so there is no bundler step that
5
+ * could inline `package.json#version` into the emitted JS — and adding one is
6
+ * out of the question for a build pipeline this simple. Read the manifest from
7
+ * disk instead, walking up from this module so every supported layout works:
8
+ *
9
+ * - source tree : <pkg>/dist/version.js -> <pkg>/package.json
10
+ * - npm install : node_modules/@polardbx/pxbaas/dist/version.js -> .../package.json
11
+ *
12
+ * The walk-up must not stop at the first manifest it finds: in a monorepo the
13
+ * workspace root (`cli/package.json`, version `0.0.0-dev`) is also an ancestor,
14
+ * which is exactly how `--version` used to report a version nobody published.
15
+ * Only the manifest that owns this package (matching `name`, or declaring the
16
+ * `pxbaas` bin) counts.
17
+ *
18
+ * Never throws: an unreadable manifest must not stop `pxbaas --help`.
19
+ */
20
+ export declare const PACKAGE_NAME = "@polardbx/pxbaas";
21
+ /** Reported when no owning manifest can be found (e.g. a single-file bundle). */
22
+ export declare const UNKNOWN_VERSION = "0.0.0-unknown";
23
+ /**
24
+ * The published version of this CLI, or {@link UNKNOWN_VERSION} when it cannot be
25
+ * determined. Synchronous on purpose: commander's `.version()` is wired up at
26
+ * module scope, before any await could run.
27
+ */
28
+ export declare function resolvePackageVersion(startDir?: string): string;
29
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,eAAO,MAAM,YAAY,qBAAqB,CAAC;AAE/C,iFAAiF;AACjF,eAAO,MAAM,eAAe,kBAAkB,CAAC;AA8B/C;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,GAAE,MAAoB,GAAG,MAAM,CAY5E"}