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.
Files changed (211) hide show
  1. package/README.md +9 -6
  2. package/bin/better-supabase.js +4 -0
  3. package/dist/{base64-CQeB1eSf.js → base64-D2gsioCY.js} +2 -2
  4. package/dist/channel-FQW-CnGR.d.ts +70 -0
  5. package/dist/claims-BAf6c7is.js +48 -0
  6. package/dist/cli/_format-Cax5EsM9.js +101 -0
  7. package/dist/cli/bin.d.ts +1 -0
  8. package/dist/cli/bin.js +48 -0
  9. package/dist/cli/codemod-DqV7612m.js +388 -0
  10. package/dist/cli/command-CK14fP91.js +502 -0
  11. package/dist/cli/compare-BmIWVEui.js +9 -0
  12. package/dist/cli/config-CPVpXP5I.js +1965 -0
  13. package/dist/cli/config-dtoekM0v.js +2 -0
  14. package/dist/cli/db-DOBPt660.js +52 -0
  15. package/dist/cli/diff-SjkO5rNr.js +752 -0
  16. package/dist/cli/dist-DBPdlPYK.js +1112 -0
  17. package/dist/cli/dist-DreZ24Sz.js +129 -0
  18. package/dist/cli/dist-xn4wlboc.js +732 -0
  19. package/dist/cli/doctor-L7Z8mYTx.js +2863 -0
  20. package/dist/cli/env-DmKv_G4A.js +108 -0
  21. package/dist/cli/env-jIFUADLY.js +511 -0
  22. package/dist/cli/errors-4v4DTtda.js +56 -0
  23. package/dist/cli/fastest-levenshtein-CFN-lNDv.js +120 -0
  24. package/dist/cli/gen-BJc9vdyu.js +2 -0
  25. package/dist/cli/gen-C2osRcr5.js +2204 -0
  26. package/dist/cli/index.d.ts +493 -0
  27. package/dist/cli/index.js +184 -0
  28. package/dist/cli/init-Saf5-R9T.js +550 -0
  29. package/dist/cli/introspect--H7oGmcd.js +81 -0
  30. package/dist/cli/io-k41_z-jT.js +24 -0
  31. package/dist/cli/json5-ChRycquj.js +787 -0
  32. package/dist/cli/jsonc-BUniUpOk.js +2 -0
  33. package/dist/cli/jsonc-D5Fu67jw.js +45 -0
  34. package/dist/cli/keys-ByKHnvP9.js +83 -0
  35. package/dist/cli/ohash-D7bG_EOb.js +277 -0
  36. package/dist/cli/openapi-Cp5Fyta-.js +66 -0
  37. package/dist/cli/project-B_GeXyHh.js +70 -0
  38. package/dist/cli/prompts-BNcNfAve.js +1142 -0
  39. package/dist/cli/prompts-BTYQGunc.js +2 -0
  40. package/dist/cli/read-sets-BfMQcKy8.js +289 -0
  41. package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
  42. package/dist/cli/run-BKR2W_79.js +351 -0
  43. package/dist/cli/seed-CUlqWh-8.js +98 -0
  44. package/dist/cli/skills-LJJIhLFR.js +137 -0
  45. package/dist/cli/sql-DzPbfngx.js +348 -0
  46. package/dist/cli/style-C0NFdJRL.js +29 -0
  47. package/dist/cli/toml-DB-MNnFs.js +424 -0
  48. package/dist/cli/version-BDJuO0UR.js +4 -0
  49. package/dist/cli/yaml-CYCbJ6et.js +2252 -0
  50. package/dist/client/index.d.ts +2 -2
  51. package/dist/client/index.js +15 -22
  52. package/dist/clone-BfgmLU90.js +21 -0
  53. package/dist/{compiler-2zqGzxVZ.d.ts → compiler-BXH_aZ7N.d.ts} +2 -2
  54. package/dist/config/index.d.ts +4 -4
  55. package/dist/config/index.js +5 -5
  56. package/dist/{config-DOsGYSiT.js → config-DreERlKo.js} +1 -1
  57. package/dist/{config-C1CYcm6o.d.ts → config-T_ejwyd3.d.ts} +176 -11
  58. package/dist/{define-DUbydmJa.d.ts → define-Bp_BZa5h.d.ts} +37 -29
  59. package/dist/{define-DF341GDj.js → define-cNKzqwL_.js} +356 -89
  60. package/dist/edge/index.d.ts +20 -13
  61. package/dist/edge/index.js +55 -26
  62. package/dist/{entitlements-DvJXoI02.d.ts → entitlements-DUxU4oHe.d.ts} +2 -2
  63. package/dist/env/index.d.ts +2 -2
  64. package/dist/env/index.js +34 -1
  65. package/dist/{errors-Bl3rkOzo.js → errors-DtwXa6b8.js} +2 -1
  66. package/dist/events/index.d.ts +3 -2
  67. package/dist/events/index.js +69 -16
  68. package/dist/events-aIO7vsIk.d.ts +230 -0
  69. package/dist/executor-BunPOO-k.d.ts +402 -0
  70. package/dist/{executor-B26lgbHD.d.ts → executor-Cghdstwu.d.ts} +1 -2
  71. package/dist/{executor-C57jx2pn.js → executor-XycESQPH.js} +3 -3
  72. package/dist/hono/index.d.ts +27 -23
  73. package/dist/hono/index.js +46 -11
  74. package/dist/impersonation-VfaGc4Q_.js +41 -0
  75. package/dist/{index-BNsABq7P.d.ts → index-BGdgBPdf.d.ts} +66 -25
  76. package/dist/{index-qriRM9cZ.d.ts → index-C7f8cOBM.d.ts} +4 -4
  77. package/dist/{index-Dy6kuF0P.d.ts → index-CLg87OBW.d.ts} +6 -1
  78. package/dist/{index-GV77NpRP.d.ts → index-DOESKG27.d.ts} +34 -9
  79. package/dist/{index-CriFFJ_p.d.ts → index-DgILJRXj.d.ts} +43 -17
  80. package/dist/{index-UJ-LUxtI.d.ts → index-DmXSxbLi.d.ts} +14 -14
  81. package/dist/{index-Cf-D2jk1.d.ts → index-Dxn2a5cw.d.ts} +2 -2
  82. package/dist/{index-CTTMS6_1.d.ts → index-SaTsEfGP.d.ts} +86 -9
  83. package/dist/{index-CADlNHK-.d.ts → index-fag8VJZ2.d.ts} +5 -6
  84. package/dist/index.d.ts +34 -17
  85. package/dist/index.js +15 -14
  86. package/dist/jobs/index.d.ts +147 -95
  87. package/dist/jobs/index.js +773 -250
  88. package/dist/{json-schema--aOXAGfU.js → json-schema-m1fiwKgN.js} +23 -2
  89. package/dist/kit-events-CTFDfSwb.js +60 -0
  90. package/dist/kit-transport-B82k1djG.d.ts +33 -0
  91. package/dist/kit-transport-DJlHQUBU.js +55 -0
  92. package/dist/{config-Be4GwsqI.js → kits-CGLLrNPd.js} +38 -10
  93. package/dist/list/index.d.ts +1 -1
  94. package/dist/list/index.js +3 -3
  95. package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
  96. package/dist/{live-QE3UPbGm.d.ts → live-D9W2M5aO.d.ts} +16 -15
  97. package/dist/lookup-BaP5bI27.js +18 -0
  98. package/dist/mcp/index.d.ts +39 -22
  99. package/dist/mcp/index.js +39 -25
  100. package/dist/{mfa-x3V3vGh-.d.ts → mfa-CusDgPaD.d.ts} +5 -1
  101. package/dist/next/image/index.js +6 -3
  102. package/dist/next/index.d.ts +60 -36
  103. package/dist/next/index.js +167 -50
  104. package/dist/notifications/index.d.ts +162 -0
  105. package/dist/notifications/index.js +264 -0
  106. package/dist/openapi/index.d.ts +1 -1
  107. package/dist/openapi/index.js +6 -6
  108. package/dist/orgs/index.d.ts +132 -0
  109. package/dist/orgs/index.js +245 -0
  110. package/dist/orpc/index.d.ts +37 -20
  111. package/dist/orpc/index.js +24 -11
  112. package/dist/otel/index.d.ts +24 -5
  113. package/dist/otel/index.js +124 -64
  114. package/dist/permdock-sql-C2Inc6Xc.d.ts +29 -0
  115. package/dist/permdock-sql-DgOfeixi.js +51 -0
  116. package/dist/plugin-DwARMuQp.js +59 -0
  117. package/dist/{plugin-DVRB8qNE.d.ts → plugin-o144f322.d.ts} +17 -5
  118. package/dist/plugins/actor/index.d.ts +5 -2
  119. package/dist/plugins/actor/index.js +22 -8
  120. package/dist/plugins/rules/index.d.ts +2 -2
  121. package/dist/plugins/rules/index.js +52 -17
  122. package/dist/plugins/soft-delete/index.d.ts +3 -3
  123. package/dist/plugins/soft-delete/index.js +14 -5
  124. package/dist/plugins/tenant/index.d.ts +3 -3
  125. package/dist/plugins/tenant/index.js +45 -21
  126. package/dist/plugins/timestamps/index.d.ts +1 -1
  127. package/dist/plugins/timestamps/index.js +4 -3
  128. package/dist/plugins/validation/index.d.ts +2 -2
  129. package/dist/plugins/validation/index.js +26 -6
  130. package/dist/{pool-B9qsLyFR.d.ts → pool-C9voM4Kw.d.ts} +24 -6
  131. package/dist/postgres/index.d.ts +5 -5
  132. package/dist/postgres/index.js +20 -10
  133. package/dist/{postgrest-DmBlevh-.d.ts → postgrest-CruYKAvV.d.ts} +1 -1
  134. package/dist/{problem-CGt1ADix.js → problem-BW1KhzSG.js} +2 -1
  135. package/dist/{problem-Z2RTQjZD.d.ts → problem-Blxe8S31.d.ts} +1 -1
  136. package/dist/query/index.d.ts +2 -2
  137. package/dist/query/index.js +3 -3
  138. package/dist/{query-BdKLTPlj.js → query-CCbo44lG.js} +18 -18
  139. package/dist/queue-BYUCjr59.d.ts +252 -0
  140. package/dist/react/index.d.ts +8 -7
  141. package/dist/react/index.js +4 -3
  142. package/dist/react/server.d.ts +16 -5
  143. package/dist/react/server.js +12 -4
  144. package/dist/react/session.d.ts +10 -4
  145. package/dist/react/session.js +11 -3
  146. package/dist/{react-DNBYNazu.js → react-C_s7kiNz.js} +138 -46
  147. package/dist/{read-set-D0qBcboM.js → read-set-DQFt1N_Y.js} +71 -15
  148. package/dist/realtime/index.d.ts +3 -3
  149. package/dist/realtime/index.js +14 -12
  150. package/dist/{index-kpgopLNv.d.ts → refresh-BTrQ_ZTp.d.ts} +6 -3
  151. package/dist/{resolve-BRciX2jK.d.ts → resolve-C15TJq77.d.ts} +22 -11
  152. package/dist/{resource-D30rp0GN.js → resource-CRxxwkQq.js} +24 -9
  153. package/dist/{resource-CwVgiI5q.d.ts → resource-D8iqWMr-.d.ts} +6 -6
  154. package/dist/respond-D2OQl62-.d.ts +371 -0
  155. package/dist/{result-DWXatkd6.js → result-BKiliPY7.js} +2 -2
  156. package/dist/server/index.d.ts +17 -15
  157. package/dist/server/index.js +16 -22
  158. package/dist/server-Csx2sRjg.js +655 -0
  159. package/dist/{shared-_6-uPL7E.js → shared-D1dRUrAg.js} +19 -4
  160. package/dist/signers-Cc6r98SW.d.ts +162 -0
  161. package/dist/{simplify-LakqK1vH.js → simplify-_0oUKqCd.js} +27 -95
  162. package/dist/sql/index.d.ts +247 -10
  163. package/dist/sql/index.js +8591 -780
  164. package/dist/{sql-BIgk12ew.js → sql-Coh6n4cC.js} +11 -3
  165. package/dist/ssr/index.d.ts +4 -4
  166. package/dist/ssr/index.js +1 -2
  167. package/dist/{standard-FUi3Z3-7.js → standard-D7r6dMUu.js} +6 -3
  168. package/dist/{standard-eudBiRk1.d.ts → standard-J4YgMOLm.d.ts} +1 -1
  169. package/dist/{stats-D78UQ8Yu.js → stats-Bqob3WqT.js} +34 -9
  170. package/dist/storage/index.d.ts +4 -4
  171. package/dist/storage/index.js +174 -27
  172. package/dist/support-DT-OhSxD.d.ts +88 -0
  173. package/dist/support-Dk6vdmEw.js +291 -0
  174. package/dist/support-view-Da5peKFg.d.ts +17 -0
  175. package/dist/support-view-g4YLBeqX.js +18 -0
  176. package/dist/{tables-Dhha3BXM.js → tables-Cb-3_VWc.js} +14 -0
  177. package/dist/{permdock-sql-Bta_G0v-.js → template-TxrGI5jR.js} +2 -31
  178. package/dist/{temporal-BwshQk0W.js → temporal-CVlIV2DZ.js} +17 -4
  179. package/dist/{temporal-required-CMxeSVPo.js → temporal-required-CAt4Dc9Z.js} +2 -2
  180. package/dist/testing/index.d.ts +113 -24
  181. package/dist/testing/index.js +375 -47
  182. package/dist/{types-DONv9SHN.d.ts → types-Dnf_wRDz.d.ts} +26 -3
  183. package/dist/user-change-CHFEUro1.js +49 -0
  184. package/dist/{webhooks-CAIFQSTM.js → verify-Ce49ETPz.js} +38 -19
  185. package/dist/{version-BfpG2gks.js → version-DM_Roffb.js} +1 -1
  186. package/dist/{view-3Po_PVlr.d.ts → view-BEf0diC5.d.ts} +10 -5
  187. package/dist/{mfa-BxoR1RkN.js → view-Bq64ki8-.js} +210 -64
  188. package/dist/webhooks/index.d.ts +136 -5
  189. package/dist/webhooks/index.js +588 -2
  190. package/dist/wire-D2dT86vi.js +35 -0
  191. package/package.json +50 -10
  192. package/schemas/config-v1.json +131 -1
  193. package/schemas/doctor-report-v1.json +10 -0
  194. package/skills/better-supabase/SKILL.md +60 -10
  195. package/skills/better-supabase/references/plugins.md +13 -14
  196. package/skills/better-supabase/references/troubleshooting.md +25 -4
  197. package/skills/better-supabase-api/SKILL.md +74 -19
  198. package/skills/better-supabase-api/references/adapters.md +48 -27
  199. package/skills/better-supabase-auth/SKILL.md +149 -0
  200. package/skills/better-supabase-auth/references/permdock.md +100 -0
  201. package/skills/better-supabase-testing/SKILL.md +58 -4
  202. package/dist/claims-CoTobNC-.js +0 -25
  203. package/dist/events-Do8jXh4D.d.ts +0 -84
  204. package/dist/executor-DynmIWhq.d.ts +0 -195
  205. package/dist/invalidate-DbxuL2jL.js +0 -18
  206. package/dist/permdock-sql-DImJULY-.d.ts +0 -17
  207. package/dist/plugin-BqR6wKMB.js +0 -23
  208. package/dist/respond-C44EZAJo.js +0 -399
  209. package/dist/respond-DAkPIdTH.d.ts +0 -175
  210. package/dist/result-c2OYgCV2.d.ts +0 -203
  211. package/dist/view-wZ-9qIUz.js +0 -45
