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,7 +1,7 @@
1
- import { g as Operation } from "../executor-CGdNQ27g.js";
2
- import { n as fromPgError, r as postgresExecutor, t as SqlClient } from "../executor-BYXQ9AGn.js";
3
- import { i as createPostgres, n as PostgresOptions, r as SqlClaims, t as Postgres } from "../pool-R2m_DkXi.js";
4
- import { t as Compiler } from "../compiler-CZ9nIuqy.js";
1
+ import { g as Operation } from "../executor-B5IoUxLE.js";
2
+ import { n as fromPgError, r as postgresExecutor, t as SqlClient } from "../executor-CZ7ImRiD.js";
3
+ import { a as PostgresTimeouts, i as PostgresOptions, n as PgPool, o as SqlClaims, r as PgPoolClient, s as createPostgres, t as BetterPostgres } from "../pool-DFwEQwmN.js";
4
+ import { t as Compiler } from "../compiler-DB3aSFOA.js";
5
5
  //#region src/compile/sql.d.ts
6
6
  interface SqlQuery {
7
7
  readonly text: string;
@@ -17,6 +17,11 @@ interface SqlPlan {
17
17
  readonly count: SqlQuery | undefined;
18
18
  /** No row can match; the executor returns an empty result without a query. */
19
19
  readonly never: boolean;
20
+ /**
21
+ * The rest of an insert split to stay under the bind-parameter limit. They
22
+ * run after this plan, in the same transaction; rows and counts add up.
23
+ */
24
+ readonly chunks?: readonly SqlPlan[];
20
25
  }
21
26
  export declare function quoteIdent(name: string): string;
22
27
  /** Compiles an operation to parameterized SQL. Rows come back as json. */
@@ -25,4 +30,4 @@ export declare function compileSql(op: Operation): SqlPlan;
25
30
  //#region src/postgres/compiler.d.ts
26
31
  export declare const sqlCompiler: Compiler<SqlPlan>;
27
32
  //#endregion
28
- export { type Postgres, type PostgresOptions, type SqlClaims, type SqlClient, type SqlPlan, type SqlQuery, createPostgres, fromPgError, postgresExecutor };
33
+ export { type BetterPostgres, type PgPool, type PgPoolClient, type PostgresOptions, type PostgresTimeouts, type SqlClaims, type SqlClient, type SqlPlan, type SqlQuery, createPostgres, fromPgError, postgresExecutor };
@@ -1,35 +1,55 @@
1
- import { n as quoteIdent, t as compileSql } from "../sql-DTjA1LPj.js";
2
- import { n as postgresExecutor, t as fromPgError } from "../executor-DeppvirK.js";
1
+ import { n as quoteIdent, t as compileSql } from "../sql-B34HU2DI.js";
2
+ import { n as postgresExecutor, t as fromPgError } from "../executor-CVt6dD0B.js";
3
3
  import { Pool } from "pg";
4
4
  //#region src/postgres/pool.ts
5
+ const DEFAULT_TIMEOUTS = {
6
+ authenticated: 8e3,
7
+ anon: 3e3
8
+ };
5
9
  const ROLES = /* @__PURE__ */ new Set(["authenticated", "anon"]);
6
10
  function roleOf(claims) {
7
11
  const role = claims.role ?? (claims.sub ? "authenticated" : "anon");
8
12
  if (!ROLES.has(role)) throw new TypeError(`Cannot run as role "${role}": only "authenticated" and "anon" are assumed. Use postgres.admin for service work.`);
9
13
  return role;
10
14
  }
15
+ function openPool(options) {
16
+ const connectionString = options.connectionString ?? process.env["SUPABASE_DB_URL"] ?? process.env["DATABASE_URL"];
17
+ if (!connectionString) throw new TypeError("createPostgres needs a connectionString, $SUPABASE_DB_URL or $DATABASE_URL");
18
+ return new Pool({
19
+ connectionString,
20
+ max: options.max ?? 10,
21
+ connectionTimeoutMillis: options.connectionTimeout ?? 1e4,
22
+ idleTimeoutMillis: options.idleTimeout ?? 1e4
23
+ });
24
+ }
11
25
  /**
12
26
  * A pooled Postgres connection for jobs, scripts and tests. Each query (or
13
27
  * transaction) runs in its own transaction; claims and role are
14
28
  * transaction-local, so nothing leaks back into the pool.
15
29
  */
16
30
  function createPostgres(options = {}) {
17
- const connectionString = options.connectionString ?? process.env["SUPABASE_DB_URL"] ?? process.env["DATABASE_URL"];
18
- if (!connectionString) throw new TypeError("createPostgres needs a connectionString, $SUPABASE_DB_URL or $DATABASE_URL");
19
- const pool = new Pool({
20
- connectionString,
21
- max: options.max ?? 10
22
- });
31
+ const pool = options.pool ?? openPool(options);
32
+ const timeouts = typeof options.statementTimeout === "number" ? {
33
+ admin: options.statementTimeout,
34
+ authenticated: options.statementTimeout,
35
+ anon: options.statementTimeout
36
+ } : {
37
+ ...DEFAULT_TIMEOUTS,
38
+ ...options.statementTimeout
39
+ };
40
+ /** Opens the transaction, then sets the timeouts, claims and role in one round trip. */
23
41
  async function begin(client, session) {
24
42
  await client.query("begin");
25
- if (options.statementTimeout !== void 0) await client.query(`set local statement_timeout = ${Math.trunc(options.statementTimeout)}`);
26
- if (session) {
27
- await client.query("select set_config('request.jwt.claims', $1, true)", [JSON.stringify({
28
- ...session.claims,
29
- role: session.role
30
- })]);
31
- await client.query(`set local role ${session.role}`);
32
- }
43
+ const settings = [];
44
+ const timeout = session?.role === "authenticated" ? timeouts.authenticated : session?.role === "anon" ? timeouts.anon : timeouts.admin;
45
+ if (timeout !== void 0) settings.push(["statement_timeout", String(Math.trunc(timeout))]);
46
+ if (options.idleInTransactionTimeout !== void 0) settings.push(["idle_in_transaction_session_timeout", String(Math.trunc(options.idleInTransactionTimeout))]);
47
+ if (session) settings.push(["request.jwt.claims", JSON.stringify({
48
+ ...session.claims,
49
+ role: session.role
50
+ })], ["role", session.role]);
51
+ if (settings.length === 0) return;
52
+ await client.query(`select ${settings.map((_, index) => `set_config($${index * 2 + 1}, $${index * 2 + 2}, true)`).join(", ")}`, settings.flat());
33
53
  }
34
54
  async function transaction(session, fn) {
35
55
  const client = await pool.connect();
@@ -64,6 +84,7 @@ function createPostgres(options = {}) {
64
84
  role: "anon"
65
85
  }),
66
86
  asUser: (claims) => clientFor(sessionFor(claims)),
87
+ executorFor: (claims) => postgresExecutor(clientFor(sessionFor(claims))),
67
88
  transaction: (fn, txOptions) => transaction(txOptions?.claims ? sessionFor(txOptions.claims) : void 0, fn),
68
89
  end: () => pool.end(),
69
90
  [Symbol.asyncDispose]: () => pool.end()
@@ -1,4 +1,4 @@
1
- import { g as Operation } from "./executor-CGdNQ27g.js";
1
+ import { g as Operation } from "./executor-B5IoUxLE.js";
2
2
  //#region src/compile/postgrest.d.ts
3
3
  /**
4
4
  * A compiled PostgREST request, expressed as calls on the public
@@ -1,4 +1,4 @@
1
- import { n as dbError } from "./errors-Bl3rkOzo.js";
1
+ import { n as dbError } from "./errors-L0xK41y_.js";
2
2
  //#region src/core/problem.ts
3
3
  const PROBLEM_TYPE_BASE = "https://bettersupabase.com/problems/";
4
4
  const PROBLEM_CONTENT_TYPE = "application/problem+json";
@@ -33,7 +33,7 @@ const INTERNAL = /* @__PURE__ */ new Set([
33
33
  /** Converts a `DbError` to Problem Details. */
34
34
  function toProblem(error, options = {}) {
35
35
  const problem = {
36
- type: `${PROBLEM_TYPE_BASE}${error.kind.replace(/_/g, "-")}`,
36
+ type: `${PROBLEM_TYPE_BASE}${error.kind.replaceAll("_", "-")}`,
37
37
  title: TITLES[error.kind],
38
38
  status: error.status,
39
39
  kind: error.kind
@@ -47,21 +47,26 @@ function toProblem(error, options = {}) {
47
47
  if ("column" in error && error.column) problem["column"] = error.column;
48
48
  if ("issues" in error) problem["issues"] = error.issues;
49
49
  if ("required" in error) problem["required"] = error.required;
50
+ if ("scopes" in error) problem["scopes"] = error.scopes;
50
51
  if ("retryAfter" in error) problem["retryAfter"] = error.retryAfter;
51
52
  return problem;
52
53
  }
53
54
  /**
54
- * An `application/problem+json` response. A 401 carries an RFC 6750
55
- * `WWW-Authenticate: Bearer` challenge.
55
+ * An `application/problem+json` response. A 401, and a 403 for a missing
56
+ * OAuth scope, carry an RFC 6750 `WWW-Authenticate: Bearer` challenge.
56
57
  */
57
58
  function problemResponse(error, options = {}) {
58
59
  const headers = new Headers(options.headers);
59
60
  headers.set("content-type", PROBLEM_CONTENT_TYPE);
61
+ const realm = (options.realm ?? "supabase").replaceAll("\"", "");
60
62
  if (error.status === 401 && !headers.has("www-authenticate")) {
61
- const realm = (options.realm ?? "supabase").replace(/"/g, "");
62
63
  const params = error.code === "MISSING_CREDENTIALS" ? "" : ", error=\"invalid_token\"";
63
64
  headers.set("www-authenticate", `Bearer realm="${realm}"${params}`);
64
65
  }
66
+ if ("scopes" in error && error.code === "INSUFFICIENT_SCOPE" && !headers.has("www-authenticate")) {
67
+ const scope = error.scopes.join(" ").replaceAll("\"", "");
68
+ headers.set("www-authenticate", `Bearer realm="${realm}", error="insufficient_scope", scope="${scope}"`);
69
+ }
65
70
  if ("retryAfter" in error && !headers.has("retry-after")) headers.set("retry-after", String(error.retryAfter));
66
71
  return new Response(JSON.stringify(toProblem(error, options)), {
67
72
  status: error.status,
@@ -87,6 +92,7 @@ function fromProblem(problem) {
87
92
  "columns",
88
93
  "column",
89
94
  "required",
95
+ "scopes",
90
96
  "retryAfter"
91
97
  ]) if (problem[key] !== void 0) extra[key] = problem[key];
92
98
  extra["issues"] = problem.issues ?? [];
@@ -1,4 +1,4 @@
1
- import { b as ValidationIssue, m as DbErrorKind, p as DbError } from "./result-CTkCZ6JA.js";
1
+ import { b as ValidationIssue, m as DbErrorKind, p as DbError } from "./result-CqEsbgYs.js";
2
2
  //#region src/core/problem.d.ts
3
3
  /** RFC 9457 Problem Details, with the `DbError` fields as extension members. */
4
4
  interface ProblemDetails {
@@ -17,6 +17,8 @@ interface ProblemDetails {
17
17
  readonly issues?: readonly ValidationIssue[];
18
18
  /** The assurance level a `forbidden` answer needs (`aal2`). */
19
19
  readonly required?: "aal1" | "aal2";
20
+ /** The OAuth scopes a `forbidden` answer needs. */
21
+ readonly scopes?: readonly string[];
20
22
  /** Seconds until a `rate_limited` caller may retry. */
21
23
  readonly retryAfter?: number;
22
24
  }
@@ -29,15 +31,15 @@ interface ProblemOptions {
29
31
  readonly expose?: boolean;
30
32
  }
31
33
  interface ProblemResponseOptions extends ProblemOptions {
32
- readonly headers?: HeadersInit;
34
+ readonly headers?: ConstructorParameters<typeof Headers>[0];
33
35
  /** `realm` of the RFC 6750 challenge on 401. */
34
36
  readonly realm?: string;
35
37
  }
36
38
  /** Converts a `DbError` to Problem Details. */
37
39
  declare function toProblem(error: DbError, options?: ProblemOptions): ProblemDetails;
38
40
  /**
39
- * An `application/problem+json` response. A 401 carries an RFC 6750
40
- * `WWW-Authenticate: Bearer` challenge.
41
+ * An `application/problem+json` response. A 401, and a 403 for a missing
42
+ * OAuth scope, carry an RFC 6750 `WWW-Authenticate: Bearer` challenge.
41
43
  */
42
44
  declare function problemResponse(error: DbError, options?: ProblemResponseOptions): Response;
43
45
  declare function isProblem(value: unknown): value is ProblemDetails;
@@ -1,2 +1,2 @@
1
- import { a as QueryHelpers, c as TableQueries, d as queryCache, f as BetterQueryMeta, i as Queries, l as createQueries, n as InfiniteOptionsOf, o as QueryKeyOf, p as invalidateTables, r as MutationOptionsOf, s as QueryOptionsOf, t as CreateQueriesOptions, u as invalidateOnMutation } from "../index-K-3WM2Hp.js";
2
- export { type BetterQueryMeta, CreateQueriesOptions, InfiniteOptionsOf, MutationOptionsOf, Queries, QueryHelpers, QueryKeyOf, QueryOptionsOf, TableQueries, createQueries, invalidateOnMutation, invalidateTables, queryCache };
1
+ import { a as QueryHelpers, c as TableQueries, d as queryCache, f as BetterQueryMeta, i as QueriesOptions, l as createQueries, n as InfiniteOptionsOf, o as QueryKeyOf, p as invalidateTables, r as MutationOptionsOf, s as QueryOptionsOf, t as BetterQueries, u as invalidateOnMutation } from "../index-DFmOpBGC.js";
2
+ export { type BetterQueries, type BetterQueryMeta, type InfiniteOptionsOf, type MutationOptionsOf, type QueriesOptions, type QueryHelpers, type QueryKeyOf, type QueryOptionsOf, type TableQueries, createQueries, invalidateOnMutation, invalidateTables, queryCache };
@@ -1,3 +1,3 @@
1
- import { t as invalidateTables } from "../invalidate-DbxuL2jL.js";
2
- import { n as invalidateOnMutation, r as queryCache, t as createQueries } from "../query-ChvDbsDE.js";
1
+ import { t as invalidateTables } from "../invalidate-CgxmRamI.js";
2
+ import { n as invalidateOnMutation, r as queryCache, t as createQueries } from "../query-BMMSWbI7.js";
3
3
  export { createQueries, invalidateOnMutation, invalidateTables, queryCache };
@@ -1,8 +1,8 @@
1
- import { t as DbException } from "./errors-Bl3rkOzo.js";
2
- import { t as invalidationTargets } from "./tables-rZxRxNPW.js";
3
- import { t as invalidateTables } from "./invalidate-DbxuL2jL.js";
4
- //#region src/query/index.ts
5
- /** Query errors stay `DbException`s, even for an `sb` with `mapError()`. */
1
+ import { t as DbException } from "./errors-L0xK41y_.js";
2
+ import { t as invalidationTargets } from "./tables-Cb-3_VWc.js";
3
+ import { t as invalidateTables } from "./invalidate-CgxmRamI.js";
4
+ //#region src/query/queries.ts
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 };
@@ -1,7 +1,7 @@
1
- import { s as Impersonator } from "../mfa-TVia554c.js";
2
- import { t as AuthSession } from "../view-D1s0wa0T.js";
3
- import { r as LiveCountSeed } from "../live-DJyZMD6w.js";
4
- import { n as MembershipClaim, r as hasEntitlement, t as EntitlementKey } from "../entitlements-Dng-ctuT.js";
5
- import { n as SessionProviderProps, r as useSession, t as SessionProvider } from "../session-C3LxnQ0e.js";
6
- 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-CBDufH1M.js";
7
- export { type AuthSession, BetterHooks, BetterSupabaseProvider, BetterSupabaseProviderProps, BroadcastOptions, BrowserLike, ClaimsOf, type EntitlementKey, type Impersonator, LiveCount, LiveCountHookOptions, type LiveCountSeed, LiveQueryHookOptions, type MembershipClaim, ProfileOf, SessionProvider, type SessionProviderProps, createHooks, hasEntitlement, useAuth, useBroadcast, useLiveCount, useLiveQuery, useSession, useSupabase };
1
+ import { s as Impersonator } from "../mfa-C7MNQ1Ob.js";
2
+ import { t as AuthSession } from "../view-B64o81wp.js";
3
+ import { r as LiveCountSeed } from "../live-BHakSWWo.js";
4
+ import { n as MembershipClaim, r as hasEntitlement, t as EntitlementKey } from "../entitlements-Dm-FHpNH.js";
5
+ import { a as ClaimsOf, 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 ClientLike, p as useBroadcast, r as BetterSupabaseProviderProps, s as LiveCount, t as BetterHooks, u as ProfileOf } from "../index-BBdvo-5d.js";
6
+ import { SessionProvider, SessionProviderProps, useSession } from "./session.js";
7
+ 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 ProfileOf, SessionProvider, type SessionProviderProps, createHooks, hasEntitlement, useAuth, useBroadcast, useLiveCount, useLiveQuery, useSession, useSupabase };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { n as useSession, t as SessionProvider } from "../session-CqEwzVup.js";
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-CQHMaESR.js";
3
4
  import { t as hasEntitlement } from "../entitlements-CTEBm7IB.js";
4
- import { a as useLiveCount, i as useBroadcast, n as createHooks, o as useLiveQuery, r as useAuth, s as useSupabase, t as BetterSupabaseProvider } from "../react-C83BdBGt.js";
5
5
  export { BetterSupabaseProvider, SessionProvider, createHooks, hasEntitlement, useAuth, useBroadcast, useLiveCount, useLiveQuery, useSession, useSupabase };
@@ -1,13 +1,13 @@
1
- import { t as AuthSession } from "../view-D1s0wa0T.js";
2
- import { n as SessionProviderProps, t as SessionProvider } from "../session-C3LxnQ0e.js";
3
- 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-CBDufH1M.js";
1
+ import { t as AuthSession } from "../view-B64o81wp.js";
2
+ import { a as ClaimsOf, f as useAuth, g as useSupabase, h as useLiveQuery, i as BroadcastOptions, l as LiveQueryHookOptions, n as BetterSupabaseProvider, o as ClientLike, p as useBroadcast, r as BetterSupabaseProviderProps, t as BetterHooks, u as ProfileOf } from "../index-BBdvo-5d.js";
3
+ import { SessionProvider, SessionProviderProps } from "./session.js";
4
4
  //#region src/react/server.d.ts
5
- /** The `react-server` build of `useSession`: await `next.session()` instead. */
5
+ /** The `react-server` build of `useSession`: await `bs.session()` instead. */
6
6
  export declare const useSession: <C = unknown, P = unknown>() => AuthSession<C, P>;
7
7
  /**
8
8
  * The `react-server` build of `createHooks`: importing a module that creates
9
9
  * hooks is safe on the server, calling a hook there throws.
10
10
  */
11
- export declare function createHooks<B extends BrowserLike>(): BetterHooks<B>;
11
+ export declare function createHooks<B extends ClientLike>(): BetterHooks<B>;
12
12
  //#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 };
13
+ export { type AuthSession, type BetterHooks, BetterSupabaseProvider, type BetterSupabaseProviderProps, type BroadcastOptions, type ClaimsOf, type ClientLike, type LiveQueryHookOptions, type ProfileOf, SessionProvider, type SessionProviderProps, useAuth, useBroadcast, useLiveQuery, useSupabase };
@@ -1,12 +1,12 @@
1
- import { i as useBroadcast, o as useLiveQuery, r as useAuth, s as useSupabase, t as BetterSupabaseProvider } from "../react-C83BdBGt.js";
1
+ import { i as useBroadcast, o as useLiveQuery, r as useAuth, s as useSupabase, t as BetterSupabaseProvider } from "../react-CQHMaESR.js";
2
2
  import { SessionProvider } from "./session.js";
3
3
  //#region src/react/server.ts
4
4
  function clientOnly(name) {
5
5
  return () => {
6
- throw new Error(`better-supabase: ${name}() runs in Client Components only. In Server Components use \`next.server()\` or \`db.$run(spec)\`.`);
6
+ throw new Error(`better-supabase: ${name}() runs in Client Components only. In Server Components use \`bs.context()\` or \`db.$run(spec)\`.`);
7
7
  };
8
8
  }
9
- /** The `react-server` build of `useSession`: await `next.session()` instead. */
9
+ /** The `react-server` build of `useSession`: await `bs.session()` instead. */
10
10
  const useSession = clientOnly("useSession");
11
11
  /**
12
12
  * The `react-server` build of `createHooks`: importing a module that creates
@@ -1,2 +1,21 @@
1
- import { n as SessionProviderProps, r as useSession, t as SessionProvider } from "../session-C3LxnQ0e.js";
2
- export { SessionProvider, SessionProviderProps, useSession };
1
+ import { t as AuthSession } from "../view-B64o81wp.js";
2
+ import { ReactNode } from "react";
3
+ //#region src/react/session.d.ts
4
+ export interface SessionProviderProps {
5
+ /**
6
+ * An unresolved `bs.session()` promise, created inside a `<Suspense>`
7
+ * boundary so the layout itself never waits for auth.
8
+ */
9
+ readonly sessionPromise: Promise<AuthSession>;
10
+ readonly children?: ReactNode;
11
+ }
12
+ /** Shares the server-verified session with Client Components. */
13
+ export declare function SessionProvider(props: SessionProviderProps): ReactNode;
14
+ /**
15
+ * The session from the nearest `<SessionProvider>`. Suspends until the
16
+ * promise resolves, so render it inside `<Suspense>`. `C` types the claims
17
+ * (the output of `betterSupabase.claims(schema)`) and `P` the profile (the output of
18
+ * `betterSupabase.userMetadata(schema)`); `createHooks().useSession` infers both.
19
+ */
20
+ export declare function useSession<C = unknown, P = unknown>(): AuthSession<C, P>;
21
+ //#endregion
@@ -1,3 +1,21 @@
1
1
  "use client";
2
- import { n as useSession, t as SessionProvider } from "../session-CqEwzVup.js";
2
+ import { createContext, createElement, use, useContext } from "react";
3
+ //#region src/react/session.ts
4
+ const SessionContext = createContext(null);
5
+ /** Shares the server-verified session with Client Components. */
6
+ function SessionProvider(props) {
7
+ return createElement(SessionContext.Provider, { value: props.sessionPromise }, props.children);
8
+ }
9
+ /**
10
+ * The session from the nearest `<SessionProvider>`. Suspends until the
11
+ * promise resolves, so render it inside `<Suspense>`. `C` types the claims
12
+ * (the output of `betterSupabase.claims(schema)`) and `P` the profile (the output of
13
+ * `betterSupabase.userMetadata(schema)`); `createHooks().useSession` infers both.
14
+ */
15
+ function useSession() {
16
+ const promise = useContext(SessionContext);
17
+ if (!promise) throw new Error("better-supabase: useSession() needs <SessionProvider sessionPromise={...}>");
18
+ return use(promise);
19
+ }
20
+ //#endregion
3
21
  export { SessionProvider, useSession };