better-supabase 0.3.0 → 0.5.0

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 (211) hide show
  1. package/README.md +9 -6
  2. package/bin/better-supabase.js +4 -0
  3. package/dist/{base64-CQeB1eSf.js → base64-D2gsioCY.js} +2 -2
  4. package/dist/channel-FQW-CnGR.d.ts +70 -0
  5. package/dist/claims-BAf6c7is.js +48 -0
  6. package/dist/cli/_format-Cax5EsM9.js +101 -0
  7. package/dist/cli/bin.d.ts +1 -0
  8. package/dist/cli/bin.js +48 -0
  9. package/dist/cli/codemod-DqV7612m.js +388 -0
  10. package/dist/cli/command-CK14fP91.js +502 -0
  11. package/dist/cli/compare-BmIWVEui.js +9 -0
  12. package/dist/cli/config-CPVpXP5I.js +1965 -0
  13. package/dist/cli/config-dtoekM0v.js +2 -0
  14. package/dist/cli/db-DOBPt660.js +52 -0
  15. package/dist/cli/diff-SjkO5rNr.js +752 -0
  16. package/dist/cli/dist-DBPdlPYK.js +1112 -0
  17. package/dist/cli/dist-DreZ24Sz.js +129 -0
  18. package/dist/cli/dist-xn4wlboc.js +732 -0
  19. package/dist/cli/doctor-L7Z8mYTx.js +2863 -0
  20. package/dist/cli/env-DmKv_G4A.js +108 -0
  21. package/dist/cli/env-jIFUADLY.js +511 -0
  22. package/dist/cli/errors-4v4DTtda.js +56 -0
  23. package/dist/cli/fastest-levenshtein-CFN-lNDv.js +120 -0
  24. package/dist/cli/gen-BJc9vdyu.js +2 -0
  25. package/dist/cli/gen-C2osRcr5.js +2204 -0
  26. package/dist/cli/index.d.ts +493 -0
  27. package/dist/cli/index.js +184 -0
  28. package/dist/cli/init-Saf5-R9T.js +550 -0
  29. package/dist/cli/introspect--H7oGmcd.js +81 -0
  30. package/dist/cli/io-k41_z-jT.js +24 -0
  31. package/dist/cli/json5-ChRycquj.js +787 -0
  32. package/dist/cli/jsonc-BUniUpOk.js +2 -0
  33. package/dist/cli/jsonc-D5Fu67jw.js +45 -0
  34. package/dist/cli/keys-ByKHnvP9.js +83 -0
  35. package/dist/cli/ohash-D7bG_EOb.js +277 -0
  36. package/dist/cli/openapi-Cp5Fyta-.js +66 -0
  37. package/dist/cli/project-B_GeXyHh.js +70 -0
  38. package/dist/cli/prompts-BNcNfAve.js +1142 -0
  39. package/dist/cli/prompts-BTYQGunc.js +2 -0
  40. package/dist/cli/read-sets-BfMQcKy8.js +289 -0
  41. package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
  42. package/dist/cli/run-BKR2W_79.js +351 -0
  43. package/dist/cli/seed-CUlqWh-8.js +98 -0
  44. package/dist/cli/skills-LJJIhLFR.js +137 -0
  45. package/dist/cli/sql-DzPbfngx.js +348 -0
  46. package/dist/cli/style-C0NFdJRL.js +29 -0
  47. package/dist/cli/toml-DB-MNnFs.js +424 -0
  48. package/dist/cli/version-BDJuO0UR.js +4 -0
  49. package/dist/cli/yaml-CYCbJ6et.js +2252 -0
  50. package/dist/client/index.d.ts +2 -2
  51. package/dist/client/index.js +15 -22
  52. package/dist/clone-BfgmLU90.js +21 -0
  53. package/dist/{compiler-2zqGzxVZ.d.ts → compiler-BXH_aZ7N.d.ts} +2 -2
  54. package/dist/config/index.d.ts +4 -4
  55. package/dist/config/index.js +5 -5
  56. package/dist/{config-DOsGYSiT.js → config-DreERlKo.js} +1 -1
  57. package/dist/{config-C1CYcm6o.d.ts → config-T_ejwyd3.d.ts} +176 -11
  58. package/dist/{define-DUbydmJa.d.ts → define-Bp_BZa5h.d.ts} +37 -29
  59. package/dist/{define-DF341GDj.js → define-cNKzqwL_.js} +356 -89
  60. package/dist/edge/index.d.ts +20 -13
  61. package/dist/edge/index.js +55 -26
  62. package/dist/{entitlements-DvJXoI02.d.ts → entitlements-DUxU4oHe.d.ts} +2 -2
  63. package/dist/env/index.d.ts +2 -2
  64. package/dist/env/index.js +34 -1
  65. package/dist/{errors-Bl3rkOzo.js → errors-DtwXa6b8.js} +2 -1
  66. package/dist/events/index.d.ts +3 -2
  67. package/dist/events/index.js +69 -16
  68. package/dist/events-aIO7vsIk.d.ts +230 -0
  69. package/dist/executor-BunPOO-k.d.ts +402 -0
  70. package/dist/{executor-B26lgbHD.d.ts → executor-Cghdstwu.d.ts} +1 -2
  71. package/dist/{executor-C57jx2pn.js → executor-XycESQPH.js} +3 -3
  72. package/dist/hono/index.d.ts +27 -23
  73. package/dist/hono/index.js +46 -11
  74. package/dist/impersonation-VfaGc4Q_.js +41 -0
  75. package/dist/{index-BNsABq7P.d.ts → index-BGdgBPdf.d.ts} +66 -25
  76. package/dist/{index-qriRM9cZ.d.ts → index-C7f8cOBM.d.ts} +4 -4
  77. package/dist/{index-Dy6kuF0P.d.ts → index-CLg87OBW.d.ts} +6 -1
  78. package/dist/{index-GV77NpRP.d.ts → index-DOESKG27.d.ts} +34 -9
  79. package/dist/{index-CriFFJ_p.d.ts → index-DgILJRXj.d.ts} +43 -17
  80. package/dist/{index-UJ-LUxtI.d.ts → index-DmXSxbLi.d.ts} +14 -14
  81. package/dist/{index-Cf-D2jk1.d.ts → index-Dxn2a5cw.d.ts} +2 -2
  82. package/dist/{index-CTTMS6_1.d.ts → index-SaTsEfGP.d.ts} +86 -9
  83. package/dist/{index-CADlNHK-.d.ts → index-fag8VJZ2.d.ts} +5 -6
  84. package/dist/index.d.ts +34 -17
  85. package/dist/index.js +15 -14
  86. package/dist/jobs/index.d.ts +147 -95
  87. package/dist/jobs/index.js +773 -250
  88. package/dist/{json-schema--aOXAGfU.js → json-schema-m1fiwKgN.js} +23 -2
  89. package/dist/kit-events-CTFDfSwb.js +60 -0
  90. package/dist/kit-transport-B82k1djG.d.ts +33 -0
  91. package/dist/kit-transport-DJlHQUBU.js +55 -0
  92. package/dist/{config-Be4GwsqI.js → kits-CGLLrNPd.js} +38 -10
  93. package/dist/list/index.d.ts +1 -1
  94. package/dist/list/index.js +3 -3
  95. package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
  96. package/dist/{live-QE3UPbGm.d.ts → live-D9W2M5aO.d.ts} +16 -15
  97. package/dist/lookup-BaP5bI27.js +18 -0
  98. package/dist/mcp/index.d.ts +39 -22
  99. package/dist/mcp/index.js +39 -25
  100. package/dist/{mfa-x3V3vGh-.d.ts → mfa-CusDgPaD.d.ts} +5 -1
  101. package/dist/next/image/index.js +6 -3
  102. package/dist/next/index.d.ts +60 -36
  103. package/dist/next/index.js +167 -50
  104. package/dist/notifications/index.d.ts +162 -0
  105. package/dist/notifications/index.js +264 -0
  106. package/dist/openapi/index.d.ts +1 -1
  107. package/dist/openapi/index.js +6 -6
  108. package/dist/orgs/index.d.ts +132 -0
  109. package/dist/orgs/index.js +245 -0
  110. package/dist/orpc/index.d.ts +37 -20
  111. package/dist/orpc/index.js +24 -11
  112. package/dist/otel/index.d.ts +24 -5
  113. package/dist/otel/index.js +124 -64
  114. package/dist/permdock-sql-C2Inc6Xc.d.ts +29 -0
  115. package/dist/permdock-sql-DgOfeixi.js +51 -0
  116. package/dist/plugin-DwARMuQp.js +59 -0
  117. package/dist/{plugin-DVRB8qNE.d.ts → plugin-o144f322.d.ts} +17 -5
  118. package/dist/plugins/actor/index.d.ts +5 -2
  119. package/dist/plugins/actor/index.js +22 -8
  120. package/dist/plugins/rules/index.d.ts +2 -2
  121. package/dist/plugins/rules/index.js +52 -17
  122. package/dist/plugins/soft-delete/index.d.ts +3 -3
  123. package/dist/plugins/soft-delete/index.js +14 -5
  124. package/dist/plugins/tenant/index.d.ts +3 -3
  125. package/dist/plugins/tenant/index.js +45 -21
  126. package/dist/plugins/timestamps/index.d.ts +1 -1
  127. package/dist/plugins/timestamps/index.js +4 -3
  128. package/dist/plugins/validation/index.d.ts +2 -2
  129. package/dist/plugins/validation/index.js +26 -6
  130. package/dist/{pool-B9qsLyFR.d.ts → pool-C9voM4Kw.d.ts} +24 -6
  131. package/dist/postgres/index.d.ts +5 -5
  132. package/dist/postgres/index.js +20 -10
  133. package/dist/{postgrest-DmBlevh-.d.ts → postgrest-CruYKAvV.d.ts} +1 -1
  134. package/dist/{problem-CGt1ADix.js → problem-BW1KhzSG.js} +2 -1
  135. package/dist/{problem-Z2RTQjZD.d.ts → problem-Blxe8S31.d.ts} +1 -1
  136. package/dist/query/index.d.ts +2 -2
  137. package/dist/query/index.js +3 -3
  138. package/dist/{query-BdKLTPlj.js → query-CCbo44lG.js} +18 -18
  139. package/dist/queue-BYUCjr59.d.ts +252 -0
  140. package/dist/react/index.d.ts +8 -7
  141. package/dist/react/index.js +4 -3
  142. package/dist/react/server.d.ts +16 -5
  143. package/dist/react/server.js +12 -4
  144. package/dist/react/session.d.ts +10 -4
  145. package/dist/react/session.js +11 -3
  146. package/dist/{react-DNBYNazu.js → react-C_s7kiNz.js} +138 -46
  147. package/dist/{read-set-D0qBcboM.js → read-set-DQFt1N_Y.js} +71 -15
  148. package/dist/realtime/index.d.ts +3 -3
  149. package/dist/realtime/index.js +14 -12
  150. package/dist/{index-kpgopLNv.d.ts → refresh-BTrQ_ZTp.d.ts} +6 -3
  151. package/dist/{resolve-BRciX2jK.d.ts → resolve-C15TJq77.d.ts} +22 -11
  152. package/dist/{resource-D30rp0GN.js → resource-CRxxwkQq.js} +24 -9
  153. package/dist/{resource-CwVgiI5q.d.ts → resource-D8iqWMr-.d.ts} +6 -6
  154. package/dist/respond-D2OQl62-.d.ts +371 -0
  155. package/dist/{result-DWXatkd6.js → result-BKiliPY7.js} +2 -2
  156. package/dist/server/index.d.ts +17 -15
  157. package/dist/server/index.js +16 -22
  158. package/dist/server-Csx2sRjg.js +655 -0
  159. package/dist/{shared-_6-uPL7E.js → shared-D1dRUrAg.js} +19 -4
  160. package/dist/signers-Cc6r98SW.d.ts +162 -0
  161. package/dist/{simplify-LakqK1vH.js → simplify-_0oUKqCd.js} +27 -95
  162. package/dist/sql/index.d.ts +247 -10
  163. package/dist/sql/index.js +8591 -780
  164. package/dist/{sql-BIgk12ew.js → sql-Coh6n4cC.js} +11 -3
  165. package/dist/ssr/index.d.ts +4 -4
  166. package/dist/ssr/index.js +1 -2
  167. package/dist/{standard-FUi3Z3-7.js → standard-D7r6dMUu.js} +6 -3
  168. package/dist/{standard-eudBiRk1.d.ts → standard-J4YgMOLm.d.ts} +1 -1
  169. package/dist/{stats-D78UQ8Yu.js → stats-Bqob3WqT.js} +34 -9
  170. package/dist/storage/index.d.ts +4 -4
  171. package/dist/storage/index.js +174 -27
  172. package/dist/support-DT-OhSxD.d.ts +88 -0
  173. package/dist/support-Dk6vdmEw.js +291 -0
  174. package/dist/support-view-Da5peKFg.d.ts +17 -0
  175. package/dist/support-view-g4YLBeqX.js +18 -0
  176. package/dist/{tables-Dhha3BXM.js → tables-Cb-3_VWc.js} +14 -0
  177. package/dist/{permdock-sql-Bta_G0v-.js → template-TxrGI5jR.js} +2 -31
  178. package/dist/{temporal-BwshQk0W.js → temporal-CVlIV2DZ.js} +17 -4
  179. package/dist/{temporal-required-CMxeSVPo.js → temporal-required-CAt4Dc9Z.js} +2 -2
  180. package/dist/testing/index.d.ts +113 -24
  181. package/dist/testing/index.js +375 -47
  182. package/dist/{types-DONv9SHN.d.ts → types-Dnf_wRDz.d.ts} +26 -3
  183. package/dist/user-change-CHFEUro1.js +49 -0
  184. package/dist/{webhooks-CAIFQSTM.js → verify-Ce49ETPz.js} +38 -19
  185. package/dist/{version-BfpG2gks.js → version-DM_Roffb.js} +1 -1
  186. package/dist/{view-3Po_PVlr.d.ts → view-BEf0diC5.d.ts} +10 -5
  187. package/dist/{mfa-BxoR1RkN.js → view-Bq64ki8-.js} +210 -64
  188. package/dist/webhooks/index.d.ts +136 -5
  189. package/dist/webhooks/index.js +588 -2
  190. package/dist/wire-D2dT86vi.js +35 -0
  191. package/package.json +50 -10
  192. package/schemas/config-v1.json +131 -1
  193. package/schemas/doctor-report-v1.json +10 -0
  194. package/skills/better-supabase/SKILL.md +60 -10
  195. package/skills/better-supabase/references/plugins.md +13 -14
  196. package/skills/better-supabase/references/troubleshooting.md +25 -4
  197. package/skills/better-supabase-api/SKILL.md +74 -19
  198. package/skills/better-supabase-api/references/adapters.md +48 -27
  199. package/skills/better-supabase-auth/SKILL.md +149 -0
  200. package/skills/better-supabase-auth/references/permdock.md +100 -0
  201. package/skills/better-supabase-testing/SKILL.md +58 -4
  202. package/dist/claims-CoTobNC-.js +0 -25
  203. package/dist/events-Do8jXh4D.d.ts +0 -84
  204. package/dist/executor-DynmIWhq.d.ts +0 -195
  205. package/dist/invalidate-DbxuL2jL.js +0 -18
  206. package/dist/permdock-sql-DImJULY-.d.ts +0 -17
  207. package/dist/plugin-BqR6wKMB.js +0 -23
  208. package/dist/respond-C44EZAJo.js +0 -399
  209. package/dist/respond-DAkPIdTH.d.ts +0 -175
  210. package/dist/result-c2OYgCV2.d.ts +0 -203
  211. package/dist/view-wZ-9qIUz.js +0 -45
