better-supabase 0.3.0 → 0.4.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 (172) hide show
  1. package/README.md +7 -6
  2. package/bin/better-supabase.js +4 -0
  3. package/dist/{base64-CQeB1eSf.js → base64-D2gsioCY.js} +2 -2
  4. package/dist/claims-BAf6c7is.js +48 -0
  5. package/dist/cli/_format-Cax5EsM9.js +101 -0
  6. package/dist/cli/bin.d.ts +1 -0
  7. package/dist/cli/bin.js +48 -0
  8. package/dist/cli/command-CK14fP91.js +502 -0
  9. package/dist/cli/compare-BmIWVEui.js +9 -0
  10. package/dist/cli/config-D9R0o1LH.js +1895 -0
  11. package/dist/cli/config-SSKSTUl2.js +2 -0
  12. package/dist/cli/db-DOBPt660.js +52 -0
  13. package/dist/cli/dist-B1MvLv-M.js +129 -0
  14. package/dist/cli/dist-CFgGknmZ.js +1112 -0
  15. package/dist/cli/dist-Du7VnEUG.js +621 -0
  16. package/dist/cli/doctor-BOym3mbL.js +2382 -0
  17. package/dist/cli/env-BZ0uy8XK.js +108 -0
  18. package/dist/cli/env-jIFUADLY.js +511 -0
  19. package/dist/cli/errors-4v4DTtda.js +56 -0
  20. package/dist/cli/fastest-levenshtein-CFN-lNDv.js +120 -0
  21. package/dist/cli/gen-Ccn_p90L.js +2008 -0
  22. package/dist/cli/gen-D5cLCULx.js +2 -0
  23. package/dist/cli/index.d.ts +493 -0
  24. package/dist/cli/index.js +184 -0
  25. package/dist/cli/init-ClnxRYBF.js +550 -0
  26. package/dist/cli/introspect-DxqfkVIv.js +81 -0
  27. package/dist/cli/io-k41_z-jT.js +24 -0
  28. package/dist/cli/json5-ChRycquj.js +787 -0
  29. package/dist/cli/jsonc-BUniUpOk.js +2 -0
  30. package/dist/cli/jsonc-D5Fu67jw.js +45 -0
  31. package/dist/cli/keys-ByKHnvP9.js +83 -0
  32. package/dist/cli/ohash-D7bG_EOb.js +277 -0
  33. package/dist/cli/openapi-8WHjxiTJ.js +66 -0
  34. package/dist/cli/project-B_GeXyHh.js +70 -0
  35. package/dist/cli/prompts-BNcNfAve.js +1142 -0
  36. package/dist/cli/prompts-BTYQGunc.js +2 -0
  37. package/dist/cli/read-sets-CMa29t9a.js +971 -0
  38. package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
  39. package/dist/cli/run-CP20LKk_.js +347 -0
  40. package/dist/cli/seed-5J6eu_Xg.js +98 -0
  41. package/dist/cli/skills-LJJIhLFR.js +137 -0
  42. package/dist/cli/sql-D4VbqmXi.js +199 -0
  43. package/dist/cli/style-C0NFdJRL.js +29 -0
  44. package/dist/cli/toml-DB-MNnFs.js +424 -0
  45. package/dist/cli/version-5mW_8sY1.js +4 -0
  46. package/dist/cli/yaml-CYCbJ6et.js +2252 -0
  47. package/dist/client/index.d.ts +2 -2
  48. package/dist/client/index.js +13 -13
  49. package/dist/{compiler-2zqGzxVZ.d.ts → compiler-DB3aSFOA.d.ts} +2 -2
  50. package/dist/config/index.js +4 -4
  51. package/dist/{config-Be4GwsqI.js → config-BpxDfnbg.js} +1 -1
  52. package/dist/{config-DOsGYSiT.js → config-CbvFmGD8.js} +1 -1
  53. package/dist/{define-DF341GDj.js → define-Bh0AqTik.js} +160 -79
  54. package/dist/{define-DUbydmJa.d.ts → define-CRS2MRV3.d.ts} +32 -28
  55. package/dist/edge/index.d.ts +8 -12
  56. package/dist/edge/index.js +50 -24
  57. package/dist/{entitlements-DvJXoI02.d.ts → entitlements-Dm-FHpNH.d.ts} +2 -2
  58. package/dist/{errors-Bl3rkOzo.js → errors-L0xK41y_.js} +1 -1
  59. package/dist/events/index.d.ts +1 -1
  60. package/dist/events/index.js +4 -4
  61. package/dist/{events-Do8jXh4D.d.ts → events-B21UOhvP.d.ts} +4 -4
  62. package/dist/{executor-DynmIWhq.d.ts → executor-B5IoUxLE.d.ts} +1 -1
  63. package/dist/{executor-C57jx2pn.js → executor-CVt6dD0B.js} +3 -3
  64. package/dist/{executor-B26lgbHD.d.ts → executor-CZ7ImRiD.d.ts} +2 -2
  65. package/dist/hono/index.d.ts +16 -23
  66. package/dist/hono/index.js +10 -10
  67. package/dist/{index-CTTMS6_1.d.ts → index-528Ugmyp.d.ts} +12 -3
  68. package/dist/{index-CADlNHK-.d.ts → index-BAy4tsAP.d.ts} +5 -5
  69. package/dist/{index-BNsABq7P.d.ts → index-BBdvo-5d.d.ts} +23 -25
  70. package/dist/{index-qriRM9cZ.d.ts → index-BhHEC04r.d.ts} +3 -3
  71. package/dist/{index-GV77NpRP.d.ts → index-D5IfUIDh.d.ts} +3 -3
  72. package/dist/{index-CriFFJ_p.d.ts → index-DFmOpBGC.d.ts} +11 -11
  73. package/dist/{index-UJ-LUxtI.d.ts → index-RlLXd8dL.d.ts} +12 -12
  74. package/dist/index.d.ts +15 -15
  75. package/dist/index.js +13 -13
  76. package/dist/{invalidate-DbxuL2jL.js → invalidate-CgxmRamI.js} +7 -1
  77. package/dist/jobs/index.d.ts +10 -4
  78. package/dist/jobs/index.js +32 -16
  79. package/dist/{json-schema--aOXAGfU.js → json-schema-DP6V7cbr.js} +1 -1
  80. package/dist/list/index.d.ts +1 -1
  81. package/dist/list/index.js +3 -3
  82. package/dist/{live-QE3UPbGm.d.ts → live-BHakSWWo.d.ts} +12 -12
  83. package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
  84. package/dist/lookup-BaP5bI27.js +18 -0
  85. package/dist/mcp/index.d.ts +18 -18
  86. package/dist/mcp/index.js +23 -18
  87. package/dist/{mfa-x3V3vGh-.d.ts → mfa-C7MNQ1Ob.d.ts} +1 -1
  88. package/dist/{mfa-BxoR1RkN.js → mfa-byfjruR9.js} +118 -29
  89. package/dist/next/image/index.js +6 -3
  90. package/dist/next/index.d.ts +38 -35
  91. package/dist/next/index.js +41 -33
  92. package/dist/openapi/index.d.ts +1 -1
  93. package/dist/openapi/index.js +6 -6
  94. package/dist/orpc/index.d.ts +17 -20
  95. package/dist/orpc/index.js +11 -11
  96. package/dist/otel/index.d.ts +5 -5
  97. package/dist/otel/index.js +81 -62
  98. package/dist/{permdock-sql-Bta_G0v-.js → permdock-sql-C4KFzLc9.js} +1 -1
  99. package/dist/{plugin-DVRB8qNE.d.ts → plugin-bNhvJwRh.d.ts} +2 -2
  100. package/dist/plugins/actor/index.d.ts +1 -1
  101. package/dist/plugins/actor/index.js +1 -1
  102. package/dist/plugins/rules/index.d.ts +2 -2
  103. package/dist/plugins/rules/index.js +42 -12
  104. package/dist/plugins/soft-delete/index.d.ts +2 -2
  105. package/dist/plugins/soft-delete/index.js +2 -2
  106. package/dist/plugins/tenant/index.d.ts +2 -2
  107. package/dist/plugins/tenant/index.js +10 -4
  108. package/dist/plugins/timestamps/index.d.ts +1 -1
  109. package/dist/plugins/timestamps/index.js +1 -1
  110. package/dist/plugins/validation/index.d.ts +2 -2
  111. package/dist/plugins/validation/index.js +3 -3
  112. package/dist/{pool-B9qsLyFR.d.ts → pool-DFwEQwmN.d.ts} +11 -4
  113. package/dist/postgres/index.d.ts +5 -5
  114. package/dist/postgres/index.js +3 -2
  115. package/dist/{postgrest-DmBlevh-.d.ts → postgrest-Bc-0Xw62.d.ts} +1 -1
  116. package/dist/{problem-CGt1ADix.js → problem-BihjPR0t.js} +1 -1
  117. package/dist/{problem-Z2RTQjZD.d.ts → problem-U8UEKccv.d.ts} +1 -1
  118. package/dist/query/index.d.ts +2 -2
  119. package/dist/query/index.js +2 -2
  120. package/dist/{query-BdKLTPlj.js → query-BMMSWbI7.js} +18 -18
  121. package/dist/react/index.d.ts +6 -6
  122. package/dist/react/index.js +1 -1
  123. package/dist/react/server.d.ts +5 -5
  124. package/dist/react/server.js +3 -3
  125. package/dist/react/session.d.ts +4 -4
  126. package/dist/react/session.js +2 -2
  127. package/dist/{react-DNBYNazu.js → react-CQHMaESR.js} +39 -39
  128. package/dist/{read-set-D0qBcboM.js → read-set-FWK8qQ58.js} +50 -15
  129. package/dist/realtime/index.d.ts +1 -1
  130. package/dist/realtime/index.js +13 -12
  131. package/dist/{index-kpgopLNv.d.ts → refresh-BwYkyNOQ.d.ts} +6 -3
  132. package/dist/{resolve-BRciX2jK.d.ts → resolve-BAqQcwMW.d.ts} +15 -10
  133. package/dist/{resource-CwVgiI5q.d.ts → resource-BJcaIfxi.d.ts} +5 -5
  134. package/dist/{resource-D30rp0GN.js → resource-My_y-Syh.js} +6 -6
  135. package/dist/{respond-DAkPIdTH.d.ts → respond-DgIbdrt8.d.ts} +31 -12
  136. package/dist/{result-DWXatkd6.js → result-Bj6yt33D.js} +2 -2
  137. package/dist/{result-c2OYgCV2.d.ts → result-CqEsbgYs.d.ts} +3 -3
  138. package/dist/server/index.d.ts +14 -14
  139. package/dist/server/index.js +12 -12
  140. package/dist/{respond-C44EZAJo.js → server-BA75B0mT.js} +139 -100
  141. package/dist/{shared-_6-uPL7E.js → shared-DnoCdMDr.js} +4 -3
  142. package/dist/{simplify-LakqK1vH.js → simplify-Cqvfr9dj.js} +67 -24
  143. package/dist/sql/index.d.ts +1 -1
  144. package/dist/sql/index.js +7 -7
  145. package/dist/{sql-BIgk12ew.js → sql-B34HU2DI.js} +3 -2
  146. package/dist/ssr/index.d.ts +4 -4
  147. package/dist/ssr/index.js +2 -2
  148. package/dist/{standard-FUi3Z3-7.js → standard-BRyBGTtp.js} +2 -2
  149. package/dist/{standard-eudBiRk1.d.ts → standard-BsaCYQJc.d.ts} +1 -1
  150. package/dist/{stats-D78UQ8Yu.js → stats-C_YxA2r1.js} +33 -8
  151. package/dist/storage/index.d.ts +2 -2
  152. package/dist/storage/index.js +26 -8
  153. package/dist/{tables-Dhha3BXM.js → tables-Cb-3_VWc.js} +14 -0
  154. package/dist/{temporal-required-CMxeSVPo.js → temporal-required-CBNHT6ni.js} +1 -1
  155. package/dist/testing/index.d.ts +20 -21
  156. package/dist/testing/index.js +45 -45
  157. package/dist/{version-BfpG2gks.js → version-Bmf7_FzM.js} +1 -1
  158. package/dist/{view-3Po_PVlr.d.ts → view-B64o81wp.d.ts} +5 -5
  159. package/dist/{view-wZ-9qIUz.js → view-BrJI2LKp.js} +1 -1
  160. package/dist/webhooks/index.d.ts +3 -3
  161. package/dist/webhooks/index.js +1 -1
  162. package/dist/{webhooks-CAIFQSTM.js → webhooks-Bh_Jf_-l.js} +37 -18
  163. package/package.json +36 -4
  164. package/skills/better-supabase/SKILL.md +57 -10
  165. package/skills/better-supabase/references/plugins.md +7 -11
  166. package/skills/better-supabase/references/troubleshooting.md +24 -4
  167. package/skills/better-supabase-api/SKILL.md +66 -18
  168. package/skills/better-supabase-api/references/adapters.md +44 -26
  169. package/skills/better-supabase-auth/SKILL.md +146 -0
  170. package/skills/better-supabase-auth/references/permdock.md +55 -0
  171. package/skills/better-supabase-testing/SKILL.md +58 -4
  172. package/dist/claims-CoTobNC-.js +0 -25
