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.
- package/README.md +7 -6
- package/bin/better-supabase.js +4 -0
- package/dist/{base64-CQeB1eSf.js → base64-D2gsioCY.js} +2 -2
- package/dist/claims-BAf6c7is.js +48 -0
- package/dist/cli/_format-Cax5EsM9.js +101 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +48 -0
- package/dist/cli/command-CK14fP91.js +502 -0
- package/dist/cli/compare-BmIWVEui.js +9 -0
- package/dist/cli/config-D9R0o1LH.js +1895 -0
- package/dist/cli/config-SSKSTUl2.js +2 -0
- package/dist/cli/db-DOBPt660.js +52 -0
- package/dist/cli/dist-B1MvLv-M.js +129 -0
- package/dist/cli/dist-CFgGknmZ.js +1112 -0
- package/dist/cli/dist-Du7VnEUG.js +621 -0
- package/dist/cli/doctor-BOym3mbL.js +2382 -0
- package/dist/cli/env-BZ0uy8XK.js +108 -0
- package/dist/cli/env-jIFUADLY.js +511 -0
- package/dist/cli/errors-4v4DTtda.js +56 -0
- package/dist/cli/fastest-levenshtein-CFN-lNDv.js +120 -0
- package/dist/cli/gen-Ccn_p90L.js +2008 -0
- package/dist/cli/gen-D5cLCULx.js +2 -0
- package/dist/cli/index.d.ts +493 -0
- package/dist/cli/index.js +184 -0
- package/dist/cli/init-ClnxRYBF.js +550 -0
- package/dist/cli/introspect-DxqfkVIv.js +81 -0
- package/dist/cli/io-k41_z-jT.js +24 -0
- package/dist/cli/json5-ChRycquj.js +787 -0
- package/dist/cli/jsonc-BUniUpOk.js +2 -0
- package/dist/cli/jsonc-D5Fu67jw.js +45 -0
- package/dist/cli/keys-ByKHnvP9.js +83 -0
- package/dist/cli/ohash-D7bG_EOb.js +277 -0
- package/dist/cli/openapi-8WHjxiTJ.js +66 -0
- package/dist/cli/project-B_GeXyHh.js +70 -0
- package/dist/cli/prompts-BNcNfAve.js +1142 -0
- package/dist/cli/prompts-BTYQGunc.js +2 -0
- package/dist/cli/read-sets-CMa29t9a.js +971 -0
- package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
- package/dist/cli/run-CP20LKk_.js +347 -0
- package/dist/cli/seed-5J6eu_Xg.js +98 -0
- package/dist/cli/skills-LJJIhLFR.js +137 -0
- package/dist/cli/sql-D4VbqmXi.js +199 -0
- package/dist/cli/style-C0NFdJRL.js +29 -0
- package/dist/cli/toml-DB-MNnFs.js +424 -0
- package/dist/cli/version-5mW_8sY1.js +4 -0
- package/dist/cli/yaml-CYCbJ6et.js +2252 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +13 -13
- package/dist/{compiler-2zqGzxVZ.d.ts → compiler-DB3aSFOA.d.ts} +2 -2
- package/dist/config/index.js +4 -4
- package/dist/{config-Be4GwsqI.js → config-BpxDfnbg.js} +1 -1
- package/dist/{config-DOsGYSiT.js → config-CbvFmGD8.js} +1 -1
- package/dist/{define-DF341GDj.js → define-Bh0AqTik.js} +160 -79
- package/dist/{define-DUbydmJa.d.ts → define-CRS2MRV3.d.ts} +32 -28
- package/dist/edge/index.d.ts +8 -12
- package/dist/edge/index.js +50 -24
- package/dist/{entitlements-DvJXoI02.d.ts → entitlements-Dm-FHpNH.d.ts} +2 -2
- package/dist/{errors-Bl3rkOzo.js → errors-L0xK41y_.js} +1 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.js +4 -4
- package/dist/{events-Do8jXh4D.d.ts → events-B21UOhvP.d.ts} +4 -4
- package/dist/{executor-DynmIWhq.d.ts → executor-B5IoUxLE.d.ts} +1 -1
- package/dist/{executor-C57jx2pn.js → executor-CVt6dD0B.js} +3 -3
- package/dist/{executor-B26lgbHD.d.ts → executor-CZ7ImRiD.d.ts} +2 -2
- package/dist/hono/index.d.ts +16 -23
- package/dist/hono/index.js +10 -10
- package/dist/{index-CTTMS6_1.d.ts → index-528Ugmyp.d.ts} +12 -3
- package/dist/{index-CADlNHK-.d.ts → index-BAy4tsAP.d.ts} +5 -5
- package/dist/{index-BNsABq7P.d.ts → index-BBdvo-5d.d.ts} +23 -25
- package/dist/{index-qriRM9cZ.d.ts → index-BhHEC04r.d.ts} +3 -3
- package/dist/{index-GV77NpRP.d.ts → index-D5IfUIDh.d.ts} +3 -3
- package/dist/{index-CriFFJ_p.d.ts → index-DFmOpBGC.d.ts} +11 -11
- package/dist/{index-UJ-LUxtI.d.ts → index-RlLXd8dL.d.ts} +12 -12
- package/dist/index.d.ts +15 -15
- package/dist/index.js +13 -13
- package/dist/{invalidate-DbxuL2jL.js → invalidate-CgxmRamI.js} +7 -1
- package/dist/jobs/index.d.ts +10 -4
- package/dist/jobs/index.js +32 -16
- package/dist/{json-schema--aOXAGfU.js → json-schema-DP6V7cbr.js} +1 -1
- package/dist/list/index.d.ts +1 -1
- package/dist/list/index.js +3 -3
- package/dist/{live-QE3UPbGm.d.ts → live-BHakSWWo.d.ts} +12 -12
- package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
- package/dist/lookup-BaP5bI27.js +18 -0
- package/dist/mcp/index.d.ts +18 -18
- package/dist/mcp/index.js +23 -18
- package/dist/{mfa-x3V3vGh-.d.ts → mfa-C7MNQ1Ob.d.ts} +1 -1
- package/dist/{mfa-BxoR1RkN.js → mfa-byfjruR9.js} +118 -29
- package/dist/next/image/index.js +6 -3
- package/dist/next/index.d.ts +38 -35
- package/dist/next/index.js +41 -33
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +6 -6
- package/dist/orpc/index.d.ts +17 -20
- package/dist/orpc/index.js +11 -11
- package/dist/otel/index.d.ts +5 -5
- package/dist/otel/index.js +81 -62
- package/dist/{permdock-sql-Bta_G0v-.js → permdock-sql-C4KFzLc9.js} +1 -1
- package/dist/{plugin-DVRB8qNE.d.ts → plugin-bNhvJwRh.d.ts} +2 -2
- package/dist/plugins/actor/index.d.ts +1 -1
- package/dist/plugins/actor/index.js +1 -1
- package/dist/plugins/rules/index.d.ts +2 -2
- package/dist/plugins/rules/index.js +42 -12
- package/dist/plugins/soft-delete/index.d.ts +2 -2
- package/dist/plugins/soft-delete/index.js +2 -2
- package/dist/plugins/tenant/index.d.ts +2 -2
- package/dist/plugins/tenant/index.js +10 -4
- package/dist/plugins/timestamps/index.d.ts +1 -1
- package/dist/plugins/timestamps/index.js +1 -1
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/plugins/validation/index.js +3 -3
- package/dist/{pool-B9qsLyFR.d.ts → pool-DFwEQwmN.d.ts} +11 -4
- package/dist/postgres/index.d.ts +5 -5
- package/dist/postgres/index.js +3 -2
- package/dist/{postgrest-DmBlevh-.d.ts → postgrest-Bc-0Xw62.d.ts} +1 -1
- package/dist/{problem-CGt1ADix.js → problem-BihjPR0t.js} +1 -1
- package/dist/{problem-Z2RTQjZD.d.ts → problem-U8UEKccv.d.ts} +1 -1
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +2 -2
- package/dist/{query-BdKLTPlj.js → query-BMMSWbI7.js} +18 -18
- package/dist/react/index.d.ts +6 -6
- package/dist/react/index.js +1 -1
- package/dist/react/server.d.ts +5 -5
- package/dist/react/server.js +3 -3
- package/dist/react/session.d.ts +4 -4
- package/dist/react/session.js +2 -2
- package/dist/{react-DNBYNazu.js → react-CQHMaESR.js} +39 -39
- package/dist/{read-set-D0qBcboM.js → read-set-FWK8qQ58.js} +50 -15
- package/dist/realtime/index.d.ts +1 -1
- package/dist/realtime/index.js +13 -12
- package/dist/{index-kpgopLNv.d.ts → refresh-BwYkyNOQ.d.ts} +6 -3
- package/dist/{resolve-BRciX2jK.d.ts → resolve-BAqQcwMW.d.ts} +15 -10
- package/dist/{resource-CwVgiI5q.d.ts → resource-BJcaIfxi.d.ts} +5 -5
- package/dist/{resource-D30rp0GN.js → resource-My_y-Syh.js} +6 -6
- package/dist/{respond-DAkPIdTH.d.ts → respond-DgIbdrt8.d.ts} +31 -12
- package/dist/{result-DWXatkd6.js → result-Bj6yt33D.js} +2 -2
- package/dist/{result-c2OYgCV2.d.ts → result-CqEsbgYs.d.ts} +3 -3
- package/dist/server/index.d.ts +14 -14
- package/dist/server/index.js +12 -12
- package/dist/{respond-C44EZAJo.js → server-BA75B0mT.js} +139 -100
- package/dist/{shared-_6-uPL7E.js → shared-DnoCdMDr.js} +4 -3
- package/dist/{simplify-LakqK1vH.js → simplify-Cqvfr9dj.js} +67 -24
- package/dist/sql/index.d.ts +1 -1
- package/dist/sql/index.js +7 -7
- package/dist/{sql-BIgk12ew.js → sql-B34HU2DI.js} +3 -2
- package/dist/ssr/index.d.ts +4 -4
- package/dist/ssr/index.js +2 -2
- package/dist/{standard-FUi3Z3-7.js → standard-BRyBGTtp.js} +2 -2
- package/dist/{standard-eudBiRk1.d.ts → standard-BsaCYQJc.d.ts} +1 -1
- package/dist/{stats-D78UQ8Yu.js → stats-C_YxA2r1.js} +33 -8
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +26 -8
- package/dist/{tables-Dhha3BXM.js → tables-Cb-3_VWc.js} +14 -0
- package/dist/{temporal-required-CMxeSVPo.js → temporal-required-CBNHT6ni.js} +1 -1
- package/dist/testing/index.d.ts +20 -21
- package/dist/testing/index.js +45 -45
- package/dist/{version-BfpG2gks.js → version-Bmf7_FzM.js} +1 -1
- package/dist/{view-3Po_PVlr.d.ts → view-B64o81wp.d.ts} +5 -5
- package/dist/{view-wZ-9qIUz.js → view-BrJI2LKp.js} +1 -1
- package/dist/webhooks/index.d.ts +3 -3
- package/dist/webhooks/index.js +1 -1
- package/dist/{webhooks-CAIFQSTM.js → webhooks-Bh_Jf_-l.js} +37 -18
- package/package.json +36 -4
- package/skills/better-supabase/SKILL.md +57 -10
- package/skills/better-supabase/references/plugins.md +7 -11
- package/skills/better-supabase/references/troubleshooting.md +24 -4
- package/skills/better-supabase-api/SKILL.md +66 -18
- package/skills/better-supabase-api/references/adapters.md +44 -26
- package/skills/better-supabase-auth/SKILL.md +146 -0
- package/skills/better-supabase-auth/references/permdock.md +55 -0
- package/skills/better-supabase-testing/SKILL.md +58 -4
- 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-
|
|
3
|
-
import { Z as QuerySpec, t as BetterSupabase } from "./define-
|
|
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>>(
|
|
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>>(
|
|
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 `
|
|
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
|
-
* `
|
|
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(
|
|
173
|
+
* using live = liveQuery(betterSupabase, supabase, spec, { onChange: () => refetch() });
|
|
174
174
|
* ```
|
|
175
175
|
*/
|
|
176
|
-
declare function liveQuery(
|
|
177
|
-
/** What `liveCount` runs the spec with: a `db` from `
|
|
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(
|
|
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(
|
|
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(
|
|
83
|
+
* using live = liveQuery(betterSupabase, supabase, spec, { onChange: () => refetch() });
|
|
80
84
|
* ```
|
|
81
85
|
*/
|
|
82
|
-
function liveQuery(
|
|
83
|
-
const touched = Array.isArray(spec) ? spec :
|
|
84
|
-
const tables = touched.filter((table) =>
|
|
85
|
-
const unwatched = touched.filter((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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 };
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -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-
|
|
3
|
-
import {
|
|
4
|
-
import { a as ResourceRouteOptions } from "../resource-
|
|
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
|
|
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
|
|
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>(
|
|
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-
|
|
2
|
-
import { t as base64ToText } from "../base64-
|
|
3
|
-
import { t as validate } from "../standard-
|
|
4
|
-
import { o as toProblem } from "../problem-
|
|
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
|
|
7
|
-
import { a as
|
|
8
|
-
import { t as defineResource } from "../resource-
|
|
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(
|
|
235
|
-
const server = createServer(
|
|
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:
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
491
|
+
return endpoint(request);
|
|
487
492
|
}
|
|
488
493
|
});
|
|
489
494
|
return mcp;
|