@@ -0,0 +1,2 @@
1
+ import { t as clackPrompter } from "./prompts-BNcNfAve.js";
2
+ export { clackPrompter };
@@ -0,0 +1,289 @@
1
+ import { i as importModule } from "./config-CPVpXP5I.js";
2
+ import { resolve } from "node:path";
3
+ import { existsSync } from "node:fs";
4
+ import { readFile } from "node:fs/promises";
5
+ import { KIT_ID_TYPES, compileReadSets, kitIdType } from "better-supabase/sql";
6
+ import { isReadSet } from "better-supabase";
7
+ //#region src/cli/permdock.ts
8
+ const PERMDOCK_CONFIGS = [
9
+ "permdock.config.ts",
10
+ "permdock.config.mts",
11
+ "permdock.config.js",
12
+ "permdock.config.mjs"
13
+ ];
14
+ /** The PermDock config file in `root`, if there is one. */
15
+ function permdockConfig(root) {
16
+ return PERMDOCK_CONFIGS.find((file) => existsSync(resolve(root, file)));
17
+ }
18
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
19
+ const isString = (value) => typeof value === "string";
20
+ const strings = (value) => Array.isArray(value) ? value.filter(isString) : [];
21
+ const column = (value) => isRecord(value) && isString(value["column"]) ? { column: value["column"] } : void 0;
22
+ function manifestValue(value, accept) {
23
+ if (!isRecord(value)) return void 0;
24
+ if (isString(value["column"])) return { column: value["column"] };
25
+ return accept(value["value"]) ? { value: value["value"] } : void 0;
26
+ }
27
+ const roleValue = (value) => isString(value) || Array.isArray(value) && value.every(isString);
28
+ function membership(value) {
29
+ if (!isRecord(value) || !isString(value["table"])) return void 0;
30
+ const user = column(value["user"]);
31
+ const id = column(value["id"]);
32
+ const scope = manifestValue(value["scope"], isString);
33
+ if (!user || !id || !scope) return void 0;
34
+ const role = manifestValue(value["role"], roleValue);
35
+ const expiresAt = column(value["expiresAt"]);
36
+ return {
37
+ table: value["table"],
38
+ user,
39
+ scope,
40
+ id,
41
+ ...role ? { role } : {},
42
+ ...expiresAt ? { expiresAt } : {},
43
+ columns: strings(value["columns"])
44
+ };
45
+ }
46
+ /** Reads a parsed manifest; throws with the reason when it isn't version 1. */
47
+ function parseManifest(json) {
48
+ if (!isRecord(json)) throw new TypeError("not a JSON object");
49
+ if (json["version"] !== 1) throw new TypeError(`version ${String(json["version"])} is not supported (this release reads version 1)`);
50
+ const hook = json["hook"];
51
+ const rls = json["rls"];
52
+ if (isRecord(rls) && rls["mode"] !== "jwt" && rls["mode"] !== "database") throw new TypeError(`rls.mode ${JSON.stringify(rls["mode"])} is not supported (this release reads "jwt" and "database")`);
53
+ const budget = isRecord(json["budget"]) ? json["budget"]["bytes"] : void 0;
54
+ return {
55
+ version: 1,
56
+ ...typeof budget === "number" ? { budget } : {},
57
+ ...isRecord(hook) && isString(hook["schema"]) && isString(hook["function"]) ? { hook: {
58
+ schema: hook["schema"],
59
+ function: hook["function"]
60
+ } } : {},
61
+ ...isString(json["tenantClaim"]) ? { tenantClaim: json["tenantClaim"] } : {},
62
+ claims: (Array.isArray(json["claims"]) ? json["claims"] : []).flatMap((claim) => isRecord(claim) && isString(claim["name"]) && isString(claim["source"]) ? [{
63
+ name: claim["name"],
64
+ source: claim["source"]
65
+ }] : []),
66
+ memberships: (Array.isArray(json["memberships"]) ? json["memberships"] : []).flatMap((entry) => {
67
+ const parsed = membership(entry);
68
+ return parsed ? [parsed] : [];
69
+ }),
70
+ ...isRecord(rls) && isString(rls["schema"]) ? { rls: {
71
+ schema: rls["schema"],
72
+ mode: rls["mode"] === "jwt" ? "jwt" : "database",
73
+ ...isString(rls["tenantClaim"]) ? { tenantClaim: rls["tenantClaim"] } : {},
74
+ scopes: (Array.isArray(rls["scopes"]) ? rls["scopes"] : []).flatMap((scope) => isRecord(scope) && isString(scope["name"]) ? [{
75
+ name: scope["name"],
76
+ ...isString(scope["type"]) ? { type: scope["type"] } : {},
77
+ ...isString(scope["within"]) ? { within: scope["within"] } : {}
78
+ }] : []),
79
+ helpers: (Array.isArray(rls["helpers"]) ? rls["helpers"] : []).flatMap((helper) => isRecord(helper) && isString(helper["name"]) && isString(helper["args"]) && isString(helper["returns"]) ? [{
80
+ name: helper["name"],
81
+ args: helper["args"],
82
+ returns: helper["returns"],
83
+ execute: strings(helper["execute"])
84
+ }] : [])
85
+ } } : {},
86
+ decidingColumns: strings(json["decidingColumns"])
87
+ };
88
+ }
89
+ /**
90
+ * The keys of a parsed `permissions.catalog.json`, each with its scope and
91
+ * its `rowConditions` flag when it is a boolean. A non-boolean flag is
92
+ * dropped, so `permdockKeyStatus` reads the key as unknown. Throws unless
93
+ * the catalog is version 1.
94
+ */
95
+ function parseCatalog(json) {
96
+ if (!isRecord(json) || !Array.isArray(json["permissions"])) throw new TypeError("has no permissions array");
97
+ if (json["version"] !== 1) throw new TypeError(`version ${String(json["version"])} is not supported (this release reads version 1)`);
98
+ return { permissions: json["permissions"].flatMap((permission) => {
99
+ if (!isRecord(permission) || !isString(permission["key"])) return [];
100
+ const flag = permission["rowConditions"];
101
+ const scope = permission["scope"];
102
+ return [{
103
+ key: permission["key"],
104
+ ...typeof flag === "boolean" ? { rowConditions: flag } : {},
105
+ ...isString(scope) ? { scope } : {}
106
+ }];
107
+ }) };
108
+ }
109
+ async function readJson(root, path) {
110
+ const absolute = resolve(root, path);
111
+ if (!existsSync(absolute)) return { missing: true };
112
+ try {
113
+ return { json: JSON.parse(await readFile(absolute, "utf8")) };
114
+ } catch (cause) {
115
+ return { problem: `${path}: ${cause instanceof Error ? cause.message : String(cause)}` };
116
+ }
117
+ }
118
+ /**
119
+ * Reads PermDock's JSON outputs: the manifest `permdock supabase inspect
120
+ * --out` writes and the catalog `permdock catalog` writes. Nothing is
121
+ * imported from PermDock. Returns `undefined` when the project has neither a
122
+ * PermDock config nor a manifest.
123
+ */
124
+ async function readPermdock(root, paths) {
125
+ const config = permdockConfig(root);
126
+ const problems = [];
127
+ const manifestFile = await readJson(root, paths.manifest);
128
+ let manifest;
129
+ if ("json" in manifestFile) try {
130
+ manifest = parseManifest(manifestFile.json);
131
+ } catch (cause) {
132
+ problems.push(`${paths.manifest}: ${cause instanceof Error ? cause.message : String(cause)}`);
133
+ }
134
+ else if ("problem" in manifestFile) problems.push(manifestFile.problem);
135
+ if (!config && !manifest && "missing" in manifestFile) return void 0;
136
+ const catalogFile = await readJson(root, paths.catalog);
137
+ let catalog;
138
+ if ("json" in catalogFile) try {
139
+ catalog = parseCatalog(catalogFile.json);
140
+ } catch (cause) {
141
+ problems.push(`${paths.catalog}: ${cause instanceof Error ? cause.message : String(cause)}`);
142
+ }
143
+ else if ("problem" in catalogFile) problems.push(catalogFile.problem);
144
+ return {
145
+ ...config ? { config } : {},
146
+ manifestPath: paths.manifest,
147
+ ...manifest ? { manifest } : {},
148
+ catalogPath: paths.catalog,
149
+ ...catalog ? { catalog } : {},
150
+ problems
151
+ };
152
+ }
153
+ /** How findings name the PermDock project: its config file or its manifest. */
154
+ const permdockSource = (project) => project.config ?? project.manifestPath;
155
+ const HOOK_MARKER = /^--\s*permdock:hook\s+v(\d+)([^\n]*)$/m;
156
+ const GRANTS_MARKER = /^--\s*permdock:grants\s+v(\d+)([^\n]*)$/m;
157
+ function markerFields(rest) {
158
+ const fields = /* @__PURE__ */ new Map();
159
+ for (const match of rest.matchAll(/(\w+)=(\S*)/g)) fields.set(match[1], match[2]);
160
+ return fields;
161
+ }
162
+ /** The `-- permdock:hook v1 schema=... tenant=... budget=... claims=...` line PermDock's hook file starts with. */
163
+ function parseHookMarker(sql) {
164
+ const match = HOOK_MARKER.exec(sql);
165
+ if (!match) return void 0;
166
+ const fields = markerFields(match[2]);
167
+ const budget = Number(fields.get("budget"));
168
+ const schema = fields.get("schema");
169
+ const tenantClaim = fields.get("tenant");
170
+ return {
171
+ version: Number(match[1]),
172
+ ...schema ? { schema } : {},
173
+ ...tenantClaim ? { tenantClaim } : {},
174
+ ...Number.isFinite(budget) && fields.has("budget") ? { budget } : {},
175
+ claims: (fields.get("claims") ?? "").split(",").filter(Boolean)
176
+ };
177
+ }
178
+ /** The `-- permdock:grants v1 schema=...` line of the migration `--grants-out` writes. */
179
+ function parseGrantsMarker(sql) {
180
+ const match = GRANTS_MARKER.exec(sql);
181
+ if (!match) return void 0;
182
+ const schema = markerFields(match[2]).get("schema");
183
+ return {
184
+ version: Number(match[1]),
185
+ ...schema ? { schema } : {}
186
+ };
187
+ }
188
+ /**
189
+ * PermDock mode, when the project uses PermDock and `entitlements.permdock`
190
+ * is not `false`. The scope is `entitlements.permdock.scope`, which must be
191
+ * one of the manifest's `rls.scopes`, else the one scope without `within`.
192
+ * No root scope, or more than one, is invalid rather than a guess. A
193
+ * PermDock project without a readable manifest or without its `rls` block
194
+ * is invalid too, so the module never falls back to `tenant` on its own.
195
+ */
196
+ function entitlementsMode(config, project) {
197
+ const setting = config.entitlements.permdock;
198
+ if (setting === false || !project) return { kind: "tenant" };
199
+ const optOut = "or set entitlements.permdock: false to keep the tenant module's memberships.";
200
+ if (!project.manifest) {
201
+ const problem = project.problems.find((entry) => entry.startsWith(project.manifestPath));
202
+ return {
203
+ kind: "invalid",
204
+ problem: problem ? `Could not read PermDock's manifest: ${problem}. Run \`permdock supabase inspect --out\` with a current PermDock, ${optOut}` : `${permdockSource(project)} is a PermDock project, but there is no ${project.manifestPath}. Run \`permdock supabase inspect --out\`, ${optOut}`
205
+ };
206
+ }
207
+ const rls = project.manifest.rls;
208
+ if (!rls) return {
209
+ kind: "invalid",
210
+ problem: `${project.manifestPath} has no rls block, so the entitlements module can't find PermDock's membership helpers. Run \`permdock rls generate\`, then \`permdock supabase inspect --out\`, ${optOut}`
211
+ };
212
+ const names = rls.scopes.map((scope) => scope.name).join(", ") || "none";
213
+ let scope;
214
+ if (setting.scope === void 0) {
215
+ const roots = rls.scopes.filter((entry) => entry.within === void 0);
216
+ if (roots.length !== 1) return {
217
+ kind: "invalid",
218
+ problem: `${project.manifestPath} has no single root scope (${roots.map((entry) => entry.name).join(", ") || "none"}), so the entitlements module can't tell which scope tenants are. Set entitlements.permdock: { scope } to one of ${names}.`
219
+ };
220
+ scope = roots[0].name;
221
+ } else {
222
+ scope = setting.scope;
223
+ if (!rls.scopes.some((entry) => entry.name === scope)) return {
224
+ kind: "invalid",
225
+ problem: `entitlements.permdock.scope is "${scope}", but ${project.manifestPath} has the scopes ${names}. Set entitlements.permdock: { scope } to one of them, or remove it to use the root scope.`
226
+ };
227
+ }
228
+ const declared = rls.scopes.find((entry) => entry.name === scope)?.type;
229
+ if (declared === void 0) return {
230
+ kind: "invalid",
231
+ problem: `${project.manifestPath} gives scope "${scope}" no type, so the entitlements module can't tell its id type. Run \`permdock supabase inspect --out\` with a current PermDock.`
232
+ };
233
+ const type = kitIdType(declared);
234
+ if (type === void 0) return {
235
+ kind: "invalid",
236
+ problem: `${project.manifestPath} gives scope "${scope}" the type ${declared}, but the entitlements module renders only ${KIT_ID_TYPES.join(", ").replace(/, (?=[^,]*$)/, " or ")} ids.`
237
+ };
238
+ return {
239
+ kind: "permdock",
240
+ permdock: {
241
+ schema: rls.schema,
242
+ scope,
243
+ idType: type,
244
+ memberships: project.manifest.memberships.map((source) => ({
245
+ table: source.table,
246
+ userColumn: source.user.column,
247
+ scope: source.scope,
248
+ idColumn: source.id.column
249
+ }))
250
+ }
251
+ };
252
+ }
253
+ /**
254
+ * The helpers the `entitlements` module calls for the chosen scope:
255
+ * `member_<scope>_ids` from `has_entitlement` as `authenticated`, and
256
+ * `member_<scope>_ids_for` from `feature_claims`, which PermDock's hook runs
257
+ * as `supabase_auth_admin`.
258
+ */
259
+ const entitlementRequirements = (permdock) => [{
260
+ kind: "member",
261
+ helper: `${permdock.schema}.member_${permdock.scope}_ids`,
262
+ caller: "has_entitlement",
263
+ role: "authenticated"
264
+ }, {
265
+ kind: "member-for",
266
+ helper: `${permdock.schema}.member_${permdock.scope}_ids_for`,
267
+ caller: "feature_claims",
268
+ role: "supabase_auth_admin"
269
+ }];
270
+ //#endregion
271
+ //#region src/cli/read-sets.ts
272
+ /** Every read set exported by the modules in `config.readSets`. */
273
+ async function loadReadSets(config) {
274
+ const sets = [];
275
+ for (const entry of config.readSets) {
276
+ const loaded = await importModule(resolve(config.root, entry));
277
+ const found = Object.values(loaded).filter(isReadSet);
278
+ if (found.length === 0) throw new Error(`${entry} exports no read set (defineReadSet)`);
279
+ for (const set of found) if (!sets.includes(set)) sets.push(set);
280
+ }
281
+ return sets;
282
+ }
283
+ /** The compiled functions for `config.readSets`; empty when none are configured. */
284
+ async function compiledReadSets(config) {
285
+ if (config.readSets.length === 0) return [];
286
+ return compileReadSets(await loadReadSets(config));
287
+ }
288
+ //#endregion
289
+ export { parseHookMarker as a, parseGrantsMarker as i, entitlementRequirements as n, permdockSource as o, entitlementsMode as r, readPermdock as s, compiledReadSets as t };
@@ -0,0 +1,24 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ export { __toESM as n, __commonJSMin as t };
@@ -0,0 +1,351 @@
1
+ import { n as __toESM } from "./rolldown-runtime-BPOCksWG.js";
2
+ import { c as parseArgs$2, i as joinRepeated, l as renderUsage, n as cliContext, o as listArgs, s as defineCommand, t as GLOBAL_ARGS, u as runCommand } from "./command-CK14fP91.js";
3
+ import { n as CliError, r as toCliError } from "./errors-4v4DTtda.js";
4
+ import { n as highlight, r as painter } from "./style-C0NFdJRL.js";
5
+ import { t as VERSION } from "./version-BDJuO0UR.js";
6
+ import { stripVTControlCharacters } from "node:util";
7
+ import { resolve } from "node:path";
8
+ //#region src/cli/legacy.ts
9
+ const ARRAY_FLAGS = /* @__PURE__ */ new Set([
10
+ "schema",
11
+ "only",
12
+ "ignore",
13
+ "agent",
14
+ "kit",
15
+ "with",
16
+ "explain"
17
+ ]);
18
+ const BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
19
+ "check",
20
+ "watch",
21
+ "json",
22
+ "strict",
23
+ "help",
24
+ "version",
25
+ "force",
26
+ "dry-run",
27
+ "no-color",
28
+ "yes",
29
+ "local",
30
+ "rotate",
31
+ "apply",
32
+ "print",
33
+ "global",
34
+ "stats",
35
+ "fix-grants"
36
+ ]);
37
+ function parseArgs$1(argv) {
38
+ const flags = {};
39
+ const positionals = [];
40
+ for (let index = 0; index < argv.length; index += 1) {
41
+ const token = argv[index];
42
+ if (token === void 0) continue;
43
+ if (token === "--") {
44
+ positionals.push(...argv.slice(index + 1));
45
+ break;
46
+ }
47
+ if (token === "-h") {
48
+ flags["help"] = true;
49
+ continue;
50
+ }
51
+ if (token.startsWith("--")) {
52
+ const body = token.slice(2);
53
+ const eq = body.indexOf("=");
54
+ if (eq !== -1) {
55
+ setFlag(flags, body.slice(0, eq), body.slice(eq + 1));
56
+ continue;
57
+ }
58
+ const next = argv[index + 1];
59
+ if (!BOOLEAN_FLAGS.has(body) && next !== void 0 && !next.startsWith("-")) {
60
+ setFlag(flags, body, next);
61
+ index += 1;
62
+ continue;
63
+ }
64
+ flags[body] = true;
65
+ continue;
66
+ }
67
+ positionals.push(token);
68
+ }
69
+ return {
70
+ command: positionals[0],
71
+ rest: positionals.slice(1),
72
+ flags
73
+ };
74
+ }
75
+ function setFlag(flags, name, value) {
76
+ if (ARRAY_FLAGS.has(name)) {
77
+ const current = flags[name];
78
+ const pieces = value.split(",").map((item) => item.trim()).filter(Boolean);
79
+ flags[name] = typeof current === "object" ? [...current, ...pieces] : pieces;
80
+ return;
81
+ }
82
+ flags[name] = value;
83
+ }
84
+ /**
85
+ * Wraps a `(context) => CommandResult` command as a citty command. Its flags
86
+ * are parsed the way 0.2 parsed them, because it declares no citty args.
87
+ */
88
+ function legacyCommand(name, command, help) {
89
+ return defineCommand({
90
+ meta: {
91
+ name,
92
+ description: help ?? ""
93
+ },
94
+ run: ({ rawArgs, data }) => {
95
+ const parsed = parseArgs$1([name, ...rawArgs]);
96
+ const context = cliContext(data);
97
+ return command({
98
+ ...context,
99
+ env: { ...context.env },
100
+ args: parsed
101
+ });
102
+ }
103
+ });
104
+ }
105
+ //#endregion
106
+ //#region src/cli/output.ts
107
+ const document = (value) => JSON.stringify(value, null, 2);
108
+ /**
109
+ * A command's result. Under `--json`, stdout gets the command's `data`, or
110
+ * `{ "message": output }` when it has none, or Problem Details when it failed
111
+ * without data; the text output moves to stderr as a diagnostic.
112
+ */
113
+ function renderResult(result, options) {
114
+ if (!options.json) return {
115
+ ...result.output ? { stdout: highlight(result.output, options.paint) } : {},
116
+ ...result.error ? { stderr: options.paint("red", result.error) } : {}
117
+ };
118
+ if (result.data === void 0 && result.error) return {
119
+ stdout: document(new CliError("failed", result.error, { exitCode: result.code }).problem),
120
+ ...result.output ? { stderr: result.output } : {}
121
+ };
122
+ const diagnostics = [...result.data !== void 0 && result.output ? [result.output] : [], ...result.error ? [result.error] : []];
123
+ return {
124
+ stdout: document(result.data ?? { message: result.output ?? "" }),
125
+ ...diagnostics.length > 0 ? { stderr: diagnostics.join("\n") } : {}
126
+ };
127
+ }
128
+ /** An error that stopped the run, with the usage text for usage errors. */
129
+ function renderError(error, options) {
130
+ if (options.json) return { stdout: document(error.problem) };
131
+ return { stderr: options.usage ? `${error.message}\n\n${options.usage}` : error.message };
132
+ }
133
+ //#endregion
134
+ //#region src/cli/run.ts
135
+ const COMMANDS = /* @__PURE__ */ new Map([
136
+ ["init", {
137
+ load: () => import("./init-Saf5-R9T.js").then((m) => m.initCommand),
138
+ description: "Writes better-supabase.config.ts, src/lib/supabase/index.ts and glue for the frameworks in package.json"
139
+ }],
140
+ ["add", {
141
+ load: () => import("./init-Saf5-R9T.js").then((m) => m.addCommand),
142
+ description: "Adds glue for an integration to an existing project"
143
+ }],
144
+ ["env", {
145
+ load: () => import("./env-jIFUADLY.js").then((m) => m.envCommand),
146
+ description: "Writes the local stack's URL and keys from `supabase status` to an env file, keeping its other lines"
147
+ }],
148
+ ["keys", {
149
+ load: () => import("./keys-ByKHnvP9.js").then((m) => m.keysCommand),
150
+ description: "Creates an ES256 signing key for the local stack, so local tokens verify through JWKS like hosted ones"
151
+ }],
152
+ ["skills", {
153
+ load: () => import("./skills-LJJIhLFR.js").then((m) => m.skillsCommand),
154
+ description: "Installs the Agent Skills that ship with this version of better-supabase"
155
+ }],
156
+ ["gen", {
157
+ load: () => import("./gen-BJc9vdyu.js").then((m) => m.genCommand),
158
+ description: "Writes database.types.ts, generated.ts and its metadata module from the database"
159
+ }],
160
+ ["introspect", {
161
+ load: () => import("./introspect--H7oGmcd.js").then((m) => m.introspectCommand),
162
+ description: "Saves the database schema as a snapshot for offline gen"
163
+ }],
164
+ ["openapi", {
165
+ load: () => import("./openapi-Cp5Fyta-.js").then((m) => m.openapiCommand),
166
+ description: "Writes the document your createOpenApi() module exports, so CI can check it for drift"
167
+ }],
168
+ ["seed", {
169
+ load: () => import("./seed-CUlqWh-8.js").then((m) => m.seedCommand),
170
+ description: "Renders the fixtures from defineSeed() (better-supabase/testing) to SQL"
171
+ }],
172
+ ["doctor", {
173
+ load: () => import("./doctor-L7Z8mYTx.js").then((m) => m.doctorCommand),
174
+ description: "Checks RLS, indexes, drift, auth config and env files; exits 1 on errors, or on warnings with --strict"
175
+ }],
176
+ ["sql", {
177
+ load: () => import("./sql-DzPbfngx.js").then((m) => m.sqlCommand),
178
+ description: "Lists, adds, syncs, upgrades and prints SQL kit modules"
179
+ }],
180
+ ["codemod", {
181
+ load: () => import("./codemod-DqV7612m.js").then((m) => m.codemodCommand),
182
+ description: "Rewrites imports and calls for renamed better-supabase APIs"
183
+ }]
184
+ ]);
185
+ function registerCommand(name, command, help) {
186
+ const def = typeof command === "function" ? legacyCommand(name, command, help) : command;
187
+ COMMANDS.set(name, {
188
+ load: () => Promise.resolve(def),
189
+ command: def
190
+ });
191
+ }
192
+ const ROOT = defineCommand({
193
+ meta: {
194
+ name: "better-supabase",
195
+ version: VERSION,
196
+ description: "Typed Supabase: codegen, doctor, the SQL kit and project setup"
197
+ },
198
+ args: GLOBAL_ARGS,
199
+ subCommands: () => Object.fromEntries([...COMMANDS].map(([name, entry]) => [name, "command" in entry ? entry.command : defineCommand({ meta: {
200
+ name,
201
+ description: entry.description
202
+ } })]))
203
+ });
204
+ /** The usage text for the CLI, or for one command; plain unless `color` is set. */
205
+ async function help(command, color = false) {
206
+ const load = command === void 0 ? void 0 : COMMANDS.get(command)?.load;
207
+ const text = load ? await renderUsage(await load(), ROOT) : await renderUsage(ROOT);
208
+ return color ? text : stripVTControlCharacters(text);
209
+ }
210
+ /** The index of the command name: the first token that is not an option or an option's value. */
211
+ function commandIndex(argv) {
212
+ for (let index = 0; index < argv.length; index += 1) {
213
+ const token = argv[index];
214
+ if (token === "--") return -1;
215
+ if (!token.startsWith("-")) return index;
216
+ if (token === "--cwd" || token === "--config") index += 1;
217
+ }
218
+ return -1;
219
+ }
220
+ function isCommandResult(value) {
221
+ return typeof value === "object" && value !== null && "code" in value && typeof value.code === "number";
222
+ }
223
+ /** The names `run()` dispatches, registered commands included. */
224
+ function commandNames() {
225
+ return [...COMMANDS.keys()];
226
+ }
227
+ /** The registered command closest to a mistyped one, if it is close enough to be a typo. */
228
+ async function suggestCommand(name) {
229
+ const names = [...COMMANDS.keys()];
230
+ if (names.length === 0) return void 0;
231
+ const { closest, distance } = await import("./fastest-levenshtein-CFN-lNDv.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
232
+ const candidate = closest(name, names);
233
+ return distance(name, candidate) <= Math.max(2, Math.floor(name.length / 3)) ? candidate : void 0;
234
+ }
235
+ const SHOWS_USAGE = /* @__PURE__ */ new Set(["usage", "unknown_command"]);
236
+ function withoutPrompts(io) {
237
+ const { prompts: _prompts, ...rest } = io;
238
+ return rest;
239
+ }
240
+ /** Runs the CLI. Never exits the process; returns the exit code and output. */
241
+ async function run(argv, options = {}) {
242
+ const stdout = [];
243
+ const stderr = [];
244
+ const io = options.io ?? {
245
+ stdout: (text) => {
246
+ stdout.push(text);
247
+ },
248
+ stderr: (text) => {
249
+ stderr.push(text);
250
+ }
251
+ };
252
+ const out = (text) => {
253
+ const line = text.endsWith("\n") ? text : `${text}\n`;
254
+ if (options.io) stdout.push(line);
255
+ io.stdout(line);
256
+ };
257
+ const fail = (text) => {
258
+ const line = text.endsWith("\n") ? text : `${text}\n`;
259
+ if (options.io) stderr.push(line);
260
+ io.stderr(line);
261
+ };
262
+ const paint = painter(io.color);
263
+ const usage = (command) => help(command, io.color === true);
264
+ const finish = (code) => ({
265
+ code,
266
+ stdout: stdout.join(""),
267
+ stderr: stderr.join("")
268
+ });
269
+ const index = commandIndex(argv);
270
+ const name = index === -1 ? void 0 : argv[index];
271
+ const rest = index === -1 ? [...argv] : argv.toSpliced(index, 1);
272
+ const flags = new Set(rest.slice(0, rest.includes("--") ? rest.indexOf("--") : void 0));
273
+ const wantsHelp = flags.has("--help") || flags.has("-h");
274
+ const json = flags.has("--json");
275
+ const report = (rendered) => {
276
+ if (rendered.stdout) out(rendered.stdout);
277
+ if (rendered.stderr) fail(rendered.stderr);
278
+ };
279
+ const reportError = async (cause) => {
280
+ const error = toCliError(cause);
281
+ const shown = error.code === "usage" ? new CliError("usage", stripVTControlCharacters(error.message)) : error;
282
+ report(renderError(shown, {
283
+ json,
284
+ paint,
285
+ ...SHOWS_USAGE.has(error.code) ? { usage: await usage(error.code === "usage" ? name : void 0) } : {}
286
+ }));
287
+ return finish(error.exitCode);
288
+ };
289
+ if (flags.has("--version") || name === "version") {
290
+ out(json ? JSON.stringify({ version: VERSION }) : VERSION);
291
+ return finish(0);
292
+ }
293
+ if (name === void 0) {
294
+ (wantsHelp ? out : fail)(await usage());
295
+ return finish(wantsHelp ? 0 : 2);
296
+ }
297
+ if (name === "help") {
298
+ out(await usage(rest.find((token) => !token.startsWith("-"))));
299
+ return finish(0);
300
+ }
301
+ const load = COMMANDS.get(name)?.load;
302
+ if (!load) {
303
+ const suggestion = await suggestCommand(name);
304
+ return reportError(new CliError("unknown_command", `Unknown command "${name}".${suggestion ? ` Did you mean "${suggestion}"?` : ""}`, suggestion ? { suggestion } : {}));
305
+ }
306
+ if (wantsHelp) {
307
+ out(await usage(name));
308
+ return finish(0);
309
+ }
310
+ let context;
311
+ let command;
312
+ try {
313
+ const [loaded, { loadConfig }, { parseEnv }] = await Promise.all([
314
+ load(),
315
+ import("./config-dtoekM0v.js"),
316
+ import("./env-DmKv_G4A.js")
317
+ ]);
318
+ command = loaded;
319
+ const globals = parseArgs$2(rest, GLOBAL_ARGS);
320
+ const cwd = resolve(options.cwd ?? ".", globals.cwd ?? ".");
321
+ const env = parseEnv(options.env ?? {});
322
+ context = {
323
+ cwd,
324
+ config: await loadConfig(cwd, globals.config).catch((cause) => {
325
+ throw cause instanceof CliError ? cause : new CliError("config_invalid", toCliError(cause).message, { cause });
326
+ }),
327
+ io: globals.json !== true && globals.yes !== true && env.CI === void 0 ? io : withoutPrompts(io),
328
+ env,
329
+ json: globals.json === true,
330
+ signal: options.signal
331
+ };
332
+ } catch (cause) {
333
+ return reportError(cause);
334
+ }
335
+ try {
336
+ const { result } = await runCommand(command, {
337
+ rawArgs: joinRepeated(rest, listArgs(command)),
338
+ data: context
339
+ });
340
+ if (!isCommandResult(result)) return finish(0);
341
+ report(renderResult(result, {
342
+ json,
343
+ paint
344
+ }));
345
+ return finish(result.code);
346
+ } catch (cause) {
347
+ return reportError(cause);
348
+ }
349
+ }
350
+ //#endregion
351
+ export { run as i, help as n, registerCommand as r, commandNames as t };