@@ -1,8 +1,8 @@
1
- import { t as DbException } from "./errors-Bl3rkOzo.js";
2
- import { t as invalidationTargets } from "./tables-Dhha3BXM.js";
3
- import { t as invalidateTables } from "./invalidate-DbxuL2jL.js";
1
+ import { t as DbException } from "./errors-DtwXa6b8.js";
2
+ import { t as invalidationTargets } from "./tables-Cb-3_VWc.js";
3
+ import { n as invalidateTables } from "./user-change-CHFEUro1.js";
4
4
  //#region src/query/queries.ts
5
- /** Query errors stay `DbException`s, even for an `sb` with `mapError()`. */
5
+ /** Query errors stay `DbException`s, even for an `betterSupabase` with `mapError()`. */
6
6
  const asException = (error) => new DbException(error);
7
7
  function isSkip(value) {
8
8
  return typeof value === "symbol";
@@ -28,13 +28,13 @@ function specQuery(runtime, spec, key) {
28
28
  ...spec.args
29
29
  ],
30
30
  queryFn: ({ signal }) => runtime.db().$run(spec, { signal }).orThrow(asException),
31
- meta: { bsTables: runtime.sb.tablesOf(spec) },
31
+ meta: { bsTables: runtime.betterSupabase.tablesOf(spec) },
32
32
  ...stale
33
33
  };
