better-supabase 0.2.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 +37 -33
- package/dist/base64-D2gsioCY.js +42 -0
- package/dist/claims-BAf6c7is.js +48 -0
- package/dist/cli/_format-Cax5EsM9.js +101 -0
- package/dist/cli/bin.js +39 -6
- 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 +295 -28
- package/dist/cli/index.js +184 -3
- 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/{version-Cqq1m3UY.js → cli/version-5mW_8sY1.js} +1 -1
- package/dist/cli/yaml-CYCbJ6et.js +2252 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +15 -25
- package/dist/{compiler-CZ9nIuqy.d.ts → compiler-DB3aSFOA.d.ts} +2 -2
- package/dist/config/index.d.ts +4 -3
- package/dist/config/index.js +5 -3
- package/dist/config-BpxDfnbg.js +129 -0
- package/dist/{index-DOsjFvMf.d.ts → config-C1CYcm6o.d.ts} +49 -49
- package/dist/{config-ClDXmVtY.js → config-CbvFmGD8.js} +14 -137
- package/dist/{define-BXMYD9AY.js → define-Bh0AqTik.js} +221 -120
- package/dist/{define-e3zI4_4g.d.ts → define-CRS2MRV3.d.ts} +36 -31
- package/dist/edge/index.d.ts +9 -13
- package/dist/edge/index.js +51 -25
- package/dist/{entitlements-Dng-ctuT.d.ts → entitlements-Dm-FHpNH.d.ts} +2 -2
- package/dist/env/index.js +203 -1
- package/dist/{errors-Bl3rkOzo.js → errors-L0xK41y_.js} +1 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.js +139 -1
- package/dist/{events-DOt3nSO-.d.ts → events-B21UOhvP.d.ts} +4 -4
- package/dist/{executor-CGdNQ27g.d.ts → executor-B5IoUxLE.d.ts} +2 -2
- package/dist/{executor-DeppvirK.js → executor-CVt6dD0B.js} +9 -4
- package/dist/{executor-BYXQ9AGn.d.ts → executor-CZ7ImRiD.d.ts} +2 -2
- package/dist/hono/index.d.ts +17 -24
- package/dist/hono/index.js +11 -11
- package/dist/{index-DuP14VHo.d.ts → index-528Ugmyp.d.ts} +30 -10
- package/dist/{index-Bw1bwtC0.d.ts → index-BAy4tsAP.d.ts} +28 -15
- package/dist/{index-CBDufH1M.d.ts → index-BBdvo-5d.d.ts} +24 -26
- package/dist/{index-DbxFr7XG.d.ts → index-BhHEC04r.d.ts} +9 -4
- package/dist/index-Cf-D2jk1.d.ts +50 -0
- package/dist/{index-Ciu5Xlml.d.ts → index-D5IfUIDh.d.ts} +6 -5
- package/dist/{index-K-3WM2Hp.d.ts → index-DFmOpBGC.d.ts} +13 -13
- package/dist/{index-D4v7sncu.d.ts → index-RlLXd8dL.d.ts} +13 -13
- package/dist/index.d.ts +17 -17
- package/dist/index.js +23 -14
- package/dist/{invalidate-DbxuL2jL.js → invalidate-CgxmRamI.js} +7 -1
- package/dist/jobs/index.d.ts +33 -26
- package/dist/jobs/index.js +44 -22
- package/dist/{json-schema-BpYqkCKf.js → json-schema-DP6V7cbr.js} +8 -3
- package/dist/lint/index.js +1 -1
- package/dist/list/index.d.ts +2 -2
- package/dist/list/index.js +131 -96
- package/dist/{live-DJyZMD6w.d.ts → live-BHakSWWo.d.ts} +26 -16
- package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
- package/dist/lookup-BaP5bI27.js +18 -0
- package/dist/mcp/index.d.ts +34 -27
- package/dist/mcp/index.js +59 -25
- package/dist/{mfa-TVia554c.d.ts → mfa-C7MNQ1Ob.d.ts} +1 -1
- package/dist/{mfa-CpLfJSde.js → mfa-byfjruR9.js} +190 -46
- package/dist/next/image/index.js +6 -3
- package/dist/next/index.d.ts +64 -48
- package/dist/next/index.js +63 -50
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +61 -38
- package/dist/orpc/index.d.ts +18 -21
- package/dist/orpc/index.js +12 -12
- package/dist/otel/index.d.ts +5 -5
- package/dist/otel/index.js +84 -63
- package/dist/{permdock-sql-CghlHPuH.js → permdock-sql-C4KFzLc9.js} +12 -7
- package/dist/permdock-sql-DImJULY-.d.ts +17 -0
- package/dist/{plugin-C4TR9J0Z.d.ts → plugin-bNhvJwRh.d.ts} +5 -4
- 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 +46 -16
- package/dist/plugins/soft-delete/index.d.ts +3 -3
- package/dist/plugins/soft-delete/index.js +4 -4
- package/dist/plugins/tenant/index.d.ts +3 -3
- package/dist/plugins/tenant/index.js +10 -4
- package/dist/plugins/timestamps/index.d.ts +1 -1
- package/dist/plugins/timestamps/index.js +2 -2
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/plugins/validation/index.js +3 -3
- package/dist/pool-DFwEQwmN.d.ts +78 -0
- package/dist/postgres/index.d.ts +10 -5
- package/dist/postgres/index.js +37 -16
- package/dist/{postgrest-cAEQ_IQN.d.ts → postgrest-Bc-0Xw62.d.ts} +1 -1
- package/dist/{problem-BTkTtRV9.js → problem-BihjPR0t.js} +11 -5
- package/dist/{problem-DlgB0lYl.d.ts → problem-U8UEKccv.d.ts} +6 -4
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +2 -2
- package/dist/{query-ChvDbsDE.js → query-BMMSWbI7.js} +19 -19
- package/dist/react/index.d.ts +7 -7
- package/dist/react/index.js +2 -2
- package/dist/react/server.d.ts +6 -6
- package/dist/react/server.js +3 -3
- package/dist/react/session.d.ts +21 -2
- package/dist/react/session.js +19 -1
- package/dist/{react-C83BdBGt.js → react-CQHMaESR.js} +59 -55
- package/dist/{read-set-4lI3W_gZ.js → read-set-FWK8qQ58.js} +51 -16
- package/dist/realtime/index.d.ts +4 -3
- package/dist/realtime/index.js +19 -17
- package/dist/{index-CG69s15v.d.ts → refresh-BwYkyNOQ.d.ts} +7 -3
- package/dist/{resolve-CjHILk2w.d.ts → resolve-BAqQcwMW.d.ts} +17 -11
- package/dist/{resource-CgZa3YG_.d.ts → resource-BJcaIfxi.d.ts} +17 -8
- package/dist/{resource-BHEWmQJK.js → resource-My_y-Syh.js} +43 -21
- package/dist/{respond-Dne1ARSa.d.ts → respond-DgIbdrt8.d.ts} +39 -14
- package/dist/{result-DWXatkd6.js → result-Bj6yt33D.js} +2 -2
- package/dist/{result-CTkCZ6JA.d.ts → result-CqEsbgYs.d.ts} +16 -11
- package/dist/server/index.d.ts +38 -13
- package/dist/server/index.js +43 -14
- package/dist/{respond-DMcbQwfN.js → server-BA75B0mT.js} +151 -96
- package/dist/{shared-_6-uPL7E.js → shared-DnoCdMDr.js} +4 -3
- package/dist/{simplify-bwJpLnaS.js → simplify-Cqvfr9dj.js} +76 -39
- package/dist/sql/index.d.ts +139 -0
- package/dist/sql/index.js +1983 -0
- package/dist/{sql-DTjA1LPj.js → sql-B34HU2DI.js} +74 -17
- 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-CyhRzctb.d.ts → standard-BsaCYQJc.d.ts} +1 -1
- package/dist/{stats-C5W-rBfR.js → stats-C_YxA2r1.js} +40 -14
- package/dist/storage/index.d.ts +4 -3
- package/dist/storage/index.js +548 -1
- package/dist/{tables-rZxRxNPW.js → tables-Cb-3_VWc.js} +19 -5
- package/dist/temporal-BwshQk0W.js +27 -0
- package/dist/temporal-required-CBNHT6ni.js +19 -0
- package/dist/testing/index.d.ts +25 -24
- package/dist/testing/index.js +165 -66
- package/dist/{types-C83v5SQz.d.ts → types-DONv9SHN.d.ts} +14 -11
- package/dist/version-Bmf7_FzM.js +4 -0
- package/dist/{view-D1s0wa0T.d.ts → view-B64o81wp.d.ts} +36 -6
- package/dist/{view-aOYizTeE.js → view-BrJI2LKp.js} +11 -2
- package/dist/webhooks/index.d.ts +19 -17
- package/dist/webhooks/index.js +1 -1
- package/dist/{webhooks-DMipjhSP.js → webhooks-Bh_Jf_-l.js} +45 -24
- package/package.json +50 -22
- package/schemas/config-v1.json +31 -1
- package/schemas/doctor-report-v1.json +17 -1
- package/schemas/snapshot-v2.json +35 -0
- package/skills/better-supabase/SKILL.md +77 -18
- package/skills/better-supabase/references/plugins.md +21 -22
- package/skills/better-supabase/references/troubleshooting.md +38 -18
- package/skills/better-supabase-api/SKILL.md +66 -18
- package/skills/better-supabase-api/references/adapters.md +64 -41
- 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 +68 -11
- package/dist/casing-da0uRTqt.js +0 -14
- package/dist/claims-CoTobNC-.js +0 -25
- package/dist/cli-DrSgDOQC.js +0 -6646
- package/dist/env-BEToab0I.js +0 -204
- package/dist/events-BuzTgn2D.js +0 -135
- package/dist/pool-R2m_DkXi.d.ts +0 -37
- package/dist/seed-CzecODcJ.js +0 -101
- package/dist/session-C3LxnQ0e.d.ts +0 -22
- package/dist/session-CqEwzVup.js +0 -20
- package/dist/storage-DuGn38fr.js +0 -527
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "./claims-
|
|
2
|
-
import { t as invalidateTables } from "./invalidate-
|
|
3
|
-
import { n as liveQuery, t as liveCount } from "./live-
|
|
4
|
-
import {
|
|
1
|
+
import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "./claims-BAf6c7is.js";
|
|
2
|
+
import { t as invalidateTables } from "./invalidate-CgxmRamI.js";
|
|
3
|
+
import { n as liveQuery, t as liveCount } from "./live-CdJBOc4f.js";
|
|
4
|
+
import { useSession } from "./react/session.js";
|
|
5
5
|
import { createContext, createElement, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
6
|
-
//#region src/react/
|
|
7
|
-
const
|
|
6
|
+
//#region src/react/hooks.ts
|
|
7
|
+
const ClientContext = createContext(null);
|
|
8
8
|
const LOADING = {
|
|
9
9
|
status: "loading",
|
|
10
10
|
user: null,
|
|
11
11
|
claims: null
|
|
12
12
|
};
|
|
13
|
-
/** Provides the
|
|
13
|
+
/** Provides the better-supabase client to the hooks. */
|
|
14
14
|
function BetterSupabaseProvider(props) {
|
|
15
|
-
const {
|
|
15
|
+
const { client, queryClient } = props;
|
|
16
16
|
const user = useRef(void 0);
|
|
17
|
-
useEffect(() =>
|
|
18
|
-
const snapshot =
|
|
17
|
+
useEffect(() => client.auth.subscribe(() => {
|
|
18
|
+
const snapshot = client.auth.current();
|
|
19
19
|
if (snapshot.status === "loading") return;
|
|
20
20
|
const id = snapshot.user?.id ?? null;
|
|
21
21
|
if (user.current !== void 0 && user.current !== id) queryClient?.removeQueries({ queryKey: ["bs"] });
|
|
22
22
|
user.current = id;
|
|
23
|
-
}), [
|
|
23
|
+
}), [client, queryClient]);
|
|
24
24
|
const value = useMemo(() => ({
|
|
25
|
-
|
|
25
|
+
client,
|
|
26
26
|
queryClient
|
|
27
|
-
}), [
|
|
28
|
-
return createElement(
|
|
27
|
+
}), [client, queryClient]);
|
|
28
|
+
return createElement(ClientContext.Provider, { value }, props.children);
|
|
29
29
|
}
|
|
30
|
-
function
|
|
31
|
-
const value = useContext(
|
|
32
|
-
if (!value) throw new Error("better-supabase: wrap your app in <BetterSupabaseProvider
|
|
30
|
+
function useClientContext() {
|
|
31
|
+
const value = useContext(ClientContext);
|
|
32
|
+
if (!value) throw new Error("better-supabase: wrap your app in <BetterSupabaseProvider client={bs}>");
|
|
33
33
|
return value;
|
|
34
34
|
}
|
|
35
|
-
function
|
|
36
|
-
return
|
|
35
|
+
function useClient() {
|
|
36
|
+
return useClientContext().client;
|
|
37
37
|
}
|
|
38
38
|
/** The session state for UI: `loading`, `signed-out` or `signed-in` with the user and claims. */
|
|
39
39
|
function useAuth() {
|
|
40
|
-
const
|
|
41
|
-
return useSyncExternalStore(
|
|
40
|
+
const client = useClient();
|
|
41
|
+
return useSyncExternalStore(client.auth.subscribe, client.auth.current, () => LOADING);
|
|
42
42
|
}
|
|
43
43
|
function useSupabase() {
|
|
44
|
-
return
|
|
44
|
+
return useClient().supabase;
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
47
|
* Hooks typed for your schema.
|
|
48
48
|
*
|
|
49
49
|
* ```ts
|
|
50
|
-
* export const { useDb, useQueries, useAuth } = createHooks<typeof
|
|
50
|
+
* export const { useDb, useQueries, useAuth } = createHooks<typeof bs>();
|
|
51
51
|
* ```
|
|
52
52
|
*/
|
|
53
53
|
function createHooks() {
|
|
54
54
|
return {
|
|
55
55
|
useDb() {
|
|
56
|
-
const
|
|
56
|
+
const client = useClient();
|
|
57
57
|
useAuth();
|
|
58
|
-
return
|
|
58
|
+
return client.db;
|
|
59
59
|
},
|
|
60
60
|
useQueries() {
|
|
61
|
-
const
|
|
61
|
+
const client = useClient();
|
|
62
62
|
useAuth();
|
|
63
|
-
return
|
|
63
|
+
return client.queries;
|
|
64
64
|
},
|
|
65
65
|
useSupabase,
|
|
66
66
|
useAuth,
|
|
@@ -76,7 +76,7 @@ function createHooks() {
|
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
78
|
function useBroadcast(topic, values, handlers, options) {
|
|
79
|
-
const {
|
|
79
|
+
const { client, queryClient } = useClientContext();
|
|
80
80
|
const auth = useAuth();
|
|
81
81
|
const [status, setStatus] = useState("closed");
|
|
82
82
|
const latest = useRef({
|
|
@@ -91,9 +91,9 @@ function useBroadcast(topic, values, handlers, options) {
|
|
|
91
91
|
const userId = auth.user?.id ?? null;
|
|
92
92
|
if (options?.invalidate && !queryClient) throw new Error("better-supabase: useBroadcast({ invalidate }) needs <BetterSupabaseProvider queryClient={...}>");
|
|
93
93
|
useEffect(() => {
|
|
94
|
-
if (!name || auth.status === "loading") return
|
|
94
|
+
if (!name || auth.status === "loading") return;
|
|
95
95
|
const matched = topic.match(name);
|
|
96
|
-
if (!matched) return
|
|
96
|
+
if (!matched) return;
|
|
97
97
|
const forward = (payload, message) => {
|
|
98
98
|
const current = latest.current;
|
|
99
99
|
const table = current.handlers;
|
|
@@ -106,7 +106,7 @@ function useBroadcast(topic, values, handlers, options) {
|
|
|
106
106
|
}
|
|
107
107
|
for (const queryKey of invalidate(message)) queryClient.invalidateQueries({ queryKey });
|
|
108
108
|
};
|
|
109
|
-
const subscription = topic.subscribe(
|
|
109
|
+
const subscription = topic.subscribe(client.supabase, matched, { "*": forward }, {
|
|
110
110
|
...latest.current.options?.self === void 0 ? {} : { self: latest.current.options.self },
|
|
111
111
|
onStatus: setStatus,
|
|
112
112
|
onInvalid: (message, issues) => latest.current.options?.onInvalid?.(message, issues)
|
|
@@ -116,7 +116,7 @@ function useBroadcast(topic, values, handlers, options) {
|
|
|
116
116
|
setStatus("closed");
|
|
117
117
|
};
|
|
118
118
|
}, [
|
|
119
|
-
|
|
119
|
+
client,
|
|
120
120
|
topic,
|
|
121
121
|
name,
|
|
122
122
|
userId,
|
|
@@ -138,23 +138,23 @@ function claimedTenant(auth, meta) {
|
|
|
138
138
|
* resubscribes when the spec, tenant or user changes.
|
|
139
139
|
*
|
|
140
140
|
* ```ts
|
|
141
|
-
* const spec =
|
|
141
|
+
* const spec = betterSupabase.spec.customers.findMany({ include: { notes: true } });
|
|
142
142
|
* const { data } = useQuery(q.$spec(spec));
|
|
143
143
|
* useLiveQuery(spec);
|
|
144
144
|
* ```
|
|
145
145
|
*/
|
|
146
146
|
function useLiveQuery(spec, options = {}) {
|
|
147
|
-
const {
|
|
147
|
+
const { client, queryClient } = useClientContext();
|
|
148
148
|
const auth = useAuth();
|
|
149
149
|
const [status, setStatus] = useState("closed");
|
|
150
150
|
if (spec && !queryClient) throw new Error("better-supabase: useLiveQuery needs <BetterSupabaseProvider queryClient={...}>");
|
|
151
151
|
const key = spec ? JSON.stringify(spec) : null;
|
|
152
|
-
const tenant = options.tenant ?? claimedTenant(auth,
|
|
152
|
+
const tenant = options.tenant ?? claimedTenant(auth, client.betterSupabase.meta);
|
|
153
153
|
const userId = auth.user?.id ?? null;
|
|
154
154
|
const debounceMs = options.debounceMs;
|
|
155
155
|
useEffect(() => {
|
|
156
|
-
if (!key || !queryClient || auth.status === "loading") return
|
|
157
|
-
const live = liveQuery(
|
|
156
|
+
if (!key || !queryClient || auth.status === "loading") return;
|
|
157
|
+
const live = liveQuery(client.betterSupabase, client.supabase, JSON.parse(key), {
|
|
158
158
|
onChange: (tables) => void invalidateTables(queryClient, tables),
|
|
159
159
|
onStatus: setStatus,
|
|
160
160
|
...tenant === void 0 ? {} : { tenant },
|
|
@@ -164,7 +164,7 @@ function useLiveQuery(spec, options = {}) {
|
|
|
164
164
|
live.unsubscribe();
|
|
165
165
|
};
|
|
166
166
|
}, [
|
|
167
|
-
|
|
167
|
+
client,
|
|
168
168
|
queryClient,
|
|
169
169
|
key,
|
|
170
170
|
tenant,
|
|
@@ -177,15 +177,15 @@ function useLiveQuery(spec, options = {}) {
|
|
|
177
177
|
/**
|
|
178
178
|
* A count that stays current: refetches only the `count` spec (a HEAD
|
|
179
179
|
* request) after each debounced change to a table it reads, and after the
|
|
180
|
-
* channel rejoins. Takes a spec or a `
|
|
180
|
+
* channel rejoins. Takes a spec or a `bs.liveCount()` seed; pass `null` to
|
|
181
181
|
* pause. Doesn't need a `QueryClient`.
|
|
182
182
|
*
|
|
183
183
|
* ```tsx
|
|
184
|
-
* const { count } = useLiveCount(seed); // seed = await
|
|
184
|
+
* const { count } = useLiveCount(seed); // seed = await bs.liveCount(spec)
|
|
185
185
|
* ```
|
|
186
186
|
*/
|
|
187
187
|
function useLiveCount(source, options = {}) {
|
|
188
|
-
const {
|
|
188
|
+
const { client } = useClientContext();
|
|
189
189
|
const auth = useAuth();
|
|
190
190
|
const seed = source && "spec" in source ? source : void 0;
|
|
191
191
|
const spec = seed ? seed.spec : source;
|
|
@@ -197,24 +197,28 @@ function useLiveCount(source, options = {}) {
|
|
|
197
197
|
});
|
|
198
198
|
const [status, setStatus] = useState("closed");
|
|
199
199
|
const key = spec ? JSON.stringify(spec) : null;
|
|
200
|
-
const tenant = options.tenant ?? claimedTenant(auth,
|
|
200
|
+
const tenant = options.tenant ?? claimedTenant(auth, client.betterSupabase.meta);
|
|
201
201
|
const userId = auth.user?.id ?? null;
|
|
202
202
|
const debounceMs = options.debounceMs;
|
|
203
203
|
const hasInitial = initial !== void 0;
|
|
204
204
|
useEffect(() => {
|
|
205
|
-
if (!key || auth.status === "loading") return
|
|
206
|
-
const live = liveCount(
|
|
205
|
+
if (!key || auth.status === "loading") return;
|
|
206
|
+
const live = liveCount(client.betterSupabase, client.supabase, client.db, JSON.parse(key), {
|
|
207
207
|
immediate: !hasInitial,
|
|
208
|
-
onCount: (count) =>
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
208
|
+
onCount: (count) => {
|
|
209
|
+
setState({
|
|
210
|
+
key,
|
|
211
|
+
count,
|
|
212
|
+
error: void 0
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
onError: (error) => {
|
|
216
|
+
setState((previous) => ({
|
|
217
|
+
key,
|
|
218
|
+
count: previous.key === key ? previous.count : void 0,
|
|
219
|
+
error
|
|
220
|
+
}));
|
|
221
|
+
},
|
|
218
222
|
onStatus: setStatus,
|
|
219
223
|
...tenant === void 0 ? {} : { tenant },
|
|
220
224
|
...debounceMs === void 0 ? {} : { debounceMs }
|
|
@@ -223,7 +227,7 @@ function useLiveCount(source, options = {}) {
|
|
|
223
227
|
live.unsubscribe();
|
|
224
228
|
};
|
|
225
229
|
}, [
|
|
226
|
-
|
|
230
|
+
client,
|
|
227
231
|
key,
|
|
228
232
|
tenant,
|
|
229
233
|
userId,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as
|
|
2
|
-
import { n as touchedTables } from "./tables-
|
|
1
|
+
import { r as builderFor, u as tableMeta } from "./simplify-Cqvfr9dj.js";
|
|
2
|
+
import { n as touchedTables } from "./tables-Cb-3_VWc.js";
|
|
3
3
|
//#region src/core/spec.ts
|
|
4
4
|
const READ_METHODS = [
|
|
5
5
|
"findMany",
|
|
@@ -40,7 +40,6 @@ function specOptions(spec) {
|
|
|
40
40
|
const value = spec.method === "findById" ? spec.args[1] : spec.args[0];
|
|
41
41
|
return typeof value === "object" && value !== null ? value : void 0;
|
|
42
42
|
}
|
|
43
|
-
const builders = /* @__PURE__ */ new WeakMap();
|
|
44
43
|
/**
|
|
45
44
|
* App keys of every table a spec reads: its table, included relations and
|
|
46
45
|
* relations used in `where`. Queries keyed by a spec go stale when any of
|
|
@@ -48,18 +47,54 @@ const builders = /* @__PURE__ */ new WeakMap();
|
|
|
48
47
|
* spec reports the error.
|
|
49
48
|
*/
|
|
50
49
|
function specTables(meta, spec) {
|
|
50
|
+
const table = meta.tables[spec.table];
|
|
51
|
+
const args = specOptions(spec);
|
|
52
|
+
if (table && args?.["include"] === void 0 && !touchesRelations(table, args?.["where"])) return [spec.table];
|
|
53
|
+
const key = specKey(spec);
|
|
54
|
+
let byKey = tablesByMeta.get(meta);
|
|
55
|
+
if (!byKey) {
|
|
56
|
+
byKey = /* @__PURE__ */ new Map();
|
|
57
|
+
tablesByMeta.set(meta, byKey);
|
|
58
|
+
}
|
|
59
|
+
const known = key === void 0 ? void 0 : byKey.get(key);
|
|
60
|
+
if (known) return [...known];
|
|
61
|
+
let tables;
|
|
51
62
|
try {
|
|
52
|
-
|
|
63
|
+
tables = readTables(meta, spec);
|
|
53
64
|
} catch {
|
|
54
|
-
|
|
65
|
+
tables = [spec.table];
|
|
66
|
+
}
|
|
67
|
+
if (key !== void 0) {
|
|
68
|
+
if (byKey.size >= SPEC_CACHE_SIZE) byKey.clear();
|
|
69
|
+
byKey.set(key, tables);
|
|
55
70
|
}
|
|
71
|
+
return [...tables];
|
|
56
72
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
const SPEC_CACHE_SIZE = 500;
|
|
74
|
+
const tablesByMeta = /* @__PURE__ */ new WeakMap();
|
|
75
|
+
/** A text key for the spec, or `undefined` when its arguments do not serialize. */
|
|
76
|
+
function specKey(spec) {
|
|
77
|
+
try {
|
|
78
|
+
return JSON.stringify([
|
|
79
|
+
spec.table,
|
|
80
|
+
spec.method,
|
|
81
|
+
spec.args
|
|
82
|
+
], (_key, value) => typeof value === "bigint" ? `${value}n` : value);
|
|
83
|
+
} catch {
|
|
84
|
+
return;
|
|
62
85
|
}
|
|
86
|
+
}
|
|
87
|
+
function touchesRelations(table, where) {
|
|
88
|
+
if (typeof where !== "object" || where === null) return false;
|
|
89
|
+
if (Array.isArray(where)) return where.some((item) => touchesRelations(table, item));
|
|
90
|
+
for (const [key, value] of Object.entries(where)) {
|
|
91
|
+
if (key in table.relations) return true;
|
|
92
|
+
if ((key === "AND" || key === "OR" || key === "NOT") && touchesRelations(table, value)) return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
function readTables(meta, spec) {
|
|
97
|
+
const builder = builderFor(meta);
|
|
63
98
|
const table = tableMeta(meta, spec.table);
|
|
64
99
|
const args = specOptions(spec);
|
|
65
100
|
const counts = spec.method === "count" || spec.method === "exists" || spec.method === "aggregate";
|
|
@@ -87,7 +122,7 @@ const TYPE = /^(?:[a-z_][a-z0-9_]*\.)?[a-z_][a-z0-9_]*(?:\[\])?$/;
|
|
|
87
122
|
/** `jsonb_build_object` takes at most 100 arguments. */
|
|
88
123
|
const MAX_ENTRIES = 50;
|
|
89
124
|
/** Placeholders are `NUL bs:<name> NUL`: no real parameter value holds a NUL. */
|
|
90
|
-
const NUL =
|
|
125
|
+
const NUL = "\0";
|
|
91
126
|
const SENTINEL = new RegExp(`${NUL}bs:([a-z_][a-z0-9_]*)${NUL}`, "gi");
|
|
92
127
|
const EXACT = new RegExp(`^${NUL}bs:([a-z_][a-z0-9_]*)${NUL}$`, "i");
|
|
93
128
|
function sentinel(name) {
|
|
@@ -98,7 +133,7 @@ function sentinel(name) {
|
|
|
98
133
|
*
|
|
99
134
|
* ```ts
|
|
100
135
|
* export const appChrome = defineReadSet(
|
|
101
|
-
*
|
|
136
|
+
* betterSupabase,
|
|
102
137
|
* 'app_chrome',
|
|
103
138
|
* { params: { userId: 'uuid' } },
|
|
104
139
|
* (s, p) => ({
|
|
@@ -111,7 +146,7 @@ function sentinel(name) {
|
|
|
111
146
|
* `p` holds placeholders, not values: pass them straight into `where` (or
|
|
112
147
|
* `in`), where the function reads them from its `p jsonb` argument.
|
|
113
148
|
*/
|
|
114
|
-
function defineReadSet(
|
|
149
|
+
function defineReadSet(betterSupabase, name, options, build) {
|
|
115
150
|
if (!NAME.test(name)) throw new TypeError(`better-supabase: read set name "${name}" must be snake_case and at most 60 characters`);
|
|
116
151
|
const params = options.params ?? {};
|
|
117
152
|
const placeholders = {};
|
|
@@ -120,10 +155,10 @@ function defineReadSet(sb, name, options, build) {
|
|
|
120
155
|
if (!TYPE.test(type)) throw new TypeError(`better-supabase: read set "${name}" parameter "${key}" has an invalid type "${type}"`);
|
|
121
156
|
placeholders[key] = type.endsWith("[]") ? [sentinel(key)] : sentinel(key);
|
|
122
157
|
}
|
|
123
|
-
const specs = build(
|
|
158
|
+
const specs = build(betterSupabase.spec, placeholders);
|
|
124
159
|
const entries = Object.entries(specs);
|
|
125
160
|
if (entries.length === 0 || entries.length > MAX_ENTRIES) throw new TypeError(`better-supabase: read set "${name}" needs between 1 and ${MAX_ENTRIES} reads`);
|
|
126
|
-
for (const [key, spec] of entries) if (!isQuerySpec(spec)) throw new TypeError(`better-supabase: read set "${name}" entry "${key}" is not a spec from
|
|
161
|
+
for (const [key, spec] of entries) if (!isQuerySpec(spec)) throw new TypeError(`better-supabase: read set "${name}" entry "${key}" is not a spec from betterSupabase.spec`);
|
|
127
162
|
return {
|
|
128
163
|
kind: "read-set",
|
|
129
164
|
name,
|
|
@@ -131,7 +166,7 @@ function defineReadSet(sb, name, options, build) {
|
|
|
131
166
|
params,
|
|
132
167
|
roles: options.roles ?? ["authenticated"],
|
|
133
168
|
specs,
|
|
134
|
-
definition:
|
|
169
|
+
definition: betterSupabase
|
|
135
170
|
};
|
|
136
171
|
}
|
|
137
172
|
function isReadSet(value) {
|
package/dist/realtime/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { x as PermdockTopicPolicy } from "../types-
|
|
1
|
+
import { x as PermdockTopicPolicy } from "../types-DONv9SHN.js";
|
|
2
|
+
import { t as PermdockCatalog } from "../permdock-sql-DImJULY-.js";
|
|
2
3
|
import { n as TemplateValues, t as TemplateParams } from "../template-mbvlysOo.js";
|
|
3
|
-
import { C as defineTopic, S as TriggerOptions, _ as TopicEvent, a as LiveSource, b as TopicOptions, c as liveQuery, d as RealtimeClient, f as RowChange, g as Topic, h as SubscriptionStatus, i as LiveQueryOptions, l as liveTopic, m as Subscription, n as LiveCountOptions, o as LiveSubscription, p as SubscribeOptions, r as LiveCountSeed, s as liveCount, t as CountRunner, u as EventSchemas, v as TopicHandlers, w as rowChange, x as TopicPayload, y as TopicMessage } from "../live-
|
|
4
|
-
export { type CountRunner, EventSchemas, type LiveCountOptions, type LiveCountSeed, type LiveQueryOptions, type LiveSource, type LiveSubscription, type PermdockTopicPolicy, RealtimeClient, RowChange, SubscribeOptions, Subscription, SubscriptionStatus, type TemplateParams, type TemplateValues, Topic, TopicEvent, TopicHandlers, TopicMessage, TopicOptions, TopicPayload, TriggerOptions, defineTopic, liveCount, liveQuery, liveTopic, rowChange };
|
|
4
|
+
import { C as defineTopic, S as TriggerOptions, _ as TopicEvent, a as LiveSource, b as TopicOptions, c as liveQuery, d as RealtimeClient, f as RowChange, g as Topic, h as SubscriptionStatus, i as LiveQueryOptions, l as liveTopic, m as Subscription, n as LiveCountOptions, o as LiveSubscription, p as SubscribeOptions, r as LiveCountSeed, s as liveCount, t as CountRunner, u as EventSchemas, v as TopicHandlers, w as rowChange, x as TopicPayload, y as TopicMessage } from "../live-BHakSWWo.js";
|
|
5
|
+
export { type CountRunner, type EventSchemas, type LiveCountOptions, type LiveCountSeed, type LiveQueryOptions, type LiveSource, type LiveSubscription, type PermdockCatalog, type PermdockTopicPolicy, type RealtimeClient, type RowChange, type SubscribeOptions, type Subscription, type SubscriptionStatus, type TemplateParams, type TemplateValues, type Topic, type TopicEvent, type TopicHandlers, type TopicMessage, type TopicOptions, type TopicPayload, type TriggerOptions, defineTopic, liveCount, liveQuery, liveTopic, rowChange };
|
package/dist/realtime/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { n as dbError } from "../errors-
|
|
2
|
-
import { i as ok, n as err, t as AsyncResult } from "../result-
|
|
3
|
-
import { i as tenantClaimPaths } from "../claims-
|
|
4
|
-
import { n as liveQuery, r as liveTopic, t as liveCount } from "../live-
|
|
5
|
-
import { s as toApp } from "../shared-
|
|
6
|
-
import { a as
|
|
1
|
+
import { n as dbError } from "../errors-L0xK41y_.js";
|
|
2
|
+
import { i as ok, n as err, t as AsyncResult } from "../result-Bj6yt33D.js";
|
|
3
|
+
import { i as tenantClaimPaths } from "../claims-BAf6c7is.js";
|
|
4
|
+
import { n as liveQuery, r as liveTopic, t as liveCount } from "../live-CdJBOc4f.js";
|
|
5
|
+
import { s as toApp } from "../shared-DnoCdMDr.js";
|
|
6
|
+
import { a as sqlIdent, i as slug, o as sqlString, r as parseTemplate, t as permdockCheck } from "../permdock-sql-C4KFzLc9.js";
|
|
7
7
|
import { REALTIME_SUBSCRIBE_STATES } from "@supabase/supabase-js";
|
|
8
|
-
//#region src/realtime/
|
|
8
|
+
//#region src/realtime/topic.ts
|
|
9
9
|
const VALUE = /^[\w.@+=-]+$/;
|
|
10
10
|
function validateValue(_name, value) {
|
|
11
11
|
return VALUE.test(value) ? void 0 : "contains characters topics do not allow";
|
|
@@ -55,7 +55,7 @@ function sendError(status, message) {
|
|
|
55
55
|
*/
|
|
56
56
|
function defineTopic(template, options = {}) {
|
|
57
57
|
const parsed = parseTemplate(template, ":", validateValue);
|
|
58
|
-
const literal = template.
|
|
58
|
+
const literal = template.replaceAll(/\{[^}]+\}/g, " ");
|
|
59
59
|
const name = slug(options.name ?? literal) || "topic";
|
|
60
60
|
const isPrivate = options.private ?? true;
|
|
61
61
|
const schemas = options.events ?? {};
|
|
@@ -71,10 +71,10 @@ function defineTopic(template, options = {}) {
|
|
|
71
71
|
if (!permdock) return void 0;
|
|
72
72
|
const where = `defineTopic(${template})`;
|
|
73
73
|
const id = permdock.scope === "global" ? void 0 : `split_part((select realtime.topic()), ':', ${String(permdock.segment ?? segment(tenantParam ?? "orgId", "PermDock"))})`;
|
|
74
|
-
const receive = permdockCheck(where, permdock, permdock.receive, id);
|
|
74
|
+
const receive = permdockCheck(where, permdock, permdock.receive, id, options.catalog);
|
|
75
75
|
return {
|
|
76
76
|
receive,
|
|
77
|
-
send: permdock.send === void 0 ? receive : permdockCheck(where, permdock, permdock.send, id)
|
|
77
|
+
send: permdock.send === void 0 ? receive : permdockCheck(where, permdock, permdock.send, id, options.catalog)
|
|
78
78
|
};
|
|
79
79
|
})();
|
|
80
80
|
if (!permdock && tenantParam && (options.tenant || parsed.params.includes(tenantParam))) {
|
|
@@ -119,8 +119,8 @@ function defineTopic(template, options = {}) {
|
|
|
119
119
|
}
|
|
120
120
|
return `${lines.join("\n")}\n`;
|
|
121
121
|
},
|
|
122
|
-
triggerSql(
|
|
123
|
-
const meta =
|
|
122
|
+
triggerSql(betterSupabase, table, trigger) {
|
|
123
|
+
const meta = betterSupabase.meta.tables[table];
|
|
124
124
|
if (!meta) throw new TypeError(`defineTopic: unknown table "${table}"`);
|
|
125
125
|
const values = trigger.values;
|
|
126
126
|
const parts = template.split(/(\{[^}]+\})/).filter(Boolean).map((part) => {
|
|
@@ -131,7 +131,7 @@ function defineTopic(template, options = {}) {
|
|
|
131
131
|
if (!db) throw new TypeError(`defineTopic: no column for {${param}} on "${table}"`);
|
|
132
132
|
return `rec.${sqlIdent(db)}::text`;
|
|
133
133
|
});
|
|
134
|
-
const schema = trigger.functionSchema ?? "
|
|
134
|
+
const schema = trigger.functionSchema ?? "better_supabase";
|
|
135
135
|
const fn = `${sqlIdent(schema)}.${sqlIdent(`bs_broadcast_${name}_${slug(meta.name)}`)}`;
|
|
136
136
|
const triggerName = sqlIdent(`bs_broadcast_${name}`);
|
|
137
137
|
const target = `${sqlIdent(meta.schema)}.${sqlIdent(meta.name)}`;
|
|
@@ -142,6 +142,7 @@ function defineTopic(template, options = {}) {
|
|
|
142
142
|
]).join(" or ");
|
|
143
143
|
return [
|
|
144
144
|
`-- better-supabase: broadcast ${meta.name} changes to ${template}`,
|
|
145
|
+
`create schema if not exists ${sqlIdent(schema)};`,
|
|
145
146
|
`create or replace function ${fn}()`,
|
|
146
147
|
"returns trigger",
|
|
147
148
|
"language plpgsql",
|
|
@@ -235,13 +236,14 @@ function defineTopic(template, options = {}) {
|
|
|
235
236
|
const topic = topicOf(values);
|
|
236
237
|
const checked = await validate(schemas[event], payload);
|
|
237
238
|
if (!checked.ok) return err(dbError("validation", `Invalid payload for ${event}`, { issues: checked.issues }));
|
|
238
|
-
|
|
239
|
+
const open = client.getChannels().some((existing) => existing.topic === `realtime:${topic}`);
|
|
240
|
+
if (isPrivate && !open) await client.realtime.setAuth();
|
|
239
241
|
const channel = client.channel(topic, { config: { private: isPrivate } });
|
|
240
242
|
try {
|
|
241
243
|
const response = await channel.httpSend(event, checked.value);
|
|
242
244
|
return response.success ? ok(void 0) : err(sendError(response.status, response.error));
|
|
243
245
|
} finally {
|
|
244
|
-
await client.removeChannel(channel);
|
|
246
|
+
if (!open) await client.removeChannel(channel);
|
|
245
247
|
}
|
|
246
248
|
});
|
|
247
249
|
}
|
|
@@ -251,8 +253,8 @@ function defineTopic(template, options = {}) {
|
|
|
251
253
|
* Reads a `realtime.broadcast_changes` message as an app-cased row change.
|
|
252
254
|
* Returns `null` for messages about other tables.
|
|
253
255
|
*/
|
|
254
|
-
function rowChange(
|
|
255
|
-
const meta =
|
|
256
|
+
function rowChange(betterSupabase, table, message) {
|
|
257
|
+
const meta = betterSupabase.meta.tables[table];
|
|
256
258
|
const payload = message.payload;
|
|
257
259
|
if (!meta || !payload || payload.table !== meta.name || payload.schema && payload.schema !== meta.schema) return null;
|
|
258
260
|
const operation = payload.operation ?? message.event;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { m as StoredSession } from "./resolve-
|
|
2
|
-
import "./view-D1s0wa0T.js";
|
|
3
|
-
import "./entitlements-Dng-ctuT.js";
|
|
1
|
+
import { m as StoredSession } from "./resolve-BAqQcwMW.js";
|
|
4
2
|
//#region src/auth/refresh.d.ts
|
|
5
3
|
interface RefreshOptions {
|
|
6
4
|
readonly url: string;
|
|
@@ -14,6 +12,12 @@ interface RefreshOptions {
|
|
|
14
12
|
readonly secretKey: string;
|
|
15
13
|
};
|
|
16
14
|
readonly fetch?: typeof fetch;
|
|
15
|
+
/**
|
|
16
|
+
* Milliseconds before a refresh counts as a network failure (the session is
|
|
17
|
+
* kept). 5000 by default.
|
|
18
|
+
*/
|
|
19
|
+
readonly timeoutMs?: number;
|
|
20
|
+
/** Epoch milliseconds, the unit JWT `exp` and `iat` math needs. */
|
|
17
21
|
readonly now?: () => number;
|
|
18
22
|
}
|
|
19
23
|
type RefreshOutcome = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { p as DbError } from "./result-
|
|
2
|
-
import { f as Logger, l as RefreshEvent } from "./events-
|
|
3
|
-
import { h as RequestContext } from "./plugin-
|
|
4
|
-
import { t as StandardSchemaV1 } from "./standard-
|
|
1
|
+
import { p as DbError } from "./result-CqEsbgYs.js";
|
|
2
|
+
import { f as Logger, l as RefreshEvent } from "./events-B21UOhvP.js";
|
|
3
|
+
import { h as RequestContext } from "./plugin-bNhvJwRh.js";
|
|
4
|
+
import { t as StandardSchemaV1 } from "./standard-BsaCYQJc.js";
|
|
5
5
|
import { t as BetterSupabaseEnv } from "./index-Dy6kuF0P.js";
|
|
6
6
|
import { CookieOptions } from "@supabase/ssr";
|
|
7
7
|
import { JWTClaims, SupabaseEnv, UserClaims } from "@supabase/server";
|
|
@@ -46,9 +46,9 @@ declare function applyCookieWrites(cookies: readonly CookieRecord[], writes: rea
|
|
|
46
46
|
//#endregion
|
|
47
47
|
//#region src/auth/resolve.d.ts
|
|
48
48
|
/**
|
|
49
|
-
* Who is calling. `C` is the claims type from `
|
|
49
|
+
* Who is calling. `C` is the claims type from `betterSupabase.claims(schema)`; the
|
|
50
50
|
* verified payload keeps every JWT claim and adds the schema's output. `P`
|
|
51
|
-
* is the `user_metadata` type from `
|
|
51
|
+
* is the `user_metadata` type from `betterSupabase.userMetadata(schema)`.
|
|
52
52
|
*/
|
|
53
53
|
type AuthState<C = unknown, P = unknown> = {
|
|
54
54
|
readonly kind: "user";
|
|
@@ -59,7 +59,7 @@ type AuthState<C = unknown, P = unknown> = {
|
|
|
59
59
|
/** Seconds since epoch, from the token's `exp`. */
|
|
60
60
|
readonly expiresAt: number | null;
|
|
61
61
|
/**
|
|
62
|
-
* `user_metadata` parsed by `
|
|
62
|
+
* `user_metadata` parsed by `betterSupabase.userMetadata(schema)`; `undefined`
|
|
63
63
|
* without a schema or when the metadata fails it. Users can write this
|
|
64
64
|
* data themselves: use it for display, never for access.
|
|
65
65
|
*/
|
|
@@ -76,7 +76,7 @@ type AuthState<C = unknown, P = unknown> = {
|
|
|
76
76
|
readonly reason: InvalidReason;
|
|
77
77
|
readonly error: DbError;
|
|
78
78
|
};
|
|
79
|
-
type InvalidReason = "token" | "claims";
|
|
79
|
+
type InvalidReason = "token" | "claims" | "actor";
|
|
80
80
|
/**
|
|
81
81
|
* What an `AuthResolver` returns. `reason` may be left out of an `invalid`
|
|
82
82
|
* state; it then counts as `token`.
|
|
@@ -101,8 +101,13 @@ interface ResolveAuthOptions {
|
|
|
101
101
|
readonly env: BetterSupabaseEnv;
|
|
102
102
|
/** Allow refreshing an expiring cookie session. Only where cookies can be written (proxy). */
|
|
103
103
|
readonly refresh?: boolean;
|
|
104
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* With `refresh`, refresh when the token expires within this many seconds.
|
|
106
|
+
* Defaults to 60. Without `refresh` a token stays valid until its `exp`.
|
|
107
|
+
*/
|
|
105
108
|
readonly leeway?: number;
|
|
109
|
+
/** Milliseconds before a refresh counts as a network failure. Defaults to 5000. */
|
|
110
|
+
readonly refreshTimeoutMs?: number;
|
|
106
111
|
/**
|
|
107
112
|
* Accept `sb_secret_` keys (`apikey` header) as service callers: `true` for
|
|
108
113
|
* any configured key, or the key names allowed (`['cron']`). Defaults to false.
|
|
@@ -117,12 +122,12 @@ interface ResolveAuthOptions {
|
|
|
117
122
|
/** Inline JWKS instead of fetching `env.jwksUrl` (tests, air-gapped). */
|
|
118
123
|
readonly jwks?: SupabaseEnv["jwks"];
|
|
119
124
|
/**
|
|
120
|
-
* Validates the verified claims (`
|
|
125
|
+
* Validates the verified claims (`betterSupabase.claims(schema)` sets it). A failure
|
|
121
126
|
* resolves to `{ kind: 'invalid', reason: 'claims' }`.
|
|
122
127
|
*/
|
|
123
128
|
readonly claims?: StandardSchemaV1;
|
|
124
129
|
/**
|
|
125
|
-
* Parses `user_metadata` into `profile` (`
|
|
130
|
+
* Parses `user_metadata` into `profile` (`betterSupabase.userMetadata(schema)` sets
|
|
126
131
|
* it). A failure leaves `profile` undefined and warns once; the session
|
|
127
132
|
* stays valid.
|
|
128
133
|
*/
|
|
@@ -140,6 +145,7 @@ interface ResolveAuthOptions {
|
|
|
140
145
|
/** Called after every refresh attempt (metrics, logging). */
|
|
141
146
|
readonly onRefresh?: (event: RefreshEvent) => void;
|
|
142
147
|
readonly fetch?: typeof fetch;
|
|
148
|
+
/** Epoch milliseconds, the unit JWT `exp` and `iat` math needs. */
|
|
143
149
|
readonly now?: () => number;
|
|
144
150
|
}
|
|
145
151
|
interface AuthResolution<C = unknown, P = unknown> {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { N as TableKey, P as TableMeta, R as Update,
|
|
2
|
-
import { b as ValidationIssue, o as Result } from "./result-
|
|
3
|
-
import { t as BetterSupabase, xt as SelectArg } from "./define-
|
|
4
|
-
import {
|
|
5
|
-
import { i as ResourceOperation } from "./index-
|
|
1
|
+
import { N as TableKey, P as TableMeta, R as Update, g as Insert, n as AnyModels, t as AnyFunctions } from "./types-DONv9SHN.js";
|
|
2
|
+
import { b as ValidationIssue, o as Result } from "./result-CqEsbgYs.js";
|
|
3
|
+
import { t as BetterSupabase, xt as SelectArg } from "./define-CRS2MRV3.js";
|
|
4
|
+
import { i as RespondOptions } from "./respond-DgIbdrt8.js";
|
|
5
|
+
import { i as ResourceOperation } from "./index-BhHEC04r.js";
|
|
6
6
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
7
7
|
//#region src/server/resource.d.ts
|
|
8
8
|
/** What a resource needs from `defineListQuery`. */
|
|
9
9
|
interface ResourceList {
|
|
10
10
|
readonly table: string;
|
|
11
|
+
readonly pagination?: ResourcePagination;
|
|
11
12
|
readonly openapi: readonly unknown[];
|
|
12
13
|
readonly jsonSchema: Readonly<Record<string, unknown>>;
|
|
13
14
|
parse(input: never): {
|
|
@@ -31,9 +32,16 @@ interface ResourceRouteOptions<M extends AnyModels, T extends TableKey<M>> {
|
|
|
31
32
|
readonly create?: StandardSchemaV1<unknown, Insert<M, T>>;
|
|
32
33
|
readonly update?: StandardSchemaV1<unknown, Update<M, T>>;
|
|
33
34
|
};
|
|
34
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Paging of the default list: `offset` (`page` and `size`) or `cursor`
|
|
37
|
+
* (`after` and `size`, keyset). A `list` query brings its own. Defaults
|
|
38
|
+
* to `offset`.
|
|
39
|
+
*/
|
|
40
|
+
readonly pagination?: ResourcePagination;
|
|
41
|
+
/** Largest page for the default list. Defaults to 200. */
|
|
35
42
|
readonly maxPageSize?: number;
|
|
36
43
|
}
|
|
44
|
+
type ResourcePagination = "offset" | "cursor";
|
|
37
45
|
interface ResourceInput {
|
|
38
46
|
/** Primary key value; strings are converted for integer keys. */
|
|
39
47
|
readonly id?: unknown;
|
|
@@ -49,6 +57,7 @@ interface ResourceHandler {
|
|
|
49
57
|
/** Name of the key parameter, or `undefined` for tables without a single-column key. */
|
|
50
58
|
readonly keyParam: string | undefined;
|
|
51
59
|
readonly list: ResourceList | undefined;
|
|
60
|
+
readonly pagination: ResourcePagination;
|
|
52
61
|
readonly maxPageSize: number;
|
|
53
62
|
/** Runs one operation as whoever `db` is bound to. Resolves to a `Result`. */
|
|
54
63
|
execute(db: object, operation: ResourceOperation, input?: ResourceInput): Promise<Result<unknown>>;
|
|
@@ -60,6 +69,6 @@ interface ResourceHandler {
|
|
|
60
69
|
* `createOpenApi`: `GET/POST /<table>` and `GET/PATCH/DELETE /<table>/{id}`.
|
|
61
70
|
* Shared by the HTTP adapters and the MCP table tools.
|
|
62
71
|
*/
|
|
63
|
-
declare function defineResource<M extends AnyModels, D, F extends AnyFunctions, E, T extends TableKey<M>>(
|
|
72
|
+
declare function defineResource<M extends AnyModels, D, F extends AnyFunctions, E, T extends TableKey<M>>(betterSupabase: BetterSupabase<M, D, F, E>, table: T, options?: ResourceRouteOptions<M, T>): ResourceHandler;
|
|
64
73
|
//#endregion
|
|
65
|
-
export {
|
|
74
|
+
export { ResourceRouteOptions as a, ResourcePagination as i, ResourceInput as n, defineResource as o, ResourceList as r, ResourceHandler as t };
|