better-supabase 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -31
- package/dist/base64-CQeB1eSf.js +42 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +4 -14
- package/dist/{compiler-CZ9nIuqy.d.ts → compiler-2zqGzxVZ.d.ts} +2 -2
- package/dist/config/index.d.ts +4 -3
- package/dist/config/index.js +5 -3
- package/dist/config-Be4GwsqI.js +129 -0
- package/dist/{index-DOsjFvMf.d.ts → config-C1CYcm6o.d.ts} +49 -49
- package/dist/{config-ClDXmVtY.js → config-DOsGYSiT.js} +14 -137
- package/dist/{define-BXMYD9AY.js → define-DF341GDj.js} +71 -51
- package/dist/{define-e3zI4_4g.d.ts → define-DUbydmJa.d.ts} +10 -9
- package/dist/edge/index.d.ts +4 -4
- package/dist/edge/index.js +4 -4
- package/dist/{entitlements-Dng-ctuT.d.ts → entitlements-DvJXoI02.d.ts} +1 -1
- package/dist/env/index.js +203 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.js +139 -1
- package/dist/{events-DOt3nSO-.d.ts → events-Do8jXh4D.d.ts} +3 -3
- package/dist/{executor-BYXQ9AGn.d.ts → executor-B26lgbHD.d.ts} +2 -2
- package/dist/{executor-DeppvirK.js → executor-C57jx2pn.js} +7 -2
- package/dist/{executor-CGdNQ27g.d.ts → executor-DynmIWhq.d.ts} +2 -2
- package/dist/hono/index.d.ts +5 -5
- package/dist/hono/index.js +4 -4
- package/dist/{index-CBDufH1M.d.ts → index-BNsABq7P.d.ts} +8 -8
- package/dist/{index-Bw1bwtC0.d.ts → index-CADlNHK-.d.ts} +27 -14
- package/dist/{index-DuP14VHo.d.ts → index-CTTMS6_1.d.ts} +19 -8
- package/dist/index-Cf-D2jk1.d.ts +50 -0
- package/dist/{index-K-3WM2Hp.d.ts → index-CriFFJ_p.d.ts} +4 -4
- package/dist/{index-Ciu5Xlml.d.ts → index-GV77NpRP.d.ts} +5 -4
- package/dist/{index-D4v7sncu.d.ts → index-UJ-LUxtI.d.ts} +3 -3
- package/dist/{index-CG69s15v.d.ts → index-kpgopLNv.d.ts} +4 -3
- package/dist/{index-DbxFr7XG.d.ts → index-qriRM9cZ.d.ts} +7 -2
- package/dist/index.d.ts +12 -12
- package/dist/index.js +16 -7
- package/dist/jobs/index.d.ts +25 -24
- package/dist/jobs/index.js +16 -10
- package/dist/{json-schema-BpYqkCKf.js → json-schema--aOXAGfU.js} +7 -2
- package/dist/lint/index.js +1 -1
- package/dist/list/index.d.ts +2 -2
- package/dist/list/index.js +128 -93
- package/dist/{live-DJyZMD6w.d.ts → live-QE3UPbGm.d.ts} +16 -6
- package/dist/mcp/index.d.ts +24 -17
- package/dist/mcp/index.js +41 -12
- package/dist/{mfa-CpLfJSde.js → mfa-BxoR1RkN.js} +74 -19
- package/dist/{mfa-TVia554c.d.ts → mfa-x3V3vGh-.d.ts} +1 -1
- package/dist/next/index.d.ts +39 -26
- package/dist/next/index.js +28 -23
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +57 -34
- package/dist/orpc/index.d.ts +6 -6
- package/dist/orpc/index.js +3 -3
- package/dist/otel/index.d.ts +2 -2
- package/dist/otel/index.js +4 -2
- package/dist/{permdock-sql-CghlHPuH.js → permdock-sql-Bta_G0v-.js} +11 -6
- package/dist/permdock-sql-DImJULY-.d.ts +17 -0
- package/dist/{plugin-C4TR9J0Z.d.ts → plugin-DVRB8qNE.d.ts} +5 -4
- package/dist/plugins/actor/index.d.ts +1 -1
- package/dist/plugins/rules/index.d.ts +2 -2
- package/dist/plugins/rules/index.js +4 -4
- package/dist/plugins/soft-delete/index.d.ts +3 -3
- package/dist/plugins/soft-delete/index.js +2 -2
- package/dist/plugins/tenant/index.d.ts +2 -2
- package/dist/plugins/timestamps/index.d.ts +1 -1
- package/dist/plugins/timestamps/index.js +1 -1
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/pool-B9qsLyFR.d.ts +71 -0
- package/dist/postgres/index.d.ts +10 -5
- package/dist/postgres/index.js +36 -16
- package/dist/{postgrest-cAEQ_IQN.d.ts → postgrest-DmBlevh-.d.ts} +1 -1
- package/dist/{problem-BTkTtRV9.js → problem-CGt1ADix.js} +10 -4
- package/dist/{problem-DlgB0lYl.d.ts → problem-Z2RTQjZD.d.ts} +6 -4
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +1 -1
- package/dist/{query-ChvDbsDE.js → query-BdKLTPlj.js} +2 -2
- package/dist/react/index.d.ts +7 -7
- package/dist/react/index.js +2 -2
- package/dist/react/server.d.ts +3 -3
- package/dist/react/server.js +1 -1
- package/dist/react/session.d.ts +21 -2
- package/dist/react/session.js +19 -1
- package/dist/{react-C83BdBGt.js → react-DNBYNazu.js} +20 -16
- package/dist/{read-set-4lI3W_gZ.js → read-set-D0qBcboM.js} +3 -3
- package/dist/realtime/index.d.ts +4 -3
- package/dist/realtime/index.js +7 -6
- package/dist/{resolve-CjHILk2w.d.ts → resolve-BRciX2jK.d.ts} +6 -5
- package/dist/{resource-CgZa3YG_.d.ts → resource-CwVgiI5q.d.ts} +16 -7
- package/dist/{resource-BHEWmQJK.js → resource-D30rp0GN.js} +38 -16
- package/dist/{respond-DMcbQwfN.js → respond-C44EZAJo.js} +35 -19
- package/dist/{respond-Dne1ARSa.d.ts → respond-DAkPIdTH.d.ts} +15 -9
- package/dist/{result-CTkCZ6JA.d.ts → result-c2OYgCV2.d.ts} +13 -8
- package/dist/server/index.d.ts +35 -10
- package/dist/server/index.js +38 -9
- package/dist/{simplify-bwJpLnaS.js → simplify-LakqK1vH.js} +10 -16
- package/dist/sql/index.d.ts +139 -0
- package/dist/sql/index.js +1983 -0
- package/dist/{sql-DTjA1LPj.js → sql-BIgk12ew.js} +72 -16
- package/dist/ssr/index.d.ts +4 -4
- package/dist/ssr/index.js +2 -2
- package/dist/{standard-CyhRzctb.d.ts → standard-eudBiRk1.d.ts} +1 -1
- package/dist/{stats-C5W-rBfR.js → stats-D78UQ8Yu.js} +8 -7
- package/dist/storage/index.d.ts +4 -3
- package/dist/storage/index.js +530 -1
- package/dist/{tables-rZxRxNPW.js → tables-Dhha3BXM.js} +5 -5
- package/dist/temporal-BwshQk0W.js +27 -0
- package/dist/temporal-required-CMxeSVPo.js +19 -0
- package/dist/testing/index.d.ts +13 -11
- package/dist/testing/index.js +128 -29
- package/dist/{types-C83v5SQz.d.ts → types-DONv9SHN.d.ts} +14 -11
- package/dist/{version-Cqq1m3UY.js → version-BfpG2gks.js} +1 -1
- package/dist/{view-D1s0wa0T.d.ts → view-3Po_PVlr.d.ts} +34 -4
- package/dist/{view-aOYizTeE.js → view-wZ-9qIUz.js} +11 -2
- package/dist/webhooks/index.d.ts +18 -16
- package/dist/webhooks/index.js +1 -1
- package/dist/{webhooks-DMipjhSP.js → webhooks-CAIFQSTM.js} +11 -9
- package/package.json +24 -28
- package/schemas/config-v1.json +31 -1
- package/schemas/doctor-report-v1.json +17 -1
- package/schemas/snapshot-v2.json +35 -0
- package/skills/better-supabase/SKILL.md +23 -11
- package/skills/better-supabase/references/plugins.md +21 -18
- package/skills/better-supabase/references/troubleshooting.md +15 -15
- package/skills/better-supabase-api/SKILL.md +7 -7
- package/skills/better-supabase-api/references/adapters.md +30 -25
- package/skills/better-supabase-testing/SKILL.md +11 -8
- package/bin/better-supabase.js +0 -4
- package/dist/casing-da0uRTqt.js +0 -14
- package/dist/cli/bin.d.ts +0 -1
- package/dist/cli/bin.js +0 -15
- package/dist/cli/index.d.ts +0 -226
- package/dist/cli/index.js +0 -3
- package/dist/cli-DrSgDOQC.js +0 -6646
- package/dist/env-BEToab0I.js +0 -204
- package/dist/events-BuzTgn2D.js +0 -135
- package/dist/pool-R2m_DkXi.d.ts +0 -37
- package/dist/seed-CzecODcJ.js +0 -101
- package/dist/session-C3LxnQ0e.d.ts +0 -22
- package/dist/session-CqEwzVup.js +0 -20
- package/dist/storage-DuGn38fr.js +0 -527
|
@@ -21,7 +21,7 @@ function parseSegment(segment) {
|
|
|
21
21
|
});
|
|
22
22
|
return parts;
|
|
23
23
|
}
|
|
24
|
-
const escapeRegex = (text) => text.
|
|
24
|
+
const escapeRegex = (text) => text.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
25
25
|
function parseTemplate(source, separator, validate) {
|
|
26
26
|
const segments = source.split(separator).map(parseSegment);
|
|
27
27
|
const params = [];
|
|
@@ -87,7 +87,7 @@ function sqlIdent(value) {
|
|
|
87
87
|
}
|
|
88
88
|
/** Postgres identifier-safe name part: `customer-logos` → `customer_logos`. */
|
|
89
89
|
function slug(value) {
|
|
90
|
-
return value.
|
|
90
|
+
return value.replaceAll(/[^A-Za-z0-9]+/g, "_").replaceAll(/^_|_$/g, "").toLowerCase();
|
|
91
91
|
}
|
|
92
92
|
//#endregion
|
|
93
93
|
//#region src/core/permdock-sql.ts
|
|
@@ -101,17 +101,22 @@ const SPLIT_KEY = /#\d+$/;
|
|
|
101
101
|
*
|
|
102
102
|
* The helpers check role and scope, not a permission's row conditions, so
|
|
103
103
|
* the condition is only correct for permissions whose grants have none
|
|
104
|
-
* beyond the scope. `#n` keys are refused
|
|
105
|
-
*
|
|
104
|
+
* beyond the scope. `#n` keys are refused, and so are keys the catalog marks
|
|
105
|
+
* with `rowConditions: true` when one is passed.
|
|
106
106
|
*/
|
|
107
|
-
function permdockCheck(where, target, key, id) {
|
|
107
|
+
function permdockCheck(where, target, key, id, catalog) {
|
|
108
108
|
if (key === "") throw new TypeError(`${where}: a PermDock permission key is empty`);
|
|
109
109
|
if (SPLIT_KEY.test(key)) throw new TypeError(`${where}: "${key}" is one part of a permission PermDock splits by row condition. Use PermDock's generated policies for it.`);
|
|
110
|
+
if (catalog?.permissions.some((permission) => permission.key === key && permission.rowConditions === true)) throw new TypeError(`${where}: "${key}" has row conditions in PermDock's catalog (rowConditions: true), which the SQL helpers don't check. Use PermDock's generated policies for it.`);
|
|
110
111
|
const schema = sqlIdent(target.schema ?? "public");
|
|
111
112
|
if (target.scope === "global") return `(select ${schema}.permdock_has(${sqlString(key)}))`;
|
|
112
113
|
if (!SCOPE.test(target.scope)) throw new TypeError(`${where}: invalid PermDock scope "${target.scope}"`);
|
|
113
114
|
if (id === void 0) throw new TypeError(`${where}: scope "${target.scope}" needs a segment`);
|
|
114
115
|
return `${id} in (select t.id::text from ${schema}.${sqlIdent(`permitted_${target.scope}_ids`)}(${sqlString(key)}) as t(id))`;
|
|
115
116
|
}
|
|
117
|
+
/** The keys a bucket or topic PermDock policy names. */
|
|
118
|
+
function permdockKeys(policy) {
|
|
119
|
+
return Object.values(policy.permdock).filter((key) => typeof key === "string");
|
|
120
|
+
}
|
|
116
121
|
//#endregion
|
|
117
|
-
export {
|
|
122
|
+
export { sqlIdent as a, slug as i, permdockKeys as n, sqlString as o, parseTemplate as r, permdockCheck as t };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/core/permdock-sql.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The part of PermDock's `permissions.catalog.json` the Storage and Realtime
|
|
4
|
+
* builders read: `import catalog from './permissions.catalog.json'`.
|
|
5
|
+
*/
|
|
6
|
+
interface PermdockCatalog {
|
|
7
|
+
readonly permissions: readonly {
|
|
8
|
+
readonly key: string;
|
|
9
|
+
readonly rowConditions?: boolean;
|
|
10
|
+
}[];
|
|
11
|
+
}
|
|
12
|
+
/** The keys a bucket or topic PermDock policy names. */
|
|
13
|
+
declare function permdockKeys(policy: {
|
|
14
|
+
readonly permdock: object;
|
|
15
|
+
}): string[];
|
|
16
|
+
//#endregion
|
|
17
|
+
export { permdockKeys as n, PermdockCatalog as t };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
/// <reference lib="esnext.temporal" />
|
|
2
|
+
import { A as SchemaMeta, P as TableMeta, n as AnyModels } from "./types-DONv9SHN.js";
|
|
3
|
+
import { g as Operation, h as MutationOp, r as Executor } from "./executor-DynmIWhq.js";
|
|
4
|
+
import { v as ErrorMapper } from "./result-c2OYgCV2.js";
|
|
4
5
|
//#region src/core/plugin.d.ts
|
|
5
6
|
/** Who is making the request. */
|
|
6
7
|
interface Actor {
|
|
@@ -28,7 +29,7 @@ interface HookArgs {
|
|
|
28
29
|
readonly schema: SchemaMeta;
|
|
29
30
|
readonly context: RequestContext;
|
|
30
31
|
readonly options: CallOptions;
|
|
31
|
-
readonly now: () =>
|
|
32
|
+
readonly now: () => Temporal.Instant;
|
|
32
33
|
}
|
|
33
34
|
type MutationKind = "insert" | "upsert" | "update" | "delete";
|
|
34
35
|
interface MutationEvent {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as Plugin, h as RequestContext } from "../../plugin-
|
|
1
|
+
import { f as Plugin, h as RequestContext } from "../../plugin-DVRB8qNE.js";
|
|
2
2
|
//#region src/plugins/actor/index.d.ts
|
|
3
3
|
export interface ActorOptions {
|
|
4
4
|
/** Custom actor id resolution. Defaults to `context.actor.id` for users and services. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as Operation } from "../../executor-
|
|
2
|
-
import { f as Plugin, m as RepositoryExtension } from "../../plugin-
|
|
1
|
+
import { g as Operation } from "../../executor-DynmIWhq.js";
|
|
2
|
+
import { f as Plugin, m as RepositoryExtension } from "../../plugin-DVRB8qNE.js";
|
|
3
3
|
//#region src/plugins/rules/index.d.ts
|
|
4
4
|
export type RuleLevel = "off" | "warn" | "error";
|
|
5
5
|
/** A level, or a level with the rule's option: `['error', 500]`. */
|
|
@@ -55,7 +55,7 @@ function sensitiveColumns(selection, table) {
|
|
|
55
55
|
return found;
|
|
56
56
|
}
|
|
57
57
|
function isBrowser() {
|
|
58
|
-
return
|
|
58
|
+
return globalThis.window !== void 0 && globalThis.document !== void 0;
|
|
59
59
|
}
|
|
60
60
|
const TEXT_TYPES = /* @__PURE__ */ new Set([
|
|
61
61
|
"text",
|
|
@@ -68,7 +68,7 @@ const templatesBySchema = /* @__PURE__ */ new WeakMap();
|
|
|
68
68
|
function bucketTemplates(schema) {
|
|
69
69
|
let templates = templatesBySchema.get(schema);
|
|
70
70
|
if (!templates) {
|
|
71
|
-
templates = Object.values(schema.buckets ?? {}).filter((bucket) => bucket.path.
|
|
71
|
+
templates = Object.values(schema.buckets ?? {}).filter((bucket) => bucket.path.replaceAll(/\{[^}]*\}|\//g, "").length > 0).map((bucket) => new RegExp(`^${bucket.path.split(/\{[^}]*\}/).map((part) => part.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("[^/]+")}$`));
|
|
72
72
|
templatesBySchema.set(schema, templates);
|
|
73
73
|
}
|
|
74
74
|
return templates;
|
|
@@ -101,13 +101,13 @@ function checks(rules) {
|
|
|
101
101
|
return depth > max ? `includes nest ${depth} levels deep (maximum ${max})` : void 0;
|
|
102
102
|
},
|
|
103
103
|
requireTenantContext: (op, { context, schema }) => {
|
|
104
|
-
if (!op.table.flags.tenant || context.actor?.kind === "service") return
|
|
104
|
+
if (!op.table.flags.tenant || context.actor?.kind === "service") return;
|
|
105
105
|
const claim = optionOf(rules.requireTenantContext, claimsOf(schema).tenant);
|
|
106
106
|
return context.tenant === void 0 && claimAt(context.claims, claim) === void 0 ? `"${op.table.key}" is tenant-scoped but the request has no tenant (context.tenant or claim "${claim}")` : void 0;
|
|
107
107
|
},
|
|
108
108
|
noAdminInBrowser: (_op, { context }) => context.actor?.kind === "service" && isBrowser() ? "a service-role connection is running in a browser" : void 0,
|
|
109
109
|
noSensitiveSelect: (op, { options }) => {
|
|
110
|
-
if (options["sensitive"] === true) return
|
|
110
|
+
if (options["sensitive"] === true) return;
|
|
111
111
|
const selection = op.kind === "select" ? op.selection : op.returning;
|
|
112
112
|
const columns = selection ? sensitiveColumns(selection, op.table) : [];
|
|
113
113
|
return columns.length > 0 ? `reads sensitive column(s) ${columns.join(", ")}; pass { sensitive: true } to allow` : void 0;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as PrimaryKeyValue } from "../../types-
|
|
2
|
-
import { t as AsyncResult } from "../../result-
|
|
3
|
-
import { f as Plugin, m as RepositoryExtension, o as HasFlag } from "../../plugin-
|
|
1
|
+
import { C as PrimaryKeyValue } from "../../types-DONv9SHN.js";
|
|
2
|
+
import { t as AsyncResult } from "../../result-c2OYgCV2.js";
|
|
3
|
+
import { f as Plugin, m as RepositoryExtension, o as HasFlag } from "../../plugin-DVRB8qNE.js";
|
|
4
4
|
//#region src/plugins/soft-delete/index.d.ts
|
|
5
5
|
export interface SoftDeleteFindArgs {
|
|
6
6
|
/** Include soft-deleted rows of the queried table. */
|
|
@@ -45,14 +45,14 @@ function softDelete() {
|
|
|
45
45
|
return {
|
|
46
46
|
kind: "update",
|
|
47
47
|
table,
|
|
48
|
-
set: { [column]: now().
|
|
48
|
+
set: { [column]: now().toString() },
|
|
49
49
|
where: op.where,
|
|
50
50
|
returning: void 0
|
|
51
51
|
};
|
|
52
52
|
},
|
|
53
53
|
repository({ table, base }) {
|
|
54
54
|
const flag = table.flags.softDelete;
|
|
55
|
-
if (!flag) return
|
|
55
|
+
if (!flag) return;
|
|
56
56
|
const update = base["update"];
|
|
57
57
|
return { restore: (key, args) => AsyncResult.from(async () => {
|
|
58
58
|
const result = await update(key, { [flag]: null }, {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as SchemaMeta } from "../../types-
|
|
2
|
-
import { f as Plugin, h as RequestContext, m as RepositoryExtension, o as HasFlag } from "../../plugin-
|
|
1
|
+
import { A as SchemaMeta } from "../../types-DONv9SHN.js";
|
|
2
|
+
import { f as Plugin, h as RequestContext, m as RepositoryExtension, o as HasFlag } from "../../plugin-DVRB8qNE.js";
|
|
3
3
|
//#region src/plugins/tenant/index.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Dotted paths to the string claims of `C` (up to three levels), e.g.
|
|
@@ -14,7 +14,7 @@ function timestamps() {
|
|
|
14
14
|
if (!flags) return op;
|
|
15
15
|
const created = dbName(table, flags.createdAt);
|
|
16
16
|
const updated = dbName(table, flags.updatedAt);
|
|
17
|
-
const stamp = now().
|
|
17
|
+
const stamp = now().toString();
|
|
18
18
|
switch (op.kind) {
|
|
19
19
|
case "insert": {
|
|
20
20
|
const stampCreated = insertsOnly(op);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as Plugin } from "../../plugin-
|
|
2
|
-
import { t as StandardSchemaV1 } from "../../standard-
|
|
1
|
+
import { f as Plugin } from "../../plugin-DVRB8qNE.js";
|
|
2
|
+
import { t as StandardSchemaV1 } from "../../standard-eudBiRk1.js";
|
|
3
3
|
//#region src/plugins/validation/index.d.ts
|
|
4
4
|
export interface TableValidators {
|
|
5
5
|
/** Validates inserts and upserts, with app-cased keys. */
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { t as SqlClient } from "./executor-B26lgbHD.js";
|
|
2
|
+
//#region src/postgres/pool.d.ts
|
|
3
|
+
/** The part of a `pg` pool client `createPostgres` uses. */
|
|
4
|
+
interface PgPoolClient {
|
|
5
|
+
query(text: string, values?: unknown[]): Promise<{
|
|
6
|
+
rows: unknown[];
|
|
7
|
+
}>;
|
|
8
|
+
release(): void;
|
|
9
|
+
}
|
|
10
|
+
/** The part of a `pg.Pool` `createPostgres` uses. */
|
|
11
|
+
interface PgPool {
|
|
12
|
+
connect(): Promise<PgPoolClient>;
|
|
13
|
+
end(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/** Statement timeouts in milliseconds by the role a transaction runs as. */
|
|
16
|
+
interface PostgresTimeouts {
|
|
17
|
+
/** The connection-string role (`admin` and `transaction` without claims). Unset by default. */
|
|
18
|
+
readonly admin?: number;
|
|
19
|
+
/** Defaults to 8000, Supabase's setting for the role. */
|
|
20
|
+
readonly authenticated?: number;
|
|
21
|
+
/** Defaults to 3000, Supabase's setting for the role. */
|
|
22
|
+
readonly anon?: number;
|
|
23
|
+
}
|
|
24
|
+
interface PostgresOptions {
|
|
25
|
+
/** Defaults to `$SUPABASE_DB_URL`, then `$DATABASE_URL`. */
|
|
26
|
+
readonly connectionString?: string;
|
|
27
|
+
/** An existing pool to run on instead of opening one. `end()` ends it. */
|
|
28
|
+
readonly pool?: PgPool;
|
|
29
|
+
readonly max?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Statement timeout in milliseconds, applied per transaction: one value
|
|
32
|
+
* for every role, or one per role. `set role` doesn't apply the role's own
|
|
33
|
+
* `statement_timeout`, so `authenticated` and `anon` get Supabase's 8 s
|
|
34
|
+
* and 3 s unless you set them.
|
|
35
|
+
*/
|
|
36
|
+
readonly statementTimeout?: number | PostgresTimeouts;
|
|
37
|
+
/** Ends a session that stays idle inside a transaction this long, in milliseconds. */
|
|
38
|
+
readonly idleInTransactionTimeout?: number;
|
|
39
|
+
/** How long `connect` waits for a connection, in milliseconds. Defaults to 10000. */
|
|
40
|
+
readonly connectionTimeout?: number;
|
|
41
|
+
/** How long an unused connection stays open, in milliseconds. Defaults to 10000. */
|
|
42
|
+
readonly idleTimeout?: number;
|
|
43
|
+
}
|
|
44
|
+
/** JWT claims to run as. `role` must be `authenticated` or `anon`. */
|
|
45
|
+
interface SqlClaims {
|
|
46
|
+
readonly sub?: string;
|
|
47
|
+
readonly role?: string;
|
|
48
|
+
readonly [claim: string]: unknown;
|
|
49
|
+
}
|
|
50
|
+
interface Postgres {
|
|
51
|
+
/** Connects as the connection-string role. On Supabase that bypasses RLS. */
|
|
52
|
+
readonly admin: SqlClient;
|
|
53
|
+
/** Runs every query as the given user, with RLS, like PostgREST does. */
|
|
54
|
+
asUser(claims: SqlClaims): SqlClient;
|
|
55
|
+
/** Runs every query as `anon`. */
|
|
56
|
+
readonly anon: SqlClient;
|
|
57
|
+
/** Runs `fn` in one transaction. Pass claims to run it as a user. */
|
|
58
|
+
transaction<T>(fn: (client: SqlClient) => Promise<T>, options?: {
|
|
59
|
+
readonly claims?: SqlClaims;
|
|
60
|
+
}): Promise<T>;
|
|
61
|
+
end(): Promise<void>;
|
|
62
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A pooled Postgres connection for jobs, scripts and tests. Each query (or
|
|
66
|
+
* transaction) runs in its own transaction; claims and role are
|
|
67
|
+
* transaction-local, so nothing leaks back into the pool.
|
|
68
|
+
*/
|
|
69
|
+
declare function createPostgres(options?: PostgresOptions): Postgres;
|
|
70
|
+
//#endregion
|
|
71
|
+
export { PostgresTimeouts as a, PostgresOptions as i, PgPoolClient as n, SqlClaims as o, Postgres as r, createPostgres as s, PgPool as t };
|
package/dist/postgres/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { g as Operation } from "../executor-
|
|
2
|
-
import { n as fromPgError, r as postgresExecutor, t as SqlClient } from "../executor-
|
|
3
|
-
import { i as
|
|
4
|
-
import { t as Compiler } from "../compiler-
|
|
1
|
+
import { g as Operation } from "../executor-DynmIWhq.js";
|
|
2
|
+
import { n as fromPgError, r as postgresExecutor, t as SqlClient } from "../executor-B26lgbHD.js";
|
|
3
|
+
import { a as PostgresTimeouts, i as PostgresOptions, n as PgPoolClient, o as SqlClaims, r as Postgres, s as createPostgres, t as PgPool } from "../pool-B9qsLyFR.js";
|
|
4
|
+
import { t as Compiler } from "../compiler-2zqGzxVZ.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 PgPool, type PgPoolClient, type Postgres, type PostgresOptions, type PostgresTimeouts, type SqlClaims, type SqlClient, type SqlPlan, type SqlQuery, createPostgres, fromPgError, postgresExecutor };
|
package/dist/postgres/index.js
CHANGED
|
@@ -1,35 +1,55 @@
|
|
|
1
|
-
import { n as quoteIdent, t as compileSql } from "../sql-
|
|
2
|
-
import { n as postgresExecutor, t as fromPgError } from "../executor-
|
|
1
|
+
import { n as quoteIdent, t as compileSql } from "../sql-BIgk12ew.js";
|
|
2
|
+
import { n as postgresExecutor, t as fromPgError } from "../executor-C57jx2pn.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
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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();
|
|
@@ -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.
|
|
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
|
|
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-
|
|
1
|
+
import { b as ValidationIssue, m as DbErrorKind, p as DbError } from "./result-c2OYgCV2.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?:
|
|
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
|
|
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;
|
package/dist/query/index.d.ts
CHANGED
|
@@ -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-
|
|
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 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-CriFFJ_p.js";
|
|
2
|
+
export { type BetterQueryMeta, type CreateQueriesOptions, type InfiniteOptionsOf, type MutationOptionsOf, type Queries, type QueryHelpers, type QueryKeyOf, type QueryOptionsOf, type TableQueries, createQueries, invalidateOnMutation, invalidateTables, queryCache };
|
package/dist/query/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { t as invalidateTables } from "../invalidate-DbxuL2jL.js";
|
|
2
|
-
import { n as invalidateOnMutation, r as queryCache, t as createQueries } from "../query-
|
|
2
|
+
import { n as invalidateOnMutation, r as queryCache, t as createQueries } from "../query-BdKLTPlj.js";
|
|
3
3
|
export { createQueries, invalidateOnMutation, invalidateTables, queryCache };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as DbException } from "./errors-Bl3rkOzo.js";
|
|
2
|
-
import { t as invalidationTargets } from "./tables-
|
|
2
|
+
import { t as invalidationTargets } from "./tables-Dhha3BXM.js";
|
|
3
3
|
import { t as invalidateTables } from "./invalidate-DbxuL2jL.js";
|
|
4
|
-
//#region src/query/
|
|
4
|
+
//#region src/query/queries.ts
|
|
5
5
|
/** Query errors stay `DbException`s, even for an `sb` with `mapError()`. */
|
|
6
6
|
const asException = (error) => new DbException(error);
|
|
7
7
|
function isSkip(value) {
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { s as Impersonator } from "../mfa-
|
|
2
|
-
import { t as AuthSession } from "../view-
|
|
3
|
-
import { r as LiveCountSeed } from "../live-
|
|
4
|
-
import { n as MembershipClaim, r as hasEntitlement, t as EntitlementKey } from "../entitlements-
|
|
5
|
-
import { n as
|
|
6
|
-
import {
|
|
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-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 };
|
package/dist/react/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
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";
|
|
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 };
|
package/dist/react/server.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as AuthSession } from "../view-
|
|
2
|
-
import { n as
|
|
3
|
-
import {
|
|
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";
|
|
3
|
+
import { SessionProvider, SessionProviderProps } from "./session.js";
|
|
4
4
|
//#region src/react/server.d.ts
|
|
5
5
|
/** The `react-server` build of `useSession`: await `next.session()` instead. */
|
|
6
6
|
export declare const useSession: <C = unknown, P = unknown>() => AuthSession<C, P>;
|
package/dist/react/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as useBroadcast, o as useLiveQuery, r as useAuth, s as useSupabase, t as BetterSupabaseProvider } from "../react-
|
|
1
|
+
import { i as useBroadcast, o as useLiveQuery, r as useAuth, s as useSupabase, t as BetterSupabaseProvider } from "../react-DNBYNazu.js";
|
|
2
2
|
import { SessionProvider } from "./session.js";
|
|
3
3
|
//#region src/react/server.ts
|
|
4
4
|
function clientOnly(name) {
|
package/dist/react/session.d.ts
CHANGED
|
@@ -1,2 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { t as AuthSession } from "../view-3Po_PVlr.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/react/session.d.ts
|
|
4
|
+
export interface SessionProviderProps {
|
|
5
|
+
/**
|
|
6
|
+
* An unresolved `next.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 `sb.claims(schema)`) and `P` the profile (the output of
|
|
18
|
+
* `sb.userMetadata(schema)`); `createHooks().useSession` infers both.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useSession<C = unknown, P = unknown>(): AuthSession<C, P>;
|
|
21
|
+
//#endregion
|
package/dist/react/session.js
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
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 `sb.claims(schema)`) and `P` the profile (the output of
|
|
13
|
+
* `sb.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 };
|