34
34
  }
35
35
  function tableQueries(runtime, table) {
36
36
  const key = ["bs", table];
37
- const specs = runtime.sb.spec[table];
37
+ const specs = runtime.betterSupabase.spec[table];
38
38
  const stale = runtime.staleTime === void 0 ? {} : { staleTime: runtime.staleTime };
39
39
  const read = (method) => (args) => isSkip(args) ? specQuery(runtime, args, [
40
40
  ...key,
@@ -84,7 +84,7 @@ function tableQueries(runtime, table) {
84
84
  }), { signal }).orThrow(asException),
85
85
  initialPageParam: null,
86
86
  getNextPageParam: (last) => last.nextCursor ?? void 0,
87
- meta: { bsTables: runtime.sb.tablesOf(specs["paginate"]({
87
+ meta: { bsTables: runtime.betterSupabase.tablesOf(specs["paginate"]({
88
88
  ...base,
89
89
  after: null
90
90
  })) },
@@ -105,14 +105,14 @@ function tableQueries(runtime, table) {
105
105
  }), { signal }).orThrow(asException),
106
106
  initialPageParam: base.page ?? 1,
107
107
  getNextPageParam: (last) => last.page.hasMore ? last.page.number + 1 : void 0,
108
- meta: { bsTables: runtime.sb.tablesOf(specs["paginate"](base)) },
108
+ meta: { bsTables: runtime.betterSupabase.tablesOf(specs["paginate"](base)) },
109
109
  ...stale
110
110
  };
111
111
  },
112
112
  create: (args) => mutation("create", (data) => call("create", data, args), [table]),
113
113
  update: (args) => mutation("update", (variables) => call("update", variables.id, variables.patch, args), [table]),
114
114
  upsert: (args) => mutation("upsert", (data) => call("upsert", data, args), [table]),
115
- delete: (args) => mutation("delete", (id) => call("delete", id, args), invalidationTargets(runtime.sb.meta, table))
115
+ delete: (args) => mutation("delete", (id) => call("delete", id, args), invalidationTargets(runtime.betterSupabase.meta, table))
116
116
  };
