better-supabase 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/bin/better-supabase.js +4 -0
- package/dist/{base64-CQeB1eSf.js → base64-D2gsioCY.js} +2 -2
- package/dist/channel-FQW-CnGR.d.ts +70 -0
- 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/codemod-DqV7612m.js +388 -0
- package/dist/cli/command-CK14fP91.js +502 -0
- package/dist/cli/compare-BmIWVEui.js +9 -0
- package/dist/cli/config-CPVpXP5I.js +1965 -0
- package/dist/cli/config-dtoekM0v.js +2 -0
- package/dist/cli/db-DOBPt660.js +52 -0
- package/dist/cli/diff-SjkO5rNr.js +752 -0
- package/dist/cli/dist-DBPdlPYK.js +1112 -0
- package/dist/cli/dist-DreZ24Sz.js +129 -0
- package/dist/cli/dist-xn4wlboc.js +732 -0
- package/dist/cli/doctor-L7Z8mYTx.js +2863 -0
- package/dist/cli/env-DmKv_G4A.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-BJc9vdyu.js +2 -0
- package/dist/cli/gen-C2osRcr5.js +2204 -0
- package/dist/cli/index.d.ts +493 -0
- package/dist/cli/index.js +184 -0
- package/dist/cli/init-Saf5-R9T.js +550 -0
- package/dist/cli/introspect--H7oGmcd.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-Cp5Fyta-.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-BfMQcKy8.js +289 -0
- package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
- package/dist/cli/run-BKR2W_79.js +351 -0
- package/dist/cli/seed-CUlqWh-8.js +98 -0
- package/dist/cli/skills-LJJIhLFR.js +137 -0
- package/dist/cli/sql-DzPbfngx.js +348 -0
- package/dist/cli/style-C0NFdJRL.js +29 -0
- package/dist/cli/toml-DB-MNnFs.js +424 -0
- package/dist/cli/version-BDJuO0UR.js +4 -0
- package/dist/cli/yaml-CYCbJ6et.js +2252 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +15 -22
- package/dist/clone-BfgmLU90.js +21 -0
- package/dist/{compiler-2zqGzxVZ.d.ts → compiler-BXH_aZ7N.d.ts} +2 -2
- package/dist/config/index.d.ts +4 -4
- package/dist/config/index.js +5 -5
- package/dist/{config-DOsGYSiT.js → config-DreERlKo.js} +1 -1
- package/dist/{config-C1CYcm6o.d.ts → config-T_ejwyd3.d.ts} +176 -11
- package/dist/{define-DUbydmJa.d.ts → define-Bp_BZa5h.d.ts} +37 -29
- package/dist/{define-DF341GDj.js → define-cNKzqwL_.js} +356 -89
- package/dist/edge/index.d.ts +20 -13
- package/dist/edge/index.js +55 -26
- package/dist/{entitlements-DvJXoI02.d.ts → entitlements-DUxU4oHe.d.ts} +2 -2
- package/dist/env/index.d.ts +2 -2
- package/dist/env/index.js +34 -1
- package/dist/{errors-Bl3rkOzo.js → errors-DtwXa6b8.js} +2 -1
- package/dist/events/index.d.ts +3 -2
- package/dist/events/index.js +69 -16
- package/dist/events-aIO7vsIk.d.ts +230 -0
- package/dist/executor-BunPOO-k.d.ts +402 -0
- package/dist/{executor-B26lgbHD.d.ts → executor-Cghdstwu.d.ts} +1 -2
- package/dist/{executor-C57jx2pn.js → executor-XycESQPH.js} +3 -3
- package/dist/hono/index.d.ts +27 -23
- package/dist/hono/index.js +46 -11
- package/dist/impersonation-VfaGc4Q_.js +41 -0
- package/dist/{index-BNsABq7P.d.ts → index-BGdgBPdf.d.ts} +66 -25
- package/dist/{index-qriRM9cZ.d.ts → index-C7f8cOBM.d.ts} +4 -4
- package/dist/{index-Dy6kuF0P.d.ts → index-CLg87OBW.d.ts} +6 -1
- package/dist/{index-GV77NpRP.d.ts → index-DOESKG27.d.ts} +34 -9
- package/dist/{index-CriFFJ_p.d.ts → index-DgILJRXj.d.ts} +43 -17
- package/dist/{index-UJ-LUxtI.d.ts → index-DmXSxbLi.d.ts} +14 -14
- package/dist/{index-Cf-D2jk1.d.ts → index-Dxn2a5cw.d.ts} +2 -2
- package/dist/{index-CTTMS6_1.d.ts → index-SaTsEfGP.d.ts} +86 -9
- package/dist/{index-CADlNHK-.d.ts → index-fag8VJZ2.d.ts} +5 -6
- package/dist/index.d.ts +34 -17
- package/dist/index.js +15 -14
- package/dist/jobs/index.d.ts +147 -95
- package/dist/jobs/index.js +773 -250
- package/dist/{json-schema--aOXAGfU.js → json-schema-m1fiwKgN.js} +23 -2
- package/dist/kit-events-CTFDfSwb.js +60 -0
- package/dist/kit-transport-B82k1djG.d.ts +33 -0
- package/dist/kit-transport-DJlHQUBU.js +55 -0
- package/dist/{config-Be4GwsqI.js → kits-CGLLrNPd.js} +38 -10
- package/dist/list/index.d.ts +1 -1
- package/dist/list/index.js +3 -3
- package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
- package/dist/{live-QE3UPbGm.d.ts → live-D9W2M5aO.d.ts} +16 -15
- package/dist/lookup-BaP5bI27.js +18 -0
- package/dist/mcp/index.d.ts +39 -22
- package/dist/mcp/index.js +39 -25
- package/dist/{mfa-x3V3vGh-.d.ts → mfa-CusDgPaD.d.ts} +5 -1
- package/dist/next/image/index.js +6 -3
- package/dist/next/index.d.ts +60 -36
- package/dist/next/index.js +167 -50
- package/dist/notifications/index.d.ts +162 -0
- package/dist/notifications/index.js +264 -0
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +6 -6
- package/dist/orgs/index.d.ts +132 -0
- package/dist/orgs/index.js +245 -0
- package/dist/orpc/index.d.ts +37 -20
- package/dist/orpc/index.js +24 -11
- package/dist/otel/index.d.ts +24 -5
- package/dist/otel/index.js +124 -64
- package/dist/permdock-sql-C2Inc6Xc.d.ts +29 -0
- package/dist/permdock-sql-DgOfeixi.js +51 -0
- package/dist/plugin-DwARMuQp.js +59 -0
- package/dist/{plugin-DVRB8qNE.d.ts → plugin-o144f322.d.ts} +17 -5
- package/dist/plugins/actor/index.d.ts +5 -2
- package/dist/plugins/actor/index.js +22 -8
- package/dist/plugins/rules/index.d.ts +2 -2
- package/dist/plugins/rules/index.js +52 -17
- package/dist/plugins/soft-delete/index.d.ts +3 -3
- package/dist/plugins/soft-delete/index.js +14 -5
- package/dist/plugins/tenant/index.d.ts +3 -3
- package/dist/plugins/tenant/index.js +45 -21
- package/dist/plugins/timestamps/index.d.ts +1 -1
- package/dist/plugins/timestamps/index.js +4 -3
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/plugins/validation/index.js +26 -6
- package/dist/{pool-B9qsLyFR.d.ts → pool-C9voM4Kw.d.ts} +24 -6
- package/dist/postgres/index.d.ts +5 -5
- package/dist/postgres/index.js +20 -10
- package/dist/{postgrest-DmBlevh-.d.ts → postgrest-CruYKAvV.d.ts} +1 -1
- package/dist/{problem-CGt1ADix.js → problem-BW1KhzSG.js} +2 -1
- package/dist/{problem-Z2RTQjZD.d.ts → problem-Blxe8S31.d.ts} +1 -1
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +3 -3
- package/dist/{query-BdKLTPlj.js → query-CCbo44lG.js} +18 -18
- package/dist/queue-BYUCjr59.d.ts +252 -0
- package/dist/react/index.d.ts +8 -7
- package/dist/react/index.js +4 -3
- package/dist/react/server.d.ts +16 -5
- package/dist/react/server.js +12 -4
- package/dist/react/session.d.ts +10 -4
- package/dist/react/session.js +11 -3
- package/dist/{react-DNBYNazu.js → react-C_s7kiNz.js} +138 -46
- package/dist/{read-set-D0qBcboM.js → read-set-DQFt1N_Y.js} +71 -15
- package/dist/realtime/index.d.ts +3 -3
- package/dist/realtime/index.js +14 -12
- package/dist/{index-kpgopLNv.d.ts → refresh-BTrQ_ZTp.d.ts} +6 -3
- package/dist/{resolve-BRciX2jK.d.ts → resolve-C15TJq77.d.ts} +22 -11
- package/dist/{resource-D30rp0GN.js → resource-CRxxwkQq.js} +24 -9
- package/dist/{resource-CwVgiI5q.d.ts → resource-D8iqWMr-.d.ts} +6 -6
- package/dist/respond-D2OQl62-.d.ts +371 -0
- package/dist/{result-DWXatkd6.js → result-BKiliPY7.js} +2 -2
- package/dist/server/index.d.ts +17 -15
- package/dist/server/index.js +16 -22
- package/dist/server-Csx2sRjg.js +655 -0
- package/dist/{shared-_6-uPL7E.js → shared-D1dRUrAg.js} +19 -4
- package/dist/signers-Cc6r98SW.d.ts +162 -0
- package/dist/{simplify-LakqK1vH.js → simplify-_0oUKqCd.js} +27 -95
- package/dist/sql/index.d.ts +247 -10
- package/dist/sql/index.js +8591 -780
- package/dist/{sql-BIgk12ew.js → sql-Coh6n4cC.js} +11 -3
- package/dist/ssr/index.d.ts +4 -4
- package/dist/ssr/index.js +1 -2
- package/dist/{standard-FUi3Z3-7.js → standard-D7r6dMUu.js} +6 -3
- package/dist/{standard-eudBiRk1.d.ts → standard-J4YgMOLm.d.ts} +1 -1
- package/dist/{stats-D78UQ8Yu.js → stats-Bqob3WqT.js} +34 -9
- package/dist/storage/index.d.ts +4 -4
- package/dist/storage/index.js +174 -27
- package/dist/support-DT-OhSxD.d.ts +88 -0
- package/dist/support-Dk6vdmEw.js +291 -0
- package/dist/support-view-Da5peKFg.d.ts +17 -0
- package/dist/support-view-g4YLBeqX.js +18 -0
- package/dist/{tables-Dhha3BXM.js → tables-Cb-3_VWc.js} +14 -0
- package/dist/{permdock-sql-Bta_G0v-.js → template-TxrGI5jR.js} +2 -31
- package/dist/{temporal-BwshQk0W.js → temporal-CVlIV2DZ.js} +17 -4
- package/dist/{temporal-required-CMxeSVPo.js → temporal-required-CAt4Dc9Z.js} +2 -2
- package/dist/testing/index.d.ts +113 -24
- package/dist/testing/index.js +375 -47
- package/dist/{types-DONv9SHN.d.ts → types-Dnf_wRDz.d.ts} +26 -3
- package/dist/user-change-CHFEUro1.js +49 -0
- package/dist/{webhooks-CAIFQSTM.js → verify-Ce49ETPz.js} +38 -19
- package/dist/{version-BfpG2gks.js → version-DM_Roffb.js} +1 -1
- package/dist/{view-3Po_PVlr.d.ts → view-BEf0diC5.d.ts} +10 -5
- package/dist/{mfa-BxoR1RkN.js → view-Bq64ki8-.js} +210 -64
- package/dist/webhooks/index.d.ts +136 -5
- package/dist/webhooks/index.js +588 -2
- package/dist/wire-D2dT86vi.js +35 -0
- package/package.json +50 -10
- package/schemas/config-v1.json +131 -1
- package/schemas/doctor-report-v1.json +10 -0
- package/skills/better-supabase/SKILL.md +60 -10
- package/skills/better-supabase/references/plugins.md +13 -14
- package/skills/better-supabase/references/troubleshooting.md +25 -4
- package/skills/better-supabase-api/SKILL.md +74 -19
- package/skills/better-supabase-api/references/adapters.md +48 -27
- package/skills/better-supabase-auth/SKILL.md +149 -0
- package/skills/better-supabase-auth/references/permdock.md +100 -0
- package/skills/better-supabase-testing/SKILL.md +58 -4
- package/dist/claims-CoTobNC-.js +0 -25
- package/dist/events-Do8jXh4D.d.ts +0 -84
- package/dist/executor-DynmIWhq.d.ts +0 -195
- package/dist/invalidate-DbxuL2jL.js +0 -18
- package/dist/permdock-sql-DImJULY-.d.ts +0 -17
- package/dist/plugin-BqR6wKMB.js +0 -23
- package/dist/respond-C44EZAJo.js +0 -399
- package/dist/respond-DAkPIdTH.d.ts +0 -175
- package/dist/result-c2OYgCV2.d.ts +0 -203
- package/dist/view-wZ-9qIUz.js +0 -45
|
@@ -32,6 +32,18 @@ function scalarKind(column) {
|
|
|
32
32
|
if (column.type === "record" || column.type === "void") return { kind: "unknown" };
|
|
33
33
|
return { kind: "string" };
|
|
34
34
|
}
|
|
35
|
+
/** App names of the columns that plugins fill from the table's flags. */
|
|
36
|
+
function managedColumns(table) {
|
|
37
|
+
const { timestamps, actor, softDelete } = table.flags;
|
|
38
|
+
return new Set([
|
|
39
|
+
timestamps?.createdAt,
|
|
40
|
+
timestamps?.updatedAt,
|
|
41
|
+
actor?.createdBy,
|
|
42
|
+
actor?.updatedBy,
|
|
43
|
+
actor?.impersonatedBy,
|
|
44
|
+
softDelete
|
|
45
|
+
].filter((name) => name !== void 0));
|
|
46
|
+
}
|
|
35
47
|
/**
|
|
36
48
|
* The generated row type of a field (its element type for arrays). Storage
|
|
37
49
|
* path columns validate as strings and are cast to their `StoragePath` brand.
|
|
@@ -43,6 +55,7 @@ function rowType(table, plan) {
|
|
|
43
55
|
/** The fields a variant accepts; read-only columns are left out of writes. */
|
|
44
56
|
function fieldsFor(table, variant, input) {
|
|
45
57
|
const fields = [];
|
|
58
|
+
const managed = managedColumns(table);
|
|
46
59
|
for (const [name, column] of Object.entries(table.columns)) {
|
|
47
60
|
if (variant === "Insert" && (column.generated || column.insertable === false)) continue;
|
|
48
61
|
if (variant === "Update" && (column.generated || column.updatable === false)) continue;
|
|
@@ -52,7 +65,8 @@ function fieldsFor(table, variant, input) {
|
|
|
52
65
|
scalar: scalarKind(column),
|
|
53
66
|
nullable: column.nullable,
|
|
54
67
|
optional: variant === "Update" || variant === "Insert" && (column.nullable || column.hasDefault),
|
|
55
|
-
customJson: Boolean(column.json && input.config.json[`${table.name}.${column.db}`])
|
|
68
|
+
customJson: Boolean(column.json && input.config.json[`${table.name}.${column.db}`]),
|
|
69
|
+
managed: managed.has(name)
|
|
56
70
|
});
|
|
57
71
|
}
|
|
58
72
|
return fields;
|
|
@@ -65,7 +79,7 @@ function variantsFor(table) {
|
|
|
65
79
|
];
|
|
66
80
|
}
|
|
67
81
|
function tableEntries(input) {
|
|
68
|
-
return Object.entries(input.meta.tables).sort(([a], [b]) => a
|
|
82
|
+
return Object.entries(input.meta.tables).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
69
83
|
}
|
|
70
84
|
function propertyKey(name) {
|
|
71
85
|
return /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name);
|
|
@@ -130,6 +144,13 @@ function scalar(kind) {
|
|
|
130
144
|
}
|
|
131
145
|
}
|
|
132
146
|
function property(plan) {
|
|
147
|
+
const schema = nullable(plan);
|
|
148
|
+
return plan.managed ? {
|
|
149
|
+
...schema,
|
|
150
|
+
readOnly: true
|
|
151
|
+
} : schema;
|
|
152
|
+
}
|
|
153
|
+
function nullable(plan) {
|
|
133
154
|
let schema = scalar(plan.scalar);
|
|
134
155
|
if (plan.column.array) schema = {
|
|
135
156
|
type: "array",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { t as cloneValue } from "./clone-BfgmLU90.js";
|
|
2
|
+
import { n as nowInstant } from "./temporal-CVlIV2DZ.js";
|
|
3
|
+
//#region src/core/kit-events.ts
|
|
4
|
+
/**
|
|
5
|
+
* Fixed OpenTelemetry attribute names for kit work, so dashboards and
|
|
6
|
+
* queries can rely on them.
|
|
7
|
+
*/
|
|
8
|
+
const KIT_ATTRIBUTES = {
|
|
9
|
+
event: "better_supabase.kit.event",
|
|
10
|
+
tenant: "better_supabase.tenant",
|
|
11
|
+
actor: "better_supabase.actor.id",
|
|
12
|
+
supportSessionId: "better_supabase.support.session_id",
|
|
13
|
+
orgId: "better_supabase.org.id",
|
|
14
|
+
invitationId: "better_supabase.invitation.id",
|
|
15
|
+
notificationType: "better_supabase.notification.type",
|
|
16
|
+
webhookEndpointId: "better_supabase.webhook.endpoint_id"
|
|
17
|
+
};
|
|
18
|
+
/** The `KIT_ATTRIBUTES` an event carries. */
|
|
19
|
+
function kitEventAttributes(event) {
|
|
20
|
+
const attributes = { [KIT_ATTRIBUTES.event]: event.type };
|
|
21
|
+
if (event.tenant) attributes[KIT_ATTRIBUTES.tenant] = event.tenant;
|
|
22
|
+
if (event.actorId) attributes[KIT_ATTRIBUTES.actor] = event.actorId;
|
|
23
|
+
const data = Object.fromEntries(Object.entries(event.data));
|
|
24
|
+
const add = (key, value) => {
|
|
25
|
+
if (typeof value === "string" && value.length > 0) attributes[key] = value;
|
|
26
|
+
};
|
|
27
|
+
add(KIT_ATTRIBUTES.supportSessionId, data["sessionId"]);
|
|
28
|
+
add(KIT_ATTRIBUTES.orgId, data["organizationId"]);
|
|
29
|
+
add(KIT_ATTRIBUTES.invitationId, data["invitationId"]);
|
|
30
|
+
add(KIT_ATTRIBUTES.notificationType, data["type"]);
|
|
31
|
+
add(KIT_ATTRIBUTES.webhookEndpointId, data["endpointId"]);
|
|
32
|
+
return attributes;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Emits a kit event on `events` with a copy of `data`. Does nothing without
|
|
36
|
+
* a `kit` handler, so kits call it unconditionally.
|
|
37
|
+
*/
|
|
38
|
+
function emitKitEvent(events, type, data, meta = {}) {
|
|
39
|
+
if (!events.has("kit")) return;
|
|
40
|
+
const event = {
|
|
41
|
+
...meta,
|
|
42
|
+
type,
|
|
43
|
+
data: cloneValue(data),
|
|
44
|
+
time: nowInstant()
|
|
45
|
+
};
|
|
46
|
+
events.emit("kit", event);
|
|
47
|
+
}
|
|
48
|
+
const matches = (pattern, type) => pattern.endsWith(".*") ? type.startsWith(pattern.slice(0, -1)) : pattern === type;
|
|
49
|
+
/**
|
|
50
|
+
* Listens to the kit events that match `pattern` (`'support.started'` or
|
|
51
|
+
* `'support.*'`). Returns a function that stops listening.
|
|
52
|
+
*/
|
|
53
|
+
function onKitEvent(betterSupabase, pattern, handler) {
|
|
54
|
+
return betterSupabase.events.on("kit", (event) => {
|
|
55
|
+
if (!matches(pattern, event.type)) return;
|
|
56
|
+
handler(event);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
export { onKitEvent as i, emitKitEvent as n, kitEventAttributes as r, KIT_ATTRIBUTES as t };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { t as SqlClient } from "./executor-Cghdstwu.js";
|
|
2
|
+
//#region src/core/kit-transport.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Calls a kit function as the current user and resolves with its result.
|
|
5
|
+
* Rejects with the raw database error (a `pg` error or a PostgREST error
|
|
6
|
+
* object), which the kit maps to a `DbError`.
|
|
7
|
+
*/
|
|
8
|
+
interface KitTransport {
|
|
9
|
+
call(schema: string, fn: string, args: Readonly<Record<string, unknown>>): Promise<unknown>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Calls the functions over Postgres, as the user `client` runs as:
|
|
13
|
+
* `sqlTransport(postgres.asUser(ctx.auth.claims))`. Works for any schema.
|
|
14
|
+
*/
|
|
15
|
+
declare function sqlTransport(client: SqlClient): KitTransport;
|
|
16
|
+
interface RpcResponse {
|
|
17
|
+
readonly data: unknown;
|
|
18
|
+
readonly error: unknown;
|
|
19
|
+
}
|
|
20
|
+
/** The part of a supabase-js client `rpcTransport` uses. */
|
|
21
|
+
interface RpcClient {
|
|
22
|
+
schema(name: string): {
|
|
23
|
+
rpc(fn: string, args: Record<string, unknown>): PromiseLike<RpcResponse>;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Calls the functions over the Data API with the user's session. The kit
|
|
28
|
+
* schema must be exposed (`[api] schemas` in `config.toml`), or the modules
|
|
29
|
+
* installed in `public` (`kits.<module>.schema`).
|
|
30
|
+
*/
|
|
31
|
+
declare function rpcTransport(client: RpcClient): KitTransport;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { sqlTransport as i, RpcClient as n, rpcTransport as r, KitTransport as t };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { r as sqlIdent } from "./template-TxrGI5jR.js";
|
|
2
|
+
//#region src/core/kit-transport.ts
|
|
3
|
+
/**
|
|
4
|
+
* Calls the functions over Postgres, as the user `client` runs as:
|
|
5
|
+
* `sqlTransport(postgres.asUser(ctx.auth.claims))`. Works for any schema.
|
|
6
|
+
*/
|
|
7
|
+
function sqlTransport(client) {
|
|
8
|
+
return { async call(schema, fn, args) {
|
|
9
|
+
const entries = Object.entries(args).filter(([, value]) => value !== void 0);
|
|
10
|
+
const params = entries.map(([, value]) => value !== null && typeof value === "object" && !Array.isArray(value) ? JSON.stringify(value) : value);
|
|
11
|
+
const list = entries.map(([name], index) => `${sqlIdent(name)} => $${String(index + 1)}`).join(", ");
|
|
12
|
+
const [row] = await client.queryRaw(`select ${sqlIdent(schema)}.${sqlIdent(fn)}(${list}) as value`, params);
|
|
13
|
+
return row?.value ?? null;
|
|
14
|
+
} };
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Calls the functions over the Data API with the user's session. The kit
|
|
18
|
+
* schema must be exposed (`[api] schemas` in `config.toml`), or the modules
|
|
19
|
+
* installed in `public` (`kits.<module>.schema`).
|
|
20
|
+
*/
|
|
21
|
+
function rpcTransport(client) {
|
|
22
|
+
return { async call(schema, fn, args) {
|
|
23
|
+
const defined = Object.fromEntries(Object.entries(args).filter(([, value]) => value !== void 0));
|
|
24
|
+
const { data, error } = await client.schema(schema).rpc(fn, defined);
|
|
25
|
+
if (error) {
|
|
26
|
+
const message = typeof error === "object" && "message" in error ? String(error.message) : String(error);
|
|
27
|
+
throw Object.assign(new Error(message), error);
|
|
28
|
+
}
|
|
29
|
+
return data;
|
|
30
|
+
} };
|
|
31
|
+
}
|
|
32
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33
|
+
/** The Postgres or PostgREST error a transport rejected with, if it is one. */
|
|
34
|
+
function rawError(cause) {
|
|
35
|
+
if (!isRecord(cause)) return void 0;
|
|
36
|
+
const field = (key) => {
|
|
37
|
+
const value = cause[key];
|
|
38
|
+
return typeof value === "string" ? value : void 0;
|
|
39
|
+
};
|
|
40
|
+
if (field("code") === void 0) return void 0;
|
|
41
|
+
const raw = {};
|
|
42
|
+
for (const key of [
|
|
43
|
+
"message",
|
|
44
|
+
"code",
|
|
45
|
+
"details",
|
|
46
|
+
"hint",
|
|
47
|
+
"constraint"
|
|
48
|
+
]) {
|
|
49
|
+
const value = field(key);
|
|
50
|
+
if (value !== void 0) raw[key] = value;
|
|
51
|
+
}
|
|
52
|
+
return raw;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { rpcTransport as n, sqlTransport as r, rawError as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as DEFAULT_CLAIMS } from "./claims-
|
|
1
|
+
import { t as DEFAULT_CLAIMS } from "./claims-BAf6c7is.js";
|
|
2
2
|
//#region src/config/config.ts
|
|
3
3
|
/** The JSON Schema document for a `json[...].schema` entry. */
|
|
4
4
|
function resolveJsonSchema(source) {
|
|
@@ -9,14 +9,16 @@ function resolveJsonSchema(source) {
|
|
|
9
9
|
return jsonSchema.input({ target: "draft-2020-12" });
|
|
10
10
|
}
|
|
11
11
|
function entitlementsOf(config = {}) {
|
|
12
|
-
const customer = config.customer
|
|
13
|
-
const dot = customer
|
|
14
|
-
if (dot <= 0) throw new TypeError(`entitlements.customer must be "table.column", got "${customer}"`);
|
|
12
|
+
const customer = config.customer;
|
|
13
|
+
const dot = customer?.lastIndexOf(".") ?? -1;
|
|
14
|
+
if (customer !== void 0 && dot <= 0) throw new TypeError(`entitlements.customer must be "table.column", got "${customer}"`);
|
|
15
15
|
return {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
...customer === void 0 ? {} : {
|
|
17
|
+
table: customer.slice(0, dot),
|
|
18
|
+
column: customer.slice(dot + 1)
|
|
19
|
+
},
|
|
18
20
|
key: config.key ?? "id",
|
|
19
|
-
permdock: config.permdock === false ? false : { scope: config.permdock
|
|
21
|
+
permdock: config.permdock === false ? false : config.permdock?.scope === void 0 ? {} : { scope: config.permdock.scope }
|
|
20
22
|
};
|
|
21
23
|
}
|
|
22
24
|
function vectorSearchOf(config = {}) {
|
|
@@ -86,7 +88,8 @@ function resolveConfig(config, root) {
|
|
|
86
88
|
tenant: pick(config.plugins?.tenant, { column: "organization_id" }),
|
|
87
89
|
actor: pick(config.plugins?.actor, {
|
|
88
90
|
createdBy: "created_by",
|
|
89
|
-
updatedBy: "updated_by"
|
|
91
|
+
updatedBy: "updated_by",
|
|
92
|
+
impersonatedBy: "impersonated_by"
|
|
90
93
|
})
|
|
91
94
|
},
|
|
92
95
|
claims: {
|
|
@@ -95,7 +98,10 @@ function resolveConfig(config, root) {
|
|
|
95
98
|
},
|
|
96
99
|
buckets: config.buckets ?? {},
|
|
97
100
|
topics: config.topics ?? {},
|
|
98
|
-
realtime: {
|
|
101
|
+
realtime: {
|
|
102
|
+
tables: config.realtime?.tables ?? [],
|
|
103
|
+
global: config.realtime?.global ?? []
|
|
104
|
+
},
|
|
99
105
|
entitlements: entitlementsOf(config.entitlements),
|
|
100
106
|
permdock: {
|
|
101
107
|
manifest: config.permdock?.manifest ?? "permdock.manifest.json",
|
|
@@ -108,6 +114,7 @@ function resolveConfig(config, root) {
|
|
|
108
114
|
testsDir: config.sql?.testsDir ?? "supabase/tests",
|
|
109
115
|
kit: config.sql?.kit ?? []
|
|
110
116
|
},
|
|
117
|
+
kits: config.kits ?? {},
|
|
111
118
|
seed: {
|
|
112
119
|
entry: config.seed?.entry ?? "supabase/seed.ts",
|
|
113
120
|
output: config.seed?.output ?? "supabase/seeds/000_better_supabase.sql"
|
|
@@ -126,4 +133,25 @@ function resolveConfig(config, root) {
|
|
|
126
133
|
};
|
|
127
134
|
}
|
|
128
135
|
//#endregion
|
|
129
|
-
|
|
136
|
+
//#region src/config/kits.ts
|
|
137
|
+
/** URL tenancy: the tenant comes from the request (a slug), not a stored setting. */
|
|
138
|
+
const DEFAULT_ACTIVE_TENANT = "resolver";
|
|
139
|
+
const KIT_SCHEMA = "better_supabase";
|
|
140
|
+
function resolveKitModule(config = {}) {
|
|
141
|
+
return {
|
|
142
|
+
mode: config.mode ?? "managed",
|
|
143
|
+
schema: config.schema ?? KIT_SCHEMA,
|
|
144
|
+
tables: config.tables ?? {},
|
|
145
|
+
columns: config.columns ?? {},
|
|
146
|
+
...config.idType === void 0 ? {} : { idType: config.idType },
|
|
147
|
+
permissions: config.permissions ?? {},
|
|
148
|
+
options: config.options ?? {},
|
|
149
|
+
hooks: {
|
|
150
|
+
schema: config.hooks?.schema ?? "public",
|
|
151
|
+
functions: config.hooks?.functions ?? {}
|
|
152
|
+
},
|
|
153
|
+
events: config.events ?? true
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
export { resolveConfig as a, defineConfig as i, resolveKitModule as n, resolveJsonSchema as o, CONFIG_SCHEMA_URL as r, DEFAULT_ACTIVE_TENANT as t };
|
package/dist/list/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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-fag8VJZ2.js";
|
|
2
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
|
@@ -35,7 +35,7 @@ function toInt(raw) {
|
|
|
35
35
|
* OpenAPI parameters and a JSON Schema derived from the same definition.
|
|
36
36
|
*
|
|
37
37
|
* ```ts
|
|
38
|
-
* export const customerList = defineListQuery(
|
|
38
|
+
* export const customerList = defineListQuery(betterSupabase, 'customers', {
|
|
39
39
|
* search: ['name', 'kvk'],
|
|
40
40
|
* facets: { status: 'status' },
|
|
41
41
|
* sorts: { name: { name: 'asc' }, newest: [{ createdAt: 'desc' }, { id: 'asc' }] },
|
|
@@ -43,8 +43,8 @@ function toInt(raw) {
|
|
|
43
43
|
* });
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
|
-
function defineListQuery(
|
|
47
|
-
const meta =
|
|
46
|
+
function defineListQuery(betterSupabase, table, config) {
|
|
47
|
+
const meta = betterSupabase.meta.tables[table];
|
|
48
48
|
if (!meta) throw new TypeError(`defineListQuery: unknown table "${table}"`);
|
|
49
49
|
const pageSize = config.pageSize ?? 50;
|
|
50
50
|
const maxPageSize = config.maxPageSize ?? 200;
|
|
@@ -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 },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { Z as QuerySpec, t as BetterSupabase } from "./define-
|
|
4
|
-
import {
|
|
1
|
+
import { P as TableKey, S as PermdockTopicPolicy, j as SchemaMeta, k as Row, n as AnyFunctions, r as AnyModels } from "./types-Dnf_wRDz.js";
|
|
2
|
+
import { _ as DbError, a as AsyncResult, u as Result, w as ValidationIssue } from "./executor-BunPOO-k.js";
|
|
3
|
+
import { Z as QuerySpec, t as BetterSupabase } from "./define-Bp_BZa5h.js";
|
|
4
|
+
import { n as PermdockCatalog } from "./permdock-sql-C2Inc6Xc.js";
|
|
5
5
|
import { n as TemplateValues, t as TemplateParams } from "./template-mbvlysOo.js";
|
|
6
6
|
import { RealtimeChannel, SupabaseClient } from "@supabase/supabase-js";
|
|
7
7
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
@@ -41,7 +41,8 @@ interface TopicOptions<E extends EventSchemas> {
|
|
|
41
41
|
readonly permdock?: PermdockTopicPolicy;
|
|
42
42
|
/**
|
|
43
43
|
* PermDock's `permissions.catalog.json`. With it, a `permdock` policy
|
|
44
|
-
* naming a permission
|
|
44
|
+
* naming a permission without `rowConditions: false` (including one the
|
|
45
|
+
* catalog doesn't list) throws.
|
|
45
46
|
*/
|
|
46
47
|
readonly catalog?: PermdockCatalog;
|
|
47
48
|
/** Let clients broadcast on the topic, not only receive. Defaults to `false`. */
|
|
@@ -78,7 +79,7 @@ interface Subscription extends Disposable, AsyncDisposable {
|
|
|
78
79
|
readonly ready: Promise<void>;
|
|
79
80
|
unsubscribe(): Promise<void>;
|
|
80
81
|
}
|
|
81
|
-
type RealtimeClient = Pick<SupabaseClient, "channel" | "removeChannel" | "realtime">;
|
|
82
|
+
type RealtimeClient = Pick<SupabaseClient, "channel" | "getChannels" | "removeChannel" | "realtime">;
|
|
82
83
|
interface TriggerOptions<M extends AnyModels, T extends keyof M, P extends string> {
|
|
83
84
|
/** Column that fills each placeholder. */
|
|
84
85
|
readonly values: { readonly [K in TemplateParams<P>]: Extract<keyof Row<M, T>, string>; };
|
|
@@ -106,7 +107,7 @@ interface Topic<P extends string, E extends EventSchemas> {
|
|
|
106
107
|
/** `realtime.messages` policies for this topic. Idempotent. */
|
|
107
108
|
sql(): string;
|
|
108
109
|
/** 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>>(
|
|
110
|
+
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
111
|
subscribe(client: RealtimeClient, values: TemplateValues<P>, handlers: TopicHandlers<E>, options?: SubscribeOptions): Subscription;
|
|
111
112
|
/** Sends over HTTP, without joining the channel. */
|
|
112
113
|
send<K extends TopicEvent<E>>(client: RealtimeClient, values: TemplateValues<P>, event: K, payload: TopicPayload<E, K>): AsyncResult<void>;
|
|
@@ -127,10 +128,10 @@ declare function defineTopic<const P extends string, const E extends EventSchema
|
|
|
127
128
|
* Reads a `realtime.broadcast_changes` message as an app-cased row change.
|
|
128
129
|
* Returns `null` for messages about other tables.
|
|
129
130
|
*/
|
|
130
|
-
declare function rowChange<M extends AnyModels, D, F extends AnyFunctions, X, T extends TableKey<M>>(
|
|
131
|
+
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
132
|
//#endregion
|
|
132
133
|
//#region src/realtime/live.d.ts
|
|
133
|
-
/** What `liveQuery` needs from `
|
|
134
|
+
/** What `liveQuery` needs from `betterSupabase`: metadata and the tables a spec reads. */
|
|
134
135
|
interface LiveSource {
|
|
135
136
|
readonly meta: SchemaMeta;
|
|
136
137
|
tablesOf(spec: QuerySpec): string[];
|
|
@@ -154,7 +155,7 @@ interface LiveSubscription extends Disposable, AsyncDisposable {
|
|
|
154
155
|
}
|
|
155
156
|
/**
|
|
156
157
|
* A count from the server plus the spec to keep it live on the client:
|
|
157
|
-
* `
|
|
158
|
+
* `bs.liveCount(spec)` makes one, `useLiveCount(seed)` reads it. `count`
|
|
158
159
|
* is `null` when the server read failed; the client then fetches it.
|
|
159
160
|
*/
|
|
160
161
|
interface LiveCountSeed<T extends string = string> {
|
|
@@ -170,11 +171,11 @@ declare function liveTopic(meta: SchemaMeta, table: string, tenant?: string): st
|
|
|
170
171
|
* table, so any number of them can run at once.
|
|
171
172
|
*
|
|
172
173
|
* ```ts
|
|
173
|
-
* using live = liveQuery(
|
|
174
|
+
* using live = liveQuery(betterSupabase, supabase, spec, { onChange: () => refetch() });
|
|
174
175
|
* ```
|
|
175
176
|
*/
|
|
176
|
-
declare function liveQuery(
|
|
177
|
-
/** What `liveCount` runs the spec with: a `db` from `
|
|
177
|
+
declare function liveQuery(betterSupabase: LiveSource, client: RealtimeClient, spec: QuerySpec | readonly string[], options: LiveQueryOptions): LiveSubscription;
|
|
178
|
+
/** What `liveCount` runs the spec with: a `db` from `betterSupabase.connect()` or `createClient()`. */
|
|
178
179
|
interface CountRunner {
|
|
179
180
|
$run(spec: QuerySpec): PromiseLike<Result<unknown>>;
|
|
180
181
|
}
|
|
@@ -191,11 +192,11 @@ interface LiveCountOptions extends Omit<LiveQueryOptions, "onChange"> {
|
|
|
191
192
|
* Responses that arrive out of order are dropped.
|
|
192
193
|
*
|
|
193
194
|
* ```ts
|
|
194
|
-
* using live = liveCount(
|
|
195
|
+
* using live = liveCount(betterSupabase, supabase, db, betterSupabase.spec.notes.count(), {
|
|
195
196
|
* onCount: (count) => render(count),
|
|
196
197
|
* });
|
|
197
198
|
* ```
|
|
198
199
|
*/
|
|
199
|
-
declare function liveCount(
|
|
200
|
+
declare function liveCount(betterSupabase: LiveSource, client: RealtimeClient, db: CountRunner, spec: QuerySpec<string, "count", number>, options: LiveCountOptions): LiveSubscription;
|
|
200
201
|
//#endregion
|
|
201
202
|
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 };
|
|
@@ -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,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as BetterSupabase } from "../define-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { P as TableKey, n as AnyFunctions, r as AnyModels } from "../types-Dnf_wRDz.js";
|
|
2
|
+
import { t as BetterSupabase } from "../define-Bp_BZa5h.js";
|
|
3
|
+
import { f as ServerContext, n as GuardOptions, p as ServerOptions, u as BetterServer } from "../respond-D2OQl62-.js";
|
|
4
|
+
import { i as ResourceOperation } from "../index-C7f8cOBM.js";
|
|
5
|
+
import { a as ResourceRouteOptions } from "../resource-D8iqWMr-.js";
|
|
5
6
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
6
7
|
//#region src/mcp/mcp.d.ts
|
|
7
8
|
export declare const MCP_PROTOCOL_VERSION: string;
|
|
@@ -23,22 +24,22 @@ interface ToolInfo {
|
|
|
23
24
|
readonly outputSchema?: Json;
|
|
24
25
|
readonly annotations?: ToolAnnotations;
|
|
25
26
|
}
|
|
26
|
-
interface ToolContext<M extends AnyModels, F extends AnyFunctions, E> extends ServerContext<M, F, E> {
|
|
27
|
+
interface ToolContext<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> extends ServerContext<M, F, E, C, P> {
|
|
27
28
|
readonly request: Request;
|
|
28
29
|
readonly signal: AbortSignal;
|
|
29
30
|
}
|
|
30
|
-
interface McpTool<M extends AnyModels, F extends AnyFunctions, E> {
|
|
31
|
+
interface McpTool<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> {
|
|
31
32
|
readonly info: ToolInfo;
|
|
32
33
|
/** Validates arguments; its output is what `run` receives. */
|
|
33
34
|
readonly input?: StandardSchemaV1;
|
|
34
35
|
/** Opaque data for the `authorize` and `visible` hooks. Never sent to clients. */
|
|
35
36
|
readonly meta?: unknown;
|
|
36
|
-
run(args: never, ctx: ToolContext<M, F, E>): unknown;
|
|
37
|
+
run(args: never, ctx: ToolContext<M, F, E, C, P>): unknown;
|
|
37
38
|
}
|
|
38
39
|
/** What the `authorize` and `visible` hooks see of a tool. */
|
|
39
40
|
interface ToolRef {
|
|
40
41
|
readonly info: ToolInfo;
|
|
41
|
-
/** The tool's `meta`, e.g. a PermDock permission. `
|
|
42
|
+
/** The tool's `meta`, e.g. a PermDock permission. For table tools, the resource's `meta` for that operation. */
|
|
42
43
|
readonly meta: unknown;
|
|
43
44
|
}
|
|
44
45
|
/** The outcome of `authorize`. `scopes` turns a refusal into an OAuth challenge. */
|
|
@@ -50,7 +51,7 @@ type ToolDecision = {
|
|
|
50
51
|
/** OAuth scopes the call needs, sent in an `insufficient_scope` challenge. */
|
|
51
52
|
readonly scopes?: readonly string[];
|
|
52
53
|
};
|
|
53
|
-
interface ToolDefinition<M extends AnyModels, F extends AnyFunctions, E, I> {
|
|
54
|
+
interface ToolDefinition<M extends AnyModels, F extends AnyFunctions, E, I, C = unknown, P = unknown> {
|
|
54
55
|
readonly name: string;
|
|
55
56
|
readonly title?: string;
|
|
56
57
|
readonly description: string;
|
|
@@ -64,10 +65,19 @@ interface ToolDefinition<M extends AnyModels, F extends AnyFunctions, E, I> {
|
|
|
64
65
|
readonly annotations?: ToolAnnotations;
|
|
65
66
|
/** Opaque data for the `authorize` and `visible` hooks. Never sent to clients. */
|
|
66
67
|
readonly meta?: unknown;
|
|
67
|
-
run(args: I, ctx: ToolContext<M, F, E>): unknown;
|
|
68
|
+
run(args: I, ctx: ToolContext<M, F, E, C, P>): unknown;
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
/** A table's tools: the REST resource options, plus `meta` per operation for `authorize` and `visible`. */
|
|
71
|
+
type ToolResourceOptions<M extends AnyModels, T extends TableKey<M>> = ResourceRouteOptions<M, T> & {
|
|
72
|
+
/**
|
|
73
|
+
* Opaque data per operation, e.g. a PermDock permission, passed to
|
|
74
|
+
* `authorize` and `visible` as the table tool's `meta`. Never sent to
|
|
75
|
+
* clients. An operation without an entry gets `undefined`.
|
|
76
|
+
*/
|
|
77
|
+
readonly meta?: { readonly [K in ResourceOperation]?: unknown; };
|
|
78
|
+
};
|
|
79
|
+
type ToolResources<M extends AnyModels> = { readonly [T in TableKey<M>]?: ToolResourceOptions<M, T> | true; };
|
|
80
|
+
interface McpOptions<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> extends ServerOptions, Omit<GuardOptions, "scopes"> {
|
|
71
81
|
readonly name: string;
|
|
72
82
|
readonly version: string;
|
|
73
83
|
readonly title?: string;
|
|
@@ -75,7 +85,7 @@ interface McpOptions<M extends AnyModels, F extends AnyFunctions, E> extends Ser
|
|
|
75
85
|
readonly instructions?: string;
|
|
76
86
|
/** Tables exposed as tools: `<table>_list`, `_get`, `_create`, `_update`, `_delete`. */
|
|
77
87
|
readonly resources?: ToolResources<M>;
|
|
78
|
-
readonly tools?: readonly McpTool<M, F, E>[];
|
|
88
|
+
readonly tools?: readonly McpTool<M, F, E, C, P>[];
|
|
79
89
|
/**
|
|
80
90
|
* Canonical URL of this MCP server (RFC 9728 `resource`). Defaults to the
|
|
81
91
|
* request URL without query.
|
|
@@ -88,7 +98,14 @@ interface McpOptions<M extends AnyModels, F extends AnyFunctions, E> extends Ser
|
|
|
88
98
|
* `insufficient_scope` challenges. `offline_access` is left out: refresh
|
|
89
99
|
* tokens are between the client and the authorization server.
|
|
90
100
|
*/
|
|
101
|
+
readonly advertisedScopes?: readonly string[];
|
|
102
|
+
/** @deprecated Use `advertisedScopes`; `requiredScopes` is what `guard` enforces. */
|
|
91
103
|
readonly scopes?: readonly string[];
|
|
104
|
+
/**
|
|
105
|
+
* Scopes a delegated token (an OAuth client or an `act` chain) needs to call
|
|
106
|
+
* the server at all. A missing one answers 403 `insufficient_scope`.
|
|
107
|
+
*/
|
|
108
|
+
readonly requiredScopes?: readonly string[];
|
|
92
109
|
/** Origins allowed to call the server (DNS rebinding protection). Defaults to any. */
|
|
93
110
|
readonly allowedOrigins?: readonly string[];
|
|
94
111
|
/**
|
|
@@ -108,25 +125,25 @@ interface McpOptions<M extends AnyModels, F extends AnyFunctions, E> extends Ser
|
|
|
108
125
|
* validate in the repository). A refusal is a tool error; a refusal with
|
|
109
126
|
* `scopes` is a 403 `insufficient_scope` challenge naming them.
|
|
110
127
|
*/
|
|
111
|
-
readonly authorize?: (ctx: ToolContext<M, F, E>, tool: ToolRef, args: unknown) => ToolDecision | Promise<ToolDecision>;
|
|
128
|
+
readonly authorize?: (ctx: ToolContext<M, F, E, C, P>, tool: ToolRef, args: unknown) => ToolDecision | Promise<ToolDecision>;
|
|
112
129
|
/**
|
|
113
130
|
* Whether the caller sees a tool in `tools/list`. A hidden tool is called
|
|
114
131
|
* like an unknown one. Lists are cached per token (`cacheScope: 'private'`).
|
|
115
132
|
*/
|
|
116
|
-
readonly visible?: (ctx: ToolContext<M, F, E>, tool: ToolRef) => boolean | Promise<boolean>;
|
|
133
|
+
readonly visible?: (ctx: ToolContext<M, F, E, C, P>, tool: ToolRef) => boolean | Promise<boolean>;
|
|
117
134
|
}
|
|
118
|
-
interface BetterMcp<M extends AnyModels, F extends AnyFunctions, E> extends BetterServer<M, F, E> {
|
|
135
|
+
interface BetterMcp<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> extends BetterServer<M, F, E, C, P> {
|
|
119
136
|
/** Everything in one handler: the MCP endpoint and `/.well-known/oauth-protected-resource`. */
|
|
120
137
|
readonly fetch: (request: Request) => Promise<Response>;
|
|
121
138
|
/** The Streamable HTTP endpoint (POST JSON-RPC). */
|
|
122
|
-
readonly
|
|
139
|
+
readonly endpoint: (request: Request) => Promise<Response>;
|
|
123
140
|
/** RFC 9728 protected resource metadata. */
|
|
124
141
|
metadata(request: Request): Response;
|
|
125
142
|
readonly tools: readonly ToolInfo[];
|
|
126
143
|
/** Adds a tool typed against this app's repositories. */
|
|
127
|
-
tool<I = Record<string, unknown>>(definition: ToolDefinition<M, F, E, I>): this;
|
|
144
|
+
tool<I = Record<string, unknown>>(definition: ToolDefinition<M, F, E, I, C, P>): this;
|
|
128
145
|
/** Calls a tool directly, e.g. from tests or another transport. */
|
|
129
|
-
call(name: string, args: unknown, ctx: ToolContext<M, F, E>): Promise<ToolResult>;
|
|
146
|
+
call(name: string, args: unknown, ctx: ToolContext<M, F, E, C, P>): Promise<ToolResult>;
|
|
130
147
|
}
|
|
131
148
|
interface ToolResult {
|
|
132
149
|
readonly content: readonly {
|
|
@@ -137,13 +154,13 @@ interface ToolResult {
|
|
|
137
154
|
readonly isError?: boolean;
|
|
138
155
|
}
|
|
139
156
|
/** A custom tool. Pass it in `createMcp({ tools: [...] })`. */
|
|
140
|
-
export declare function defineTool<M extends AnyModels, F extends AnyFunctions, E, I = Record<string, unknown
|
|
157
|
+
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
158
|
/**
|
|
142
159
|
* An MCP server (Streamable HTTP, stateless) whose tools run as the caller:
|
|
143
160
|
* the Bearer token from the MCP client is verified and every query goes
|
|
144
161
|
* through RLS. Answers 401 with RFC 9728 metadata so clients can sign in with
|
|
145
162
|
* Supabase Auth's OAuth server.
|
|
146
163
|
*/
|
|
147
|
-
export declare function createMcp<M extends AnyModels, D, F extends AnyFunctions, E>(
|
|
164
|
+
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
165
|
//#endregion
|
|
149
|
-
export type { BetterMcp, GuardOptions, McpOptions, McpTool, ResourceRouteOptions, ToolAnnotations, ToolContext, ToolDecision, ToolDefinition, ToolInfo, ToolRef, ToolResources, ToolResult };
|
|
166
|
+
export type { BetterMcp, GuardOptions, McpOptions, McpTool, ResourceRouteOptions, ToolAnnotations, ToolContext, ToolDecision, ToolDefinition, ToolInfo, ToolRef, ToolResourceOptions, ToolResources, ToolResult };
|