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
|
@@ -1,66 +1,60 @@
|
|
|
1
|
-
import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "./claims-
|
|
2
|
-
import {
|
|
3
|
-
import { n as liveQuery, t as liveCount } from "./live-
|
|
1
|
+
import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "./claims-BAf6c7is.js";
|
|
2
|
+
import { n as invalidateTables, t as clearOnUserChange } from "./user-change-CHFEUro1.js";
|
|
3
|
+
import { n as liveQuery, t as liveCount } from "./live-CdJBOc4f.js";
|
|
4
4
|
import { useSession } from "./react/session.js";
|
|
5
|
-
import {
|
|
5
|
+
import { REALTIME_SUBSCRIBE_STATES } from "@supabase/supabase-js";
|
|
6
|
+
import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
6
7
|
//#region src/react/hooks.ts
|
|
7
|
-
const
|
|
8
|
+
const ClientContext = createContext(null);
|
|
8
9
|
const LOADING = {
|
|
9
10
|
status: "loading",
|
|
10
11
|
user: null,
|
|
11
12
|
claims: null
|
|
12
13
|
};
|
|
13
|
-
/** Provides the
|
|
14
|
+
/** Provides the better-supabase client to the hooks. */
|
|
14
15
|
function BetterSupabaseProvider(props) {
|
|
15
|
-
const {
|
|
16
|
-
|
|
17
|
-
useEffect(() => browser.auth.subscribe(() => {
|
|
18
|
-
const snapshot = browser.auth.current();
|
|
19
|
-
if (snapshot.status === "loading") return;
|
|
20
|
-
const id = snapshot.user?.id ?? null;
|
|
21
|
-
if (user.current !== void 0 && user.current !== id) queryClient?.removeQueries({ queryKey: ["bs"] });
|
|
22
|
-
user.current = id;
|
|
23
|
-
}), [browser, queryClient]);
|
|
16
|
+
const { client, queryClient } = props;
|
|
17
|
+
useEffect(() => queryClient ? clearOnUserChange(queryClient, client.auth) : void 0, [client, queryClient]);
|
|
24
18
|
const value = useMemo(() => ({
|
|
25
|
-
|
|
19
|
+
client,
|
|
26
20
|
queryClient
|
|
27
|
-
}), [
|
|
28
|
-
return createElement(
|
|
21
|
+
}), [client, queryClient]);
|
|
22
|
+
return createElement(ClientContext.Provider, { value }, props.children);
|
|
29
23
|
}
|
|
30
|
-
function
|
|
31
|
-
const value = useContext(
|
|
32
|
-
if (!value) throw new Error("better-supabase: wrap your app in <BetterSupabaseProvider
|
|
24
|
+
function useClientContext() {
|
|
25
|
+
const value = useContext(ClientContext);
|
|
26
|
+
if (!value) throw new Error("better-supabase: wrap your app in <BetterSupabaseProvider client={bs}>");
|
|
33
27
|
return value;
|
|
34
28
|
}
|
|
35
|
-
function
|
|
36
|
-
return
|
|
29
|
+
function useClient() {
|
|
30
|
+
return useClientContext().client;
|
|
37
31
|
}
|
|
38
32
|
/** The session state for UI: `loading`, `signed-out` or `signed-in` with the user and claims. */
|
|
39
33
|
function useAuth() {
|
|
40
|
-
const
|
|
41
|
-
return useSyncExternalStore(
|
|
34
|
+
const client = useClient();
|
|
35
|
+
return useSyncExternalStore(client.auth.subscribe, client.auth.current, () => LOADING);
|
|
42
36
|
}
|
|
43
37
|
function useSupabase() {
|
|
44
|
-
return
|
|
38
|
+
return useClient().supabase;
|
|
45
39
|
}
|
|
46
40
|
/**
|
|
47
41
|
* Hooks typed for your schema.
|
|
48
42
|
*
|
|
49
43
|
* ```ts
|
|
50
|
-
* export const { useDb, useQueries, useAuth } = createHooks<typeof
|
|
44
|
+
* export const { useDb, useQueries, useAuth } = createHooks<typeof bs>();
|
|
51
45
|
* ```
|
|
52
46
|
*/
|
|
53
47
|
function createHooks() {
|
|
54
48
|
return {
|
|
55
49
|
useDb() {
|
|
56
|
-
const
|
|
50
|
+
const client = useClient();
|
|
57
51
|
useAuth();
|
|
58
|
-
return
|
|
52
|
+
return client.db;
|
|
59
53
|
},
|
|
60
54
|
useQueries() {
|
|
61
|
-
const
|
|
55
|
+
const client = useClient();
|
|
62
56
|
useAuth();
|
|
63
|
-
return
|
|
57
|
+
return client.queries;
|
|
64
58
|
},
|
|
65
59
|
useSupabase,
|
|
66
60
|
useAuth,
|
|
@@ -76,7 +70,7 @@ function createHooks() {
|
|
|
76
70
|
* ```
|
|
77
71
|
*/
|
|
78
72
|
function useBroadcast(topic, values, handlers, options) {
|
|
79
|
-
const {
|
|
73
|
+
const { client, queryClient } = useClientContext();
|
|
80
74
|
const auth = useAuth();
|
|
81
75
|
const [status, setStatus] = useState("closed");
|
|
82
76
|
const latest = useRef({
|
|
@@ -106,7 +100,7 @@ function useBroadcast(topic, values, handlers, options) {
|
|
|
106
100
|
}
|
|
107
101
|
for (const queryKey of invalidate(message)) queryClient.invalidateQueries({ queryKey });
|
|
108
102
|
};
|
|
109
|
-
const subscription = topic.subscribe(
|
|
103
|
+
const subscription = topic.subscribe(client.supabase, matched, { "*": forward }, {
|
|
110
104
|
...latest.current.options?.self === void 0 ? {} : { self: latest.current.options.self },
|
|
111
105
|
onStatus: setStatus,
|
|
112
106
|
onInvalid: (message, issues) => latest.current.options?.onInvalid?.(message, issues)
|
|
@@ -116,7 +110,7 @@ function useBroadcast(topic, values, handlers, options) {
|
|
|
116
110
|
setStatus("closed");
|
|
117
111
|
};
|
|
118
112
|
}, [
|
|
119
|
-
|
|
113
|
+
client,
|
|
120
114
|
topic,
|
|
121
115
|
name,
|
|
122
116
|
userId,
|
|
@@ -138,23 +132,23 @@ function claimedTenant(auth, meta) {
|
|
|
138
132
|
* resubscribes when the spec, tenant or user changes.
|
|
139
133
|
*
|
|
140
134
|
* ```ts
|
|
141
|
-
* const spec =
|
|
135
|
+
* const spec = betterSupabase.spec.customers.findMany({ include: { notes: true } });
|
|
142
136
|
* const { data } = useQuery(q.$spec(spec));
|
|
143
137
|
* useLiveQuery(spec);
|
|
144
138
|
* ```
|
|
145
139
|
*/
|
|
146
140
|
function useLiveQuery(spec, options = {}) {
|
|
147
|
-
const {
|
|
141
|
+
const { client, queryClient } = useClientContext();
|
|
148
142
|
const auth = useAuth();
|
|
149
143
|
const [status, setStatus] = useState("closed");
|
|
150
144
|
if (spec && !queryClient) throw new Error("better-supabase: useLiveQuery needs <BetterSupabaseProvider queryClient={...}>");
|
|
151
145
|
const key = spec ? JSON.stringify(spec) : null;
|
|
152
|
-
const tenant = options.tenant ?? claimedTenant(auth,
|
|
146
|
+
const tenant = options.tenant ?? claimedTenant(auth, client.betterSupabase.meta);
|
|
153
147
|
const userId = auth.user?.id ?? null;
|
|
154
148
|
const debounceMs = options.debounceMs;
|
|
155
149
|
useEffect(() => {
|
|
156
150
|
if (!key || !queryClient || auth.status === "loading") return;
|
|
157
|
-
const live = liveQuery(
|
|
151
|
+
const live = liveQuery(client.betterSupabase, client.supabase, JSON.parse(key), {
|
|
158
152
|
onChange: (tables) => void invalidateTables(queryClient, tables),
|
|
159
153
|
onStatus: setStatus,
|
|
160
154
|
...tenant === void 0 ? {} : { tenant },
|
|
@@ -164,7 +158,7 @@ function useLiveQuery(spec, options = {}) {
|
|
|
164
158
|
live.unsubscribe();
|
|
165
159
|
};
|
|
166
160
|
}, [
|
|
167
|
-
|
|
161
|
+
client,
|
|
168
162
|
queryClient,
|
|
169
163
|
key,
|
|
170
164
|
tenant,
|
|
@@ -177,15 +171,15 @@ function useLiveQuery(spec, options = {}) {
|
|
|
177
171
|
/**
|
|
178
172
|
* A count that stays current: refetches only the `count` spec (a HEAD
|
|
179
173
|
* request) after each debounced change to a table it reads, and after the
|
|
180
|
-
* channel rejoins. Takes a spec or a `
|
|
174
|
+
* channel rejoins. Takes a spec or a `bs.liveCount()` seed; pass `null` to
|
|
181
175
|
* pause. Doesn't need a `QueryClient`.
|
|
182
176
|
*
|
|
183
177
|
* ```tsx
|
|
184
|
-
* const { count } = useLiveCount(seed); // seed = await
|
|
178
|
+
* const { count } = useLiveCount(seed); // seed = await bs.liveCount(spec)
|
|
185
179
|
* ```
|
|
186
180
|
*/
|
|
187
181
|
function useLiveCount(source, options = {}) {
|
|
188
|
-
const {
|
|
182
|
+
const { client } = useClientContext();
|
|
189
183
|
const auth = useAuth();
|
|
190
184
|
const seed = source && "spec" in source ? source : void 0;
|
|
191
185
|
const spec = seed ? seed.spec : source;
|
|
@@ -197,13 +191,13 @@ function useLiveCount(source, options = {}) {
|
|
|
197
191
|
});
|
|
198
192
|
const [status, setStatus] = useState("closed");
|
|
199
193
|
const key = spec ? JSON.stringify(spec) : null;
|
|
200
|
-
const tenant = options.tenant ?? claimedTenant(auth,
|
|
194
|
+
const tenant = options.tenant ?? claimedTenant(auth, client.betterSupabase.meta);
|
|
201
195
|
const userId = auth.user?.id ?? null;
|
|
202
196
|
const debounceMs = options.debounceMs;
|
|
203
197
|
const hasInitial = initial !== void 0;
|
|
204
198
|
useEffect(() => {
|
|
205
199
|
if (!key || auth.status === "loading") return;
|
|
206
|
-
const live = liveCount(
|
|
200
|
+
const live = liveCount(client.betterSupabase, client.supabase, client.db, JSON.parse(key), {
|
|
207
201
|
immediate: !hasInitial,
|
|
208
202
|
onCount: (count) => {
|
|
209
203
|
setState({
|
|
@@ -227,7 +221,7 @@ function useLiveCount(source, options = {}) {
|
|
|
227
221
|
live.unsubscribe();
|
|
228
222
|
};
|
|
229
223
|
}, [
|
|
230
|
-
|
|
224
|
+
client,
|
|
231
225
|
key,
|
|
232
226
|
tenant,
|
|
233
227
|
userId,
|
|
@@ -243,4 +237,102 @@ function useLiveCount(source, options = {}) {
|
|
|
243
237
|
};
|
|
244
238
|
}
|
|
245
239
|
//#endregion
|
|
246
|
-
|
|
240
|
+
//#region src/react/notifications.ts
|
|
241
|
+
const unread = (items) => items.filter((item) => typeof item === "object" && item !== null && "readAt" in item && item.readAt === null).length;
|
|
242
|
+
/** Joins a private topic and returns the function that leaves it. */
|
|
243
|
+
function watchTopic(supabase, topic, watch) {
|
|
244
|
+
let closed = false;
|
|
245
|
+
let joined = false;
|
|
246
|
+
const channel = supabase.channel(topic, { config: { private: true } });
|
|
247
|
+
channel.on("broadcast", { event: "*" }, (message) => {
|
|
248
|
+
watch.onMessage(message.event, message["payload"]);
|
|
249
|
+
});
|
|
250
|
+
(async () => {
|
|
251
|
+
watch.onStatus("joining");
|
|
252
|
+
await supabase.realtime.setAuth();
|
|
253
|
+
if (closed) return;
|
|
254
|
+
channel.subscribe((state) => {
|
|
255
|
+
switch (state) {
|
|
256
|
+
case REALTIME_SUBSCRIBE_STATES.SUBSCRIBED:
|
|
257
|
+
if (joined) watch.onRejoin();
|
|
258
|
+
joined = true;
|
|
259
|
+
watch.onStatus("subscribed");
|
|
260
|
+
return;
|
|
261
|
+
case REALTIME_SUBSCRIBE_STATES.CLOSED:
|
|
262
|
+
watch.onStatus("closed");
|
|
263
|
+
return;
|
|
264
|
+
case REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR:
|
|
265
|
+
case REALTIME_SUBSCRIBE_STATES.TIMED_OUT:
|
|
266
|
+
watch.onStatus("error");
|
|
267
|
+
return;
|
|
268
|
+
default: throw new Error(`Unknown realtime status ${String(state)}`);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
})();
|
|
272
|
+
return () => {
|
|
273
|
+
closed = true;
|
|
274
|
+
supabase.removeChannel(channel);
|
|
275
|
+
watch.onStatus("closed");
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* The signed-in user's notifications, kept current: loads them, then loads
|
|
280
|
+
* again after each broadcast on `topic` and after the channel rejoins.
|
|
281
|
+
*
|
|
282
|
+
* ```tsx
|
|
283
|
+
* const { items, count } = useNotifications({
|
|
284
|
+
* topic: `org:${orgId}:notifications:${userId}`,
|
|
285
|
+
* load: () => listNotifications(orgId),
|
|
286
|
+
* });
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
function useNotifications(options) {
|
|
290
|
+
const supabase = useSupabase();
|
|
291
|
+
const auth = useAuth();
|
|
292
|
+
const [items, setItems] = useState(void 0);
|
|
293
|
+
const [error, setError] = useState(void 0);
|
|
294
|
+
const [status, setStatus] = useState("closed");
|
|
295
|
+
const latest = useRef(options);
|
|
296
|
+
latest.current = options;
|
|
297
|
+
const userId = auth.user?.id ?? null;
|
|
298
|
+
const refresh = useCallback(async () => {
|
|
299
|
+
const current = latest.current;
|
|
300
|
+
try {
|
|
301
|
+
const merged = (await Promise.all([current.load, ...current.sources ?? []].map((source) => source()))).flat();
|
|
302
|
+
setItems(current.sort ? [...merged].sort(current.sort) : merged);
|
|
303
|
+
setError(void 0);
|
|
304
|
+
} catch (cause) {
|
|
305
|
+
setError(cause);
|
|
306
|
+
}
|
|
307
|
+
}, []);
|
|
308
|
+
const topic = options.topic;
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
if (auth.status !== "signed-in") return;
|
|
311
|
+
refresh();
|
|
312
|
+
if (!topic) return;
|
|
313
|
+
return watchTopic(supabase, topic, {
|
|
314
|
+
onMessage: (event, payload) => {
|
|
315
|
+
latest.current.onMessage?.(event, payload);
|
|
316
|
+
refresh();
|
|
317
|
+
},
|
|
318
|
+
onRejoin: () => void refresh(),
|
|
319
|
+
onStatus: setStatus
|
|
320
|
+
});
|
|
321
|
+
}, [
|
|
322
|
+
supabase,
|
|
323
|
+
topic,
|
|
324
|
+
userId,
|
|
325
|
+
auth.status,
|
|
326
|
+
refresh
|
|
327
|
+
]);
|
|
328
|
+
const list = items ?? [];
|
|
329
|
+
return {
|
|
330
|
+
items,
|
|
331
|
+
count: (options.count ?? unread)(list),
|
|
332
|
+
status,
|
|
333
|
+
error,
|
|
334
|
+
refresh
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
//#endregion
|
|
338
|
+
export { useBroadcast as a, useSupabase as c, useAuth as i, BetterSupabaseProvider as n, useLiveCount as o, createHooks as r, useLiveQuery as s, useNotifications as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as
|
|
2
|
-
import { n as touchedTables } from "./tables-
|
|
1
|
+
import { r as builderFor, s as tableMeta } from "./simplify-_0oUKqCd.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];
|
|
55
66
|
}
|
|
67
|
+
if (key !== void 0) {
|
|
68
|
+
if (byKey.size >= SPEC_CACHE_SIZE) byKey.clear();
|
|
69
|
+
byKey.set(key, tables);
|
|
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;
|
|
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;
|
|
62
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";
|
|
@@ -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,11 @@ 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`);
|
|
162
|
+
warnUnscopedReads(betterSupabase, name, specs);
|
|
127
163
|
return {
|
|
128
164
|
kind: "read-set",
|
|
129
165
|
name,
|
|
@@ -131,9 +167,29 @@ function defineReadSet(sb, name, options, build) {
|
|
|
131
167
|
params,
|
|
132
168
|
roles: options.roles ?? ["authenticated"],
|
|
133
169
|
specs,
|
|
134
|
-
definition:
|
|
170
|
+
definition: betterSupabase
|
|
135
171
|
};
|
|
136
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* The generated function runs the reads as compiled at `gen` time, without
|
|
175
|
+
* the runtime's `transformQuery` plugins, so tenant and soft-delete filters
|
|
176
|
+
* that only those plugins add never reach it.
|
|
177
|
+
*/
|
|
178
|
+
function warnUnscopedReads(betterSupabase, name, specs) {
|
|
179
|
+
const scoping = betterSupabase.plugins.filter((plugin) => plugin.transformQuery !== void 0 && plugin.name !== "rules").map((plugin) => plugin.name);
|
|
180
|
+
if (scoping.length === 0) return;
|
|
181
|
+
const { meta } = betterSupabase;
|
|
182
|
+
const tables = [...new Set(Object.values(specs).flatMap((spec) => specTables(meta, spec)))].filter((key) => {
|
|
183
|
+
const flags = meta.tables[key]?.flags;
|
|
184
|
+
return flags?.tenant !== void 0 || flags?.softDelete !== void 0;
|
|
185
|
+
});
|
|
186
|
+
if (tables.length === 0) return;
|
|
187
|
+
betterSupabase.events.logger.warn(`read set "${name}" reads ${tables.join(", ")}, which ${scoping.join(", ")} scope at runtime; its generated function only sees those filters when the specs spell them out (or RLS enforces them)`, {
|
|
188
|
+
readSet: name,
|
|
189
|
+
tables,
|
|
190
|
+
plugins: scoping
|
|
191
|
+
});
|
|
192
|
+
}
|
|
137
193
|
function isReadSet(value) {
|
|
138
194
|
return typeof value === "object" && value !== null && value.kind === "read-set" && typeof value.name === "string";
|
|
139
195
|
}
|
package/dist/realtime/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { S as PermdockTopicPolicy } from "../types-Dnf_wRDz.js";
|
|
2
|
+
import { n as PermdockCatalog } from "../permdock-sql-C2Inc6Xc.js";
|
|
3
3
|
import { n as TemplateValues, t as TemplateParams } from "../template-mbvlysOo.js";
|
|
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-
|
|
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-D9W2M5aO.js";
|
|
5
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,9 +1,10 @@
|
|
|
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 {
|
|
6
|
-
import {
|
|
1
|
+
import { n as dbError } from "../errors-DtwXa6b8.js";
|
|
2
|
+
import { i as ok, n as err, t as AsyncResult } from "../result-BKiliPY7.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 { i as sqlString, n as slug, r as sqlIdent, t as parseTemplate } from "../template-TxrGI5jR.js";
|
|
6
|
+
import { c as toApp } from "../shared-D1dRUrAg.js";
|
|
7
|
+
import { n as permdockCheck } from "../permdock-sql-DgOfeixi.js";
|
|
7
8
|
import { REALTIME_SUBSCRIBE_STATES } from "@supabase/supabase-js";
|
|
8
9
|
//#region src/realtime/topic.ts
|
|
9
10
|
const VALUE = /^[\w.@+=-]+$/;
|
|
@@ -119,8 +120,8 @@ function defineTopic(template, options = {}) {
|
|
|
119
120
|
}
|
|
120
121
|
return `${lines.join("\n")}\n`;
|
|
121
122
|
},
|
|
122
|
-
triggerSql(
|
|
123
|
-
const meta =
|
|
123
|
+
triggerSql(betterSupabase, table, trigger) {
|
|
124
|
+
const meta = betterSupabase.meta.tables[table];
|
|
124
125
|
if (!meta) throw new TypeError(`defineTopic: unknown table "${table}"`);
|
|
125
126
|
const values = trigger.values;
|
|
126
127
|
const parts = template.split(/(\{[^}]+\})/).filter(Boolean).map((part) => {
|
|
@@ -236,13 +237,14 @@ function defineTopic(template, options = {}) {
|
|
|
236
237
|
const topic = topicOf(values);
|
|
237
238
|
const checked = await validate(schemas[event], payload);
|
|
238
239
|
if (!checked.ok) return err(dbError("validation", `Invalid payload for ${event}`, { issues: checked.issues }));
|
|
239
|
-
|
|
240
|
+
const open = client.getChannels().some((existing) => existing.topic === `realtime:${topic}`);
|
|
241
|
+
if (isPrivate && !open) await client.realtime.setAuth();
|
|
240
242
|
const channel = client.channel(topic, { config: { private: isPrivate } });
|
|
241
243
|
try {
|
|
242
244
|
const response = await channel.httpSend(event, checked.value);
|
|
243
245
|
return response.success ? ok(void 0) : err(sendError(response.status, response.error));
|
|
244
246
|
} finally {
|
|
245
|
-
await client.removeChannel(channel);
|
|
247
|
+
if (!open) await client.removeChannel(channel);
|
|
246
248
|
}
|
|
247
249
|
});
|
|
248
250
|
}
|
|
@@ -252,8 +254,8 @@ function defineTopic(template, options = {}) {
|
|
|
252
254
|
* Reads a `realtime.broadcast_changes` message as an app-cased row change.
|
|
253
255
|
* Returns `null` for messages about other tables.
|
|
254
256
|
*/
|
|
255
|
-
function rowChange(
|
|
256
|
-
const meta =
|
|
257
|
+
function rowChange(betterSupabase, table, message) {
|
|
258
|
+
const meta = betterSupabase.meta.tables[table];
|
|
257
259
|
const payload = message.payload;
|
|
258
260
|
if (!meta || !payload || payload.table !== meta.name || payload.schema && payload.schema !== meta.schema) return null;
|
|
259
261
|
const operation = payload.operation ?? message.event;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { m as StoredSession } from "./resolve-
|
|
2
|
-
import "./view-3Po_PVlr.js";
|
|
3
|
-
import "./entitlements-DvJXoI02.js";
|
|
1
|
+
import { m as StoredSession } from "./resolve-C15TJq77.js";
|
|
4
2
|
//#region src/auth/refresh.d.ts
|
|
5
3
|
interface RefreshOptions {
|
|
6
4
|
readonly url: string;
|
|
@@ -14,6 +12,11 @@ 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;
|
|
17
20
|
/** Epoch milliseconds, the unit JWT `exp` and `iat` math needs. */
|
|
18
21
|
readonly now?: () => number;
|
|
19
22
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as StandardSchemaV1 } from "./standard-
|
|
5
|
-
import { t as BetterSupabaseEnv } from "./index-
|
|
1
|
+
import { _ as DbError } from "./executor-BunPOO-k.js";
|
|
2
|
+
import { E as Logger, l as RefreshEvent } from "./events-aIO7vsIk.js";
|
|
3
|
+
import { g as RequestContext } from "./plugin-o144f322.js";
|
|
4
|
+
import { t as StandardSchemaV1 } from "./standard-J4YgMOLm.js";
|
|
5
|
+
import { t as BetterSupabaseEnv } from "./index-CLg87OBW.js";
|
|
6
6
|
import { CookieOptions } from "@supabase/ssr";
|
|
7
7
|
import { JWTClaims, SupabaseEnv, UserClaims } from "@supabase/server";
|
|
8
8
|
//#region src/auth/session.d.ts
|
|
@@ -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
|
*/
|
|
@@ -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.
|
|
@@ -114,15 +119,21 @@ interface ResolveAuthOptions {
|
|
|
114
119
|
readonly name?: string;
|
|
115
120
|
readonly options?: CookieOptions;
|
|
116
121
|
};
|
|
122
|
+
/**
|
|
123
|
+
* Read the session cookie. Defaults to true. `false` suits endpoints only
|
|
124
|
+
* bearer clients call (MCP): a browser's cookie then can't authorize a
|
|
125
|
+
* request another site makes it send.
|
|
126
|
+
*/
|
|
127
|
+
readonly cookies?: boolean;
|
|
117
128
|
/** Inline JWKS instead of fetching `env.jwksUrl` (tests, air-gapped). */
|
|
118
129
|
readonly jwks?: SupabaseEnv["jwks"];
|
|
119
130
|
/**
|
|
120
|
-
* Validates the verified claims (`
|
|
131
|
+
* Validates the verified claims (`betterSupabase.claims(schema)` sets it). A failure
|
|
121
132
|
* resolves to `{ kind: 'invalid', reason: 'claims' }`.
|
|
122
133
|
*/
|
|
123
134
|
readonly claims?: StandardSchemaV1;
|
|
124
135
|
/**
|
|
125
|
-
* Parses `user_metadata` into `profile` (`
|
|
136
|
+
* Parses `user_metadata` into `profile` (`betterSupabase.userMetadata(schema)` sets
|
|
126
137
|
* it). A failure leaves `profile` undefined and warns once; the session
|
|
127
138
|
* stays valid.
|
|
128
139
|
*/
|