better-supabase 0.4.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 (179) hide show
  1. package/README.md +2 -0
  2. package/dist/channel-FQW-CnGR.d.ts +70 -0
  3. package/dist/cli/bin.js +1 -1
  4. package/dist/cli/codemod-DqV7612m.js +388 -0
  5. package/dist/cli/{config-D9R0o1LH.js → config-CPVpXP5I.js} +78 -8
  6. package/dist/cli/{config-SSKSTUl2.js → config-dtoekM0v.js} +1 -1
  7. package/dist/cli/{read-sets-CMa29t9a.js → diff-SjkO5rNr.js} +1 -220
  8. package/dist/cli/{dist-CFgGknmZ.js → dist-DBPdlPYK.js} +4 -4
  9. package/dist/cli/{dist-B1MvLv-M.js → dist-DreZ24Sz.js} +1 -1
  10. package/dist/cli/{dist-Du7VnEUG.js → dist-xn4wlboc.js} +112 -1
  11. package/dist/cli/{doctor-BOym3mbL.js → doctor-L7Z8mYTx.js} +531 -50
  12. package/dist/cli/{env-BZ0uy8XK.js → env-DmKv_G4A.js} +1 -1
  13. package/dist/cli/gen-BJc9vdyu.js +2 -0
  14. package/dist/cli/{gen-Ccn_p90L.js → gen-C2osRcr5.js} +283 -87
  15. package/dist/cli/index.d.ts +1 -1
  16. package/dist/cli/index.js +4 -4
  17. package/dist/cli/{init-ClnxRYBF.js → init-Saf5-R9T.js} +2 -2
  18. package/dist/cli/{introspect-DxqfkVIv.js → introspect--H7oGmcd.js} +2 -2
  19. package/dist/cli/{openapi-8WHjxiTJ.js → openapi-Cp5Fyta-.js} +1 -1
  20. package/dist/cli/read-sets-BfMQcKy8.js +289 -0
  21. package/dist/cli/{run-CP20LKk_.js → run-BKR2W_79.js} +16 -12
  22. package/dist/cli/{seed-5J6eu_Xg.js → seed-CUlqWh-8.js} +1 -1
  23. package/dist/cli/sql-DzPbfngx.js +348 -0
  24. package/dist/cli/{version-5mW_8sY1.js → version-BDJuO0UR.js} +1 -1
  25. package/dist/client/index.d.ts +1 -1
  26. package/dist/client/index.js +3 -10
  27. package/dist/clone-BfgmLU90.js +21 -0
  28. package/dist/{compiler-DB3aSFOA.d.ts → compiler-BXH_aZ7N.d.ts} +2 -2
  29. package/dist/config/index.d.ts +4 -4
  30. package/dist/config/index.js +4 -4
  31. package/dist/{config-CbvFmGD8.js → config-DreERlKo.js} +1 -1
  32. package/dist/{config-C1CYcm6o.d.ts → config-T_ejwyd3.d.ts} +176 -11
  33. package/dist/{define-CRS2MRV3.d.ts → define-Bp_BZa5h.d.ts} +11 -7
  34. package/dist/{define-Bh0AqTik.js → define-cNKzqwL_.js} +202 -16
  35. package/dist/edge/index.d.ts +16 -5
  36. package/dist/edge/index.js +10 -7
  37. package/dist/{entitlements-Dm-FHpNH.d.ts → entitlements-DUxU4oHe.d.ts} +1 -1
  38. package/dist/env/index.d.ts +2 -2
  39. package/dist/env/index.js +34 -1
  40. package/dist/{errors-L0xK41y_.js → errors-DtwXa6b8.js} +1 -0
  41. package/dist/events/index.d.ts +3 -2
  42. package/dist/events/index.js +65 -12
  43. package/dist/events-aIO7vsIk.d.ts +230 -0
  44. package/dist/{result-CqEsbgYs.d.ts → executor-BunPOO-k.d.ts} +200 -1
  45. package/dist/{executor-CZ7ImRiD.d.ts → executor-Cghdstwu.d.ts} +1 -2
  46. package/dist/{executor-CVt6dD0B.js → executor-XycESQPH.js} +3 -3
  47. package/dist/hono/index.d.ts +17 -6
  48. package/dist/hono/index.js +40 -5
  49. package/dist/impersonation-VfaGc4Q_.js +41 -0
  50. package/dist/{index-BBdvo-5d.d.ts → index-BGdgBPdf.d.ts} +49 -6
  51. package/dist/{index-BhHEC04r.d.ts → index-C7f8cOBM.d.ts} +2 -2
  52. package/dist/{index-Dy6kuF0P.d.ts → index-CLg87OBW.d.ts} +6 -1
  53. package/dist/{index-D5IfUIDh.d.ts → index-DOESKG27.d.ts} +33 -8
  54. package/dist/{index-DFmOpBGC.d.ts → index-DgILJRXj.d.ts} +35 -9
  55. package/dist/{index-RlLXd8dL.d.ts → index-DmXSxbLi.d.ts} +4 -4
  56. package/dist/{index-Cf-D2jk1.d.ts → index-Dxn2a5cw.d.ts} +2 -2
  57. package/dist/{index-528Ugmyp.d.ts → index-SaTsEfGP.d.ts} +76 -8
  58. package/dist/{index-BAy4tsAP.d.ts → index-fag8VJZ2.d.ts} +3 -4
  59. package/dist/index.d.ts +30 -13
  60. package/dist/index.js +10 -9
  61. package/dist/jobs/index.d.ts +147 -101
  62. package/dist/jobs/index.js +744 -237
  63. package/dist/{json-schema-DP6V7cbr.js → json-schema-m1fiwKgN.js} +22 -1
  64. package/dist/kit-events-CTFDfSwb.js +60 -0
  65. package/dist/kit-transport-B82k1djG.d.ts +33 -0
  66. package/dist/kit-transport-DJlHQUBU.js +55 -0
  67. package/dist/{config-BpxDfnbg.js → kits-CGLLrNPd.js} +37 -9
  68. package/dist/list/index.d.ts +1 -1
  69. package/dist/{live-BHakSWWo.d.ts → live-D9W2M5aO.d.ts} +6 -5
  70. package/dist/mcp/index.d.ts +25 -8
  71. package/dist/mcp/index.js +23 -14
  72. package/dist/{mfa-C7MNQ1Ob.d.ts → mfa-CusDgPaD.d.ts} +5 -1
  73. package/dist/next/index.d.ts +31 -10
  74. package/dist/next/index.js +136 -27
  75. package/dist/notifications/index.d.ts +162 -0
  76. package/dist/notifications/index.js +264 -0
  77. package/dist/openapi/index.d.ts +1 -1
  78. package/dist/openapi/index.js +2 -2
  79. package/dist/orgs/index.d.ts +132 -0
  80. package/dist/orgs/index.js +245 -0
  81. package/dist/orpc/index.d.ts +28 -8
  82. package/dist/orpc/index.js +16 -3
  83. package/dist/otel/index.d.ts +21 -2
  84. package/dist/otel/index.js +50 -9
  85. package/dist/permdock-sql-C2Inc6Xc.d.ts +29 -0
  86. package/dist/permdock-sql-DgOfeixi.js +51 -0
  87. package/dist/plugin-DwARMuQp.js +59 -0
  88. package/dist/{plugin-bNhvJwRh.d.ts → plugin-o144f322.d.ts} +17 -5
  89. package/dist/plugins/actor/index.d.ts +5 -2
  90. package/dist/plugins/actor/index.js +22 -8
  91. package/dist/plugins/rules/index.d.ts +2 -2
  92. package/dist/plugins/rules/index.js +15 -10
  93. package/dist/plugins/soft-delete/index.d.ts +3 -3
  94. package/dist/plugins/soft-delete/index.js +14 -5
  95. package/dist/plugins/tenant/index.d.ts +2 -2
  96. package/dist/plugins/tenant/index.js +38 -20
  97. package/dist/plugins/timestamps/index.d.ts +1 -1
  98. package/dist/plugins/timestamps/index.js +4 -3
  99. package/dist/plugins/validation/index.d.ts +2 -2
  100. package/dist/plugins/validation/index.js +26 -6
  101. package/dist/{pool-DFwEQwmN.d.ts → pool-C9voM4Kw.d.ts} +17 -6
  102. package/dist/postgres/index.d.ts +5 -5
  103. package/dist/postgres/index.js +20 -11
  104. package/dist/{postgrest-Bc-0Xw62.d.ts → postgrest-CruYKAvV.d.ts} +1 -1
  105. package/dist/{problem-BihjPR0t.js → problem-BW1KhzSG.js} +2 -1
  106. package/dist/{problem-U8UEKccv.d.ts → problem-Blxe8S31.d.ts} +1 -1
  107. package/dist/query/index.d.ts +2 -2
  108. package/dist/query/index.js +3 -3
  109. package/dist/{query-BMMSWbI7.js → query-CCbo44lG.js} +2 -2
  110. package/dist/queue-BYUCjr59.d.ts +252 -0
  111. package/dist/react/index.d.ts +8 -7
  112. package/dist/react/index.js +4 -3
  113. package/dist/react/server.d.ts +14 -3
  114. package/dist/react/server.js +10 -2
  115. package/dist/react/session.d.ts +7 -1
  116. package/dist/react/session.js +9 -1
  117. package/dist/{react-CQHMaESR.js → react-C_s7kiNz.js} +103 -11
  118. package/dist/{read-set-FWK8qQ58.js → read-set-DQFt1N_Y.js} +22 -1
  119. package/dist/realtime/index.d.ts +3 -3
  120. package/dist/realtime/index.js +5 -4
  121. package/dist/{refresh-BwYkyNOQ.d.ts → refresh-BTrQ_ZTp.d.ts} +1 -1
  122. package/dist/{resolve-BAqQcwMW.d.ts → resolve-C15TJq77.d.ts} +11 -5
  123. package/dist/{resource-My_y-Syh.js → resource-CRxxwkQq.js} +22 -7
  124. package/dist/{resource-BJcaIfxi.d.ts → resource-D8iqWMr-.d.ts} +5 -5
  125. package/dist/respond-D2OQl62-.d.ts +371 -0
  126. package/dist/{result-Bj6yt33D.js → result-BKiliPY7.js} +1 -1
  127. package/dist/server/index.d.ts +14 -12
  128. package/dist/server/index.js +11 -17
  129. package/dist/{server-BA75B0mT.js → server-Csx2sRjg.js} +251 -34
  130. package/dist/{shared-DnoCdMDr.js → shared-D1dRUrAg.js} +16 -2
  131. package/dist/signers-Cc6r98SW.d.ts +162 -0
  132. package/dist/{simplify-Cqvfr9dj.js → simplify-_0oUKqCd.js} +4 -115
  133. package/dist/sql/index.d.ts +247 -10
  134. package/dist/sql/index.js +8590 -779
  135. package/dist/{sql-B34HU2DI.js → sql-Coh6n4cC.js} +9 -2
  136. package/dist/ssr/index.d.ts +4 -4
  137. package/dist/ssr/index.js +1 -2
  138. package/dist/{standard-BRyBGTtp.js → standard-D7r6dMUu.js} +6 -3
  139. package/dist/{standard-BsaCYQJc.d.ts → standard-J4YgMOLm.d.ts} +1 -1
  140. package/dist/{stats-C_YxA2r1.js → stats-Bqob3WqT.js} +4 -4
  141. package/dist/storage/index.d.ts +4 -4
  142. package/dist/storage/index.js +155 -26
  143. package/dist/support-DT-OhSxD.d.ts +88 -0
  144. package/dist/support-Dk6vdmEw.js +291 -0
  145. package/dist/support-view-Da5peKFg.d.ts +17 -0
  146. package/dist/support-view-g4YLBeqX.js +18 -0
  147. package/dist/{permdock-sql-C4KFzLc9.js → template-TxrGI5jR.js} +2 -31
  148. package/dist/{temporal-BwshQk0W.js → temporal-CVlIV2DZ.js} +17 -4
  149. package/dist/{temporal-required-CBNHT6ni.js → temporal-required-CAt4Dc9Z.js} +2 -2
  150. package/dist/testing/index.d.ts +100 -10
  151. package/dist/testing/index.js +336 -8
  152. package/dist/{types-DONv9SHN.d.ts → types-Dnf_wRDz.d.ts} +26 -3
  153. package/dist/user-change-CHFEUro1.js +49 -0
  154. package/dist/{webhooks-Bh_Jf_-l.js → verify-Ce49ETPz.js} +5 -5
  155. package/dist/{version-Bmf7_FzM.js → version-DM_Roffb.js} +1 -1
  156. package/dist/{view-B64o81wp.d.ts → view-BEf0diC5.d.ts} +8 -3
  157. package/dist/{mfa-byfjruR9.js → view-Bq64ki8-.js} +95 -38
  158. package/dist/webhooks/index.d.ts +135 -4
  159. package/dist/webhooks/index.js +588 -2
  160. package/dist/wire-D2dT86vi.js +35 -0
  161. package/package.json +16 -8
  162. package/schemas/config-v1.json +131 -1
  163. package/schemas/doctor-report-v1.json +10 -0
  164. package/skills/better-supabase/SKILL.md +9 -6
  165. package/skills/better-supabase/references/plugins.md +6 -3
  166. package/skills/better-supabase/references/troubleshooting.md +1 -0
  167. package/skills/better-supabase-api/SKILL.md +9 -2
  168. package/skills/better-supabase-api/references/adapters.md +11 -8
  169. package/skills/better-supabase-auth/SKILL.md +3 -0
  170. package/skills/better-supabase-auth/references/permdock.md +56 -11
  171. package/dist/cli/gen-D5cLCULx.js +0 -2
  172. package/dist/cli/sql-D4VbqmXi.js +0 -199
  173. package/dist/events-B21UOhvP.d.ts +0 -84
  174. package/dist/executor-B5IoUxLE.d.ts +0 -195
  175. package/dist/invalidate-CgxmRamI.js +0 -24
  176. package/dist/permdock-sql-DImJULY-.d.ts +0 -17
  177. package/dist/plugin-BqR6wKMB.js +0 -23
  178. package/dist/respond-DgIbdrt8.d.ts +0 -194
  179. package/dist/view-BrJI2LKp.js +0 -45