@@ -1,6 +1,6 @@
1
1
  import { A as SchemaMeta, N as TableKey, O as Row, n as AnyModels, t as AnyFunctions, x as PermdockTopicPolicy } from "./types-DONv9SHN.js";
2
- import { b as ValidationIssue, o as Result, p as DbError, t as AsyncResult } from "./result-c2OYgCV2.js";
3
- import { Z as QuerySpec, t as BetterSupabase } from "./define-DUbydmJa.js";
2
+ import { b as ValidationIssue, o as Result, p as DbError, t as AsyncResult } from "./result-CqEsbgYs.js";
3
+ import { Z as QuerySpec, t as BetterSupabase } from "./define-CRS2MRV3.js";
4
4
  import { t as PermdockCatalog } from "./permdock-sql-DImJULY-.js";
5
5
  import { n as TemplateValues, t as TemplateParams } from "./template-mbvlysOo.js";
6
6
  import { RealtimeChannel, SupabaseClient } from "@supabase/supabase-js";
@@ -78,7 +78,7 @@ interface Subscription extends Disposable, AsyncDisposable {
78
78
  readonly ready: Promise<void>;
79
79
  unsubscribe(): Promise<void>;
80
80
  }
81
- type RealtimeClient = Pick<SupabaseClient, "channel" | "removeChannel" | "realtime">;
81
+ type RealtimeClient = Pick<SupabaseClient, "channel" | "getChannels" | "removeChannel" | "realtime">;
82
82
  interface TriggerOptions<M extends AnyModels, T extends keyof M, P extends string> {
83
83
  /** Column that fills each placeholder. */
84
84
  readonly values: { readonly [K in TemplateParams<P>]: Extract<keyof Row<M, T>, string>; };
@@ -106,7 +106,7 @@ interface Topic<P extends string, E extends EventSchemas> {
106
106
  /** `realtime.messages` policies for this topic. Idempotent. */
107
107
  sql(): string;
108
108
  /** A trigger that broadcasts row changes (`realtime.broadcast_changes`) to this topic. */
109
- triggerSql<M extends AnyModels, D, F extends AnyFunctions, X, T extends TableKey<M>>(sb: BetterSupabase<M, D, F, X>, table: T, options: TriggerOptions<M, T, P>): string;
109
+ triggerSql<M extends AnyModels, D, F extends AnyFunctions, X, T extends TableKey<M>>(betterSupabase: BetterSupabase<M, D, F, X>, table: T, options: TriggerOptions<M, T, P>): string;
110
110
  subscribe(client: RealtimeClient, values: TemplateValues<P>, handlers: TopicHandlers<E>, options?: SubscribeOptions): Subscription;
111
111
  /** Sends over HTTP, without joining the channel. */
112
112
  send<K extends TopicEvent<E>>(client: RealtimeClient, values: TemplateValues<P>, event: K, payload: TopicPayload<E, K>): AsyncResult<void>;
@@ -127,10 +127,10 @@ declare function defineTopic<const P extends string, const E extends EventSchema
127
127
  * Reads a `realtime.broadcast_changes` message as an app-cased row change.
128
128
  * Returns `null` for messages about other tables.
129
129
  */
130
- declare function rowChange<M extends AnyModels, D, F extends AnyFunctions, X, T extends TableKey<M>>(sb: BetterSupabase<M, D, F, X>, table: T, message: TopicMessage): RowChange<Row<M, T>> | null;
130
+ declare function rowChange<M extends AnyModels, D, F extends AnyFunctions, X, T extends TableKey<M>>(betterSupabase: BetterSupabase<M, D, F, X>, table: T, message: TopicMessage): RowChange<Row<M, T>> | null;
131
131
  //#endregion
132
132
  //#region src/realtime/live.d.ts
133
- /** What `liveQuery` needs from `sb`: metadata and the tables a spec reads. */
133
+ /** What `liveQuery` needs from `betterSupabase`: metadata and the tables a spec reads. */
134
134
  interface LiveSource {
135
135
  readonly meta: SchemaMeta;
136
136
  tablesOf(spec: QuerySpec): string[];
@@ -154,7 +154,7 @@ interface LiveSubscription extends Disposable, AsyncDisposable {
154
154
  }
155
155
  /**
156
156
  * A count from the server plus the spec to keep it live on the client:
157
- * `next.liveCount(spec)` makes one, `useLiveCount(seed)` reads it. `count`
157
+ * `bs.liveCount(spec)` makes one, `useLiveCount(seed)` reads it. `count`
158
158
  * is `null` when the server read failed; the client then fetches it.
159
159
  */
160
160
  interface LiveCountSeed<T extends string = string> {
@@ -170,11 +170,11 @@ declare function liveTopic(meta: SchemaMeta, table: string, tenant?: string): st
170
170
  * table, so any number of them can run at once.
171
171
  *
172
172
  * ```ts
173
- * using live = liveQuery(sb, supabase, spec, { onChange: () => refetch() });
173
+ * using live = liveQuery(betterSupabase, supabase, spec, { onChange: () => refetch() });
174
174
  * ```
175
175
  */
176
- declare function liveQuery(sb: LiveSource, client: RealtimeClient, spec: QuerySpec | readonly string[], options: LiveQueryOptions): LiveSubscription;
177
- /** What `liveCount` runs the spec with: a `db` from `sb.connect()` or `createBrowser()`. */
176
+ declare function liveQuery(betterSupabase: LiveSource, client: RealtimeClient, spec: QuerySpec | readonly string[], options: LiveQueryOptions): LiveSubscription;
177
+ /** What `liveCount` runs the spec with: a `db` from `betterSupabase.connect()` or `createClient()`. */
178
178
  interface CountRunner {
179
179
  $run(spec: QuerySpec): PromiseLike<Result<unknown>>;
180
180
  }
@@ -191,11 +191,11 @@ interface LiveCountOptions extends Omit<LiveQueryOptions, "onChange"> {
191
191
  * Responses that arrive out of order are dropped.
192
192
  *
193
193
  * ```ts
194
- * using live = liveCount(sb, supabase, db, sb.spec.notes.count(), {
194
+ * using live = liveCount(betterSupabase, supabase, db, betterSupabase.spec.notes.count(), {
195
195
  * onCount: (count) => render(count),
196
196
  * });
197
197
  * ```
198
198
  */
199
- declare function liveCount(sb: LiveSource, client: RealtimeClient, db: CountRunner, spec: QuerySpec<string, "count", number>, options: LiveCountOptions): LiveSubscription;
199
+ declare function liveCount(betterSupabase: LiveSource, client: RealtimeClient, db: CountRunner, spec: QuerySpec<string, "count", number>, options: LiveCountOptions): LiveSubscription;
200
200
  //#endregion
201
201
  export { defineTopic as C, TriggerOptions as S, TopicEvent as _, LiveSource as a, TopicOptions as b, liveQuery as c, RealtimeClient as d, RowChange as f, Topic as g, SubscriptionStatus as h, LiveQueryOptions as i, liveTopic as l, Subscription as m, LiveCountOptions as n, LiveSubscription as o, SubscribeOptions as p, LiveCountSeed as r, liveCount as s, CountRunner as t, EventSchemas as u, TopicHandlers as v, rowChange as w, TopicPayload as x, TopicMessage as y };
@@ -64,6 +64,10 @@ function join(client, topic, listener) {
64
64
  left = true;
65
65
  current.listeners.delete(listener);
66
66
  if (current.listeners.size > 0) return;
67
+ await new Promise((resolve) => {
68
+ setTimeout(resolve, 0);
69
+ });
70
+ if (current.listeners.size > 0 || byTopic.get(topic) !== current) return;
67
71
  byTopic.delete(topic);
68
72
  await client.removeChannel(current.channel);
69
73
  }
@@ -76,13 +80,13 @@ function join(client, topic, listener) {
76
80
  * table, so any number of them can run at once.
77
81
  *
78
82
  * ```ts
79
- * using live = liveQuery(sb, supabase, spec, { onChange: () => refetch() });
83
+ * using live = liveQuery(betterSupabase, supabase, spec, { onChange: () => refetch() });
80
84
  * ```
81
85
  */
82
- function liveQuery(sb, client, spec, options) {
83
- const touched = Array.isArray(spec) ? spec : sb.tablesOf(spec);
84
- const tables = touched.filter((table) => sb.meta.realtime?.[table]);
85
- const unwatched = touched.filter((table) => !sb.meta.realtime?.[table]);
86
+ function liveQuery(betterSupabase, client, spec, options) {
87
+ const touched = Array.isArray(spec) ? spec : betterSupabase.tablesOf(spec);
88
+ const tables = touched.filter((table) => betterSupabase.meta.realtime?.[table]);
89
+ const unwatched = touched.filter((table) => !betterSupabase.meta.realtime?.[table]);
86
90
  const debounceMs = options.debounceMs ?? 100;
87
91
  const changed = /* @__PURE__ */ new Set();
88
92
  let timer;
@@ -94,7 +98,7 @@ function liveQuery(sb, client, spec, options) {
94
98
  changed.clear();
95
99
  options.onChange(batch);
96
100
  };
97
- const memberships = tables.map((table) => join(client, liveTopic(sb.meta, table, options.tenant), () => {
101
+ const memberships = tables.map((table) => join(client, liveTopic(betterSupabase.meta, table, options.tenant), () => {
98
102
  changed.add(table);
99
103
  if (timer !== void 0) clearTimeout(timer);
100
104
  timer = setTimeout(flush, debounceMs);
@@ -130,12 +134,12 @@ function liveQuery(sb, client, spec, options) {
130
134
  * Responses that arrive out of order are dropped.
131
135
  *
132
136
  * ```ts
133
- * using live = liveCount(sb, supabase, db, sb.spec.notes.count(), {
137
+ * using live = liveCount(betterSupabase, supabase, db, betterSupabase.spec.notes.count(), {
134
138
  * onCount: (count) => render(count),
135
139
  * });
136
140
  * ```
137
141
  */
138
- function liveCount(sb, client, db, spec, options) {
142
+ function liveCount(betterSupabase, client, db, spec, options) {
139
143
  let latest = 0;
140
144
  let closed = false;
141
145
  const refetch = () => {
@@ -146,7 +150,7 @@ function liveCount(sb, client, db, spec, options) {
146
150
  else options.onError?.(result.error);
147
151
  });
148
152
  };
149
- const live = liveQuery(sb, client, spec, {
153
+ const live = liveQuery(betterSupabase, client, spec, {
150
154
  onChange: refetch,
151
155
  ...options.tenant === void 0 ? {} : { tenant: options.tenant },
152
156
  ...options.debounceMs === void 0 ? {} : { debounceMs: options.debounceMs },
@@ -0,0 +1,18 @@
1
+ //#region src/schema/lookup.ts
2
+ const lookups = /* @__PURE__ */ new WeakMap();
3
+ /** The cached lookup for a table; metadata is immutable after `defineSchema`. */
4
+ function lookupOf(table) {
5
+ let lookup = lookups.get(table);
6
+ if (!lookup) {
7
+ const entries = Object.entries(table.columns);
8
+ lookup = {
9
+ entries,
10
+ byDb: new Map(entries.map((entry) => [entry[1].db, entry])),
11
+ keys: [table.primaryKey, ...Object.values(table.uniqueKeys)]
12
+ };
13
+ lookups.set(table, lookup);
14
+ }
15
+ return lookup;
16
+ }
17
+ //#endregion
18
+ export { lookupOf as t };
@@ -1,7 +1,7 @@
1
1
  import { N as TableKey, n as AnyModels, t as AnyFunctions } from "../types-DONv9SHN.js";
2
- import { t as BetterSupabase } from "../define-DUbydmJa.js";
3
- import { d as ServerContext, f as ServerOptions, l as BetterServer, n as GuardOptions } from "../respond-DAkPIdTH.js";
4
- import { a as ResourceRouteOptions } from "../resource-CwVgiI5q.js";
2
+ import { t as BetterSupabase } from "../define-CRS2MRV3.js";
3
+ import { f as ServerContext, n as GuardOptions, p as ServerOptions, u as BetterServer } from "../respond-DgIbdrt8.js";
4
+ import { a as ResourceRouteOptions } from "../resource-BJcaIfxi.js";
5
5
  import { StandardSchemaV1 } from "@standard-schema/spec";
6
6
  //#region src/mcp/mcp.d.ts
7
7
  export declare const MCP_PROTOCOL_VERSION: string;
@@ -23,17 +23,17 @@ interface ToolInfo {
23
23
  readonly outputSchema?: Json;
24
24
  readonly annotations?: ToolAnnotations;
25
25
  }
26
- interface ToolContext<M extends AnyModels, F extends AnyFunctions, E> extends ServerContext<M, F, E> {
26
+ interface ToolContext<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> extends ServerContext<M, F, E, C, P> {
27
27
  readonly request: Request;
28
28
  readonly signal: AbortSignal;
29
29
  }
30
- interface McpTool<M extends AnyModels, F extends AnyFunctions, E> {
30
+ interface McpTool<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> {
31
31
  readonly info: ToolInfo;
32
32
  /** Validates arguments; its output is what `run` receives. */
33
33
  readonly input?: StandardSchemaV1;
34
34
  /** Opaque data for the `authorize` and `visible` hooks. Never sent to clients. */
35
35
  readonly meta?: unknown;
36
- run(args: never, ctx: ToolContext<M, F, E>): unknown;
36
+ run(args: never, ctx: ToolContext<M, F, E, C, P>): unknown;
37
37
  }
38
38
  /** What the `authorize` and `visible` hooks see of a tool. */
39
39
  interface ToolRef {
@@ -50,7 +50,7 @@ type ToolDecision = {
50
50
  /** OAuth scopes the call needs, sent in an `insufficient_scope` challenge. */
51
51
  readonly scopes?: readonly string[];
52
52
  };
53
- interface ToolDefinition<M extends AnyModels, F extends AnyFunctions, E, I> {
53
+ interface ToolDefinition<M extends AnyModels, F extends AnyFunctions, E, I, C = unknown, P = unknown> {
54
54
  readonly name: string;
55
55
  readonly title?: string;
56
56
  readonly description: string;
@@ -64,10 +64,10 @@ interface ToolDefinition<M extends AnyModels, F extends AnyFunctions, E, I> {
64
64
  readonly annotations?: ToolAnnotations;
65
65
  /** Opaque data for the `authorize` and `visible` hooks. Never sent to clients. */
66
66
  readonly meta?: unknown;
67
- run(args: I, ctx: ToolContext<M, F, E>): unknown;
67
+ run(args: I, ctx: ToolContext<M, F, E, C, P>): unknown;
68
68
  }
69
69
  type ToolResources<M extends AnyModels> = { readonly [T in TableKey<M>]?: ResourceRouteOptions<M, T> | true; };
70
- interface McpOptions<M extends AnyModels, F extends AnyFunctions, E> extends ServerOptions, GuardOptions {
70
+ interface McpOptions<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> extends ServerOptions, GuardOptions {
71
71
  readonly name: string;
72
72
  readonly version: string;
73
73
  readonly title?: string;
@@ -75,7 +75,7 @@ interface McpOptions<M extends AnyModels, F extends AnyFunctions, E> extends Ser
75
75
  readonly instructions?: string;
76
76
  /** Tables exposed as tools: `<table>_list`, `_get`, `_create`, `_update`, `_delete`. */
77
77
  readonly resources?: ToolResources<M>;
78
- readonly tools?: readonly McpTool<M, F, E>[];
78
+ readonly tools?: readonly McpTool<M, F, E, C, P>[];
79
79
  /**
80
80
  * Canonical URL of this MCP server (RFC 9728 `resource`). Defaults to the
81
81
  * request URL without query.
@@ -108,25 +108,25 @@ interface McpOptions<M extends AnyModels, F extends AnyFunctions, E> extends Ser
108
108
  * validate in the repository). A refusal is a tool error; a refusal with
109
109
  * `scopes` is a 403 `insufficient_scope` challenge naming them.
110
110
  */
111
- readonly authorize?: (ctx: ToolContext<M, F, E>, tool: ToolRef, args: unknown) => ToolDecision | Promise<ToolDecision>;
111
+ readonly authorize?: (ctx: ToolContext<M, F, E, C, P>, tool: ToolRef, args: unknown) => ToolDecision | Promise<ToolDecision>;
112
112
  /**
113
113
  * Whether the caller sees a tool in `tools/list`. A hidden tool is called
114
114
  * like an unknown one. Lists are cached per token (`cacheScope: 'private'`).
115
115
  */
116
- readonly visible?: (ctx: ToolContext<M, F, E>, tool: ToolRef) => boolean | Promise<boolean>;
116
+ readonly visible?: (ctx: ToolContext<M, F, E, C, P>, tool: ToolRef) => boolean | Promise<boolean>;
117
117
  }
118
- interface BetterMcp<M extends AnyModels, F extends AnyFunctions, E> extends BetterServer<M, F, E> {
118
+ interface BetterMcp<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> extends BetterServer<M, F, E, C, P> {
119
119
  /** Everything in one handler: the MCP endpoint and `/.well-known/oauth-protected-resource`. */
120
120
  readonly fetch: (request: Request) => Promise<Response>;
121
121
  /** The Streamable HTTP endpoint (POST JSON-RPC). */
122
- readonly handler: (request: Request) => Promise<Response>;
122
+ readonly endpoint: (request: Request) => Promise<Response>;
123
123
  /** RFC 9728 protected resource metadata. */
124
124
  metadata(request: Request): Response;
125
125
  readonly tools: readonly ToolInfo[];
126
126
  /** Adds a tool typed against this app's repositories. */
127
- tool<I = Record<string, unknown>>(definition: ToolDefinition<M, F, E, I>): this;
127
+ tool<I = Record<string, unknown>>(definition: ToolDefinition<M, F, E, I, C, P>): this;
128
128
  /** Calls a tool directly, e.g. from tests or another transport. */
129
- call(name: string, args: unknown, ctx: ToolContext<M, F, E>): Promise<ToolResult>;
129
+ call(name: string, args: unknown, ctx: ToolContext<M, F, E, C, P>): Promise<ToolResult>;
130
130
  }
131
131
  interface ToolResult {
132
132
  readonly content: readonly {
@@ -137,13 +137,13 @@ interface ToolResult {
137
137
  readonly isError?: boolean;
138
138
  }
139
139
  /** A custom tool. Pass it in `createMcp({ tools: [...] })`. */
140
- export declare function defineTool<M extends AnyModels, F extends AnyFunctions, E, I = Record<string, unknown>>(definition: ToolDefinition<M, F, E, I>): McpTool<M, F, E>;
140
+ export declare function defineTool<M extends AnyModels, F extends AnyFunctions, E, I = Record<string, unknown>, C = unknown, P = unknown>(definition: ToolDefinition<M, F, E, I, C, P>): McpTool<M, F, E, C, P>;
141
141
  /**
142
142
  * An MCP server (Streamable HTTP, stateless) whose tools run as the caller:
143
143
  * the Bearer token from the MCP client is verified and every query goes
144
144
  * through RLS. Answers 401 with RFC 9728 metadata so clients can sign in with
145
145
  * Supabase Auth's OAuth server.
146
146
  */
147
- export declare function createMcp<M extends AnyModels, D, F extends AnyFunctions, E>(sb: BetterSupabase<M, D, F, E>, options: McpOptions<M, F, E>): BetterMcp<M, F, E>;
147
+ export declare function createMcp<M extends AnyModels, D, F extends AnyFunctions, E, C = unknown, P = unknown>(betterSupabase: BetterSupabase<M, D, F, E, C, P>, options: McpOptions<M, F, E, C, P>): BetterMcp<M, F, E, C, P>;
148
148
  //#endregion
149
149
  export type { BetterMcp, GuardOptions, McpOptions, McpTool, ResourceRouteOptions, ToolAnnotations, ToolContext, ToolDecision, ToolDefinition, ToolInfo, ToolRef, ToolResources, ToolResult };
package/dist/mcp/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { n as dbError } from "../errors-Bl3rkOzo.js";
2
- import { t as base64ToText } from "../base64-CQeB1eSf.js";
3
- import { t as validate } from "../standard-FUi3Z3-7.js";
4
- import { o as toProblem } from "../problem-CGt1ADix.js";
1
+ import { n as dbError } from "../errors-L0xK41y_.js";
2
+ import { t as base64ToText } from "../base64-D2gsioCY.js";
3
+ import { t as validate } from "../standard-BRyBGTtp.js";
4
+ import { o as toProblem } from "../problem-BihjPR0t.js";
5
5
  import { t as SPEC_PINS } from "../spec-pins-C3oc-Tdp.js";
6
- import { t as buildJsonSchema } from "../json-schema--aOXAGfU.js";
7
- import { a as settle, c as withExtra, n as guard, o as createServer, s as extendServer, t as defaultExpose } from "../respond-C44EZAJo.js";
8
- import { t as defineResource } from "../resource-D30rp0GN.js";
6
+ import { t as buildJsonSchema } from "../json-schema-DP6V7cbr.js";
7
+ import { a as guard, c as settle, i as defaultExpose, n as extendServer, r as withExtra, t as createServer } from "../server-BA75B0mT.js";
8
+ import { t as defineResource } from "../resource-My_y-Syh.js";
9
9
  import { fromSupabaseUrl, unauthorizedResponse } from "@supabase/server/oauth-protected-resource";
10
10
  //#region src/mcp/mcp.ts
11
11
  const MCP_PROTOCOL_VERSION = SPEC_PINS.mcp;
@@ -231,17 +231,19 @@ function canonical(request) {
231
231
  * through RLS. Answers 401 with RFC 9728 metadata so clients can sign in with
232
232
  * Supabase Auth's OAuth server.
233
233
  */
234
- function createMcp(sb, options) {
235
- const server = createServer(sb, options);
234
+ function createMcp(betterSupabase, options) {
235
+ const server = createServer(betterSupabase, options);
236
236
  const expose = options.exposeErrors ?? defaultExpose();
237
237
  const defs = buildJsonSchema({
238
- meta: sb.meta,
238
+ meta: betterSupabase.meta,
239
239
  config: { json: options.json ?? {} }
240
240
  })["$defs"];
241
241
  const registry = /* @__PURE__ */ new Map();
242
+ let allTools;
242
243
  const register = (entry) => {
243
244
  if (registry.has(entry.info.name)) throw new TypeError(`Duplicate MCP tool "${entry.info.name}"`);
244
245
  registry.set(entry.info.name, entry);
246
+ allTools = void 0;
245
247
  };
246
248
  const failure = (error) => textResult(toProblem(error, { expose }), true);
247
249
  const refused = async (tool, args, ctx) => {
@@ -256,7 +258,7 @@ function createMcp(sb, options) {
256
258
  const isVisible = async (tool, ctx) => !options.visible || options.visible(ctx, tool);
257
259
  for (const [table, raw] of Object.entries(options.resources ?? {})) {
258
260
  if (!raw) continue;
259
- const resource = defineResource(sb, table, raw === true ? {} : raw);
261
+ const resource = defineResource(betterSupabase, table, raw === true ? {} : raw);
260
262
  for (const { info, operation } of tableTools(resource, defs)) {
261
263
  const ref = {
262
264
  info,
@@ -302,8 +304,11 @@ function createMcp(sb, options) {
302
304
  });
303
305
  };
304
306
  for (const tool of options.tools ?? []) addTool(tool);
305
- const listTools = () => [...registry.values()].map((entry) => entry.info);
306
- const visibleTools = async (ctx) => {
307
+ const listTools = () => allTools ??= [...registry.values()].map((entry) => entry.info);
308
+ /** Without a `visible` hook every caller sees the same list, built once. */
309
+ const visibleTools = async (context) => {
310
+ if (!options.visible) return listTools();
311
+ const ctx = context();
307
312
  const entries = [...registry.values()];
308
313
  const shown = await Promise.all(entries.map((entry) => isVisible(entry, ctx)));
309
314
  return entries.filter((_, index) => shown[index]).map((e) => e.info);
@@ -376,7 +381,7 @@ function createMcp(sb, options) {
376
381
  if (sent === null || headerName(sent) !== name) return mismatch(`Mcp-Name must be ${name}`);
377
382
  }
378
383
  };
379
- const handler = async (request) => {
384
+ const endpoint = async (request) => {
380
385
  const origin = request.headers.get("origin");
381
386
  if (origin && options.allowedOrigins && !options.allowedOrigins.includes(origin)) return rpcError(null, INVALID_REQUEST, "Origin not allowed", 403);
382
387
  if (options.allowedHosts && !hostAllowed(request, options.allowedHosts)) return rpcError(null, INVALID_REQUEST, "Host not allowed", 403);
@@ -437,7 +442,7 @@ function createMcp(sb, options) {
437
442
  }
438
443
  case "ping": return modern ? notFound() : reply({});
439
444
  case "tools/list": return reply({
440
- tools: await visibleTools(toolContext()),
445
+ tools: await visibleTools(toolContext),
441
446
  ...modern ? {
442
447
  ttlMs: LIST_TTL_MS,
443
448
  cacheScope: "private"
@@ -465,14 +470,14 @@ function createMcp(sb, options) {
465
470
  }, { headers: { "access-control-allow-origin": "*" } });
466
471
  const mcp = extendServer(server, {
467
472
  get tools() {
468
- return listTools();
473
+ return [...listTools()];
469
474
  },
470
475
  tool(definition) {
471
476
  addTool(defineTool(definition));
472
477
  return mcp;
473
478
  },
474
479
  call,
475
- handler,
480
+ endpoint,
476
481
  metadata,
477
482
  fetch(request) {
478
483
  const { pathname } = new URL(request.url);
@@ -483,7 +488,7 @@ function createMcp(sb, options) {
483
488
  "access-control-allow-methods": "GET"
484
489
  }
485
490
  }) : metadata(request));
486
- return handler(request);
491
+ return endpoint(request);
487
492
  }
488
493
  });
489
494
  return mcp;
@@ -1,4 +1,4 @@
1
- import { p as DbError } from "./result-c2OYgCV2.js";
1
+ import { p as DbError } from "./result-CqEsbgYs.js";
2
2
  //#region src/auth/impersonation.d.ts
3
3
  /** The admin acting as the user, from the RFC 8693 `act` claim. */
4
4
  interface Impersonator {