117
117
  }
118
118
  /**
@@ -123,19 +123,19 @@ function tableQueries(runtime, table) {
123
123
  * changed table.
124
124
  *
125
125
  * ```ts
126
- * const q = createQueries(sb, () => browser.db);
126
+ * const q = createQueries(betterSupabase, () => bs.db);
127
127
  * const { data } = useQuery(q.customers.findMany({ select: ['id', 'name'] }));
128
128
  * ```
129
129
  */
130
- function createQueries(sb, db, options = {}) {
130
+ function createQueries(betterSupabase, db, options = {}) {
131
131
  const runtime = {
132
- sb,
132
+ betterSupabase,
133
133
  db: typeof db === "function" ? db : () => db,
134
134
  staleTime: options.staleTime
135
135
  };
136
136
  const stale = options.staleTime === void 0 ? {} : { staleTime: options.staleTime };
137
137
  const queries = {
138
- key: ["bs"],
138
+ $key: ["bs"],
139
139
  $spec: (spec) => specQuery(runtime, spec),
140
140
  $prefetch: (client, spec) => client.prefetchQuery(specQuery(runtime, spec)),
141
141
  $rpc: (name, args, rpcOptions = {}) => ({
@@ -156,10 +156,10 @@ function createQueries(sb, db, options = {}) {
156
156
  name
157
157
  ],
158
158
  mutationFn: (args) => runtime.db().$rpc(name, args ?? {}).orThrow(asException),
159
- onSuccess: (_data, _variables, _result, context) => invalidateTables(context.client, (sb.options.rpc?.[name]?.invalidates ?? []).flatMap((table) => invalidationTargets(sb.meta, table)))
159
+ onSuccess: (_data, _variables, _result, context) => invalidateTables(context.client, (betterSupabase.options.rpc?.[name]?.invalidates ?? []).flatMap((table) => invalidationTargets(betterSupabase.meta, table)))
160
160
  })
161
161
  };
162
- for (const table of Object.keys(sb.meta.tables)) {
162
+ for (const table of Object.keys(betterSupabase.meta.tables)) {
163
163
  let built;
164
164
  Object.defineProperty(queries, table, {
165
165
  enumerable: true,
@@ -178,9 +178,9 @@ function queryCache(client) {
178
178
  invalidate: (target) => invalidateTables(client, target.tables)
179
179
  };
180
180
  }
181
- /** Invalidates affected queries for every mutation and declared RPC `sb` performs in this runtime. */
182
- function invalidateOnMutation(sb, client) {
183
- return sb.cache(queryCache(client));
181
+ /** Invalidates affected queries for every mutation and declared RPC `betterSupabase` performs in this runtime. */
182
+ function invalidateOnMutation(betterSupabase, client) {
183
+ return betterSupabase.cache(queryCache(client));
184
184
  }
185
185
  //#endregion
186
186
  export { invalidateOnMutation as n, queryCache as r, createQueries as t };
@@ -0,0 +1,252 @@
1
+ /// <reference lib="esnext.temporal" />
2
+ import { _ as DbError, a as AsyncResult } from "./executor-BunPOO-k.js";
3
+ import { g as RequestContext, t as Actor } from "./plugin-o144f322.js";
4
+ import { t as SqlClient } from "./executor-Cghdstwu.js";
5
+ import { StandardSchemaV1 } from "@standard-schema/spec";
6
+ //#region src/jobs/queue.d.ts
7
+ type QueueSchemas = Readonly<Record<string, StandardSchemaV1>>;
8
+ type PayloadIn<Q extends QueueSchemas, N extends keyof Q> = StandardSchemaV1.InferInput<Q[N]>;
9
+ type PayloadOut<Q extends QueueSchemas, N extends keyof Q> = StandardSchemaV1.InferOutput<Q[N]>;
10
+ /** The actor and tenant of the request that enqueued a job. */
11
+ interface JobContext {
12
+ readonly actor?: Actor;
13
+ readonly tenant?: string;
14
+ }
15
+ interface Job<P = unknown> {
16
+ /** The pgmq message id. */
17
+ readonly id: number;
18
+ readonly queue: string;
19
+ readonly payload: P;
20
+ /** 1 on the first run (pgmq's `read_ct`). */
21
+ readonly attempts: number;
22
+ readonly maxAttempts: number;
23
+ readonly enqueuedAt: Temporal.Instant;
24
+ /** End of the lease: the job becomes claimable again after this. */
25
+ readonly visibleUntil: Temporal.Instant;
26
+ readonly lastError: string | null;
27
+ /**
28
+ * The actor and tenant recorded at enqueue, ready for `db.$with(job.context)`.
29
+ * Without a recorded tenant, `tenant()` applies its `onMissing` unless the
30
+ * worker runs with `allTenants: true`.
31
+ */
32
+ readonly context: RequestContext;
33
+ }
34
+ interface EnqueueOptions {
35
+ /** Run no earlier than this. */
36
+ readonly runAt?: Temporal.Instant;
37
+ /** Seconds to wait before running. */
38
+ readonly delay?: number;
39
+ /** Defaults to 5. After this many failed attempts the job is archived as dead. */
40
+ readonly maxAttempts?: number;
41
+ /**
42
+ * While a job with this key is waiting or running, enqueueing again returns
43
+ * its id. SQL connections only.
44
+ */
45
+ readonly dedupeKey?: string;
46
+ /**
47
+ * The request context whose actor and tenant the job records, next to the
48
+ * payload. The tenant is `context.tenant`, the one `tenant()` resolved, or
49
+ * the `tenant_id` claim (then `app_metadata.tenant_id`).
50
+ */
51
+ readonly context?: RequestContext;
52
+ }
53
+ interface ScheduleOptions {
54
+ /** The actor and tenant every scheduled run records, as in `enqueue`. */
55
+ readonly context?: RequestContext;
56
+ /**
57
+ * The IANA time zone the cron fields are read in. Defaults to `UTC`.
58
+ * Other zones need `kits.jobs.options.scheduler: "drain"`.
59
+ */
60
+ readonly timeZone?: string;
61
+ }
62
+ interface RunSchedulesOptions {
63
+ /** Seconds a claimed schedule stays leased. Defaults to 60. */
64
+ readonly lease?: number;
65
+ /** Defaults to 100. */
66
+ readonly batch?: number;
67
+ }
68
+ interface DrainOptions extends Omit<WorkOptions, "pollInterval" | "maxPollInterval" | "signal"> {
69
+ /** Stop claiming after this many ms; claimed jobs still finish. */
70
+ readonly budgetMs?: number;
71
+ }
72
+ interface DrainRouteOptions<Q extends QueueSchemas> extends Omit<DrainOptions, "onError"> {
73
+ /**
74
+ * The bearer token callers send (`Authorization: Bearer <secret>`), such
75
+ * as Vercel's `CRON_SECRET`. Required.
76
+ */
77
+ readonly secret: string | undefined;
78
+ /** The queues to drain, in order, with their handlers. */
79
+ readonly handlers: { readonly [N in Extract<keyof Q, string>]?: JobHandler<PayloadOut<Q, N>>; };
80
+ /** Total time in ms for schedules and queues. Defaults to 50000. */
81
+ readonly budgetMs?: number;
82
+ /** Enqueue due schedules first (the drain scheduler). Defaults to true. */
83
+ readonly schedules?: boolean;
84
+ readonly onError?: (error: DbError, job?: Job) => void;
85
+ }
86
+ interface DrainRouteResult {
87
+ /** Schedules whose run was enqueued. */
88
+ readonly schedules: number;
89
+ readonly queues: Readonly<Record<string, DrainResult>>;
90
+ /** True when the budget ran out before every queue was empty. */
91
+ readonly budgetExhausted: boolean;
92
+ }
93
+ interface ClaimOptions {
94
+ /** Defaults to 1. */
95
+ readonly batch?: number;
96
+ /** Seconds a claimed job stays invisible to other workers. Defaults to 300. */
97
+ readonly lease?: number;
98
+ }
99
+ interface FailOptions {
100
+ /** Retry after this many seconds instead of the exponential backoff. SQL connections only. */
101
+ readonly retryIn?: number;
102
+ }
103
+ type JobHandler<P> = (payload: P, job: Job<P>, signal: AbortSignal) => unknown;
104
+ interface WorkOptions extends ClaimOptions {
105
+ /** Jobs handled at once. Defaults to 1. */
106
+ readonly concurrency?: number;
107
+ /**
108
+ * First wait between polls when the queue is empty, in ms. Defaults to
109
+ * 1000. Each empty poll doubles the wait up to `maxPollInterval`; a claimed
110
+ * job resets it.
111
+ */
112
+ readonly pollInterval?: number;
113
+ /** Longest wait between empty polls, in ms. Defaults to 30000. */
114
+ readonly maxPollInterval?: number;
115
+ /** Stops the loop; running jobs finish first. */
116
+ readonly signal?: AbortSignal;
117
+ readonly onError?: (error: DbError, job: Job) => void;
118
+ /**
119
+ * Run jobs that recorded no tenant with a context that `tenant()` and
120
+ * tenant buckets don't scope. Off by default, so such jobs get the
121
+ * `onMissing` of `tenant()`.
122
+ */
123
+ readonly allTenants?: boolean;
124
+ }
125
+ interface DrainResult {
126
+ readonly succeeded: number;
127
+ readonly failed: number;
128
+ }
129
+ interface Jobs<Q extends QueueSchemas> {
130
+ /** Validates the payload with the queue's schema, then enqueues it. Returns the job id. */
131
+ enqueue<N extends Extract<keyof Q, string>>(queue: N, payload: PayloadIn<Q, N>, options?: EnqueueOptions): AsyncResult<number>;
132
+ claim<N extends Extract<keyof Q, string>>(queue: N, options?: ClaimOptions): AsyncResult<Job<PayloadOut<Q, N>>[]>;
133
+ /** Archives the job. `false` when the lease was lost (another worker claimed it since). */
134
+ complete(job: Job): AsyncResult<boolean>;
135
+ /** Returns the new state: `queued` (will retry), `dead` (archived), or `null` when the lease was lost. */
136
+ fail(job: Job, error: unknown, options?: FailOptions): AsyncResult<"queued" | "dead" | null>;
137
+ /** Pushes the lease out by `lease` seconds. `false` when it was lost or the transport can't. */
138
+ extend(job: Job, lease: number): AsyncResult<boolean>;
139
+ /**
140
+ * Enqueues a dead letter again with its payload and attempts, and removes
141
+ * it from the archive. Returns the new id, or `null` when `id` is not a
142
+ * dead letter of `queue`. SQL connections only.
143
+ */
144
+ replay(queue: Extract<keyof Q, string>, id: number): AsyncResult<number | null>;
145
+ /**
146
+ * Enqueues `payload` on a cron schedule (`'0 3 * * *'`, `'@daily'`,
147
+ * `'30 seconds'`), with pg_cron or the drain scheduler
148
+ * (`kits.jobs.options.scheduler`). Re-scheduling a name replaces it. SQL
149
+ * connections only.
150
+ */
151
+ schedule<N extends Extract<keyof Q, string>>(name: string, cron: string, queue: N, payload: PayloadIn<Q, N>, options?: ScheduleOptions): AsyncResult<void>;
152
+ unschedule(name: string): AsyncResult<boolean>;
153
+ /**
154
+ * Enqueues one run of every due schedule (the drain scheduler) and moves
155
+ * it to its next time. Returns how many ran. Missed runs collapse into one.
156
+ */
157
+ runSchedules(options?: RunSchedulesOptions): AsyncResult<number>;
158
+ /** Processes ready jobs until the queue is empty or the budget is spent. For cron and edge invocations. */
159
+ drain<N extends Extract<keyof Q, string>>(queue: N, handler: JobHandler<PayloadOut<Q, N>>, options?: DrainOptions): Promise<DrainResult>;
160
+ /**
161
+ * A route handler for a cron caller such as Vercel Cron: checks the bearer
162
+ * secret, runs due schedules, then drains each queue in `handlers` within
163
+ * the budget, and answers with a `DrainRouteResult`.
164
+ */
165
+ drainRoute(options: DrainRouteOptions<Q>): (request: Request) => Promise<Response>;
166
+ /** Polls and processes jobs until `signal` aborts. */
167
+ work<N extends Extract<keyof Q, string>>(queue: N, handler: JobHandler<PayloadOut<Q, N>>, options?: WorkOptions): Promise<DrainResult>;
168
+ }
169
+ /** The body of a queued message, on pgmq and the table backend alike. */
170
+ interface QueueMessageBody {
171
+ readonly payload?: unknown;
172
+ readonly max_attempts?: number;
173
+ readonly last_error?: string;
174
+ }
175
+ /** A claimed message, as `better_supabase.claim_jobs` returns it. */
176
+ interface QueueMessageRow {
177
+ readonly id: string | number;
178
+ /** 1 on the first claim; a lease token for complete, fail and extend. */
179
+ readonly attempts: number;
180
+ readonly enqueued_at: Date | string;
181
+ readonly visible_until: Date | string;
182
+ readonly message: QueueMessageBody | null;
183
+ }
184
+ /** A schedule whose run is due, claimed by `runSchedules`. */
185
+ interface DueSchedule {
186
+ readonly name: string;
187
+ readonly cron: string;
188
+ readonly timeZone: string;
189
+ readonly queue: string;
190
+ /** The payload as stored, with its recorded context. */
191
+ readonly payload: unknown;
192
+ readonly nextRun: Temporal.Instant;
193
+ }
194
+ /** A Supabase client, or anything with `.schema(name).rpc(fn, args)`. */
195
+ interface QueueRpcClient {
196
+ schema(name: string): {
197
+ rpc(fn: string, args: Readonly<Record<string, unknown>>): PromiseLike<{
198
+ data: unknown;
199
+ error: unknown;
200
+ }>;
201
+ };
202
+ }
203
+ /**
204
+ * Where `createJobs` stores jobs. `sqlQueueBackend` (the `jobs` SQL kit
205
+ * module, on pgmq or its table backend) and `pgmqPublicBackend` ship with
206
+ * the package; `testQueueBackend` from `better-supabase/testing` checks
207
+ * another one.
208
+ */
209
+ interface QueueBackend {
210
+ readonly apiVersion: 1;
211
+ readonly name: string;
212
+ /** Whether `extend` works, so long-running batches keep their lease. */
213
+ readonly leases: boolean;
214
+ send(queue: string, payload: unknown, delay: number, maxAttempts: number, dedupeKey: string | undefined): Promise<number>;
215
+ read(queue: string, lease: number, batch: number): Promise<readonly QueueMessageRow[]>;
216
+ /** `false` when the lease was lost. */
217
+ complete(job: Job): Promise<boolean>;
218
+ fail(job: Job, error: string, retryIn: number | undefined): Promise<"queued" | "dead" | null>;
219
+ extend(job: Job, lease: number): Promise<boolean>;
220
+ /** Re-enqueues a dead letter; `null` when it isn't one. Absent when the backend can't. */
221
+ replay?(queue: string, id: number): Promise<number | null>;
222
+ schedule(name: string, cron: string, queue: string, payload: unknown, timeZone: string, nextRun: Temporal.Instant): Promise<void>;
223
+ unschedule(name: string): Promise<boolean>;
224
+ /** Leases due schedules (the drain scheduler); absent or empty with pg_cron. */
225
+ dueSchedules?(lease: number, batch: number): Promise<readonly DueSchedule[]>;
226
+ /** Moves a schedule from `ran` to `next`; `false` when it changed since the claim. */
227
+ advanceSchedule?(name: string, ran: Temporal.Instant, next: Temporal.Instant): Promise<boolean>;
228
+ }
229
+ /**
230
+ * The `jobs` SQL kit module over a service SQL connection. The same
231
+ * functions back both `kits.jobs.options.backend` values (pgmq and table)
232
+ * and both schedulers.
233
+ */
234
+ declare function sqlQueueBackend(sql: SqlClient): QueueBackend;
235
+ /**
236
+ * Supabase's `pgmq_public` RPCs (Integrations, Queues, "Expose Queues via
237
+ * PostgREST"). No lease check on complete, no retry delay, no deduplication
238
+ * and no schedules: a failed job reappears when its lease ends.
239
+ */
240
+ declare function pgmqPublicBackend(client: QueueRpcClient): QueueBackend;
241
+ /**
242
+ * Typed jobs on Supabase Queues (pgmq), over the `jobs` SQL kit module.
243
+ *
244
+ * Pass a service SQL connection (`postgres.admin`, `ctx.sql`) for the full
245
+ * feature set, a service-role Supabase client to go through the
246
+ * `pgmq_public` RPCs where no direct connection exists (edge functions), or
247
+ * any `QueueBackend`. Queue names are lowercase letters, digits and
248
+ * underscores.
249
+ */
250
+ declare function createJobs<const Q extends QueueSchemas>(source: SqlClient | QueueRpcClient | QueueBackend, queues: Q): Jobs<Q>;
251
+ //#endregion
252
+ export { sqlQueueBackend as C, pgmqPublicBackend as S, QueueSchemas as _, DrainRouteResult as a, WorkOptions as b, FailOptions as c, JobHandler as d, Jobs as f, QueueRpcClient as g, QueueMessageRow as h, DrainRouteOptions as i, Job as l, QueueMessageBody as m, DrainOptions as n, DueSchedule as o, QueueBackend as p, DrainResult as r, EnqueueOptions as s, ClaimOptions as t, JobContext as u, RunSchedulesOptions as v, createJobs as x, ScheduleOptions as y };
@@ -1,7 +1,8 @@
1
- import { s as Impersonator } from "../mfa-x3V3vGh-.js";
2
- import { t as AuthSession } from "../view-3Po_PVlr.js";
3
- import { r as LiveCountSeed } from "../live-QE3UPbGm.js";
4
- import { n as MembershipClaim, r as hasEntitlement, t as EntitlementKey } from "../entitlements-DvJXoI02.js";
5
- import { a as BrowserLike, c as LiveCountHookOptions, d as createHooks, f as useAuth, g as useSupabase, h as useLiveQuery, i as BroadcastOptions, l as LiveQueryHookOptions, m as useLiveCount, n as BetterSupabaseProvider, o as ClaimsOf, p as useBroadcast, r as BetterSupabaseProviderProps, s as LiveCount, t as BetterHooks, u as ProfileOf } from "../index-BNsABq7P.js";
6
- import { SessionProvider, SessionProviderProps, useSession } from "./session.js";
7
- export { type AuthSession, type BetterHooks, BetterSupabaseProvider, type BetterSupabaseProviderProps, type BroadcastOptions, type BrowserLike, type ClaimsOf, type EntitlementKey, type Impersonator, type LiveCount, type LiveCountHookOptions, type LiveCountSeed, type LiveQueryHookOptions, type MembershipClaim, type ProfileOf, SessionProvider, type SessionProviderProps, createHooks, hasEntitlement, useAuth, useBroadcast, useLiveCount, useLiveQuery, useSession, useSupabase };
1
+ import { s as Impersonator } from "../mfa-CusDgPaD.js";
2
+ import { t as AuthSession } from "../view-BEf0diC5.js";
3
+ import { r as LiveCountSeed } from "../live-D9W2M5aO.js";
4
+ import { n as supportOf, t as SupportView } from "../support-view-Da5peKFg.js";
5
+ import { n as MembershipClaim, r as hasEntitlement, t as EntitlementKey } from "../entitlements-DUxU4oHe.js";
6
+ import { _ as useBroadcast, a as BetterHooks, b as useSupabase, c as BroadcastOptions, d as LiveCount, f as LiveCountHookOptions, g as useAuth, h as createHooks, i as useNotifications, l as ClaimsOf, m as ProfileOf, n as NotificationsState, o as BetterSupabaseProvider, p as LiveQueryHookOptions, r as UseNotificationsOptions, s as BetterSupabaseProviderProps, t as NotificationSource, u as ClientLike, v as useLiveCount, y as useLiveQuery } from "../index-BGdgBPdf.js";
7
+ import { SessionProvider, SessionProviderProps, useSession, useSupportSession } from "./session.js";
8
+ export { type AuthSession, type BetterHooks, BetterSupabaseProvider, type BetterSupabaseProviderProps, type BroadcastOptions, type ClaimsOf, type ClientLike, type EntitlementKey, type Impersonator, type LiveCount, type LiveCountHookOptions, type LiveCountSeed, type LiveQueryHookOptions, type MembershipClaim, type NotificationSource, type NotificationsState, type ProfileOf, SessionProvider, type SessionProviderProps, type SupportView, type UseNotificationsOptions, createHooks, hasEntitlement, supportOf, useAuth, useBroadcast, useLiveCount, useLiveQuery, useNotifications, useSession, useSupabase, useSupportSession };
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import { SessionProvider, useSession } from "./session.js";
3
- import { a as useLiveCount, i as useBroadcast, n as createHooks, o as useLiveQuery, r as useAuth, s as useSupabase, t as BetterSupabaseProvider } from "../react-DNBYNazu.js";
2
+ import { t as supportOf } from "../support-view-g4YLBeqX.js";
3
+ import { SessionProvider, useSession, useSupportSession } from "./session.js";
4
+ import { a as useBroadcast, c as useSupabase, i as useAuth, n as BetterSupabaseProvider, o as useLiveCount, r as createHooks, s as useLiveQuery, t as useNotifications } from "../react-C_s7kiNz.js";
4
5
  import { t as hasEntitlement } from "../entitlements-CTEBm7IB.js";
5
- export { BetterSupabaseProvider, SessionProvider, createHooks, hasEntitlement, useAuth, useBroadcast, useLiveCount, useLiveQuery, useSession, useSupabase };
6
+ export { BetterSupabaseProvider, SessionProvider, createHooks, hasEntitlement, supportOf, useAuth, useBroadcast, useLiveCount, useLiveQuery, useNotifications, useSession, useSupabase, useSupportSession };
@@ -1,13 +1,24 @@
1
- import { t as AuthSession } from "../view-3Po_PVlr.js";
2
- import { a as BrowserLike, f as useAuth, g as useSupabase, h as useLiveQuery, i as BroadcastOptions, l as LiveQueryHookOptions, n as BetterSupabaseProvider, o as ClaimsOf, p as useBroadcast, r as BetterSupabaseProviderProps, t as BetterHooks, u as ProfileOf } from "../index-BNsABq7P.js";
1
+ import { Z as QuerySpec } from "../define-Bp_BZa5h.js";
2
+ import { s as Impersonator } from "../mfa-CusDgPaD.js";
3
+ import { t as AuthSession } from "../view-BEf0diC5.js";
4
+ import { r as LiveCountSeed } from "../live-D9W2M5aO.js";
5
+ import { n as supportOf, t as SupportView } from "../support-view-Da5peKFg.js";
6
+ import { n as MembershipClaim, r as hasEntitlement, t as EntitlementKey } from "../entitlements-DUxU4oHe.js";
7
+ import { _ as useBroadcast, a as BetterHooks, b as useSupabase, c as BroadcastOptions, d as LiveCount, f as LiveCountHookOptions, g as useAuth, l as ClaimsOf, m as ProfileOf, n as NotificationsState, o as BetterSupabaseProvider, p as LiveQueryHookOptions, r as UseNotificationsOptions, s as BetterSupabaseProviderProps, t as NotificationSource, u as ClientLike, y as useLiveQuery } from "../index-BGdgBPdf.js";
3
8
  import { SessionProvider, SessionProviderProps } from "./session.js";
4
9
  //#region src/react/server.d.ts
5
- /** The `react-server` build of `useSession`: await `next.session()` instead. */
10
+ /** The `react-server` build of `useSession`: await `bs.session()` instead. */
6
11
  export declare const useSession: <C = unknown, P = unknown>() => AuthSession<C, P>;
12
+ /** The `react-server` build of `useSupportSession`: use `supportOf(await bs.session())` instead. */
13
+ export declare const useSupportSession: () => SupportView | undefined;
14
+ /** The `react-server` build of `useLiveCount`: render the `bs.liveCount()` seed instead. */
15
+ export declare const useLiveCount: (source: QuerySpec<string, "count", number> | LiveCountSeed | null | undefined, options?: LiveCountHookOptions) => LiveCount;
16
+ /** The `react-server` build of `useNotifications`: call `notifications.list()` instead. */
17
+ export declare const useNotifications: <T>(options: UseNotificationsOptions<T>) => NotificationsState<T>;
7
18
  /**
8
19
  * The `react-server` build of `createHooks`: importing a module that creates
9
20
  * hooks is safe on the server, calling a hook there throws.
10
21
  */
11
- export declare function createHooks<B extends BrowserLike>(): BetterHooks<B>;
22
+ export declare function createHooks<B extends ClientLike>(): BetterHooks<B>;
12
23
  //#endregion
13
- export { type AuthSession, type BetterHooks, BetterSupabaseProvider, type BetterSupabaseProviderProps, type BroadcastOptions, type BrowserLike, type ClaimsOf, type LiveQueryHookOptions, type ProfileOf, SessionProvider, type SessionProviderProps, useAuth, useBroadcast, useLiveQuery, useSupabase };
24
+ export { type AuthSession, type BetterHooks, BetterSupabaseProvider, type BetterSupabaseProviderProps, type BroadcastOptions, type ClaimsOf, type ClientLike, type EntitlementKey, type Impersonator, type LiveCount, type LiveCountHookOptions, type LiveCountSeed, type LiveQueryHookOptions, type MembershipClaim, type NotificationSource, type NotificationsState, type ProfileOf, SessionProvider, type SessionProviderProps, type SupportView, type UseNotificationsOptions, hasEntitlement, supportOf, useAuth, useBroadcast, useLiveQuery, useSupabase };
@@ -1,13 +1,21 @@
1
- import { i as useBroadcast, o as useLiveQuery, r as useAuth, s as useSupabase, t as BetterSupabaseProvider } from "../react-DNBYNazu.js";
1
+ import { t as supportOf } from "../support-view-g4YLBeqX.js";
2
+ import { a as useBroadcast, c as useSupabase, i as useAuth, n as BetterSupabaseProvider, s as useLiveQuery } from "../react-C_s7kiNz.js";
3
+ import { t as hasEntitlement } from "../entitlements-CTEBm7IB.js";
2
4
  import { SessionProvider } from "./session.js";
3
5
  //#region src/react/server.ts
4
6
  function clientOnly(name) {
5
7
  return () => {
6
- throw new Error(`better-supabase: ${name}() runs in Client Components only. In Server Components use \`next.server()\` or \`db.$run(spec)\`.`);
8
+ throw new Error(`better-supabase: ${name}() runs in Client Components only. In Server Components use \`bs.context()\` or \`db.$run(spec)\`.`);
7
9
  };
8
10
  }
9
- /** The `react-server` build of `useSession`: await `next.session()` instead. */
11
+ /** The `react-server` build of `useSession`: await `bs.session()` instead. */
10
12
  const useSession = clientOnly("useSession");
13
+ /** The `react-server` build of `useSupportSession`: use `supportOf(await bs.session())` instead. */
14
+ const useSupportSession = clientOnly("useSupportSession");
15
+ /** The `react-server` build of `useLiveCount`: render the `bs.liveCount()` seed instead. */
16
+ const useLiveCount = clientOnly("useLiveCount");
17
+ /** The `react-server` build of `useNotifications`: call `notifications.list()` instead. */
18
+ const useNotifications = clientOnly("useNotifications");
11
19
  /**
12
20
  * The `react-server` build of `createHooks`: importing a module that creates
13
21
  * hooks is safe on the server, calling a hook there throws.
@@ -22,4 +30,4 @@ function createHooks() {
22
30
  };
23
31
  }
24
32
  //#endregion
25
- export { BetterSupabaseProvider, SessionProvider, createHooks, useAuth, useBroadcast, useLiveQuery, useSession, useSupabase };
33
+ export { BetterSupabaseProvider, SessionProvider, createHooks, hasEntitlement, supportOf, useAuth, useBroadcast, useLiveCount, useLiveQuery, useNotifications, useSession, useSupabase, useSupportSession };
@@ -1,9 +1,10 @@
1
- import { t as AuthSession } from "../view-3Po_PVlr.js";
1
+ import { t as AuthSession } from "../view-BEf0diC5.js";
2
+ import { t as SupportView } from "../support-view-Da5peKFg.js";
2
3
  import { ReactNode } from "react";
3
4
  //#region src/react/session.d.ts
4
5
  export interface SessionProviderProps {
5
6
  /**
6
- * An unresolved `next.session()` promise, created inside a `<Suspense>`
7
+ * An unresolved `bs.session()` promise, created inside a `<Suspense>`
7
8
  * boundary so the layout itself never waits for auth.
8
9
  */
9
10
  readonly sessionPromise: Promise<AuthSession>;
@@ -14,8 +15,13 @@ export declare function SessionProvider(props: SessionProviderProps): ReactNode;
14
15
  /**
15
16
  * The session from the nearest `<SessionProvider>`. Suspends until the
16
17
  * promise resolves, so render it inside `<Suspense>`. `C` types the claims
17
- * (the output of `sb.claims(schema)`) and `P` the profile (the output of
18
- * `sb.userMetadata(schema)`); `createHooks().useSession` infers both.
18
+ * (the output of `betterSupabase.claims(schema)`) and `P` the profile (the output of
19
+ * `betterSupabase.userMetadata(schema)`); `createHooks().useSession` infers both.
19
20
  */
20
21
  export declare function useSession<C = unknown, P = unknown>(): AuthSession<C, P>;
22
+ /**
23
+ * The support session the page renders in, for a "Viewing as" banner, or
24
+ * `undefined` for a normal session. Needs `<SessionProvider>` like `useSession`.
25
+ */
26
+ export declare function useSupportSession(): SupportView | undefined;
21
27
  //#endregion
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { t as supportOf } from "../support-view-g4YLBeqX.js";
2
3
  import { createContext, createElement, use, useContext } from "react";
3
4
  //#region src/react/session.ts
4
5
  const SessionContext = createContext(null);
@@ -9,13 +10,20 @@ function SessionProvider(props) {
9
10
  /**
10
11
  * The session from the nearest `<SessionProvider>`. Suspends until the
11
12
  * promise resolves, so render it inside `<Suspense>`. `C` types the claims
12
- * (the output of `sb.claims(schema)`) and `P` the profile (the output of
13
- * `sb.userMetadata(schema)`); `createHooks().useSession` infers both.
13
+ * (the output of `betterSupabase.claims(schema)`) and `P` the profile (the output of
14
+ * `betterSupabase.userMetadata(schema)`); `createHooks().useSession` infers both.
14
15
  */
15
16
  function useSession() {
16
17
  const promise = useContext(SessionContext);
17
18
  if (!promise) throw new Error("better-supabase: useSession() needs <SessionProvider sessionPromise={...}>");
18
19
  return use(promise);
19
20
  }
21
+ /**
22
+ * The support session the page renders in, for a "Viewing as" banner, or
23
+ * `undefined` for a normal session. Needs `<SessionProvider>` like `useSession`.
24
+ */
25
+ function useSupportSession() {
26
+ return supportOf(useSession());
27
+ }
20
28
  //#endregion
21
- export { SessionProvider, useSession };
29
+ export { SessionProvider, useSession, useSupportSession };