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.
Files changed (190) hide show
  1. package/README.md +37 -33
  2. package/dist/base64-D2gsioCY.js +42 -0
  3. package/dist/claims-BAf6c7is.js +48 -0
  4. package/dist/cli/_format-Cax5EsM9.js +101 -0
  5. package/dist/cli/bin.js +39 -6
  6. package/dist/cli/command-CK14fP91.js +502 -0
  7. package/dist/cli/compare-BmIWVEui.js +9 -0
  8. package/dist/cli/config-D9R0o1LH.js +1895 -0
  9. package/dist/cli/config-SSKSTUl2.js +2 -0
  10. package/dist/cli/db-DOBPt660.js +52 -0
  11. package/dist/cli/dist-B1MvLv-M.js +129 -0
  12. package/dist/cli/dist-CFgGknmZ.js +1112 -0
  13. package/dist/cli/dist-Du7VnEUG.js +621 -0
  14. package/dist/cli/doctor-BOym3mbL.js +2382 -0
  15. package/dist/cli/env-BZ0uy8XK.js +108 -0
  16. package/dist/cli/env-jIFUADLY.js +511 -0
  17. package/dist/cli/errors-4v4DTtda.js +56 -0
  18. package/dist/cli/fastest-levenshtein-CFN-lNDv.js +120 -0
  19. package/dist/cli/gen-Ccn_p90L.js +2008 -0
  20. package/dist/cli/gen-D5cLCULx.js +2 -0
  21. package/dist/cli/index.d.ts +295 -28
  22. package/dist/cli/index.js +184 -3
  23. package/dist/cli/init-ClnxRYBF.js +550 -0
  24. package/dist/cli/introspect-DxqfkVIv.js +81 -0
  25. package/dist/cli/io-k41_z-jT.js +24 -0
  26. package/dist/cli/json5-ChRycquj.js +787 -0
  27. package/dist/cli/jsonc-BUniUpOk.js +2 -0
  28. package/dist/cli/jsonc-D5Fu67jw.js +45 -0
  29. package/dist/cli/keys-ByKHnvP9.js +83 -0
  30. package/dist/cli/ohash-D7bG_EOb.js +277 -0
  31. package/dist/cli/openapi-8WHjxiTJ.js +66 -0
  32. package/dist/cli/project-B_GeXyHh.js +70 -0
  33. package/dist/cli/prompts-BNcNfAve.js +1142 -0
  34. package/dist/cli/prompts-BTYQGunc.js +2 -0
  35. package/dist/cli/read-sets-CMa29t9a.js +971 -0
  36. package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
  37. package/dist/cli/run-CP20LKk_.js +347 -0
  38. package/dist/cli/seed-5J6eu_Xg.js +98 -0
  39. package/dist/cli/skills-LJJIhLFR.js +137 -0
  40. package/dist/cli/sql-D4VbqmXi.js +199 -0
  41. package/dist/cli/style-C0NFdJRL.js +29 -0
  42. package/dist/cli/toml-DB-MNnFs.js +424 -0
  43. package/dist/{version-Cqq1m3UY.js → cli/version-5mW_8sY1.js} +1 -1
  44. package/dist/cli/yaml-CYCbJ6et.js +2252 -0
  45. package/dist/client/index.d.ts +2 -2
  46. package/dist/client/index.js +15 -25
  47. package/dist/{compiler-CZ9nIuqy.d.ts → compiler-DB3aSFOA.d.ts} +2 -2
  48. package/dist/config/index.d.ts +4 -3
  49. package/dist/config/index.js +5 -3
  50. package/dist/config-BpxDfnbg.js +129 -0
  51. package/dist/{index-DOsjFvMf.d.ts → config-C1CYcm6o.d.ts} +49 -49
  52. package/dist/{config-ClDXmVtY.js → config-CbvFmGD8.js} +14 -137
  53. package/dist/{define-BXMYD9AY.js → define-Bh0AqTik.js} +221 -120
  54. package/dist/{define-e3zI4_4g.d.ts → define-CRS2MRV3.d.ts} +36 -31
  55. package/dist/edge/index.d.ts +9 -13
  56. package/dist/edge/index.js +51 -25
  57. package/dist/{entitlements-Dng-ctuT.d.ts → entitlements-Dm-FHpNH.d.ts} +2 -2
  58. package/dist/env/index.js +203 -1
  59. package/dist/{errors-Bl3rkOzo.js → errors-L0xK41y_.js} +1 -1
  60. package/dist/events/index.d.ts +1 -1
  61. package/dist/events/index.js +139 -1
  62. package/dist/{events-DOt3nSO-.d.ts → events-B21UOhvP.d.ts} +4 -4
  63. package/dist/{executor-CGdNQ27g.d.ts → executor-B5IoUxLE.d.ts} +2 -2
  64. package/dist/{executor-DeppvirK.js → executor-CVt6dD0B.js} +9 -4
  65. package/dist/{executor-BYXQ9AGn.d.ts → executor-CZ7ImRiD.d.ts} +2 -2
  66. package/dist/hono/index.d.ts +17 -24
  67. package/dist/hono/index.js +11 -11
  68. package/dist/{index-DuP14VHo.d.ts → index-528Ugmyp.d.ts} +30 -10
  69. package/dist/{index-Bw1bwtC0.d.ts → index-BAy4tsAP.d.ts} +28 -15
  70. package/dist/{index-CBDufH1M.d.ts → index-BBdvo-5d.d.ts} +24 -26
  71. package/dist/{index-DbxFr7XG.d.ts → index-BhHEC04r.d.ts} +9 -4
  72. package/dist/index-Cf-D2jk1.d.ts +50 -0
  73. package/dist/{index-Ciu5Xlml.d.ts → index-D5IfUIDh.d.ts} +6 -5
  74. package/dist/{index-K-3WM2Hp.d.ts → index-DFmOpBGC.d.ts} +13 -13
  75. package/dist/{index-D4v7sncu.d.ts → index-RlLXd8dL.d.ts} +13 -13
  76. package/dist/index.d.ts +17 -17
  77. package/dist/index.js +23 -14
  78. package/dist/{invalidate-DbxuL2jL.js → invalidate-CgxmRamI.js} +7 -1
  79. package/dist/jobs/index.d.ts +33 -26
  80. package/dist/jobs/index.js +44 -22
  81. package/dist/{json-schema-BpYqkCKf.js → json-schema-DP6V7cbr.js} +8 -3
  82. package/dist/lint/index.js +1 -1
  83. package/dist/list/index.d.ts +2 -2
  84. package/dist/list/index.js +131 -96
  85. package/dist/{live-DJyZMD6w.d.ts → live-BHakSWWo.d.ts} +26 -16
  86. package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
  87. package/dist/lookup-BaP5bI27.js +18 -0
  88. package/dist/mcp/index.d.ts +34 -27
  89. package/dist/mcp/index.js +59 -25
  90. package/dist/{mfa-TVia554c.d.ts → mfa-C7MNQ1Ob.d.ts} +1 -1
  91. package/dist/{mfa-CpLfJSde.js → mfa-byfjruR9.js} +190 -46
  92. package/dist/next/image/index.js +6 -3
  93. package/dist/next/index.d.ts +64 -48
  94. package/dist/next/index.js +63 -50
  95. package/dist/openapi/index.d.ts +1 -1
  96. package/dist/openapi/index.js +61 -38
  97. package/dist/orpc/index.d.ts +18 -21
  98. package/dist/orpc/index.js +12 -12
  99. package/dist/otel/index.d.ts +5 -5
  100. package/dist/otel/index.js +84 -63
  101. package/dist/{permdock-sql-CghlHPuH.js → permdock-sql-C4KFzLc9.js} +12 -7
  102. package/dist/permdock-sql-DImJULY-.d.ts +17 -0
  103. package/dist/{plugin-C4TR9J0Z.d.ts → plugin-bNhvJwRh.d.ts} +5 -4
  104. package/dist/plugins/actor/index.d.ts +1 -1
  105. package/dist/plugins/actor/index.js +1 -1
  106. package/dist/plugins/rules/index.d.ts +2 -2
  107. package/dist/plugins/rules/index.js +46 -16
  108. package/dist/plugins/soft-delete/index.d.ts +3 -3
  109. package/dist/plugins/soft-delete/index.js +4 -4
  110. package/dist/plugins/tenant/index.d.ts +3 -3
  111. package/dist/plugins/tenant/index.js +10 -4
  112. package/dist/plugins/timestamps/index.d.ts +1 -1
  113. package/dist/plugins/timestamps/index.js +2 -2
  114. package/dist/plugins/validation/index.d.ts +2 -2
  115. package/dist/plugins/validation/index.js +3 -3
  116. package/dist/pool-DFwEQwmN.d.ts +78 -0
  117. package/dist/postgres/index.d.ts +10 -5
  118. package/dist/postgres/index.js +37 -16
  119. package/dist/{postgrest-cAEQ_IQN.d.ts → postgrest-Bc-0Xw62.d.ts} +1 -1
  120. package/dist/{problem-BTkTtRV9.js → problem-BihjPR0t.js} +11 -5
  121. package/dist/{problem-DlgB0lYl.d.ts → problem-U8UEKccv.d.ts} +6 -4
  122. package/dist/query/index.d.ts +2 -2
  123. package/dist/query/index.js +2 -2
  124. package/dist/{query-ChvDbsDE.js → query-BMMSWbI7.js} +19 -19
  125. package/dist/react/index.d.ts +7 -7
  126. package/dist/react/index.js +2 -2
  127. package/dist/react/server.d.ts +6 -6
  128. package/dist/react/server.js +3 -3
  129. package/dist/react/session.d.ts +21 -2
  130. package/dist/react/session.js +19 -1
  131. package/dist/{react-C83BdBGt.js → react-CQHMaESR.js} +59 -55
  132. package/dist/{read-set-4lI3W_gZ.js → read-set-FWK8qQ58.js} +51 -16
  133. package/dist/realtime/index.d.ts +4 -3
  134. package/dist/realtime/index.js +19 -17
  135. package/dist/{index-CG69s15v.d.ts → refresh-BwYkyNOQ.d.ts} +7 -3
  136. package/dist/{resolve-CjHILk2w.d.ts → resolve-BAqQcwMW.d.ts} +17 -11
  137. package/dist/{resource-CgZa3YG_.d.ts → resource-BJcaIfxi.d.ts} +17 -8
  138. package/dist/{resource-BHEWmQJK.js → resource-My_y-Syh.js} +43 -21
  139. package/dist/{respond-Dne1ARSa.d.ts → respond-DgIbdrt8.d.ts} +39 -14
  140. package/dist/{result-DWXatkd6.js → result-Bj6yt33D.js} +2 -2
  141. package/dist/{result-CTkCZ6JA.d.ts → result-CqEsbgYs.d.ts} +16 -11
  142. package/dist/server/index.d.ts +38 -13
  143. package/dist/server/index.js +43 -14
  144. package/dist/{respond-DMcbQwfN.js → server-BA75B0mT.js} +151 -96
  145. package/dist/{shared-_6-uPL7E.js → shared-DnoCdMDr.js} +4 -3
  146. package/dist/{simplify-bwJpLnaS.js → simplify-Cqvfr9dj.js} +76 -39
  147. package/dist/sql/index.d.ts +139 -0
  148. package/dist/sql/index.js +1983 -0
  149. package/dist/{sql-DTjA1LPj.js → sql-B34HU2DI.js} +74 -17
  150. package/dist/ssr/index.d.ts +4 -4
  151. package/dist/ssr/index.js +2 -2
  152. package/dist/{standard-FUi3Z3-7.js → standard-BRyBGTtp.js} +2 -2
  153. package/dist/{standard-CyhRzctb.d.ts → standard-BsaCYQJc.d.ts} +1 -1
  154. package/dist/{stats-C5W-rBfR.js → stats-C_YxA2r1.js} +40 -14
  155. package/dist/storage/index.d.ts +4 -3
  156. package/dist/storage/index.js +548 -1
  157. package/dist/{tables-rZxRxNPW.js → tables-Cb-3_VWc.js} +19 -5
  158. package/dist/temporal-BwshQk0W.js +27 -0
  159. package/dist/temporal-required-CBNHT6ni.js +19 -0
  160. package/dist/testing/index.d.ts +25 -24
  161. package/dist/testing/index.js +165 -66
  162. package/dist/{types-C83v5SQz.d.ts → types-DONv9SHN.d.ts} +14 -11
  163. package/dist/version-Bmf7_FzM.js +4 -0
  164. package/dist/{view-D1s0wa0T.d.ts → view-B64o81wp.d.ts} +36 -6
  165. package/dist/{view-aOYizTeE.js → view-BrJI2LKp.js} +11 -2
  166. package/dist/webhooks/index.d.ts +19 -17
  167. package/dist/webhooks/index.js +1 -1
  168. package/dist/{webhooks-DMipjhSP.js → webhooks-Bh_Jf_-l.js} +45 -24
  169. package/package.json +50 -22
  170. package/schemas/config-v1.json +31 -1
  171. package/schemas/doctor-report-v1.json +17 -1
  172. package/schemas/snapshot-v2.json +35 -0
  173. package/skills/better-supabase/SKILL.md +77 -18
  174. package/skills/better-supabase/references/plugins.md +21 -22
  175. package/skills/better-supabase/references/troubleshooting.md +38 -18
  176. package/skills/better-supabase-api/SKILL.md +66 -18
  177. package/skills/better-supabase-api/references/adapters.md +64 -41
  178. package/skills/better-supabase-auth/SKILL.md +146 -0
  179. package/skills/better-supabase-auth/references/permdock.md +55 -0
  180. package/skills/better-supabase-testing/SKILL.md +68 -11
  181. package/dist/casing-da0uRTqt.js +0 -14
  182. package/dist/claims-CoTobNC-.js +0 -25
  183. package/dist/cli-DrSgDOQC.js +0 -6646
  184. package/dist/env-BEToab0I.js +0 -204
  185. package/dist/events-BuzTgn2D.js +0 -135
  186. package/dist/pool-R2m_DkXi.d.ts +0 -37
  187. package/dist/seed-CzecODcJ.js +0 -101
  188. package/dist/session-C3LxnQ0e.d.ts +0 -22
  189. package/dist/session-CqEwzVup.js +0 -20
  190. package/dist/storage-DuGn38fr.js +0 -527