package/README.md CHANGED
@@ -64,6 +64,8 @@ if (!result.ok) return result; // DbError: kind, message, status, code
64
64
  | `better-supabase/hono`, `/orpc`, `/edge` | Framework adapters |
65
65
  | `better-supabase/mcp` | MCP servers whose tools run as the signed-in user |
66
66
  | `better-supabase/jobs` | Supabase Queues jobs, idempotency keys and a webhook inbox |
67
+ | `better-supabase/orgs` | Organizations, members, invitations and switching from the SQL kit |
68
+ | `better-supabase/notifications` | Sending, listing and delivering notifications from the SQL kit |
67
69
  | `better-supabase/list` | Search, facets, sorting and pagination from one definition |
68
70
  | `better-supabase/storage`, `/realtime` | Typed bucket paths and broadcast topics |
69
71
  | `better-supabase/env` | Validated Supabase settings |
@@ -0,0 +1,70 @@
1
+ /// <reference lib="esnext.temporal" />
2
+ //#region src/notifications/types.d.ts
3
+ /** A subject a notification is about, e.g. `{ type: 'task', id: '42' }`. */
4
+ interface NotificationSubject {
5
+ readonly type: string;
6
+ readonly id: string;
7
+ /** Shown in the list, e.g. the task title, kept as it was at send time. */
8
+ readonly label?: string;
9
+ }
10
+ /** One notification as its recipient sees it. */
11
+ interface NotificationItem<K extends string = string, D = unknown> {
12
+ /** The recipient row id: pass it to `markRead` and `dismiss`. */
13
+ readonly id: string;
14
+ /** The shared event id, the same for every recipient. */
15
+ readonly eventId: string;
16
+ readonly type: K;
17
+ readonly data: D;
18
+ readonly tenant: string | null;
19
+ readonly actorId: string | null;
20
+ readonly subject: NotificationSubject | null;
21
+ readonly summary: string | null;
22
+ readonly actionPath: string | null;
23
+ readonly priority: string | null;
24
+ readonly createdAt: Temporal.Instant;
25
+ readonly readAt: Temporal.Instant | null;
26
+ readonly resolvedAt: Temporal.Instant | null;
27
+ }
28
+ /** What `render` returns: the text for one notification, in one locale. */
29
+ interface RenderedText {
30
+ readonly title: string;
31
+ readonly body?: string;
32
+ }
33
+ //#endregion
34
+ //#region src/notifications/channel.d.ts
35
+ /** One pending delivery a channel sends: the notification and who gets it. */
36
+ interface NotificationMessage {
37
+ readonly deliveryId: string;
38
+ /** The channel name, e.g. `email`. */
39
+ readonly channel: string;
40
+ /** 1 on the first try. */
41
+ readonly attempts: number;
42
+ readonly userId: string;
43
+ /** The recipient's `auth.users` email, for email channels. */
44
+ readonly email: string | null;
45
+ readonly notification: NotificationItem;
46
+ /** What `render` returned for it, when `createNotifications` has one. */
47
+ readonly text?: RenderedText;
48
+ }
49
+ interface NotificationSendResult {
50
+ /** `skipped` when the channel decided not to send. Defaults to `sent`. */
51
+ readonly status?: "sent" | "skipped";
52
+ /** The provider's name, e.g. `resend` or `fcm`. */
53
+ readonly provider?: string;
54
+ /** The provider's id for the message, kept for support and webhooks. */
55
+ readonly providerMessageId?: string;
56
+ }
57
+ /**
58
+ * Sends notifications on one channel (email, push, Slack). The delivery
59
+ * worker (`notifications.deliver()`) claims pending deliveries for the
60
+ * channel's `name` and calls `send` for each. Throwing retries the delivery
61
+ * after its lease, up to `maxAttempts`, then marks it `failed`.
62
+ */
63
+ interface NotificationChannel {
64
+ readonly apiVersion: 1;
65
+ /** Matches the `channel` the deliveries were created for. */
66
+ readonly name: string;
67
+ send(message: NotificationMessage): NotificationSendResult | void | Promise<NotificationSendResult | void>;
68
+ }
69
+ //#endregion
70
+ export { NotificationSubject as a, NotificationItem as i, NotificationMessage as n, RenderedText as o, NotificationSendResult as r, NotificationChannel as t };
package/dist/cli/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as run } from "./run-CP20LKk_.js";
2
+ import { i as run } from "./run-BKR2W_79.js";
3
3
  import { t as colorEnabled } from "./style-C0NFdJRL.js";
