@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.
Files changed (180) hide show
  1. package/README.md +224 -0
  2. package/dist/app/local-index.d.ts +70 -0
  3. package/dist/app/local-index.d.ts.map +1 -0
  4. package/dist/app/local-index.js +140 -0
  5. package/dist/app/local-index.js.map +1 -0
  6. package/dist/app/preflight.d.ts +24 -1
  7. package/dist/app/preflight.d.ts.map +1 -1
  8. package/dist/app/preflight.js +47 -11
  9. package/dist/app/preflight.js.map +1 -1
  10. package/dist/app/spec-lint.d.ts.map +1 -1
  11. package/dist/app/spec-lint.js +16 -0
  12. package/dist/app/spec-lint.js.map +1 -1
  13. package/dist/app/templates.d.ts +24 -0
  14. package/dist/app/templates.d.ts.map +1 -1
  15. package/dist/app/templates.js.map +1 -1
  16. package/dist/cli/help-guides.d.ts +17 -0
  17. package/dist/cli/help-guides.d.ts.map +1 -0
  18. package/dist/cli/help-guides.js +132 -0
  19. package/dist/cli/help-guides.js.map +1 -0
  20. package/dist/cli/root.d.ts.map +1 -1
  21. package/dist/cli/root.js +6 -0
  22. package/dist/cli/root.js.map +1 -1
  23. package/dist/commands/app/index.d.ts.map +1 -1
  24. package/dist/commands/app/index.js +687 -47
  25. package/dist/commands/app/index.js.map +1 -1
  26. package/dist/commands/completion/index.d.ts.map +1 -1
  27. package/dist/commands/completion/index.js +5 -1
  28. package/dist/commands/completion/index.js.map +1 -1
  29. package/dist/commands/data/index.d.ts +52 -0
  30. package/dist/commands/data/index.d.ts.map +1 -1
  31. package/dist/commands/data/index.js +201 -39
  32. package/dist/commands/data/index.js.map +1 -1
  33. package/dist/commands/db/index.d.ts +15 -0
  34. package/dist/commands/db/index.d.ts.map +1 -1
  35. package/dist/commands/db/index.js +200 -55
  36. package/dist/commands/db/index.js.map +1 -1
  37. package/dist/commands/functions/new.d.ts +4 -0
  38. package/dist/commands/functions/new.d.ts.map +1 -1
  39. package/dist/commands/functions/new.js +24 -9
  40. package/dist/commands/functions/new.js.map +1 -1
  41. package/dist/commands/gen/index.d.ts.map +1 -1
  42. package/dist/commands/gen/index.js +13 -10
  43. package/dist/commands/gen/index.js.map +1 -1
  44. package/dist/commands/guide/index.d.ts +8 -0
  45. package/dist/commands/guide/index.d.ts.map +1 -0
  46. package/dist/commands/guide/index.js +20 -0
  47. package/dist/commands/guide/index.js.map +1 -0
  48. package/dist/commands/instance/index.d.ts.map +1 -1
  49. package/dist/commands/instance/index.js +120 -0
  50. package/dist/commands/instance/index.js.map +1 -1
  51. package/dist/commands/login/index.d.ts.map +1 -1
  52. package/dist/commands/login/index.js +23 -63
  53. package/dist/commands/login/index.js.map +1 -1
  54. package/dist/commands/profile/import-env.d.ts +7 -2
  55. package/dist/commands/profile/import-env.d.ts.map +1 -1
  56. package/dist/commands/profile/import-env.js +141 -16
  57. package/dist/commands/profile/import-env.js.map +1 -1
  58. package/dist/commands/profile/index.d.ts.map +1 -1
  59. package/dist/commands/profile/index.js +16 -1
  60. package/dist/commands/profile/index.js.map +1 -1
  61. package/dist/commands/skill/index.d.ts.map +1 -1
  62. package/dist/commands/skill/index.js +89 -14
  63. package/dist/commands/skill/index.js.map +1 -1
  64. package/dist/commands/storage/index.d.ts.map +1 -1
  65. package/dist/commands/storage/index.js +209 -7
  66. package/dist/commands/storage/index.js.map +1 -1
  67. package/dist/commands/tenant/index.d.ts +19 -0
  68. package/dist/commands/tenant/index.d.ts.map +1 -0
  69. package/dist/commands/tenant/index.js +667 -0
  70. package/dist/commands/tenant/index.js.map +1 -0
  71. package/dist/commands/whoami/index.js +19 -0
  72. package/dist/commands/whoami/index.js.map +1 -1
  73. package/dist/credentials/credential-store.d.ts +30 -1
  74. package/dist/credentials/credential-store.d.ts.map +1 -1
  75. package/dist/credentials/credential-store.js +114 -12
  76. package/dist/credentials/credential-store.js.map +1 -1
  77. package/dist/credentials/env-file.d.ts +48 -7
  78. package/dist/credentials/env-file.d.ts.map +1 -1
  79. package/dist/credentials/env-file.js +91 -16
  80. package/dist/credentials/env-file.js.map +1 -1
  81. package/dist/credentials/index.d.ts +2 -0
  82. package/dist/credentials/index.d.ts.map +1 -1
  83. package/dist/credentials/index.js +2 -0
  84. package/dist/credentials/index.js.map +1 -1
  85. package/dist/credentials/jwt-introspect.d.ts +7 -0
  86. package/dist/credentials/jwt-introspect.d.ts.map +1 -1
  87. package/dist/credentials/jwt-introspect.js.map +1 -1
  88. package/dist/credentials/masker.d.ts +3 -0
  89. package/dist/credentials/masker.d.ts.map +1 -1
  90. package/dist/credentials/masker.js +3 -0
  91. package/dist/credentials/masker.js.map +1 -1
  92. package/dist/credentials/profile.d.ts +12 -0
  93. package/dist/credentials/profile.d.ts.map +1 -1
  94. package/dist/credentials/profile.js +23 -0
  95. package/dist/credentials/profile.js.map +1 -1
  96. package/dist/credentials/tty-guard.d.ts +10 -0
  97. package/dist/credentials/tty-guard.d.ts.map +1 -1
  98. package/dist/credentials/tty-guard.js +32 -0
  99. package/dist/credentials/tty-guard.js.map +1 -1
  100. package/dist/db/apply-schema.d.ts +98 -11
  101. package/dist/db/apply-schema.d.ts.map +1 -1
  102. package/dist/db/apply-schema.js +247 -80
  103. package/dist/db/apply-schema.js.map +1 -1
  104. package/dist/db/introspect.d.ts +54 -0
  105. package/dist/db/introspect.d.ts.map +1 -0
  106. package/dist/db/introspect.js +140 -0
  107. package/dist/db/introspect.js.map +1 -0
  108. package/dist/db/sql-file.d.ts +55 -0
  109. package/dist/db/sql-file.d.ts.map +1 -1
  110. package/dist/db/sql-file.js +417 -0
  111. package/dist/db/sql-file.js.map +1 -1
  112. package/dist/instance/zero-whitelist.d.ts +39 -0
  113. package/dist/instance/zero-whitelist.d.ts.map +1 -0
  114. package/dist/instance/zero-whitelist.js +67 -0
  115. package/dist/instance/zero-whitelist.js.map +1 -0
  116. package/dist/main.js +26 -3
  117. package/dist/main.js.map +1 -1
  118. package/dist/skill/agents-md.d.ts +25 -0
  119. package/dist/skill/agents-md.d.ts.map +1 -0
  120. package/dist/skill/agents-md.js +62 -0
  121. package/dist/skill/agents-md.js.map +1 -0
  122. package/dist/skill/hosts.d.ts +31 -7
  123. package/dist/skill/hosts.d.ts.map +1 -1
  124. package/dist/skill/hosts.js +65 -7
  125. package/dist/skill/hosts.js.map +1 -1
  126. package/dist/skill/installer.d.ts +15 -3
  127. package/dist/skill/installer.d.ts.map +1 -1
  128. package/dist/skill/installer.js +62 -24
  129. package/dist/skill/installer.js.map +1 -1
  130. package/dist/tenant/bundle.d.ts +66 -0
  131. package/dist/tenant/bundle.d.ts.map +1 -0
  132. package/dist/tenant/bundle.js +132 -0
  133. package/dist/tenant/bundle.js.map +1 -0
  134. package/dist/tenant/guide.d.ts +50 -0
  135. package/dist/tenant/guide.d.ts.map +1 -0
  136. package/dist/tenant/guide.js +152 -0
  137. package/dist/tenant/guide.js.map +1 -0
  138. package/dist/tenant/probe.d.ts +65 -0
  139. package/dist/tenant/probe.d.ts.map +1 -0
  140. package/dist/tenant/probe.js +159 -0
  141. package/dist/tenant/probe.js.map +1 -0
  142. package/dist/tenant/verify.d.ts +37 -0
  143. package/dist/tenant/verify.d.ts.map +1 -0
  144. package/dist/tenant/verify.js +132 -0
  145. package/dist/tenant/verify.js.map +1 -0
  146. package/dist/version.d.ts +29 -0
  147. package/dist/version.d.ts.map +1 -0
  148. package/dist/version.js +65 -0
  149. package/dist/version.js.map +1 -0
  150. package/package.json +3 -3
  151. package/skills/pxbaas-app-spec/SKILL.md +4 -2
  152. package/skills/pxbaas-app-spec/references/deploy-options.md +3 -2
  153. package/skills/pxbaas-app-spec/references/runtime-contract.md +2 -2
  154. package/skills/pxbaas-app-spec/references/templates-examples.md +7 -4
  155. package/skills/pxbaas-cli/SKILL.md +26 -8
  156. package/skills/pxbaas-cli/references/app-deploy.md +46 -3
  157. package/skills/pxbaas-cli/references/auth-and-credentials.md +30 -2
  158. package/skills/pxbaas-cli/references/data-postgrest.md +19 -3
  159. package/skills/pxbaas-cli/references/db-and-meta.md +17 -0
  160. package/skills/pxbaas-cli/references/multi-tenant-apps.md +35 -4
  161. package/skills/pxbaas-cli/references/provision.md +16 -1
  162. package/skills/pxbaas-cli/references/safety-and-two-phase.md +42 -13
  163. package/skills/pxbaas-cli/references/tenant-admin.md +122 -0
  164. package/skills/pxbaas-cli/references/troubleshooting.md +4 -1
  165. package/templates/webapp/csr-bff/db/rls.json +13 -0
  166. package/templates/webapp/csr-bff/db/schema.sql +8 -28
  167. package/templates/webapp/manifest.json +131 -8
  168. package/templates/webapp/react-vite-hono/backend/index.ts +21 -4
  169. package/templates/webapp/ssr-blog/db/rls.json +13 -0
  170. package/templates/webapp/ssr-blog/db/schema.sql +8 -28
  171. package/templates/webapp/ssr-hono/backend/index.ts +50 -31
  172. package/templates/webapp/ssr-shop/db/rls.json +16 -0
  173. package/templates/webapp/ssr-shop/db/schema.sql +12 -42
  174. package/dist/commands/login/login.d.ts +0 -3
  175. package/dist/commands/login/login.d.ts.map +0 -1
  176. package/dist/commands/login/login.js +0 -185
  177. package/dist/commands/login/login.js.map +0 -1
  178. /package/templates/webapp/vanilla-static/frontend/{app.js → dist/app.js} +0 -0
  179. /package/templates/webapp/vanilla-static/frontend/{index.html → dist/index.html} +0 -0
  180. /package/templates/webapp/vanilla-static/frontend/{style.css → dist/style.css} +0 -0