@@ -1,66 +1,66 @@
1
- import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "./claims-CoTobNC-.js";
2
- import { t as invalidateTables } from "./invalidate-DbxuL2jL.js";
3
- import { n as liveQuery, t as liveCount } from "./live-D8rV1Ldw.js";
4
- import { n as useSession } from "./session-CqEwzVup.js";
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/index.ts
7
- const BrowserContext = createContext(null);
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 browser client to the hooks. */
13
+ /** Provides the better-supabase client to the hooks. */
14
14
  function BetterSupabaseProvider(props) {
15
- const { browser, queryClient } = props;
15
+ const { client, queryClient } = props;
16
16
  const user = useRef(void 0);
17
- useEffect(() => browser.auth.subscribe(() => {
18
- const snapshot = browser.auth.current();
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
- }), [browser, queryClient]);
23
+ }), [client, queryClient]);
24
24
  const value = useMemo(() => ({
25
- browser,
25
+ client,
26
26
  queryClient
27
- }), [browser, queryClient]);
28
- return createElement(BrowserContext.Provider, { value }, props.children);
27
+ }), [client, queryClient]);
28
+ return createElement(ClientContext.Provider, { value }, props.children);
29
29
  }
30
- function useBrowserContext() {
31
- const value = useContext(BrowserContext);
32
- if (!value) throw new Error("better-supabase: wrap your app in <BetterSupabaseProvider browser={browser}>");
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 useBrowser() {
36
- return useBrowserContext().browser;
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 browser = useBrowser();
41
- return useSyncExternalStore(browser.auth.subscribe, browser.auth.current, () => LOADING);
40
+ const client = useClient();
41
+ return useSyncExternalStore(client.auth.subscribe, client.auth.current, () => LOADING);
42
42
  }
43
43
  function useSupabase() {
44
- return useBrowser().supabase;
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 browser>();
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 browser = useBrowser();
56
+ const client = useClient();
57
57
  useAuth();
58
- return browser.db;
58
+ return client.db;
59
59
  },
60
60
  useQueries() {
61
- const browser = useBrowser();
61
+ const client = useClient();
62
62
  useAuth();
63
- return browser.queries;
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 { browser, queryClient } = useBrowserContext();
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 void 0;
94
+ if (!name || auth.status === "loading") return;
95
95
  const matched = topic.match(name);
96
- if (!matched) return void 0;
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(browser.supabase, matched, { "*": forward }, {
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
- browser,
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 = sb.spec.customers.findMany({ include: { notes: true } });
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 { browser, queryClient } = useBrowserContext();
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, browser.sb.meta);
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 void 0;
157
- const live = liveQuery(browser.sb, browser.supabase, JSON.parse(key), {
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
- browser,
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 `next.liveCount()` seed; pass `null` to
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 next.liveCount(spec)
184
+ * const { count } = useLiveCount(seed); // seed = await bs.liveCount(spec)
185
185
  * ```
186
186
  */
187
187
  function useLiveCount(source, options = {}) {
188
- const { browser } = useBrowserContext();
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, browser.sb.meta);
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 void 0;
206
- const live = liveCount(browser.sb, browser.supabase, browser.db, JSON.parse(key), {
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) => setState({
209
- key,
210
- count,
211
- error: void 0
212
- }),
213
- onError: (error) => setState((previous) => ({
214
- key,
215
- count: previous.key === key ? previous.count : void 0,
216
- error
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
- browser,
230
+ client,
227
231
  key,
228
232
  tenant,
229
233
  userId,
@@ -1,5 +1,5 @@
1
- import { r as IrBuilder, u as tableMeta } from "./simplify-bwJpLnaS.js";
2
- import { n as touchedTables } from "./tables-rZxRxNPW.js";
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
- return readTables(meta, spec);
63
+ tables = readTables(meta, spec);
53
64
  } catch {
54
- return [spec.table];
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
- function readTables(meta, spec) {
58
- let builder = builders.get(meta);
59
- if (!builder) {
60
- builder = new IrBuilder(meta);
61
- builders.set(meta, builder);
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 = String.fromCharCode(0);
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
- * sb,
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(sb, name, options, build) {
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(sb.spec, placeholders);
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 sb.spec`);
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: sb
169
+ definition: betterSupabase
135
170
  };
136
171
  }
137
172
  function isReadSet(value) {
@@ -1,4 +1,5 @@
1
- import { x as PermdockTopicPolicy } from "../types-C83v5SQz.js";
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-DJyZMD6w.js";
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 };
@@ -1,11 +1,11 @@
1
- import { n as dbError } from "../errors-Bl3rkOzo.js";
2
- import { i as ok, n as err, t as AsyncResult } from "../result-DWXatkd6.js";
3
- import { i as tenantClaimPaths } from "../claims-CoTobNC-.js";
4
- import { n as liveQuery, r as liveTopic, t as liveCount } from "../live-D8rV1Ldw.js";
5
- import { s as toApp } from "../shared-_6-uPL7E.js";
6
- import { a as sqlString, i as sqlIdent, n as parseTemplate, r as slug, t as permdockCheck } from "../permdock-sql-CghlHPuH.js";
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/index.ts
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.replace(/\{[^}]+\}/g, " ");
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(sb, table, trigger) {
123
- const meta = sb.meta.tables[table];
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 ?? "public";
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
- if (isPrivate) await client.realtime.setAuth();
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(sb, table, message) {
255
- const meta = sb.meta.tables[table];
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-CjHILk2w.js";
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-CTkCZ6JA.js";
2
- import { f as Logger, l as RefreshEvent } from "./events-DOt3nSO-.js";
3
- import { h as RequestContext } from "./plugin-C4TR9J0Z.js";
4
- import { t as StandardSchemaV1 } from "./standard-CyhRzctb.js";
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 `sb.claims(schema)`; the
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 `sb.userMetadata(schema)`.
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 `sb.userMetadata(schema)`; `undefined`
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
- /** Refresh when the token expires within this many seconds. Defaults to 60. */
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 (`sb.claims(schema)` sets it). A failure
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` (`sb.userMetadata(schema)` sets
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, _ as Insert, n as AnyModels, t as AnyFunctions } from "./types-C83v5SQz.js";
2
- import { b as ValidationIssue, o as Result } from "./result-CTkCZ6JA.js";
3
- import { t as BetterSupabase, xt as SelectArg } from "./define-e3zI4_4g.js";
4
- import { r as RespondOptions } from "./respond-Dne1ARSa.js";
5
- import { i as ResourceOperation } from "./index-DbxFr7XG.js";
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
- /** Largest page for the default `page`/`size` list. Defaults to 200. */
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>>(sb: BetterSupabase<M, D, F, E>, table: T, options?: ResourceRouteOptions<M, T>): ResourceHandler;
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 { defineResource as a, ResourceRouteOptions as i, ResourceInput as n, ResourceList as r, ResourceHandler as t };
74
+ export { ResourceRouteOptions as a, ResourcePagination as i, ResourceInput as n, defineResource as o, ResourceList as r, ResourceHandler as t };