4
4
  import { text } from "node:stream/consumers";
5
5
  //#region src/cli/bin.ts
@@ -0,0 +1,388 @@
1
+ import { r as defineCliCommand } from "./command-CK14fP91.js";
2
+ import { r as writeIfChanged } from "./io-k41_z-jT.js";
3
+ import { i as plain, r as painter } from "./style-C0NFdJRL.js";
4
+ import { t as fileDiff } from "./diff-SjkO5rNr.js";
5
+ import { extname, join, relative, resolve } from "node:path";
6
+ import { readFile, readdir, stat } from "node:fs/promises";
7
+ //#region src/cli/codemod.ts
8
+ const CODEMODS = {
9
+ "0.4": {
10
+ name: "0.4",
11
+ description: "Renames from 0.3 to 0.4 (the naming page lists them)",
12
+ imports: {
13
+ createBrowser: "createClient",
14
+ BetterBrowser: "BetterClient",
15
+ BrowserOptions: "ClientOptions",
16
+ BrowserAuth: "ClientAuth",
17
+ BetterEnv: "HonoEnv",
18
+ HandlerOptions: "MiddlewareOptions",
19
+ Queries: "BetterQueries",
20
+ CreateQueriesOptions: "QueriesOptions",
21
+ Postgres: "BetterPostgres",
22
+ DefineSupabaseOptions: "SupabaseOptions"
23
+ },
24
+ members: [
25
+ {
26
+ from: "serverFor",
27
+ to: "contextForSession"
28
+ },
29
+ {
30
+ from: "toORPCError",
31
+ to: "toOrpcError"
32
+ },
33
+ {
34
+ from: "$table",
35
+ to: "$tableName",
36
+ notCalled: true
37
+ }
38
+ ],
39
+ props: [{
40
+ component: "BetterSupabaseProvider",
41
+ from: "browser",
42
+ to: "client"
43
+ }],
44
+ review: [
45
+ {
46
+ pattern: /\.server\(\)/,
47
+ message: "`next.server()` is `bs.context()` on the createNext() instance"
48
+ },
49
+ {
50
+ pattern: /\.handle\(\)/,
51
+ message: "Hono's `bs.handle()` is `bs.handler()`"
52
+ },
53
+ {
54
+ pattern: /\bmcp\.handler\b/,
55
+ message: "`mcp.handler` is `bs.endpoint`"
56
+ },
57
+ {
58
+ pattern: /\.sb\b/,
59
+ message: "`client.sb` is `client.betterSupabase`"
60
+ },
61
+ {
62
+ pattern: /\btestExecutor\(\s*\{[^}]*\bsb\b/,
63
+ message: "`{ sb }` in testExecutor is `{ betterSupabase }`"
64
+ }
65
+ ]
66
+ },
67
+ "0.5": {
68
+ name: "0.5",
69
+ description: "Renames from 0.4 to 0.5: createMcp's scopes is advertisedScopes",
70
+ options: [{
71
+ call: "createMcp",
72
+ from: "scopes",
73
+ to: "advertisedScopes"
74
+ }]
75
+ }
76
+ };
77
+ /** `[start, end)` ranges of code, outside strings, template literals and comments. */
78
+ function codeRanges(text) {
79
+ const ranges = [];
80
+ let start = 0;
81
+ let index = 0;
82
+ const skip = (end) => {
83
+ if (index > start) ranges.push([start, index]);
84
+ index = end;
85
+ start = end;
86
+ };
87
+ while (index < text.length) {
88
+ const char = text[index];
89
+ const next = text[index + 1];
90
+ if (char === "/" && next === "/") {
91
+ const end = text.indexOf("\n", index);
92
+ skip(end === -1 ? text.length : end);
93
+ } else if (char === "/" && next === "*") {
94
+ const end = text.indexOf("*/", index + 2);
95
+ skip(end === -1 ? text.length : end + 2);
96
+ } else if (char === "\"" || char === "'" || char === "`") {
97
+ let end = index + 1;
98
+ while (end < text.length && text[end] !== char) {
99
+ if (text[end] === "\\") end += 1;
100
+ if (char !== "`" && text[end] === "\n") break;
101
+ end += 1;
102
+ }
103
+ skip(text[end] === char ? end + 1 : Math.min(end, text.length));
104
+ } else index += 1;
105
+ }
106
+ if (index > start) ranges.push([start, index]);
107
+ return ranges;
108
+ }
109
+ function applyEdits(text, edits) {
110
+ let out = "";
111
+ let cursor = 0;
112
+ for (const edit of [...edits].sort((a, b) => a.start - b.start)) {
113
+ if (edit.start < cursor) continue;
114
+ out += text.slice(cursor, edit.start) + edit.text;
115
+ cursor = edit.end;
116
+ }
117
+ return out + text.slice(cursor);
118
+ }
119
+ const escapeRegExp = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
120
+ function inCode(ranges, index) {
121
+ let low = 0;
122
+ let high = ranges.length - 1;
123
+ while (low <= high) {
124
+ const middle = low + high >> 1;
125
+ const [start, end] = ranges[middle];
126
+ if (index < start) high = middle - 1;
127
+ else if (index >= end) low = middle + 1;
128
+ else return true;
129
+ }
130
+ return false;
131
+ }
132
+ const OPENING = "({[";
133
+ const CLOSING = ")}]";
134
+ /** Matches of `pattern` that start in code. */
135
+ function codeMatches(text, pattern, ranges) {
136
+ return [...text.matchAll(pattern)].filter((match) => inCode(ranges, match.index));
137
+ }
138
+ const IMPORT = /\b(import|export)\s+(type\s+)?\{([^}]*)\}\s*from\s*(["'])better-supabase(?:\/[\w./-]*)?\4/g;
139
+ function renameImports(text, renames) {
140
+ const ranges = codeRanges(text);
141
+ const locals = /* @__PURE__ */ new Set();
142
+ const edits = [];
143
+ for (const match of codeMatches(text, IMPORT, ranges)) {
144
+ const list = match[3];
145
+ const listStart = match.index + match[0].indexOf("{") + 1;
146
+ const renamed = list.replaceAll(/(\btype\s+)?([\w$]+)(\s+as\s+[\w$]+)?/g, (spec, type, name, alias) => {
147
+ const to = renames[name];
148
+ if (to === void 0) return spec;
149
+ if (alias === void 0 && match[1] === "import") locals.add(name);
150
+ return `${type ?? ""}${to}${alias ?? ""}`;
151
+ });
152
+ if (renamed !== list) edits.push({
153
+ start: listStart,
154
+ end: listStart + list.length,
155
+ text: renamed
156
+ });
157
+ }
158
+ return {
159
+ text: applyEdits(text, edits),
160
+ locals
161
+ };
162
+ }
163
+ function renameIdentifiers(text, renames) {
164
+ if (renames.size === 0) return text;
165
+ const ranges = codeRanges(text);
166
+ const names = [...renames.keys()].map(escapeRegExp).join("|");
167
+ return applyEdits(text, codeMatches(text, new RegExp(`(?<![\\w$.])(?:${names})(?![\\w$])`, "g"), ranges).map((match) => ({
168
+ start: match.index,
169
+ end: match.index + match[0].length,
170
+ text: renames.get(match[0])
171
+ })));
172
+ }
173
+ function renameMembers(text, members) {
174
+ const ranges = codeRanges(text);
175
+ return applyEdits(text, members.flatMap((member) => codeMatches(text, new RegExp(`\\.${escapeRegExp(member.from)}(?![\\w$])${member.notCalled === true ? "(?!\\s*\\()" : ""}`, "g"), ranges).map((match) => ({
176
+ start: match.index,
177
+ end: match.index + match[0].length,
178
+ text: `.${member.to}`
179
+ }))));
180
+ }
181
+ function renameProps(text, props) {
182
+ const ranges = codeRanges(text);
183
+ const edits = [];
184
+ for (const prop of props) {
185
+ const tag = new RegExp(`<${escapeRegExp(prop.component)}(?![\\w$.])`, "g");
186
+ for (const match of codeMatches(text, tag, ranges)) {
187
+ let depth = 0;
188
+ for (let index = match.index + match[0].length; index < text.length; index += 1) {
189
+ if (!inCode(ranges, index)) continue;
190
+ const char = text[index];
191
+ if (char === "{") depth += 1;
192
+ else if (char === "}") depth -= 1;
193
+ else if (char === ">" && depth === 0) break;
194
+ if (depth === 0 && /\s/.test(text[index - 1] ?? "") && text.startsWith(`${prop.from}=`, index)) edits.push({
195
+ start: index,
196
+ end: index + prop.from.length,
197
+ text: prop.to
198
+ });
199
+ }
200
+ }
201
+ }
202
+ return applyEdits(text, edits);
203
+ }
204
+ /** The index after the bracket that closes the one at `open`, in code only. */
205
+ function closing(text, open, ranges) {
206
+ let depth = 0;
207
+ for (let index = open; index < text.length; index += 1) {
208
+ if (!inCode(ranges, index)) continue;
209
+ const char = text[index];
210
+ if (OPENING.includes(char)) depth += 1;
211
+ else if (CLOSING.includes(char)) {
212
+ depth -= 1;
213
+ if (depth === 0) return index + 1;
214
+ }
215
+ }
216
+ return text.length;
217
+ }
218
+ /** Calls `visit(index, depth)` for each code character from `open` to its closing bracket. */
219
+ function walkBrackets(text, open, ranges, visit) {
220
+ const end = closing(text, open, ranges);
221
+ let depth = 0;
222
+ for (let index = open; index < end; index += 1) {
223
+ if (!inCode(ranges, index)) continue;
224
+ const char = text[index];
225
+ if (OPENING.includes(char)) depth += 1;
226
+ else if (CLOSING.includes(char)) depth -= 1;
227
+ visit(index, depth, char);
228
+ }
229
+ }
230
+ /** Where `key` is a top-level key of the object literal at `open`. */
231
+ function topLevelKeys(text, open, key, ranges) {
232
+ const keys = [];
233
+ let previous = "";
234
+ walkBrackets(text, open, ranges, (index, depth, char) => {
235
+ if (depth === 1 && (previous === "{" || previous === ",") && text.startsWith(key, index) && !/[\w$]/.test(text[index + key.length] ?? "")) {
236
+ const after = /^\s*(\S)/.exec(text.slice(index + key.length))?.[1];
237
+ if (after === ":") keys.push({
238
+ index,
239
+ shorthand: false
240
+ });
241
+ else if (after === "," || after === "}") keys.push({
242
+ index,
243
+ shorthand: true
244
+ });
245
+ }
246
+ if (depth === 1 && !/\s/.test(char)) previous = char;
247
+ });
248
+ return keys;
249
+ }
250
+ function renameOptions(text, options) {
251
+ const ranges = codeRanges(text);
252
+ const edits = [];
253
+ for (const option of options) {
254
+ const call = new RegExp(`(?<![\\w$.])${escapeRegExp(option.call)}\\s*(?:<[^>]*>)?\\s*\\(`, "g");
255
+ for (const match of codeMatches(text, call, ranges)) {
256
+ const objects = [];
257
+ walkBrackets(text, match.index + match[0].length - 1, ranges, (index, depth, char) => {
258
+ if (depth === 2 && char === "{") objects.push(index);
259
+ });
260
+ for (const object of objects) for (const { index, shorthand } of topLevelKeys(text, object, option.from, ranges)) edits.push({
261
+ start: index,
262
+ end: index + option.from.length,
263
+ text: shorthand ? `${option.to}: ${option.from}` : option.to
264
+ });
265
+ }
266
+ }
267
+ return applyEdits(text, edits);
268
+ }
269
+ /** Applies one codemod to a source file. */
270
+ function applyCodemod(codemod, source) {
271
+ let text = source;
272
+ if (codemod.imports) {
273
+ const imported = renameImports(text, codemod.imports);
274
+ text = renameIdentifiers(imported.text, new Map([...imported.locals].map((name) => [name, codemod.imports[name]])));
275
+ }
276
+ if (codemod.members) text = renameMembers(text, codemod.members);
277
+ if (codemod.props) text = renameProps(text, codemod.props);
278
+ if (codemod.options) text = renameOptions(text, codemod.options);
279
+ const review = (codemod.review ?? []).flatMap((hint) => text.split("\n").flatMap((line, index) => hint.pattern.test(line) ? [{
280
+ line: index + 1,
281
+ message: hint.message
282
+ }] : []));
283
+ return {
284
+ text,
285
+ review
286
+ };
287
+ }
288
+ //#endregion
289
+ //#region src/cli/commands/codemod.ts
290
+ const CODEMOD_ARGS = {
291
+ name: {
292
+ type: "positional",
293
+ required: false,
294
+ description: "The codemod (0.4 or 0.5), then the files or directories to rewrite (default: the project)"
295
+ },
296
+ "dry-run": {
297
+ type: "boolean",
298
+ description: "Show the changes without writing them"
299
+ }
300
+ };
301
+ const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
302
+ ".ts",
303
+ ".tsx",
304
+ ".mts",
305
+ ".cts",
306
+ ".js",
307
+ ".jsx",
308
+ ".mjs",
309
+ ".cjs"
310
+ ]);
311
+ const SKIPPED_DIRS = /* @__PURE__ */ new Set([
312
+ "node_modules",
313
+ ".git",
314
+ ".next",
315
+ ".turbo",
316
+ ".vercel",
317
+ "dist",
318
+ "build",
319
+ "coverage"
320
+ ]);
321
+ /** Source files under `path`, skipping dependencies, build output and `.d.ts` files. */
322
+ async function sourceFiles(path) {
323
+ const info = await stat(path).catch(() => void 0);
324
+ if (!info) return [];
325
+ if (info.isFile()) return [path];
326
+ const files = [];
327
+ for (const entry of await readdir(path, { withFileTypes: true })) {
328
+ const full = join(path, entry.name);
329
+ if (entry.isDirectory()) {
330
+ if (!SKIPPED_DIRS.has(entry.name)) files.push(...await sourceFiles(full));
331
+ } else if (SOURCE_EXTENSIONS.has(extname(entry.name)) && !entry.name.endsWith(".d.ts")) files.push(full);
332
+ }
333
+ return files.sort();
334
+ }
335
+ async function runCodemod(config, args, paint = plain) {
336
+ const [name, ...paths] = args._;
337
+ const names = Object.entries(CODEMODS).map(([key, codemod]) => ` ${key.padEnd(5)} ${codemod.description}`).join("\n");
338
+ if (name === void 0) return {
339
+ code: 2,
340
+ error: `Name a codemod:\n${names}`
341
+ };
342
+ const codemod = CODEMODS[name];
343
+ if (!codemod) return {
344
+ code: 2,
345
+ error: `Unknown codemod "${name}". Codemods:\n${names}`
346
+ };
347
+ const roots = (paths.length > 0 ? paths : ["."]).map((path) => resolve(config.root, path));
348
+ const files = [...new Set((await Promise.all(roots.map(sourceFiles))).flat())];
349
+ const dryRun = args["dry-run"] === true;
350
+ const changed = [];
351
+ const diffs = [];
352
+ const review = [];
353
+ for (const file of files) {
354
+ const source = await readFile(file, "utf8");
355
+ const result = applyCodemod(codemod, source);
356
+ const path = relative(config.root, file);
357
+ review.push(...result.review.map((hint) => ({
358
+ file: path,
359
+ ...hint
360
+ })));
361
+ if (result.text === source) continue;
362
+ changed.push(path);
363
+ if (dryRun) diffs.push(fileDiff(path, source, result.text, paint));
364
+ else await writeIfChanged(file, result.text);
365
+ }
366
+ const lines = [...diffs, changed.length === 0 ? `Nothing to change in ${String(files.length)} files.` : `${dryRun ? "Would update" : "Updated"} ${String(changed.length)} of ${String(files.length)} files:\n${changed.map((path) => ` ${path}`).join("\n")}`];
367
+ if (review.length > 0) lines.push("", "Check these by hand:", ...review.map((hint) => ` ${hint.file}:${String(hint.line)}: ${hint.message}`));
368
+ return {
369
+ code: 0,
370
+ output: lines.join("\n"),
371
+ data: {
372
+ codemod: codemod.name,
373
+ dryRun,
374
+ changed,
375
+ review
376
+ }
377
+ };
378
+ }
379
+ const codemodCommand = defineCliCommand({
380
+ meta: {
381
+ name: "codemod",
382
+ description: "Rewrites imports and calls for renamed better-supabase APIs"
383
+ },
384
+ args: CODEMOD_ARGS,
385
+ run: (args, { config, io }) => runCodemod(config, args, painter(io.color))
386
+ });
387
+ //#endregion
388
+ export { codemodCommand };
@@ -1,7 +1,7 @@
1
1
  import { n as CliError } from "./errors-4v4DTtda.js";