@@ -1,23 +1,36 @@
1
1
  /**
2
- * Single-tenant schema apply engine shared by `pxbaas db push <file>` and
3
- * `pxbaas app db-init <name>`.
2
+ * Schema apply engine shared by `pxbaas db push <file>` and `pxbaas app db-init <name>`.
4
3
  *
5
- * Safety contract (agreed design):
6
- * - The plan (every statement) is shown BEFORE anything runs.
4
+ * Two execution identities (chosen by profile.mode via {@link getSchemaSink}):
5
+ * - single-tenant → MetaDriver `/pg/query` with the global service_role key
6
+ * (that key IS the platform admin, so it can also write the central RLS
7
+ * registry `supabase._mysqlrest_rls_*` directly).
8
+ * - multi-tenant → TenantDdlDriver `/api/tenant-ddl/*` with the per-tenant
9
+ * service_role key. DDL/DML runs on the tenant's OWN database; RLS goes
10
+ * through the structured endpoints (the tenant account has NO grant on the
11
+ * shared `supabase` database, so a raw central INSERT would be denied).
12
+ *
13
+ * Safety contract (agreed design, unchanged):
14
+ * - The plan (every step) is shown BEFORE anything runs.
7
15
  * - Execution requires explicit authorization: an interactive confirm, or
8
16
  * `--yes` for non-interactive use. `--dry-run` only previews.
9
- * - Statements run sequentially and STOP ON THE FIRST ERROR.
10
- * - No automatic rollback — already-applied statements stay applied.
11
- * - Multi-tenant profiles are rejected: tenant DDL is out of scope (it needs
12
- * the global service_role key via POST /pg/query with tenant_<id>.<table>).
17
+ * - Steps run sequentially and STOP ON THE FIRST ERROR.
18
+ * - No automatic rollback — already-applied steps stay applied.
19
+ *
20
+ * RLS source (see plan §5, decision R-C "hybrid"):
21
+ * - a declarative `db/rls.json` is preferred when present;
22
+ * - otherwise the `INSERT ... supabase._mysqlrest_rls_*` statements embedded in
23
+ * schema.sql are parsed (multi-tenant) or run verbatim (single-tenant).
13
24
  */
