better-supabase 0.1.0 → 0.3.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 +34 -31
- package/dist/base64-CQeB1eSf.js +42 -0
- package/dist/claims-CoTobNC-.js +25 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +4 -14
- package/dist/{compiler-DL18ukPe.d.ts → compiler-2zqGzxVZ.d.ts} +2 -2
- package/dist/config/index.d.ts +4 -3
- package/dist/config/index.js +5 -3
- package/dist/config-Be4GwsqI.js +129 -0
- package/dist/{index-BD6wKthp.d.ts → config-C1CYcm6o.d.ts} +75 -54
- package/dist/{config-D-aR2ZoN.js → config-DOsGYSiT.js} +14 -136
- package/dist/{define-QGkq04oe.js → define-DF341GDj.js} +133 -110
- package/dist/{define-CTfWw-SS.d.ts → define-DUbydmJa.d.ts} +32 -14
- package/dist/edge/index.d.ts +4 -4
- package/dist/edge/index.js +4 -4
- package/dist/entitlements-CTEBm7IB.js +20 -0
- package/dist/entitlements-DvJXoI02.d.ts +42 -0
- package/dist/env/index.js +203 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.js +139 -1
- package/dist/{events-2OJsVG_d.d.ts → events-Do8jXh4D.d.ts} +3 -3
- package/dist/{executor-Bje4suQF.d.ts → executor-B26lgbHD.d.ts} +2 -2
- package/dist/{executor-Ceq60hPM.js → executor-C57jx2pn.js} +7 -2
- package/dist/{executor-Bazhgsgq.d.ts → executor-DynmIWhq.d.ts} +2 -2
- package/dist/guards-BnzDvFrz.js +10 -0
- package/dist/hono/index.d.ts +5 -5
- package/dist/hono/index.js +4 -4
- package/dist/{index-Hf8PP9sP.d.ts → index-BNsABq7P.d.ts} +17 -13
- package/dist/{index-JXHBuS53.d.ts → index-CADlNHK-.d.ts} +27 -14
- package/dist/{index-Nxo3TJcm.d.ts → index-CTTMS6_1.d.ts} +27 -8
- package/dist/index-Cf-D2jk1.d.ts +50 -0
- package/dist/{index-Dup-nSe9.d.ts → index-CriFFJ_p.d.ts} +4 -4
- package/dist/{index-DQVvHzjW.d.ts → index-GV77NpRP.d.ts} +5 -4
- package/dist/{index-Sw43J8HG.d.ts → index-UJ-LUxtI.d.ts} +6 -6
- package/dist/{index-cEeweTeM.d.ts → index-kpgopLNv.d.ts} +4 -3
- package/dist/{index-DRid0qIv.d.ts → index-qriRM9cZ.d.ts} +7 -2
- package/dist/index.d.ts +13 -13
- package/dist/index.js +18 -8
- package/dist/jobs/index.d.ts +25 -24
- package/dist/jobs/index.js +19 -12
- package/dist/{json-schema-BbwO2mZg.js → json-schema--aOXAGfU.js} +9 -3
- package/dist/lint/index.js +1 -1
- package/dist/list/index.d.ts +2 -2
- package/dist/list/index.js +128 -93
- package/dist/{live-6b9i72Ux.d.ts → live-QE3UPbGm.d.ts} +27 -6
- package/dist/logger-glM28NVN.js +21 -0
- package/dist/mcp/index.d.ts +59 -15
- package/dist/mcp/index.js +229 -67
- package/dist/{mfa-CpogP66z.js → mfa-BxoR1RkN.js} +97 -22
- package/dist/{mfa-TVia554c.d.ts → mfa-x3V3vGh-.d.ts} +1 -1
- package/dist/next/index.d.ts +51 -38
- package/dist/next/index.js +31 -25
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +58 -35
- package/dist/orpc/index.d.ts +6 -6
- package/dist/orpc/index.js +3 -3
- package/dist/otel/index.d.ts +3 -3
- package/dist/otel/index.js +5 -3
- package/dist/{template-BeOGnynM.js → permdock-sql-Bta_G0v-.js} +32 -3
- package/dist/permdock-sql-DImJULY-.d.ts +17 -0
- package/dist/{plugin-HvGqCurB.d.ts → plugin-DVRB8qNE.d.ts} +5 -4
- package/dist/plugins/actor/index.d.ts +1 -1
- package/dist/plugins/rules/index.d.ts +4 -3
- package/dist/plugins/rules/index.js +8 -15
- package/dist/plugins/soft-delete/index.d.ts +3 -3
- package/dist/plugins/soft-delete/index.js +2 -2
- package/dist/plugins/tenant/index.d.ts +10 -4
- package/dist/plugins/tenant/index.js +15 -13
- 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/pool-B9qsLyFR.d.ts +71 -0
- package/dist/postgres/index.d.ts +10 -5
- package/dist/postgres/index.js +36 -16
- package/dist/{postgrest-Dm-vhY6R.d.ts → postgrest-DmBlevh-.d.ts} +1 -1
- package/dist/{problem-DPu6Fh-t.js → problem-CGt1ADix.js} +14 -8
- package/dist/{problem-DlgB0lYl.d.ts → problem-Z2RTQjZD.d.ts} +6 -4
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +1 -1
- package/dist/{query-ChvDbsDE.js → query-BdKLTPlj.js} +2 -2
- package/dist/react/index.d.ts +7 -7
- package/dist/react/index.js +3 -3
- package/dist/react/server.d.ts +5 -5
- package/dist/react/server.js +1 -1
- package/dist/react/session.d.ts +21 -2
- package/dist/react/session.js +19 -1
- package/dist/{react-CrOvrnIP.js → react-DNBYNazu.js} +28 -23
- package/dist/{read-set-DhX2d04c.js → read-set-D0qBcboM.js} +3 -3
- package/dist/realtime/index.d.ts +4 -2
- package/dist/realtime/index.js +30 -14
- package/dist/{resolve-DW8h9NPm.d.ts → resolve-BRciX2jK.d.ts} +25 -9
- package/dist/{resource-SkPTRJDD.d.ts → resource-CwVgiI5q.d.ts} +16 -7
- package/dist/{resource-CYiu6Ygi.js → resource-D30rp0GN.js} +38 -16
- package/dist/{respond-4-dhoV7x.js → respond-C44EZAJo.js} +38 -19
- package/dist/{respond-PoTpy5DT.d.ts → respond-DAkPIdTH.d.ts} +23 -17
- package/dist/{result-CTkCZ6JA.d.ts → result-c2OYgCV2.d.ts} +13 -8
- package/dist/server/index.d.ts +35 -10
- package/dist/server/index.js +38 -9
- package/dist/{simplify-oHiDKRVQ.js → simplify-LakqK1vH.js} +22 -28
- package/dist/{spec-pins-t6sPaHvl.js → spec-pins-C3oc-Tdp.js} +1 -1
- package/dist/{spec-pins-CJPVghHy.d.ts → spec-pins-CqorWDnO.d.ts} +1 -1
- package/dist/sql/index.d.ts +139 -0
- package/dist/sql/index.js +1983 -0
- package/dist/{sql-M8l3fnS0.js → sql-BIgk12ew.js} +72 -16
- package/dist/ssr/index.d.ts +5 -5
- package/dist/ssr/index.js +3 -3
- package/dist/{standard-CyhRzctb.d.ts → standard-eudBiRk1.d.ts} +1 -1
- package/dist/{stats-3iy8u3_P.js → stats-D78UQ8Yu.js} +8 -7
- package/dist/storage/index.d.ts +4 -2
- package/dist/storage/index.js +530 -1
- package/dist/{tables-rZxRxNPW.js → tables-Dhha3BXM.js} +5 -5
- package/dist/temporal-BwshQk0W.js +27 -0
- package/dist/temporal-required-CMxeSVPo.js +19 -0
- package/dist/testing/index.d.ts +49 -16
- package/dist/testing/index.js +233 -66
- package/dist/{types-C2fslP1z.d.ts → types-DONv9SHN.d.ts} +68 -12
- package/dist/{version-Cqq1m3UY.js → version-BfpG2gks.js} +1 -1
- package/dist/view-3Po_PVlr.d.ts +79 -0
- package/dist/{view-B6F9QbG-.js → view-wZ-9qIUz.js} +12 -2
- package/dist/webhooks/index.d.ts +19 -17
- package/dist/webhooks/index.js +1 -1
- package/dist/{webhooks-DbMTJJX2.js → webhooks-CAIFQSTM.js} +12 -10
- package/package.json +30 -30
- package/schemas/config-v1.json +80 -5
- package/schemas/doctor-report-v1.json +18 -1
- package/schemas/snapshot-v2.json +39 -0
- package/skills/better-supabase/SKILL.md +23 -11
- package/skills/better-supabase/references/plugins.md +28 -16
- package/skills/better-supabase/references/troubleshooting.md +15 -15
- package/skills/better-supabase-api/SKILL.md +9 -9
- package/skills/better-supabase-api/references/adapters.md +30 -25
- package/skills/better-supabase-testing/SKILL.md +15 -11
- package/bin/better-supabase.js +0 -3
- package/dist/casing-da0uRTqt.js +0 -14
- package/dist/cli/bin.d.ts +0 -1
- package/dist/cli/bin.js +0 -15
- package/dist/cli/index.d.ts +0 -226
- package/dist/cli/index.js +0 -3
- package/dist/cli-CoByWYja.js +0 -6472
- package/dist/entitlements-BBg61DQZ.d.ts +0 -20
- package/dist/entitlements-BC_khwRy.js +0 -17
- package/dist/env-BEToab0I.js +0 -204
- package/dist/events-BuzTgn2D.js +0 -135
- package/dist/pool-BFeqzwQS.d.ts +0 -37
- package/dist/seed-CzecODcJ.js +0 -101
- package/dist/session-C3osL21k.d.ts +0 -21
- package/dist/session-CD-3orO_.js +0 -19
- package/dist/storage-BWXVUXGk.js +0 -461
- package/dist/view-B0ltUmTi.d.ts +0 -43
package/dist/jobs/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { c as mapDbError, n as dbError, t as DbException } from "../errors-Bl3rkOzo.js";
|
|
2
|
+
import { n as nowInstant } from "../temporal-BwshQk0W.js";
|
|
3
|
+
import { t as temporal } from "../temporal-required-CMxeSVPo.js";
|
|
2
4
|
import { i as ok, n as err, o as toDbError, t as AsyncResult } from "../result-DWXatkd6.js";
|
|
3
5
|
import { t as validate } from "../standard-FUi3Z3-7.js";
|
|
4
|
-
import { a as problemResponse } from "../problem-
|
|
5
|
-
import { t as fromPgError } from "../executor-
|
|
6
|
-
import { c as verifyWebhook } from "../webhooks-
|
|
7
|
-
//#region src/jobs/
|
|
6
|
+
import { a as problemResponse } from "../problem-CGt1ADix.js";
|
|
7
|
+
import { t as fromPgError } from "../executor-C57jx2pn.js";
|
|
8
|
+
import { c as verifyWebhook } from "../webhooks-CAIFQSTM.js";
|
|
9
|
+
//#region src/jobs/jobs.ts
|
|
8
10
|
function run(fn) {
|
|
9
11
|
return AsyncResult.from(async () => {
|
|
10
12
|
try {
|
|
@@ -22,7 +24,10 @@ function workerId() {
|
|
|
22
24
|
return `worker-${crypto.randomUUID().slice(0, 8)}`;
|
|
23
25
|
}
|
|
24
26
|
const sleep = (ms, signal) => new Promise((resolve) => {
|
|
25
|
-
if (signal?.aborted)
|
|
27
|
+
if (signal?.aborted) {
|
|
28
|
+
resolve();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
26
31
|
const timer = setTimeout(done, ms);
|
|
27
32
|
function done() {
|
|
28
33
|
clearTimeout(timer);
|
|
@@ -102,7 +107,7 @@ function postgrestTransport(client) {
|
|
|
102
107
|
const call = async (fn, args) => {
|
|
103
108
|
const { data, error } = await client.schema("pgmq_public").rpc(fn, args);
|
|
104
109
|
if (error) {
|
|
105
|
-
const message = typeof error === "object" &&
|
|
110
|
+
const message = typeof error === "object" && "message" in error ? String(error.message) : String(error);
|
|
106
111
|
throw new Error(`pgmq_public.${fn}: ${message}`, { cause: error });
|
|
107
112
|
}
|
|
108
113
|
return data;
|
|
@@ -149,7 +154,8 @@ function postgrestTransport(client) {
|
|
|
149
154
|
unschedule: () => sqlOnly("unschedule")
|
|
150
155
|
};
|
|
151
156
|
}
|
|
152
|
-
|
|
157
|
+
/** pgmq and the inbox return `timestamptz` as text over RPC and as `Date` from `pg`. */
|
|
158
|
+
const toInstant = (value) => value instanceof Date ? temporal().Instant.fromEpochMilliseconds(value.getTime()) : temporal().Instant.from(value);
|
|
153
159
|
function toJob(queue, row) {
|
|
154
160
|
const message = row.message ?? {};
|
|
155
161
|
return {
|
|
@@ -158,8 +164,8 @@ function toJob(queue, row) {
|
|
|
158
164
|
payload: message.payload,
|
|
159
165
|
attempts: row.attempts,
|
|
160
166
|
maxAttempts: message.max_attempts ?? 5,
|
|
161
|
-
enqueuedAt:
|
|
162
|
-
visibleUntil:
|
|
167
|
+
enqueuedAt: toInstant(row.enqueued_at),
|
|
168
|
+
visibleUntil: toInstant(row.visible_until),
|
|
163
169
|
lastError: message.last_error ?? null
|
|
164
170
|
};
|
|
165
171
|
}
|
|
@@ -254,7 +260,7 @@ function createJobs(source, queues) {
|
|
|
254
260
|
return AsyncResult.from(async () => {
|
|
255
261
|
const valid = await validate(schemaOf(queue), payload, "payload");
|
|
256
262
|
if (!valid.ok) return valid;
|
|
257
|
-
const delay = enqueueOptions.delay ?? (enqueueOptions.runAt ? Math.max(0, Math.ceil((enqueueOptions.runAt.
|
|
263
|
+
const delay = enqueueOptions.delay ?? (enqueueOptions.runAt ? Math.max(0, Math.ceil((enqueueOptions.runAt.epochMilliseconds - nowInstant().epochMilliseconds) / 1e3)) : 0);
|
|
258
264
|
return run(() => transport.send(queue, valid.data, delay, enqueueOptions.maxAttempts ?? 5, enqueueOptions.dedupeKey));
|
|
259
265
|
});
|
|
260
266
|
},
|
|
@@ -435,7 +441,7 @@ function createInbox(sql, options) {
|
|
|
435
441
|
payload: row.payload,
|
|
436
442
|
headers: row.headers,
|
|
437
443
|
attempts: row.attempts,
|
|
438
|
-
receivedAt:
|
|
444
|
+
receivedAt: toInstant(row.received_at)
|
|
439
445
|
};
|
|
440
446
|
try {
|
|
441
447
|
const outcome = await handler(message);
|
|
@@ -458,7 +464,8 @@ function createInbox(sql, options) {
|
|
|
458
464
|
/** The Stripe event sent when a customer's active entitlements change. */
|
|
459
465
|
const ENTITLEMENTS_UPDATED = "entitlements.active_entitlement_summary.updated";
|
|
460
466
|
function stripeCustomerOf(payload) {
|
|
461
|
-
|
|
467
|
+
if (typeof payload !== "object" || payload === null) return void 0;
|
|
468
|
+
const customer = (payload.data?.object)?.customer;
|
|
462
469
|
if (typeof customer === "string") return customer;
|
|
463
470
|
const id = customer?.id;
|
|
464
471
|
return typeof id === "string" ? id : void 0;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as isList } from "./guards-BnzDvFrz.js";
|
|
1
2
|
//#region src/generators/shared.ts
|
|
2
3
|
const INTEGER = /* @__PURE__ */ new Set([
|
|
3
4
|
"int2",
|
|
@@ -18,7 +19,8 @@ function scalarKind(column) {
|
|
|
18
19
|
values: column.enum
|
|
19
20
|
};
|
|
20
21
|
if (column.json) return { kind: "json" };
|
|
21
|
-
if (column.codec === "
|
|
22
|
+
if (column.codec === "instant") return { kind: "instant" };
|
|
23
|
+
if (column.codec === "plainDateTime") return { kind: "plainDateTime" };
|
|
22
24
|
if (column.codec === "bigint") return { kind: "bigint" };
|
|
23
25
|
if (column.codec === "string") return { kind: "string" };
|
|
24
26
|
if (column.type === "uuid") return { kind: "uuid" };
|
|
@@ -106,10 +108,14 @@ function scalar(kind) {
|
|
|
106
108
|
type: "string",
|
|
107
109
|
format: "date"
|
|
108
110
|
};
|
|
109
|
-
case "
|
|
111
|
+
case "instant": return {
|
|
110
112
|
type: "string",
|
|
111
113
|
format: "date-time"
|
|
112
114
|
};
|
|
115
|
+
case "plainDateTime": return {
|
|
116
|
+
type: "string",
|
|
117
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$"
|
|
118
|
+
};
|
|
113
119
|
case "bigint": return {
|
|
114
120
|
type: "string",
|
|
115
121
|
pattern: "^-?\\d+$"
|
|
@@ -132,7 +138,7 @@ function property(plan) {
|
|
|
132
138
|
if (!plan.nullable) return schema;
|
|
133
139
|
if (Object.keys(schema).length === 0) return schema;
|
|
134
140
|
const { enum: values, ...rest } = schema;
|
|
135
|
-
if (
|
|
141
|
+
if (isList(values)) return {
|
|
136
142
|
...rest,
|
|
137
143
|
type: ["string", "null"],
|
|
138
144
|
enum: [...values, null]
|
package/dist/lint/index.js
CHANGED
|
@@ -16,7 +16,7 @@ function receiverName(node) {
|
|
|
16
16
|
return receiver.property.name;
|
|
17
17
|
}
|
|
18
18
|
/** Matches `order_items`, `orderItems` and `public.order_items` alike. */
|
|
19
|
-
const tableKey = (name) => (name.split(".").at(-1) ?? name).
|
|
19
|
+
const tableKey = (name) => (name.split(".").at(-1) ?? name).replaceAll("_", "").toLowerCase();
|
|
20
20
|
function keyName(property) {
|
|
21
21
|
if (property.computed) return void 0;
|
|
22
22
|
if (property.key.type === "Identifier") return property.key.name;
|
package/dist/list/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ListPage, c as
|
|
2
|
-
export { FacetCounts, FacetInfo, ListDefinition, ListExtra, ListPage, ListParseResult, ListParsers, ListQuery, ListQueryConfig, ListQueryInput, ListSearchParams, OpenApiParameter, ParserSpec, UNSET, defineListQuery };
|
|
1
|
+
import { a as ListPage, c as ListParsers, d as ListQueryInput, f as ListSearchParams, g as defineListQuery, h as UNSET, i as ListExtra, l as ListQuery, m as ParserSpec, n as FacetInfo, o as ListPagination, p as OpenApiParameter, r as ListDefinition, s as ListParseResult, t as FacetCounts, u as ListQueryConfig } from "../index-CADlNHK-.js";
|
|
2
|
+
export { type FacetCounts, type FacetInfo, type ListDefinition, type ListExtra, type ListPage, type ListPagination, type ListParseResult, type ListParsers, type ListQuery, type ListQueryConfig, type ListQueryInput, type ListSearchParams, type OpenApiParameter, type ParserSpec, UNSET, defineListQuery };
|
package/dist/list/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
//#region src/list/
|
|
1
|
+
//#region src/list/list-query.ts
|
|
2
2
|
/** Facet value meaning "not set": filters with `is null`. */
|
|
3
3
|
const UNSET = "__unset__";
|
|
4
4
|
const RESERVED = /* @__PURE__ */ new Set([
|
|
5
5
|
"q",
|
|
6
6
|
"sort",
|
|
7
7
|
"page",
|
|
8
|
+
"after",
|
|
8
9
|
"size"
|
|
9
10
|
]);
|
|
10
11
|
function first(value) {
|
|
@@ -13,8 +14,9 @@ function first(value) {
|
|
|
13
14
|
function all(value) {
|
|
14
15
|
return (typeof value === "string" ? [value] : [...value ?? []]).flatMap((entry) => entry.split(",")).map((entry) => entry.trim()).filter(Boolean);
|
|
15
16
|
}
|
|
17
|
+
const isParamValue = (value) => value === void 0 || typeof value === "string" || Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
16
18
|
function isSearchParams(value) {
|
|
17
|
-
return value instanceof URLSearchParams || !("facets" in value && typeof value.facets === "object");
|
|
19
|
+
return value instanceof URLSearchParams || !("facets" in value && typeof value.facets === "object") && Object.values(value).every(isParamValue);
|
|
18
20
|
}
|
|
19
21
|
function readRecord(input) {
|
|
20
22
|
if (!(input instanceof URLSearchParams)) return input;
|
|
@@ -47,6 +49,7 @@ function defineListQuery(sb, table, config) {
|
|
|
47
49
|
const pageSize = config.pageSize ?? 50;
|
|
48
50
|
const maxPageSize = config.maxPageSize ?? 200;
|
|
49
51
|
const maxSearch = config.maxSearchLength ?? 200;
|
|
52
|
+
const cursor = config.pagination === "cursor";
|
|
50
53
|
const sortKeys = Object.keys(config.sorts);
|
|
51
54
|
const facetEntries = Object.entries(config.facets ?? {});
|
|
52
55
|
for (const [key, column] of facetEntries) {
|
|
@@ -96,6 +99,18 @@ function defineListQuery(sb, table, config) {
|
|
|
96
99
|
message: "Must be a whole number of at least 1",
|
|
97
100
|
path: ["page"]
|
|
98
101
|
});
|
|
102
|
+
else if (cursor && page !== 1) issues.push({
|
|
103
|
+
message: "This list pages with `after`, not `page`",
|
|
104
|
+
path: ["page"]
|
|
105
|
+
});
|
|
106
|
+
let after;
|
|
107
|
+
if (raw.after !== void 0 && raw.after !== "") {
|
|
108
|
+
if (cursor && typeof raw.after === "string") after = raw.after;
|
|
109
|
+
else issues.push({
|
|
110
|
+
message: cursor ? "Must be text" : "This list pages with `page`, not `after`",
|
|
111
|
+
path: ["after"]
|
|
112
|
+
});
|
|
113
|
+
}
|
|
99
114
|
const size = raw.size === void 0 || raw.size === "" ? pageSize : toInt(raw.size);
|
|
100
115
|
if (size === void 0 || !Number.isInteger(size) || size < 1 || size > maxPageSize) issues.push({
|
|
101
116
|
message: `Must be a whole number from 1 to ${String(maxPageSize)}`,
|
|
@@ -121,6 +136,7 @@ function defineListQuery(sb, table, config) {
|
|
|
121
136
|
...q ? { q } : {},
|
|
122
137
|
sort,
|
|
123
138
|
page: page ?? 1,
|
|
139
|
+
...after ? { after } : {},
|
|
124
140
|
size: size ?? pageSize,
|
|
125
141
|
facets: facetValues
|
|
126
142
|
}
|
|
@@ -143,6 +159,7 @@ function defineListQuery(sb, table, config) {
|
|
|
143
159
|
q: first(record["q"]),
|
|
144
160
|
sort: first(record["sort"]),
|
|
145
161
|
page: first(record["page"]),
|
|
162
|
+
after: first(record["after"]),
|
|
146
163
|
size: first(record["size"]),
|
|
147
164
|
facets: facetValues
|
|
148
165
|
});
|
|
@@ -160,6 +177,7 @@ function defineListQuery(sb, table, config) {
|
|
|
160
177
|
q: typed.q,
|
|
161
178
|
sort: typed.sort,
|
|
162
179
|
page: typed.page,
|
|
180
|
+
after: typed.after,
|
|
163
181
|
size: typed.size,
|
|
164
182
|
facets: rawFacets
|
|
165
183
|
});
|
|
@@ -195,12 +213,15 @@ function defineListQuery(sb, table, config) {
|
|
|
195
213
|
}
|
|
196
214
|
function args(query) {
|
|
197
215
|
const filter = where(query);
|
|
216
|
+
const paging = cursor ? { after: query.after ?? null } : {
|
|
217
|
+
page: query.page,
|
|
218
|
+
count: config.count ?? "exact"
|
|
219
|
+
};
|
|
198
220
|
return {
|
|
199
221
|
...filter ? { where: filter } : {},
|
|
200
222
|
orderBy: config.sorts[query.sort],
|
|
201
|
-
page: query.page,
|
|
202
223
|
size: query.size,
|
|
203
|
-
|
|
224
|
+
...paging
|
|
204
225
|
};
|
|
205
226
|
}
|
|
206
227
|
/** Whether a group's value passes the facet's selected values. */
|
|
@@ -249,6 +270,10 @@ function defineListQuery(sb, table, config) {
|
|
|
249
270
|
serialize: (value) => value
|
|
250
271
|
},
|
|
251
272
|
page: intParser,
|
|
273
|
+
after: {
|
|
274
|
+
parse: (value) => value || null,
|
|
275
|
+
serialize: (value) => value
|
|
276
|
+
},
|
|
252
277
|
size: intParser,
|
|
253
278
|
...Object.fromEntries(facets.map((facet) => [facet.key, listParser]))
|
|
254
279
|
};
|
|
@@ -261,8 +286,102 @@ function defineListQuery(sb, table, config) {
|
|
|
261
286
|
uniqueItems: true
|
|
262
287
|
});
|
|
263
288
|
const searchDescription = config.search ? Array.isArray(config.search) ? `Case-insensitive search in ${config.search.join(", ")}.` : "Full-text search (web search syntax)." : void 0;
|
|
289
|
+
const openapi = [
|
|
290
|
+
...searchDescription ? [{
|
|
291
|
+
name: "q",
|
|
292
|
+
in: "query",
|
|
293
|
+
required: false,
|
|
294
|
+
description: searchDescription,
|
|
295
|
+
schema: {
|
|
296
|
+
type: "string",
|
|
297
|
+
maxLength: maxSearch
|
|
298
|
+
}
|
|
299
|
+
}] : [],
|
|
300
|
+
{
|
|
301
|
+
name: "sort",
|
|
302
|
+
in: "query",
|
|
303
|
+
required: false,
|
|
304
|
+
description: `Ordering. Default \`${config.defaultSort}\`.`,
|
|
305
|
+
schema: {
|
|
306
|
+
type: "string",
|
|
307
|
+
enum: sortKeys,
|
|
308
|
+
default: config.defaultSort
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
cursor ? {
|
|
312
|
+
name: "after",
|
|
313
|
+
in: "query",
|
|
314
|
+
required: false,
|
|
315
|
+
description: "`nextCursor` of the previous page. Leave it out for the first page.",
|
|
316
|
+
schema: { type: "string" }
|
|
317
|
+
} : {
|
|
318
|
+
name: "page",
|
|
319
|
+
in: "query",
|
|
320
|
+
required: false,
|
|
321
|
+
description: "1-based page number.",
|
|
322
|
+
schema: {
|
|
323
|
+
type: "integer",
|
|
324
|
+
minimum: 1,
|
|
325
|
+
default: 1
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
name: "size",
|
|
330
|
+
in: "query",
|
|
331
|
+
required: false,
|
|
332
|
+
description: "Page size.",
|
|
333
|
+
schema: {
|
|
334
|
+
type: "integer",
|
|
335
|
+
minimum: 1,
|
|
336
|
+
maximum: maxPageSize,
|
|
337
|
+
default: pageSize
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
...facets.map((facet) => ({
|
|
341
|
+
name: facet.key,
|
|
342
|
+
in: "query",
|
|
343
|
+
required: false,
|
|
344
|
+
description: `Filter on ${facet.column}. Comma-separated; any value matches.${facet.nullable ? ` \`${UNSET}\` matches empty.` : ""}`,
|
|
345
|
+
schema: facetSchema(facet),
|
|
346
|
+
style: "form",
|
|
347
|
+
explode: false
|
|
348
|
+
}))
|
|
349
|
+
];
|
|
350
|
+
const jsonSchema = {
|
|
351
|
+
type: "object",
|
|
352
|
+
additionalProperties: false,
|
|
353
|
+
properties: {
|
|
354
|
+
...searchDescription ? { q: {
|
|
355
|
+
type: "string",
|
|
356
|
+
maxLength: maxSearch,
|
|
357
|
+
description: searchDescription
|
|
358
|
+
} } : {},
|
|
359
|
+
sort: {
|
|
360
|
+
type: "string",
|
|
361
|
+
enum: sortKeys,
|
|
362
|
+
default: config.defaultSort
|
|
363
|
+
},
|
|
364
|
+
...cursor ? { after: { type: "string" } } : { page: {
|
|
365
|
+
type: "integer",
|
|
366
|
+
minimum: 1,
|
|
367
|
+
default: 1
|
|
368
|
+
} },
|
|
369
|
+
size: {
|
|
370
|
+
type: "integer",
|
|
371
|
+
minimum: 1,
|
|
372
|
+
maximum: maxPageSize,
|
|
373
|
+
default: pageSize
|
|
374
|
+
},
|
|
375
|
+
...facets.length > 0 ? { facets: {
|
|
376
|
+
type: "object",
|
|
377
|
+
additionalProperties: false,
|
|
378
|
+
properties: Object.fromEntries(facets.map((facet) => [facet.key, facetSchema(facet)]))
|
|
379
|
+
} } : {}
|
|
380
|
+
}
|
|
381
|
+
};
|
|
264
382
|
return {
|
|
265
383
|
table,
|
|
384
|
+
pagination: config.pagination ?? "offset",
|
|
266
385
|
defaults,
|
|
267
386
|
facets,
|
|
268
387
|
parse,
|
|
@@ -279,7 +398,8 @@ function defineListQuery(sb, table, config) {
|
|
|
279
398
|
if (query.q) params.set("q", query.q);
|
|
280
399
|
if (query.sort && query.sort !== config.defaultSort) params.set("sort", query.sort);
|
|
281
400
|
if (query.page && query.page !== 1) params.set("page", String(query.page));
|
|
282
|
-
if (query.
|
|
401
|
+
if (query.after) params.set("after", query.after);
|
|
402
|
+
if (query.size !== void 0 && query.size > 0 && query.size !== pageSize) params.set("size", String(query.size));
|
|
283
403
|
for (const facet of facets) {
|
|
284
404
|
const values = query.facets?.[facet.key];
|
|
285
405
|
if (values && values.length > 0) params.set(facet.key, values.join(","));
|
|
@@ -297,7 +417,7 @@ function defineListQuery(sb, table, config) {
|
|
|
297
417
|
const page = repository.paginate({
|
|
298
418
|
...extra,
|
|
299
419
|
...base,
|
|
300
|
-
count: count ?? base["count"],
|
|
420
|
+
...cursor ? {} : { count: count ?? base["count"] },
|
|
301
421
|
...combined ? { where: combined } : {}
|
|
302
422
|
});
|
|
303
423
|
if (!config.facetCounts) return page;
|
|
@@ -317,93 +437,8 @@ function defineListQuery(sb, table, config) {
|
|
|
317
437
|
facetCounts: marginals(rows, query)
|
|
318
438
|
})));
|
|
319
439
|
},
|
|
320
|
-
openapi
|
|
321
|
-
|
|
322
|
-
name: "q",
|
|
323
|
-
in: "query",
|
|
324
|
-
required: false,
|
|
325
|
-
description: searchDescription,
|
|
326
|
-
schema: {
|
|
327
|
-
type: "string",
|
|
328
|
-
maxLength: maxSearch
|
|
329
|
-
}
|
|
330
|
-
}] : [],
|
|
331
|
-
{
|
|
332
|
-
name: "sort",
|
|
333
|
-
in: "query",
|
|
334
|
-
required: false,
|
|
335
|
-
description: `Ordering. Default \`${config.defaultSort}\`.`,
|
|
336
|
-
schema: {
|
|
337
|
-
type: "string",
|
|
338
|
-
enum: sortKeys,
|
|
339
|
-
default: config.defaultSort
|
|
340
|
-
}
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
name: "page",
|
|
344
|
-
in: "query",
|
|
345
|
-
required: false,
|
|
346
|
-
description: "1-based page number.",
|
|
347
|
-
schema: {
|
|
348
|
-
type: "integer",
|
|
349
|
-
minimum: 1,
|
|
350
|
-
default: 1
|
|
351
|
-
}
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
name: "size",
|
|
355
|
-
in: "query",
|
|
356
|
-
required: false,
|
|
357
|
-
description: "Page size.",
|
|
358
|
-
schema: {
|
|
359
|
-
type: "integer",
|
|
360
|
-
minimum: 1,
|
|
361
|
-
maximum: maxPageSize,
|
|
362
|
-
default: pageSize
|
|
363
|
-
}
|
|
364
|
-
},
|
|
365
|
-
...facets.map((facet) => ({
|
|
366
|
-
name: facet.key,
|
|
367
|
-
in: "query",
|
|
368
|
-
required: false,
|
|
369
|
-
description: `Filter on ${facet.column}. Comma-separated; any value matches.${facet.nullable ? ` \`${UNSET}\` matches empty.` : ""}`,
|
|
370
|
-
schema: facetSchema(facet),
|
|
371
|
-
style: "form",
|
|
372
|
-
explode: false
|
|
373
|
-
}))
|
|
374
|
-
],
|
|
375
|
-
jsonSchema: {
|
|
376
|
-
type: "object",
|
|
377
|
-
additionalProperties: false,
|
|
378
|
-
properties: {
|
|
379
|
-
...searchDescription ? { q: {
|
|
380
|
-
type: "string",
|
|
381
|
-
maxLength: maxSearch,
|
|
382
|
-
description: searchDescription
|
|
383
|
-
} } : {},
|
|
384
|
-
sort: {
|
|
385
|
-
type: "string",
|
|
386
|
-
enum: sortKeys,
|
|
387
|
-
default: config.defaultSort
|
|
388
|
-
},
|
|
389
|
-
page: {
|
|
390
|
-
type: "integer",
|
|
391
|
-
minimum: 1,
|
|
392
|
-
default: 1
|
|
393
|
-
},
|
|
394
|
-
size: {
|
|
395
|
-
type: "integer",
|
|
396
|
-
minimum: 1,
|
|
397
|
-
maximum: maxPageSize,
|
|
398
|
-
default: pageSize
|
|
399
|
-
},
|
|
400
|
-
...facets.length > 0 ? { facets: {
|
|
401
|
-
type: "object",
|
|
402
|
-
additionalProperties: false,
|
|
403
|
-
properties: Object.fromEntries(facets.map((facet) => [facet.key, facetSchema(facet)]))
|
|
404
|
-
} } : {}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
440
|
+
openapi,
|
|
441
|
+
jsonSchema
|
|
407
442
|
};
|
|
408
443
|
}
|
|
409
444
|
//#endregion
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
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-
|
|
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";
|
|
4
|
+
import { t as PermdockCatalog } from "./permdock-sql-DImJULY-.js";
|
|
4
5
|
import { n as TemplateValues, t as TemplateParams } from "./template-mbvlysOo.js";
|
|
5
6
|
import { RealtimeChannel, SupabaseClient } from "@supabase/supabase-js";
|
|
6
7
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
7
|
-
//#region src/realtime/
|
|
8
|
+
//#region src/realtime/topic.d.ts
|
|
8
9
|
type EventSchemas = Readonly<Record<string, StandardSchemaV1>>;
|
|
9
10
|
interface TopicOptions<E extends EventSchemas> {
|
|
10
11
|
/** Name used for generated policies and functions. Defaults to the template's literal parts. */
|
|
@@ -15,7 +16,7 @@ interface TopicOptions<E extends EventSchemas> {
|
|
|
15
16
|
readonly private?: boolean;
|
|
16
17
|
/**
|
|
17
18
|
* Tenant check for the generated policy. Defaults to `{orgId}` against
|
|
18
|
-
* `
|
|
19
|
+
* `tenant_id` / `app_metadata.tenant_id` when the template has `{orgId}`.
|
|
19
20
|
*/
|
|
20
21
|
readonly tenant?: false | {
|
|
21
22
|
readonly param?: string;
|
|
@@ -26,6 +27,23 @@ interface TopicOptions<E extends EventSchemas> {
|
|
|
26
27
|
readonly owner?: false | {
|
|
27
28
|
readonly param?: string;
|
|
28
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Authorize with PermDock's SQL helpers instead of the tenant claim:
|
|
32
|
+
* `permitted_<scope>_ids(receive)` on the scope segment (or
|
|
33
|
+
* `permdock_has` for `scope: 'global'`), and `send` for broadcasting.
|
|
34
|
+
*
|
|
35
|
+
* The helpers check role and scope only. Use this just for permissions
|
|
36
|
+
* whose grants have no row conditions beyond the scope: for a permission
|
|
37
|
+
* with row conditions (e.g. `authorId = principal.id`) every member of the
|
|
38
|
+
* scope could join. Pass `catalog` to refuse those keys here;
|
|
39
|
+
* `better-supabase doctor` (BS214) refuses them from the catalog file.
|
|
40
|
+
*/
|
|
41
|
+
readonly permdock?: PermdockTopicPolicy;
|
|
42
|
+
/**
|
|
43
|
+
* PermDock's `permissions.catalog.json`. With it, a `permdock` policy
|
|
44
|
+
* naming a permission with `rowConditions: true` throws.
|
|
45
|
+
*/
|
|
46
|
+
readonly catalog?: PermdockCatalog;
|
|
29
47
|
/** Let clients broadcast on the topic, not only receive. Defaults to `false`. */
|
|
30
48
|
readonly send?: boolean;
|
|
31
49
|
/** Also authorize presence. Defaults to `false`. */
|
|
@@ -66,7 +84,10 @@ interface TriggerOptions<M extends AnyModels, T extends keyof M, P extends strin
|
|
|
66
84
|
readonly values: { readonly [K in TemplateParams<P>]: Extract<keyof Row<M, T>, string>; };
|
|
67
85
|
/** Defaults to all three. */
|
|
68
86
|
readonly events?: readonly ("insert" | "update" | "delete")[];
|
|
69
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Schema for the generated function. Defaults to `better_supabase`, which
|
|
89
|
+
* the Data API does not expose.
|
|
90
|
+
*/
|
|
70
91
|
readonly functionSchema?: string;
|
|
71
92
|
}
|
|
72
93
|
interface RowChange<R> {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/core/logger.ts
|
|
2
|
+
const log = (method) => (message, fields) => {
|
|
3
|
+
if (fields === void 0) console[method](`better-supabase: ${message}`);
|
|
4
|
+
else console[method](`better-supabase: ${message}`, fields);
|
|
5
|
+
};
|
|
6
|
+
/** The default: `console`, with a `better-supabase:` prefix. */
|
|
7
|
+
const consoleLogger = {
|
|
8
|
+
debug: log("debug"),
|
|
9
|
+
info: log("info"),
|
|
10
|
+
warn: log("warn"),
|
|
11
|
+
error: log("error")
|
|
12
|
+
};
|
|
13
|
+
const noop = () => {};
|
|
14
|
+
const silentLogger = {
|
|
15
|
+
debug: noop,
|
|
16
|
+
info: noop,
|
|
17
|
+
warn: noop,
|
|
18
|
+
error: noop
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { silentLogger as n, consoleLogger as t };
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as BetterSupabase } from "../define-
|
|
3
|
-
import { d as ServerContext, f as ServerOptions, l as BetterServer, n as GuardOptions } from "../respond-
|
|
4
|
-
import {
|
|
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";
|
|
5
5
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
6
|
-
//#region src/mcp/
|
|
6
|
+
//#region src/mcp/mcp.d.ts
|
|
7
7
|
export declare const MCP_PROTOCOL_VERSION: string;
|
|
8
8
|
type Json = Readonly<Record<string, unknown>>;
|
|
9
9
|
/** MCP tool annotations (hints for clients, not guarantees). */
|
|
10
|
-
|
|
10
|
+
interface ToolAnnotations {
|
|
11
11
|
readonly title?: string;
|
|
12
12
|
readonly readOnlyHint?: boolean;
|
|
13
13
|
readonly destructiveHint?: boolean;
|
|
@@ -15,7 +15,7 @@ export interface ToolAnnotations {
|
|
|
15
15
|
readonly openWorldHint?: boolean;
|
|
16
16
|
}
|
|
17
17
|
/** A tool as listed by `tools/list`. */
|
|
18
|
-
|
|
18
|
+
interface ToolInfo {
|
|
19
19
|
readonly name: string;
|
|
20
20
|
readonly title?: string;
|
|
21
21
|
readonly description?: string;
|
|
@@ -23,17 +23,34 @@ export interface ToolInfo {
|
|
|
23
23
|
readonly outputSchema?: Json;
|
|
24
24
|
readonly annotations?: ToolAnnotations;
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
interface ToolContext<M extends AnyModels, F extends AnyFunctions, E> extends ServerContext<M, F, E> {
|
|
27
27
|
readonly request: Request;
|
|
28
28
|
readonly signal: AbortSignal;
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
interface McpTool<M extends AnyModels, F extends AnyFunctions, E> {
|
|
31
31
|
readonly info: ToolInfo;
|
|
32
32
|
/** Validates arguments; its output is what `run` receives. */
|
|
33
33
|
readonly input?: StandardSchemaV1;
|
|
34
|
+
/** Opaque data for the `authorize` and `visible` hooks. Never sent to clients. */
|
|
35
|
+
readonly meta?: unknown;
|
|
34
36
|
run(args: never, ctx: ToolContext<M, F, E>): unknown;
|
|
35
37
|
}
|
|
36
|
-
|
|
38
|
+
/** What the `authorize` and `visible` hooks see of a tool. */
|
|
39
|
+
interface ToolRef {
|
|
40
|
+
readonly info: ToolInfo;
|
|
41
|
+
/** The tool's `meta`, e.g. a PermDock permission. `undefined` for table tools. */
|
|
42
|
+
readonly meta: unknown;
|
|
43
|
+
}
|
|
44
|
+
/** The outcome of `authorize`. `scopes` turns a refusal into an OAuth challenge. */
|
|
45
|
+
type ToolDecision = {
|
|
46
|
+
readonly allowed: true;
|
|
47
|
+
} | {
|
|
48
|
+
readonly allowed: false;
|
|
49
|
+
readonly reason?: string;
|
|
50
|
+
/** OAuth scopes the call needs, sent in an `insufficient_scope` challenge. */
|
|
51
|
+
readonly scopes?: readonly string[];
|
|
52
|
+
};
|
|
53
|
+
interface ToolDefinition<M extends AnyModels, F extends AnyFunctions, E, I> {
|
|
37
54
|
readonly name: string;
|
|
38
55
|
readonly title?: string;
|
|
39
56
|
readonly description: string;
|
|
@@ -45,10 +62,12 @@ export interface ToolDefinition<M extends AnyModels, F extends AnyFunctions, E,
|
|
|
45
62
|
readonly inputSchema?: Json;
|
|
46
63
|
readonly outputSchema?: Json;
|
|
47
64
|
readonly annotations?: ToolAnnotations;
|
|
65
|
+
/** Opaque data for the `authorize` and `visible` hooks. Never sent to clients. */
|
|
66
|
+
readonly meta?: unknown;
|
|
48
67
|
run(args: I, ctx: ToolContext<M, F, E>): unknown;
|
|
49
68
|
}
|
|
50
|
-
|
|
51
|
-
|
|
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 {
|
|
52
71
|
readonly name: string;
|
|
53
72
|
readonly version: string;
|
|
54
73
|
readonly title?: string;
|
|
@@ -64,14 +83,39 @@ export interface McpOptions<M extends AnyModels, F extends AnyFunctions, E> exte
|
|
|
64
83
|
readonly resource?: string | ((request: Request) => string);
|
|
65
84
|
/** Defaults to Supabase Auth of `env.url` (`<url>/auth/v1`). */
|
|
66
85
|
readonly authorizationServers?: readonly string[];
|
|
86
|
+
/**
|
|
87
|
+
* Scopes the tools need, published as RFC 9728 `scopes_supported` and in
|
|
88
|
+
* `insufficient_scope` challenges. `offline_access` is left out: refresh
|
|
89
|
+
* tokens are between the client and the authorization server.
|
|
90
|
+
*/
|
|
91
|
+
readonly scopes?: readonly string[];
|
|
67
92
|
/** Origins allowed to call the server (DNS rebinding protection). Defaults to any. */
|
|
68
93
|
readonly allowedOrigins?: readonly string[];
|
|
94
|
+
/**
|
|
95
|
+
* Hostnames the `Host` header may name, without the port (DNS rebinding
|
|
96
|
+
* protection). List the production, preview and local hosts. Defaults to any.
|
|
97
|
+
*/
|
|
98
|
+
readonly allowedHosts?: readonly string[];
|
|
99
|
+
/** A page that explains how to connect, published as RFC 9728 `resource_documentation`. */
|
|
100
|
+
readonly resourceDocumentation?: string;
|
|
69
101
|
/** Custom jsonb types, as in `createOpenApi`. */
|
|
70
102
|
readonly json?: Readonly<Record<string, unknown>>;
|
|
71
103
|
/** Include internal error messages in tool results. Defaults to `NODE_ENV === 'development'`. */
|
|
72
104
|
readonly exposeErrors?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Decides each `tools/call` after the arguments are validated and before
|
|
107
|
+
* `run`. `args` are the validated arguments (raw for table tools, which
|
|
108
|
+
* validate in the repository). A refusal is a tool error; a refusal with
|
|
109
|
+
* `scopes` is a 403 `insufficient_scope` challenge naming them.
|
|
110
|
+
*/
|
|
111
|
+
readonly authorize?: (ctx: ToolContext<M, F, E>, tool: ToolRef, args: unknown) => ToolDecision | Promise<ToolDecision>;
|
|
112
|
+
/**
|
|
113
|
+
* Whether the caller sees a tool in `tools/list`. A hidden tool is called
|
|
114
|
+
* like an unknown one. Lists are cached per token (`cacheScope: 'private'`).
|
|
115
|
+
*/
|
|
116
|
+
readonly visible?: (ctx: ToolContext<M, F, E>, tool: ToolRef) => boolean | Promise<boolean>;
|
|
73
117
|
}
|
|
74
|
-
|
|
118
|
+
interface BetterMcp<M extends AnyModels, F extends AnyFunctions, E> extends BetterServer<M, F, E> {
|
|
75
119
|
/** Everything in one handler: the MCP endpoint and `/.well-known/oauth-protected-resource`. */
|
|
76
120
|
readonly fetch: (request: Request) => Promise<Response>;
|
|
77
121
|
/** The Streamable HTTP endpoint (POST JSON-RPC). */
|
|
@@ -84,7 +128,7 @@ export interface BetterMcp<M extends AnyModels, F extends AnyFunctions, E> exten
|
|
|
84
128
|
/** Calls a tool directly, e.g. from tests or another transport. */
|
|
85
129
|
call(name: string, args: unknown, ctx: ToolContext<M, F, E>): Promise<ToolResult>;
|
|
86
130
|
}
|
|
87
|
-
|
|
131
|
+
interface ToolResult {
|
|
88
132
|
readonly content: readonly {
|
|
89
133
|
readonly type: "text";
|
|
90
134
|
readonly text: string;
|
|
@@ -102,4 +146,4 @@ export declare function defineTool<M extends AnyModels, F extends AnyFunctions,
|
|
|
102
146
|
*/
|
|
103
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>;
|
|
104
148
|
//#endregion
|
|
105
|
-
export type { GuardOptions, ResourceRouteOptions };
|
|
149
|
+
export type { BetterMcp, GuardOptions, McpOptions, McpTool, ResourceRouteOptions, ToolAnnotations, ToolContext, ToolDecision, ToolDefinition, ToolInfo, ToolRef, ToolResources, ToolResult };
|