2
2
  import { t as display } from "./io-k41_z-jT.js";
3
- import { c as resolve$1, i as extname, n as basename$1, o as join$1, r as dirname$1, s as normalize$1, t as resolveModulePath } from "./dist-CFgGknmZ.js";
4
- import { a as literal, c as picklist, d as safeParse, f as strictObject, h as unknown, i as getDotPath, m as union, n as boolean, o as number, p as string, r as custom, s as optional, t as array, u as record } from "./dist-Du7VnEUG.js";
3
+ import { c as resolve$1, i as extname$1, n as basename$1, o as join$1, r as dirname$1, s as normalize$1, t as resolveModulePath } from "./dist-DBPdlPYK.js";
4
+ import { _ as unknown, a as literal, c as objectWithRest, f as record, g as union, h as string, i as getDotPath, l as optional, m as strictObject, n as boolean, o as nullable, p as safeParse, r as custom, s as number, t as array, u as picklist } from "./dist-xn4wlboc.js";
5
5
  import * as nodeUtil from "node:util";
6
6
  import { join, posix, resolve } from "node:path";
7
7
  import { existsSync, readFileSync, statSync } from "node:fs";
@@ -454,7 +454,7 @@ async function loadConfig$1(options) {
454
454
  dir: options.cwd
455
455
  }));