14
25
  import inquirer from "inquirer";
15
- import { MetaDriver } from "@polardbx/pxbaas-client";
26
+ import { MetaDriver, TenantDdlDriver, } from "@polardbx/pxbaas-client";
16
27
  import { CredentialStore, ProfileManager, formatError, formatSuccess, formatWarning, } from "../credentials/index.js";
17
- import { buildStatementPlan, SCHEMA_PLACEHOLDER } from "./sql-file.js";
28
+ import { buildStatementPlan, partitionStatements, parseRlsPolicyInsert, parseRlsTableInsert, renderRlsPolicyInsert, renderRlsTableInsert, splitSqlStatements, substituteSchema, substituteSchemaForTenant, SCHEMA_PLACEHOLDER, } from "./sql-file.js";
18
29
  /**
19
30
  * Resolve the active profile into a single-tenant MetaDriver.
20
31
  * @throws when there is no profile, no credentials, or the profile is multi-tenant.
32
+ * @deprecated prefer {@link getSchemaSink}, which supports both modes. Kept for
33
+ * single-tenant callers and existing tests.
21
34
  */
22
35
  export async function getSingleTenantMetaDriver(role = "service_role") {
23
36
  const profileManager = new ProfileManager();
@@ -43,102 +56,187 @@ export async function getSingleTenantMetaDriver(role = "service_role") {
43
56
  return { driver, useServiceRole: role === "service_role", profileName: profile.name };
44
57
  }
45
58
  /**
46
- * Show the plan, obtain authorization, then apply statements sequentially with
47
- * stop-on-first-error semantics. Never rolls back.
59
+ * Resolve the active profile into a mode-appropriate {@link SchemaSink}.
60
+ * Unlike {@link getSingleTenantMetaDriver}, a multi-tenant profile is fully
61
+ * supported: DDL/RLS route through the tenant self-service endpoints using the
62
+ * per-tenant service_role key (Kong injects the trusted X-Tenant-Id).
48
63
  */
49
- export async function applySqlStatements(rawSql, source, opts, executor) {
50
- const { statements, substituted } = buildStatementPlan(rawSql, opts.schema);
51
- if (statements.length === 0) {
52
- if (!opts.json) {
53
- console.log(formatWarning(`No executable statements found in ${source}.`));
64
+ export async function getSchemaSink(role = "service_role") {
65
+ const profileManager = new ProfileManager();
66
+ const profile = await profileManager.getCurrentProfile();
67
+ if (!profile) {
68
+ throw new Error('No active profile. Use "pxbaas login" to authenticate first.');
69
+ }
70
+ const credentials = await new CredentialStore().getCredentials(profile.name);
71
+ if (!credentials) {
72
+ throw new Error(`No credentials found for profile: ${profile.name}. Use "pxbaas login" to authenticate.`);
73
+ }
74
+ if (profile.mode === "multi-tenant") {
75
+ if (!profile.tenantId) {
76
+ throw new Error('Multi-tenant profile is missing tenantId; re-run "pxbaas login --tenant-id <id>" ' +
77
+ "with this tenant's per-tenant anon/service keys.");
54
78
  }
79
+ // Only the per-tenant service_role key is accepted by /api/tenant-ddl (the
80
+ // resolver role-gates on service_role). Kong injects X-Tenant-Id from the JWT.
81
+ const driver = new TenantDdlDriver({
82
+ endpoint: profile.endpoint,
83
+ serviceRoleKey: credentials.serviceRoleKey,
84
+ });
55
85
  return {
56
- source,
57
- schema: opts.schema,
58
- total: 0,
59
- executed: 0,
60
- failed: 0,
61
- dryRun: opts.dryRun,
62
- authorized: false,
63
- statements: [],
86
+ mode: "multi-tenant",
87
+ profileName: profile.name,
88
+ runStatement: (sql) => driver.query(sql),
89
+ applyRlsTable: (input) => driver.upsertRlsTable(input),
90
+ applyRlsPolicy: (input) => driver.upsertRlsPolicy(input),
91
+ renderRlsTable: (input) => `RLS ${input.rls_forced ? "FORCE" : "ENABLE"} ${input.table_name}`,
92
+ renderRlsPolicy: (input) => `RLS POLICY ${input.policy_name} ON ${input.table_name} ` +
93
+ `[${(input.command ?? "ALL").toString().toUpperCase()} / ${input.role_name ?? "*"}]`,
94
+ dropTable: (table) => driver.query(`DROP TABLE IF EXISTS ${quoteIdent(table)}`),
95
+ purgeRlsForTable: async (table) => {
96
+ assertSafeIdent(table);
97
+ const policies = await driver.listRlsPolicies(table);
98
+ for (const p of policies)
99
+ await driver.deleteRlsPolicy(table, p.policy_name);
100
+ // Remove the central toggle row via DELETE /rls/tables. Tolerate instances
101
+ // that predate the endpoint (it 404/405s): degrade to leaving the benign
102
+ // row rather than failing the whole purge.
103
+ let toggleRemoved = false;
104
+ try {
105
+ await driver.deleteRlsTable(table);
106
+ toggleRemoved = true;
107
+ }
108
+ catch {
109
+ toggleRemoved = false;
110
+ }
111
+ return { policiesDeleted: policies.length, toggleRemoved };
112
+ },
64
113
  };
65
114
  }
115
+ const driver = new MetaDriver({
116
+ endpoint: profile.endpoint,
117
+ anonKey: credentials.anonKey,
118
+ serviceRoleKey: credentials.serviceRoleKey,
119
+ tenantId: profile.tenantId,
120
+ });
121
+ const useServiceRole = role === "service_role";
122
+ return {
123
+ mode: "single-tenant",
124
+ profileName: profile.name,
125
+ runStatement: (sql) => driver.query(sql, useServiceRole),
126
+ // Single-tenant: the service_role key is the platform admin, so RLS is
127
+ // written straight into the central registry via /pg/query.
128
+ applyRlsTable: (input, ctx) => driver.query(renderRlsTableInsert(ctx.schema, input), useServiceRole),
129
+ applyRlsPolicy: (input, ctx) => driver.query(renderRlsPolicyInsert(ctx.schema, input), useServiceRole),
130
+ renderRlsTable: (input, ctx) => renderRlsTableInsert(ctx.schema, input),
131
+ renderRlsPolicy: (input, ctx) => renderRlsPolicyInsert(ctx.schema, input),
132
+ dropTable: (table, ctx) => driver.query(`DROP TABLE IF EXISTS ${quoteIdent(ctx.schema)}.${quoteIdent(table)}`, useServiceRole),
133
+ purgeRlsForTable: async (table, ctx) => {
134
+ assertSafeIdent(table);
135
+ const schemaLit = sqlQuote(ctx.schema);
136
+ const tableLit = sqlQuote(table);
137
+ const found = await driver.query(`SELECT policy_name FROM supabase._mysqlrest_rls_policies ` +
138
+ `WHERE table_schema = '${schemaLit}' AND table_name = '${tableLit}'`, useServiceRole);
139
+ const names = found.rows.map((r) => String(r.policy_name));
140
+ for (const pn of names) {
141
+ await driver.query(`DELETE FROM supabase._mysqlrest_rls_policies WHERE table_schema = '${schemaLit}' ` +
142
+ `AND table_name = '${tableLit}' AND policy_name = '${sqlQuote(pn)}'`, useServiceRole);
143
+ }
144
+ await driver.query(`DELETE FROM supabase._mysqlrest_rls_tables WHERE table_schema = '${schemaLit}' AND table_name = '${tableLit}'`, useServiceRole);
145
+ return { policiesDeleted: names.length, toggleRemoved: true };
146
+ },
147
+ };
148
+ }
149
+ const SAFE_IDENT_RE = /^[A-Za-z0-9_]+$/;
150
+ /** Reject anything but a bare identifier before interpolating into DDL. */
151
+ function assertSafeIdent(name) {
152
+ if (!SAFE_IDENT_RE.test(name) || name.length > 64) {
153
+ throw new Error(`Unsafe table identifier refused: '${name}'`);
154
+ }
155
+ }
156
+ /** Backtick-quote a validated identifier. */
157
+ function quoteIdent(name) {
158
+ assertSafeIdent(name);
159
+ return `\`${name}\``;
160
+ }
161
+ /** Escape a single-quoted SQL string literal. */
162
+ function sqlQuote(value) {
163
+ return String(value).replace(/'/g, "''");
164
+ }
165
+ /**
166
+ * Shared show-plan → authorize → execute-sequentially (stop on first error) core.
167
+ * Used by both {@link applySqlStatements} and {@link applySchema} so the safety
168
+ * contract lives in exactly one place.
169
+ */
170
+ async function executePlan(params) {
171
+ const { items, opts, source } = params;
172
+ const skippedAll = () => items.map((it, i) => ({ index: i + 1, sql: it.label, kind: it.kind, status: "skipped" }));
173
+ const envelope = (partial, statements) => ({
174
+ source,
175
+ schema: opts.schema,
176
+ total: partial.total,
177
+ executed: partial.executed,
178
+ failed: partial.failed,
179
+ dryRun: partial.dryRun,
180
+ authorized: partial.authorized,
181
+ statements,
182
+ ...(params.mode ? { mode: params.mode } : {}),
183
+ ...(params.rls ? { rls: params.rls } : {}),
184
+ });
185
+ if (items.length === 0) {
186
+ if (!opts.json) {
187
+ console.log(formatWarning(`No executable statements found in ${source}.`));
188
+ }
189
+ return envelope({ total: 0, executed: 0, failed: 0, dryRun: opts.dryRun, authorized: false }, []);
190
+ }
66
191
  // 1) Show the plan (text mode). JSON callers receive the structured result.
67
192
  if (!opts.json) {
68
193
  console.log(formatSuccess(`Plan for ${source} (schema: ${opts.schema})`));
69
- if (!substituted) {
70
- console.log(formatWarning(`Script contains no ${SCHEMA_PLACEHOLDER} placeholder; --schema has no effect.`));
71
- }
72
- statements.forEach((sql, i) => {
73
- console.log(`\n[${i + 1}/${statements.length}] ${sql}`);
194
+ for (const w of params.preWarnings ?? [])
195
+ console.log(formatWarning(w));
196
+ items.forEach((it, i) => {
197
+ console.log(`\n[${i + 1}/${items.length}] ${it.label}`);
74
198
  });
75
199
  console.log("");
76
200
  }
77
201
  // 2) Dry run: preview only.
78
202
  if (opts.dryRun) {
79
203
  if (!opts.json) {
80
- console.log(formatWarning(`Dry run: 0 of ${statements.length} statement(s) executed.`));
204
+ console.log(formatWarning(`Dry run: 0 of ${items.length} statement(s) executed.`));
81
205
  }
82
- return {
83
- source,
84
- schema: opts.schema,
85
- total: statements.length,
86
- executed: 0,
87
- failed: 0,
88
- dryRun: true,
89
- authorized: false,
90
- statements: statements.map((sql, i) => ({
91
- index: i + 1,
92
- sql,
93
- status: "skipped",
94
- })),
95
- };
206
+ return envelope({ total: items.length, executed: 0, failed: 0, dryRun: true, authorized: false }, skippedAll());
96
207
  }
97
208
  // 3) Authorization gate.
98
- const authorized = await authorize(statements.length, opts);
209
+ const authorized = await authorize(items.length, opts);
99
210
  if (!authorized) {
100
211
  if (!opts.json) {
101
212
  console.log(formatWarning("Aborted by operator; nothing was executed."));
102
213
  }
103
- return {
104
- source,
105
- schema: opts.schema,
106
- total: statements.length,
107
- executed: 0,
108
- failed: 0,
109
- dryRun: false,
110
- authorized: false,
111
- statements: statements.map((sql, i) => ({
112
- index: i + 1,
113
- sql,
114
- status: "skipped",
115
- })),
116
- };
214
+ return envelope({ total: items.length, executed: 0, failed: 0, dryRun: false, authorized: false }, skippedAll());
117
215
  }
118
216
  // 4) Execute sequentially; stop on the first error; no rollback.
119
217
  const results = [];
120
218
  let executed = 0;
121
219
  let failed = 0;
122
- for (let i = 0; i < statements.length; i++) {
123
- const sql = statements[i];
124
- const r = { index: i + 1, sql, status: "pending" };
220
+ for (let i = 0; i < items.length; i++) {
221
+ const item = items[i];
222
+ const r = { index: i + 1, sql: item.label, kind: item.kind, status: "pending" };
125
223
  results.push(r);
126
224
  try {
127
- await executor(sql);
225
+ await item.exec();
128
226
  r.status = "ok";
129
227
  executed++;
130
228
  if (!opts.json)
131
- console.log(formatSuccess(`[${i + 1}/${statements.length}] ok`));
229
+ console.log(formatSuccess(`[${i + 1}/${items.length}] ok`));
132
230
  }
133
231
  catch (e) {
134
232
  r.status = "failed";
135
233
  r.error = e instanceof Error ? e.message : String(e);
136
234
  failed++;
137
235
  if (!opts.json) {
138
- console.error(formatError(`[${i + 1}/${statements.length}] failed: ${r.error}`));
236
+ console.error(formatError(`[${i + 1}/${items.length}] failed: ${r.error}`));
139
237
  }
140
- for (let j = i + 1; j < statements.length; j++) {
141
- results.push({ index: j + 1, sql: statements[j], status: "skipped" });
238
+ for (let j = i + 1; j < items.length; j++) {
239
+ results.push({ index: j + 1, sql: items[j].label, kind: items[j].kind, status: "skipped" });
142
240
  }
143
241
  break;
144
242
  }
@@ -146,23 +244,92 @@ export async function applySqlStatements(rawSql, source, opts, executor) {
146
244
  if (!opts.json) {
147
245
  console.log("");
148
246
  if (failed === 0) {
149
- console.log(formatSuccess(`Applied ${executed}/${statements.length} statement(s) to schema '${opts.schema}'.`));
247
+ console.log(formatSuccess(`Applied ${executed}/${items.length} statement(s) to schema '${opts.schema}'.`));
150
248
  }
151
249
  else {
152
250
  console.log(formatError(`Stopped after failure: ${executed} ok, ${failed} failed, ` +
153
- `${statements.length - executed - failed} skipped. No rollback performed.`));
251
+ `${items.length - executed - failed} skipped. No rollback performed.`));
154
252
  }
155
253
  }
156
- return {
157
- source,
158
- schema: opts.schema,
159
- total: statements.length,
160
- executed,
161
- failed,
162
- dryRun: false,
163
- authorized: true,
164
- statements: results,
165
- };
254
+ return envelope({ total: items.length, executed, failed, dryRun: false, authorized: true }, results);
255
+ }
256
+ /**
257
+ * Apply a raw SQL script through an injected executor (single-tenant legacy
258
+ * path). Schema substitution uses the single-tenant rule; RLS statements are
259
+ * NOT diverted (they run verbatim through the executor). For mode-aware apply
260
+ * with RLS diversion use {@link applySchema}.
261
+ */
262
+ export async function applySqlStatements(rawSql, source, opts, executor) {
263
+ const { statements, substituted } = buildStatementPlan(rawSql, opts.schema);
264
+ const items = statements.map((sql) => ({
265
+ label: sql,
266
+ kind: "sql",
267
+ exec: () => executor(sql),
268
+ }));
269
+ const preWarnings = substituted
270
+ ? []
271
+ : [`Script contains no ${SCHEMA_PLACEHOLDER} placeholder; --schema has no effect.`];
272
+ return executePlan({ items, opts, source, preWarnings });
273
+ }
274
+ /**
275
+ * Mode-aware apply used by `db push` and `app db-init`.
276
+ *
277
+ * - Splits the script, then (multi-tenant OR when rls.json is present) diverts
278
+ * the embedded central-registry RLS INSERTs out of the raw-SQL stream.
279
+ * - RLS source: `db/rls.json` when present; else parsed from schema.sql
280
+ * (multi-tenant) or left embedded (single-tenant legacy).
281
+ * - `__SCHEMA__`: single-tenant → --schema; multi-tenant → de-qualified.
282
+ * - Order: DDL/seed first (tables must exist), then RLS tables, then policies.
283
+ */
284
+ export async function applySchema(params, sink) {
285
+ const statements = splitSqlStatements(params.rawSql);
286
+ const { rlsTableInserts, rlsPolicyInserts, plain } = partitionStatements(statements);
287
+ const embeddedRlsCount = rlsTableInserts.length + rlsPolicyInserts.length;
288
+ const rls = params.rls;
289
+ const hasRlsJson = Boolean(rls && (rls.tables.length > 0 || rls.policies.length > 0));
290
+ // Single-tenant without rls.json keeps the legacy behavior: run schema.sql
291
+ // verbatim (embedded RLS INSERTs work through the admin /pg/query channel).
292
+ const divertEmbedded = sink.mode === "multi-tenant" || hasRlsJson;
293
+ const rawRun = divertEmbedded ? plain : statements;
294
+ const preWarnings = [];
295
+ let tables = [];
296
+ let policies = [];
297
+ let rlsSource = "none";
298
+ if (hasRlsJson) {
299
+ tables = rls.tables;
300
+ policies = rls.policies;
301
+ rlsSource = "rls.json";
302
+ if (embeddedRlsCount > 0) {
303
+ preWarnings.push(`db/rls.json is present — ignoring ${embeddedRlsCount} RLS INSERT statement(s) embedded ` +
304
+ `in ${params.source} to keep a single source of truth.`);
305
+ }
306
+ }
307
+ else if (sink.mode === "multi-tenant") {
308
+ tables = rlsTableInserts.flatMap(parseRlsTableInsert);
309
+ policies = rlsPolicyInserts.flatMap(parseRlsPolicyInsert);
310
+ rlsSource = tables.length || policies.length ? "schema.sql" : "none";
311
+ }
312
+ const substitute = (sql) => sink.mode === "multi-tenant" ? substituteSchemaForTenant(sql) : substituteSchema(sql, params.schema);
313
+ const ctx = { schema: params.schema };
314
+ const items = [];
315
+ for (const sql of rawRun) {
316
+ const rendered = substitute(sql);
317
+ items.push({ label: rendered, kind: "sql", exec: () => sink.runStatement(rendered) });
318
+ }
319
+ for (const t of tables) {
320
+ items.push({ label: sink.renderRlsTable(t, ctx), kind: "rls-table", exec: () => sink.applyRlsTable(t, ctx) });
321
+ }
322
+ for (const p of policies) {
323
+ items.push({ label: sink.renderRlsPolicy(p, ctx), kind: "rls-policy", exec: () => sink.applyRlsPolicy(p, ctx) });
324
+ }
325
+ return executePlan({
326
+ items,
327
+ opts: params,
328
+ source: params.source,
329
+ preWarnings,
330
+ mode: sink.mode,
331
+ rls: { tables: tables.length, policies: policies.length, source: rlsSource },
332
+ });
166
333
  }
167
334
  /**
168
335
  * Decide whether execution is authorized. `--yes` authorizes outright; JSON mode
@@ -1 +1 @@
1
- {"version":3,"file":"apply-schema.js","sourceRoot":"","sources":["../../src/db/apply-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EACL,eAAe,EACf,cAAc,EACd,WAAW,EACX,aAAa,EACb,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAkCvE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,OAAgC,cAAc;IAE9C,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,iBAAiB,EAAE,CAAC;IACzD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,kFAAkF;YAChF,sFAAsF;YACtF,4EAA4E,CAC/E,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,IAAI,eAAe,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,qCAAqC,OAAO,CAAC,IAAI,uCAAuC,CACzF,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC;QAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,OAAO,EAAE,WAAW,CAAC,OAAO;QAC5B,cAAc,EAAE,WAAW,CAAC,cAAc;QAC1C,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,KAAK,cAAc,EAAE,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;AACxF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAc,EACd,MAAc,EACd,IAAkB,EAClB,QAAqB;IAErB,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5E,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,qCAAqC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO;YACL,MAAM;YACN,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,CAAC;YACR,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,UAAU,EAAE,KAAK;YACjB,UAAU,EAAE,EAAE;SACf,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,YAAY,MAAM,aAAa,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC1E,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CACT,aAAa,CACX,sBAAsB,kBAAkB,uCAAuC,CAChF,CACF,CAAC;QACJ,CAAC;QACD,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;YAC5B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,4BAA4B;IAC5B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CACT,aAAa,CAAC,iBAAiB,UAAU,CAAC,MAAM,yBAAyB,CAAC,CAC3E,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM;YACN,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,UAAU,CAAC,MAAM;YACxB,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,KAAK;YACjB,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtC,KAAK,EAAE,CAAC,GAAG,CAAC;gBACZ,GAAG;gBACH,MAAM,EAAE,SAAkB;aAC3B,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;IAED,yBAAyB;IACzB,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,4CAA4C,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO;YACL,MAAM;YACN,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,UAAU,CAAC,MAAM;YACxB,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,KAAK;YACb,UAAU,EAAE,KAAK;YACjB,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtC,KAAK,EAAE,CAAC,GAAG,CAAC;gBACZ,GAAG;gBACH,MAAM,EAAE,SAAkB;aAC3B,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;IAED,iEAAiE;IACjE,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,CAAC,GAAoB,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACpB,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC;YAChB,QAAQ,EAAE,CAAC;YACX,IAAI,CAAC,IAAI,CAAC,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC;QACnF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC;YACpB,CAAC,CAAC,KAAK,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACrD,MAAM,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CACX,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,aAAa,CAAC,CAAC,KAAK,EAAE,CAAC,CAClE,CAAC;YACJ,CAAC;YACD,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;YACxE,CAAC;YACD,MAAM;QACR,CAAC;IACH,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CACT,aAAa,CACX,WAAW,QAAQ,IAAI,UAAU,CAAC,MAAM,4BAA4B,IAAI,CAAC,MAAM,IAAI,CACpF,CACF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CACT,WAAW,CACT,0BAA0B,QAAQ,QAAQ,MAAM,WAAW;gBACzD,GAAG,UAAU,CAAC,MAAM,GAAG,QAAQ,GAAG,MAAM,kCAAkC,CAC7E,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM;QACN,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,KAAK,EAAE,UAAU,CAAC,MAAM;QACxB,QAAQ;QACR,MAAM;QACN,MAAM,EAAE,KAAK;QACb,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,OAAO;KACpB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,SAAS,CAAC,KAAa,EAAE,IAAkB;IACxD,IAAI,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,qEAAqE;YACnE,2DAA2D,CAC9D,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,qEAAqE;YACnE,kDAAkD,CACrD,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAkB;QACpD;YACE,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,WAAW,KAAK,iCAAiC,IAAI,CAAC,MAAM,4BAA4B;YACjG,OAAO,EAAE,KAAK;SACf;KACF,CAAC,CAAC;IACH,OAAO,EAAE,CAAC;AACZ,CAAC"}
1
+ {"version":3,"file":"apply-schema.js","sourceRoot":"","sources":["../../src/db/apply-schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Schema introspection shared by `db tables`, `db schema`, and `gen types`.
3
+ *
4
+ * Why this exists (fixes defect C1): those three commands used the Meta API
5
+ * (`MetaDriver` -> `/pg/*`) unconditionally. In multi-tenant mode `/pg/*` only
6
+ * accepts the platform/global service_role key, so a per-tenant key is rejected
7
+ * with 401 (`Authentication failed`) — even though the same credentials work for
8
+ * `db query` (which already routes through tenant-ddl), `data *` (REST), and
9
+ * `storage`. See `db/apply-schema.ts` ("per-tenant keys are rejected 401 on
10
+ * /pg/query").
11
+ *
12
+ * The fix keeps single-tenant behavior EXACTLY as before (Meta API) and adds a
13
+ * multi-tenant path that runs the same portable `information_schema` queries
14
+ * through `TenantDdlDriver` (which the tenant key CAN call). The introspection
15
+ * SQL is backend-agnostic, so it is factored into pure functions that take an
16
+ * injectable `SqlRunner` — trivial to unit-test without a network.
17
+ */
18
+ import { type TableInfo, type TableColumn, type TableIndex } from '@polardbx/pxbaas-client';
19
+ /** Runs a SELECT and returns bare rows. Backed by MetaDriver (single-tenant
20
+ * `/pg/query`) or TenantDdlDriver (multi-tenant `/api/tenant-ddl/query`). */
21
+ export type SqlRunner = (sql: string) => Promise<Record<string, unknown>[]>;
22
+ /** List tables/views via information_schema (portable across both drivers). */
23
+ export declare function listTablesViaSql(run: SqlRunner, schema?: string): Promise<TableInfo[]>;
24
+ /** List a table's columns via information_schema (mirrors MetaDriver SQL). */
25
+ export declare function getTableColumnsViaSql(run: SqlRunner, table: string, schema?: string): Promise<TableColumn[]>;
26
+ /** List a table's indexes via information_schema (mirrors MetaDriver SQL). */
27
+ export declare function getTableIndexesViaSql(run: SqlRunner, table: string, schema?: string): Promise<TableIndex[]>;
28
+ /** A schema introspector bound to the correct backend for the profile's mode. */
29
+ export interface SchemaIntrospector {
30
+ /** Human label for the schema being introspected (tenant db in multi-tenant). */
31
+ currentSchema(): Promise<string>;
32
+ listTables(): Promise<TableInfo[]>;
33
+ getColumns(table: string): Promise<TableColumn[]>;
34
+ getIndexes(table: string): Promise<TableIndex[]>;
35
+ }
36
+ export interface MakeIntrospectorOptions {
37
+ /** Profile mode; 'multi-tenant' routes through tenant-ddl, else Meta API. */
38
+ mode?: string;
39
+ endpoint: string;
40
+ anonKey: string;
41
+ serviceRoleKey?: string;
42
+ tenantId?: string;
43
+ /** Single-tenant explicit schema (default 'public'). Ignored in multi-tenant. */
44
+ schema?: string;
45
+ /** Single-tenant: use the service_role key for Meta API reads (default true). */
46
+ useServiceRole?: boolean;
47
+ }
48
+ /**
49
+ * Build the mode-appropriate introspector.
50
+ * - multi-tenant: TenantDdlDriver + information_schema scoped to DATABASE().
51
+ * - single-tenant: the existing MetaDriver behavior, unchanged.
52
+ */
53
+ export declare function makeIntrospector(opts: MakeIntrospectorOptions): SchemaIntrospector;
54
+ //# sourceMappingURL=introspect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../src/db/introspect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,yBAAyB,CAAC;AAEjC;8EAC8E;AAC9E,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;AAuB5E,+EAA+E;AAC/E,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,SAAS,EACd,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,SAAS,EAAE,CAAC,CAetB;AAED,8EAA8E;AAC9E,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,EAAE,CAAC,CAmBxB;AAED,8EAA8E;AAC9E,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,EAAE,CAAC,CAiBvB;AAED,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACnC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAClD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,uBAAuB;IACtC,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,kBAAkB,CA+ClF"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Schema introspection shared by `db tables`, `db schema`, and `gen types`.
3
+ *
4
+ * Why this exists (fixes defect C1): those three commands used the Meta API
5
+ * (`MetaDriver` -> `/pg/*`) unconditionally. In multi-tenant mode `/pg/*` only
6
+ * accepts the platform/global service_role key, so a per-tenant key is rejected
7
+ * with 401 (`Authentication failed`) — even though the same credentials work for
8
+ * `db query` (which already routes through tenant-ddl), `data *` (REST), and
9
+ * `storage`. See `db/apply-schema.ts` ("per-tenant keys are rejected 401 on
10
+ * /pg/query").
11
+ *
12
+ * The fix keeps single-tenant behavior EXACTLY as before (Meta API) and adds a
13
+ * multi-tenant path that runs the same portable `information_schema` queries
14
+ * through `TenantDdlDriver` (which the tenant key CAN call). The introspection
15
+ * SQL is backend-agnostic, so it is factored into pure functions that take an
16
+ * injectable `SqlRunner` — trivial to unit-test without a network.
17
+ */
18
+ import { MetaDriver, TenantDdlDriver, } from '@polardbx/pxbaas-client';
19
+ /** Escape a single-quoted SQL string literal. */
20
+ function esc(value) {
21
+ return value.replace(/'/g, "''");
22
+ }
23
+ /**
24
+ * Schema predicate for information_schema filters. An explicit schema filters by
25
+ * name; otherwise scope to the connection's current database via DATABASE() —
26
+ * correct for multi-tenant, where the tenant-ddl connection is bound to the
27
+ * tenant's own database (tenant_<id>), not a Postgres-style `public`.
28
+ */
29
+ function schemaPredicate(schema) {
30
+ return schema && schema !== ''
31
+ ? `table_schema = '${esc(schema)}'`
32
+ : 'table_schema = DATABASE()';
33
+ }
34
+ function toBool(v) {
35
+ return v === 1 || v === true || v === '1';
36
+ }
37
+ /** List tables/views via information_schema (portable across both drivers). */
38
+ export async function listTablesViaSql(run, schema) {
39
+ const sql = `SELECT table_schema AS \`schema\`, table_name AS \`name\`, table_type AS \`type\`, ` +
40
+ `table_rows AS \`rowCount\`, table_comment AS \`comment\` ` +
41
+ `FROM information_schema.tables ` +
42
+ `WHERE ${schemaPredicate(schema)} AND table_type IN ('BASE TABLE','VIEW') ` +
43
+ `ORDER BY table_name`;
44
+ const rows = await run(sql);
45
+ return rows.map((t) => ({
46
+ schema: String(t.schema ?? ''),
47
+ name: String(t.name ?? ''),
48
+ type: String(t.type ?? '').toUpperCase() === 'VIEW' ? 'view' : 'table',
49
+ rowCount: t.rowCount != null ? Number(t.rowCount) : undefined,
50
+ comment: t.comment != null && t.comment !== '' ? String(t.comment) : undefined,
51
+ }));
52
+ }
53
+ /** List a table's columns via information_schema (mirrors MetaDriver SQL). */
54
+ export async function getTableColumnsViaSql(run, table, schema) {
55
+ const sql = `SELECT column_name AS \`name\`, data_type AS \`dataType\`, ` +
56
+ `CASE WHEN is_nullable='YES' THEN 1 ELSE 0 END AS \`isNullable\`, ` +
57
+ `column_default AS \`defaultValue\`, ` +
58
+ `CASE WHEN column_key='PRI' THEN 1 ELSE 0 END AS \`isPrimaryKey\`, ` +
59
+ `column_comment AS \`comment\` ` +
60
+ `FROM information_schema.columns ` +
61
+ `WHERE ${schemaPredicate(schema)} AND table_name='${esc(table)}' ` +
62
+ `ORDER BY ordinal_position`;
63
+ const rows = await run(sql);
64
+ return rows.map((row) => ({
65
+ name: String(row.name),
66
+ dataType: String(row.dataType),
67
+ isNullable: toBool(row.isNullable),
68
+ defaultValue: row.defaultValue == null ? null : String(row.defaultValue),
69
+ isPrimaryKey: toBool(row.isPrimaryKey),
70
+ comment: row.comment != null && row.comment !== '' ? String(row.comment) : undefined,
71
+ }));
72
+ }
73
+ /** List a table's indexes via information_schema (mirrors MetaDriver SQL). */
74
+ export async function getTableIndexesViaSql(run, table, schema) {
75
+ const sql = `SELECT index_name AS \`name\`, ` +
76
+ `GROUP_CONCAT(column_name ORDER BY seq_in_index) AS \`cols\`, ` +
77
+ `CASE WHEN MIN(non_unique)=0 THEN 1 ELSE 0 END AS \`isUnique\`, ` +
78
+ `CASE WHEN index_name='PRIMARY' THEN 1 ELSE 0 END AS \`isPrimary\` ` +
79
+ `FROM information_schema.statistics ` +
80
+ `WHERE ${schemaPredicate(schema)} AND table_name='${esc(table)}' ` +
81
+ `GROUP BY index_name`;
82
+ const rows = await run(sql);
83
+ return rows.map((row) => ({
84
+ name: String(row.name),
85
+ columns: row.cols != null && row.cols !== '' ? String(row.cols).split(',') : [],
86
+ isUnique: toBool(row.isUnique),
87
+ isPrimary: toBool(row.isPrimary),
88
+ type: 'BTREE',
89
+ }));
90
+ }
91
+ /**
92
+ * Build the mode-appropriate introspector.
93
+ * - multi-tenant: TenantDdlDriver + information_schema scoped to DATABASE().
94
+ * - single-tenant: the existing MetaDriver behavior, unchanged.
95
+ */
96
+ export function makeIntrospector(opts) {
97
+ if (opts.mode === 'multi-tenant') {
98
+ if (!opts.tenantId) {
99
+ throw new Error('Multi-tenant profile is missing tenantId; re-run "pxbaas login --tenant-id <id>" with per-tenant keys.');
100
+ }
101
+ const tenantDriver = new TenantDdlDriver({
102
+ endpoint: opts.endpoint,
103
+ serviceRoleKey: opts.serviceRoleKey,
104
+ });
105
+ const run = async (sql) => (await tenantDriver.query(sql));
106
+ let cachedSchema = null;
107
+ return {
108
+ async currentSchema() {
109
+ if (cachedSchema == null) {
110
+ const rows = await run('SELECT DATABASE() AS db');
111
+ cachedSchema = rows.length > 0 ? String(rows[0].db ?? '') : '';
112
+ }
113
+ return cachedSchema;
114
+ },
115
+ listTables: () => listTablesViaSql(run),
116
+ getColumns: (table) => getTableColumnsViaSql(run, table),
117
+ getIndexes: (table) => getTableIndexesViaSql(run, table),
118
+ };
119
+ }
120
+ const metaDriver = new MetaDriver({
121
+ endpoint: opts.endpoint,
122
+ anonKey: opts.anonKey,
123
+ serviceRoleKey: opts.serviceRoleKey,
124
+ tenantId: opts.tenantId,
125
+ });
126
+ const schema = opts.schema ?? 'public';
127
+ const useServiceRole = opts.useServiceRole ?? true;
128
+ return {
129
+ async currentSchema() {
130
+ return schema;
131
+ },
132
+ async listTables() {
133
+ const all = await metaDriver.listTables(useServiceRole);
134
+ return all.filter((t) => t.schema === schema);
135
+ },
136
+ getColumns: (table) => metaDriver.getTableColumns(table, schema, useServiceRole),
137
+ getIndexes: (table) => metaDriver.getTableIndexes(table, schema, useServiceRole),
138
+ };
139
+ }
140
+ //# sourceMappingURL=introspect.js.map