456
456
  if (options.globalRc) {
457
- const { findWorkspaceDir } = await import("./dist-B1MvLv-M.js");
457
+ const { findWorkspaceDir } = await import("./dist-DreZ24Sz.js");
458
458
  const workspaceDir = await findWorkspaceDir(options.cwd).catch(() => {});
459
459
  if (workspaceDir) rcSources.push(read({
460
460
  name: options.rcFile,
@@ -470,7 +470,7 @@ async function loadConfig$1(options) {
470
470
  }
471
471
  if (options.packageJson) {
472
472
  const keys = (Array.isArray(options.packageJson) ? options.packageJson : [typeof options.packageJson === "string" ? options.packageJson : options.name]).filter((t) => t && typeof t === "string");
473
- const { readPackageJSON } = await import("./dist-B1MvLv-M.js");
473
+ const { readPackageJSON } = await import("./dist-DreZ24Sz.js");
474
474
  const pkgJsonFile = await readPackageJSON(options.cwd).catch(() => {});
475
475
  rawConfigs.packageJson = _merger({}, ...keys.map((key) => pkgJsonFile?.[key]));
476
476
  }
@@ -602,7 +602,7 @@ async function resolveConfig$1(source, options, sourceOptions = {}) {
602
602
  })).dir;
603
603
  }
604
604
  if (NPM_PACKAGE_RE.test(source)) source = tryResolve(source, options) || source;
605
- const ext = extname(source);
605
+ const ext = extname$1(source);
606
606
  const isDir = _isDirectory(resolve$1(options.cwd, source)) ?? (!ext || ext === basename$1(source));
607
607
  const cwd = resolve$1(options.cwd, isDir ? source : dirname$1(source));
608
608
  if (isDir) source = options.configFile;
@@ -616,7 +616,7 @@ async function resolveConfig$1(source, options, sourceOptions = {}) {
616
616
  res.configFile = tryResolve(resolve$1(cwd, source), options) || tryResolve(resolve$1(cwd, ".config", source.replace(/\.config$/, "")), options) || tryResolve(resolve$1(cwd, ".config", source), options) || source;
617
617
  if (!existsSync(res.configFile)) return res;
618
618
  res._configFile = res.configFile;
619
- const configFileExt = extname(res.configFile) || "";
619
+ const configFileExt = extname$1(res.configFile) || "";
620
620
  if (configFileExt in ASYNC_LOADERS) res.config = (await ASYNC_LOADERS[configFileExt]())(await readFile(res.configFile, "utf8"));
621
621
  else {
622
622
  const _resolveModule = options.resolveModule || ((mod) => mod.default || mod);
@@ -696,6 +696,56 @@ const isGenerator = (value) => typeof value === "object" && value !== null && "n
696
696
  * checks the leaves a typo or an old value breaks; nested objects the
697
697
  * library reads loosely stay loose.
698
698
  */
699
+ const kitModuleEntries = {
700
+ mode: optional(picklist([
701
+ "managed",
702
+ "adopt",
703
+ "custom"
704
+ ])),
705
+ schema: optional(string()),
706
+ tables: optional(record(string(), nullable(string()))),
707
+ columns: optional(record(string(), record(string(), nullable(string())))),
708
+ idType: optional(string()),
709
+ permissions: optional(stringRecord),
710
+ options: optional(record(string(), unknown())),
711
+ hooks: optional(strictObject({
712
+ schema: optional(string()),
713
+ functions: optional(stringRecord)
714
+ })),
715
+ events: optional(boolean())
716
+ };
717
+ const accessKit = strictObject({
718
+ ...kitModuleEntries,
719
+ model: optional(picklist([
720
+ "roles",
721
+ "catalog",
722
+ "permdock",
723
+ "custom"
724
+ ])),
725
+ roles: optional(record(string(), strings)),
726
+ functions: optional(strictObject({
727
+ can: optional(string()),
728
+ tenantIdsWith: optional(string()),
729
+ isPlatform: optional(string()),
730
+ canUser: optional(string()),
731
+ canAssign: optional(string()),
732
+ permissionClaims: optional(string())
733
+ })),
734
+ platformClaim: optional(string()),
735
+ disabled: optional(strictObject({
736
+ tenant: optional(string()),
737
+ user: optional(string()),
738
+ userKey: optional(string())
739
+ })),
740
+ activeTenant: optional(union([picklist(["claim", "resolver"]), strictObject({
741
+ profileColumn: string(),
742
+ key: optional(string())
743
+ })])),
744
+ permdock: optional(strictObject({
745
+ schema: optional(string()),
746
+ scope: optional(string())
747
+ }))
748
+ });
699
749
  const ConfigSchema = strictObject({
700
750
  $schema: optional(string()),
701
751
  source: optional(strictObject({
@@ -744,7 +794,10 @@ const ConfigSchema = strictObject({
744
794
  })),
745
795
  buckets: optional(record(string(), record(string(), unknown()))),
746
796
  topics: optional(stringRecord),
747
- realtime: optional(strictObject({ tables: optional(strings) })),
797
+ realtime: optional(strictObject({
798
+ tables: optional(strings),
799
+ global: optional(strings)
800
+ })),
748
801
  entitlements: optional(strictObject({
749
802
  customer: optional(string()),
750
803
  key: optional(string()),
@@ -768,6 +821,7 @@ const ConfigSchema = strictObject({
768
821
  testsDir: optional(string()),
769
822
  kit: optional(strings)
770
823
  })),
824
+ kits: optional(objectWithRest({ access: optional(accessKit) }, strictObject(kitModuleEntries))),
771
825
  seed: optional(strictObject({
772
826
  entry: optional(string()),
773
827
  output: optional(string())
@@ -1747,6 +1801,22 @@ function pgFunctionHooks(document) {
1747
1801
  }] : [];
1748
1802
  });
1749
1803
  }
1804
+ /** The enabled Auth hooks with an `http://` or `https://` URI, by hook name. */
1805
+ function httpHooks(document) {
1806
+ const hooks = tomlGet(document, ["auth", "hook"]);
1807
+ if (typeof hooks !== "object" || Array.isArray(hooks)) return [];
1808
+ return Object.entries(hooks).flatMap(([hook, table]) => {
1809
+ if (typeof table !== "object" || Array.isArray(table)) return [];
1810
+ const { enabled, uri, secrets } = table;
1811
+ if (enabled !== true && enabled !== "true" || typeof uri !== "string") return [];
1812
+ if (!/^https?:\/\//i.test(uri.trim()) || !URL.canParse(uri.trim())) return [];
1813
+ return [{
1814
+ hook,
1815
+ uri: new URL(uri.trim()),
1816
+ secrets: typeof secrets === "string" ? secrets : void 0
1817
+ }];
1818
+ });
1819
+ }
1750
1820
  /** pg-delta when `[experimental.pgdelta] enabled = true`, otherwise the legacy migra engine. */
1751
1821
  function diffEngine(toml) {
1752
1822
  const enabled = tomlGet(toml?.document ?? {}, [
@@ -1892,4 +1962,4 @@ async function databaseUrl(config, env, fromStdin) {
1892
1962
  return `postgresql://postgres:postgres@127.0.0.1:${await readSupabasePort(config.root, "db") ?? 54322}/postgres`;
1893
1963
  }
1894
1964
  //#endregion
1895
- export { loadConfig as a, diffEngine as c, readSupabaseToml as d, schemaPaths as f, importModule as i, migrationCommand as l, findConfig as n, readSupabasePort as o, tomlGet as p, importExport as r, stdinDatabaseUrl as s, databaseUrl as t, pgFunctionHooks as u };
1965
+ export { loadConfig as a, diffEngine as c, pgFunctionHooks as d, readSupabaseToml as f, importModule as i, httpHooks as l, tomlGet as m, findConfig as n, readSupabasePort as o, schemaPaths as p, importExport as r, stdinDatabaseUrl as s, databaseUrl as t, migrationCommand as u };
@@ -1,2 +1,2 @@
1
- import { a as loadConfig, i as importModule, n as findConfig, o as readSupabasePort, r as importExport, s as stdinDatabaseUrl, t as databaseUrl } from "./config-D9R0o1LH.js";
1
+ import { a as loadConfig, i as importModule, n as findConfig, o as readSupabasePort, r as importExport, s as stdinDatabaseUrl, t as databaseUrl } from "./config-CPVpXP5I.js";
2
2
  export { databaseUrl, findConfig, importExport, importModule, loadConfig, readSupabasePort, stdinDatabaseUrl };