better-supabase 0.0.0 → 0.1.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/LICENSE +21 -0
- package/README.md +88 -1
- package/bin/better-supabase.js +3 -0
- package/dist/casing-da0uRTqt.js +14 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +15 -0
- package/dist/cli/index.d.ts +226 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli-CoByWYja.js +6472 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +112 -0
- package/dist/compiler-DL18ukPe.d.ts +14 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +3 -0
- package/dist/config-D-aR2ZoN.js +276 -0
- package/dist/define-CTfWw-SS.d.ts +662 -0
- package/dist/define-QGkq04oe.js +1068 -0
- package/dist/edge/index.d.ts +43 -0
- package/dist/edge/index.js +103 -0
- package/dist/entitlements-BBg61DQZ.d.ts +20 -0
- package/dist/entitlements-BC_khwRy.js +17 -0
- package/dist/env/index.d.ts +2 -0
- package/dist/env/index.js +2 -0
- package/dist/env-BEToab0I.js +204 -0
- package/dist/errors-Bl3rkOzo.js +196 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.js +2 -0
- package/dist/events-2OJsVG_d.d.ts +84 -0
- package/dist/events-BuzTgn2D.js +135 -0
- package/dist/executor-Bazhgsgq.d.ts +195 -0
- package/dist/executor-Bje4suQF.d.ts +25 -0
- package/dist/executor-Ceq60hPM.js +89 -0
- package/dist/hono/index.d.ts +45 -0
- package/dist/hono/index.js +70 -0
- package/dist/index-BD6wKthp.d.ts +597 -0
- package/dist/index-DQVvHzjW.d.ts +74 -0
- package/dist/index-DRid0qIv.d.ts +76 -0
- package/dist/index-Dup-nSe9.d.ts +117 -0
- package/dist/index-Dy6kuF0P.d.ts +71 -0
- package/dist/index-Hf8PP9sP.d.ts +116 -0
- package/dist/index-JXHBuS53.d.ts +144 -0
- package/dist/index-Nxo3TJcm.d.ts +208 -0
- package/dist/index-Sw43J8HG.d.ts +62 -0
- package/dist/index-cEeweTeM.d.ts +38 -0
- package/dist/index.d.ts +110 -0
- package/dist/index.js +42 -0
- package/dist/invalidate-DbxuL2jL.js +18 -0
- package/dist/jobs/index.d.ts +173 -0
- package/dist/jobs/index.js +477 -0
- package/dist/json-schema-BbwO2mZg.js +181 -0
- package/dist/lint/index.d.ts +75 -0
- package/dist/lint/index.js +167 -0
- package/dist/list/index.d.ts +2 -0
- package/dist/list/index.js +410 -0
- package/dist/live-6b9i72Ux.d.ts +180 -0
- package/dist/live-D8rV1Ldw.js +168 -0
- package/dist/mcp/index.d.ts +105 -0
- package/dist/mcp/index.js +330 -0
- package/dist/mfa-CpogP66z.js +521 -0
- package/dist/mfa-TVia554c.d.ts +44 -0
- package/dist/next/image/index.d.ts +34 -0
- package/dist/next/image/index.js +40 -0
- package/dist/next/index.d.ts +210 -0
- package/dist/next/index.js +426 -0
- package/dist/openapi/index.d.ts +2 -0
- package/dist/openapi/index.js +332 -0
- package/dist/orpc/index.d.ts +46 -0
- package/dist/orpc/index.js +50 -0
- package/dist/otel/index.d.ts +40 -0
- package/dist/otel/index.js +168 -0
- package/dist/path-Cv__-OTj.d.ts +17 -0
- package/dist/plugin-BqR6wKMB.js +23 -0
- package/dist/plugin-HvGqCurB.d.ts +118 -0
- package/dist/plugins/actor/index.d.ts +13 -0
- package/dist/plugins/actor/index.js +43 -0
- package/dist/plugins/rules/index.d.ts +88 -0
- package/dist/plugins/rules/index.js +174 -0
- package/dist/plugins/soft-delete/index.d.ts +38 -0
- package/dist/plugins/soft-delete/index.js +69 -0
- package/dist/plugins/tenant/index.d.ts +43 -0
- package/dist/plugins/tenant/index.js +73 -0
- package/dist/plugins/timestamps/index.d.ts +9 -0
- package/dist/plugins/timestamps/index.js +37 -0
- package/dist/plugins/validation/index.d.ts +24 -0
- package/dist/plugins/validation/index.js +59 -0
- package/dist/pool-BFeqzwQS.d.ts +37 -0
- package/dist/postgres/index.d.ts +28 -0
- package/dist/postgres/index.js +79 -0
- package/dist/postgrest-Dm-vhY6R.d.ts +43 -0
- package/dist/problem-DPu6Fh-t.js +97 -0
- package/dist/problem-DlgB0lYl.d.ts +47 -0
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +3 -0
- package/dist/query-ChvDbsDE.js +186 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.js +5 -0
- package/dist/react/server.d.ts +13 -0
- package/dist/react/server.js +25 -0
- package/dist/react/session.d.ts +2 -0
- package/dist/react/session.js +3 -0
- package/dist/react-CrOvrnIP.js +241 -0
- package/dist/read-set-DhX2d04c.js +216 -0
- package/dist/realtime/index.d.ts +3 -0
- package/dist/realtime/index.js +253 -0
- package/dist/resolve-DW8h9NPm.d.ts +155 -0
- package/dist/resource-CYiu6Ygi.js +175 -0
- package/dist/resource-SkPTRJDD.d.ts +65 -0
- package/dist/respond-4-dhoV7x.js +380 -0
- package/dist/respond-PoTpy5DT.d.ts +169 -0
- package/dist/result-CTkCZ6JA.d.ts +198 -0
- package/dist/result-DWXatkd6.js +103 -0
- package/dist/scope-CDHcS7dE.js +90 -0
- package/dist/seed-CzecODcJ.js +101 -0
- package/dist/server/index.d.ts +42 -0
- package/dist/server/index.js +68 -0
- package/dist/session-C3osL21k.d.ts +21 -0
- package/dist/session-CD-3orO_.js +19 -0
- package/dist/shared-_6-uPL7E.js +57 -0
- package/dist/simplify-oHiDKRVQ.js +665 -0
- package/dist/spec-pins-CJPVghHy.d.ts +20 -0
- package/dist/spec-pins-t6sPaHvl.js +20 -0
- package/dist/sql-M8l3fnS0.js +260 -0
- package/dist/ssr/index.d.ts +5 -0
- package/dist/ssr/index.js +4 -0
- package/dist/standard-CyhRzctb.d.ts +7 -0
- package/dist/standard-FUi3Z3-7.js +21 -0
- package/dist/stats-3iy8u3_P.js +566 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage-BWXVUXGk.js +461 -0
- package/dist/tables-rZxRxNPW.js +59 -0
- package/dist/template-BeOGnynM.js +93 -0
- package/dist/template-mbvlysOo.d.ts +6 -0
- package/dist/testing/index.d.ts +294 -0
- package/dist/testing/index.js +751 -0
- package/dist/types-6cYK9pbJ.js +29 -0
- package/dist/types-C2fslP1z.d.ts +195 -0
- package/dist/version-Cqq1m3UY.js +4 -0
- package/dist/view-B0ltUmTi.d.ts +43 -0
- package/dist/view-B6F9QbG-.js +35 -0
- package/dist/webhooks/index.d.ts +152 -0
- package/dist/webhooks/index.js +2 -0
- package/dist/webhooks-DbMTJJX2.js +139 -0
- package/package.json +246 -17
- package/schemas/config-v1.json +328 -0
- package/schemas/doctor-report-v1.json +105 -0
- package/schemas/snapshot-v2.json +1002 -0
- package/skills/better-supabase/SKILL.md +84 -0
- package/skills/better-supabase/references/plugins.md +56 -0
- package/skills/better-supabase/references/troubleshooting.md +39 -0
- package/skills/better-supabase-api/SKILL.md +67 -0
- package/skills/better-supabase-api/references/adapters.md +108 -0
- package/skills/better-supabase-testing/SKILL.md +65 -0
- package/index.js +0 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
//#region src/core/errors.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Extra fields carried by each error kind. Plugins can add kinds through the
|
|
4
|
+
* `errors` extension point; apps that want the new kinds in the union can add
|
|
5
|
+
* them to this interface.
|
|
6
|
+
*/
|
|
7
|
+
interface DbErrorKinds {
|
|
8
|
+
not_found: Record<never, never>;
|
|
9
|
+
unauthorized: Record<never, never>;
|
|
10
|
+
/** `required`: the assurance level the route needs, when a second factor is missing. */
|
|
11
|
+
forbidden: {
|
|
12
|
+
required?: "aal1" | "aal2";
|
|
13
|
+
};
|
|
14
|
+
conflict: {
|
|
15
|
+
constraint?: string;
|
|
16
|
+
columns?: readonly string[];
|
|
17
|
+
};
|
|
18
|
+
foreign_key: {
|
|
19
|
+
constraint?: string;
|
|
20
|
+
columns?: readonly string[];
|
|
21
|
+
};
|
|
22
|
+
check: {
|
|
23
|
+
constraint?: string;
|
|
24
|
+
};
|
|
25
|
+
not_null: {
|
|
26
|
+
column?: string;
|
|
27
|
+
};
|
|
28
|
+
exclusion: {
|
|
29
|
+
constraint?: string;
|
|
30
|
+
};
|
|
31
|
+
invalid_input: Record<never, never>;
|
|
32
|
+
raised: Record<never, never>;
|
|
33
|
+
timeout: Record<never, never>;
|
|
34
|
+
serialization: Record<never, never>;
|
|
35
|
+
network: Record<never, never>;
|
|
36
|
+
aborted: Record<never, never>;
|
|
37
|
+
invalid_request: Record<never, never>;
|
|
38
|
+
validation: {
|
|
39
|
+
issues: readonly ValidationIssue[];
|
|
40
|
+
};
|
|
41
|
+
multiple_rows: Record<never, never>;
|
|
42
|
+
stale: Record<never, never>;
|
|
43
|
+
/** `retryAfter`: seconds until the window resets (the `Retry-After` header). */
|
|
44
|
+
rate_limited: {
|
|
45
|
+
retryAfter?: number;
|
|
46
|
+
};
|
|
47
|
+
unexpected: Record<never, never>;
|
|
48
|
+
}
|
|
49
|
+
type DbErrorKind = keyof DbErrorKinds;
|
|
50
|
+
interface ValidationIssue {
|
|
51
|
+
readonly message: string;
|
|
52
|
+
readonly path?: readonly PropertyKey[];
|
|
53
|
+
}
|
|
54
|
+
interface DbErrorBase<K extends DbErrorKind> {
|
|
55
|
+
readonly kind: K;
|
|
56
|
+
readonly message: string;
|
|
57
|
+
/** SQLSTATE or PostgREST code (`23505`, `PGRST116`), when known. */
|
|
58
|
+
readonly code?: string;
|
|
59
|
+
/** Suggested HTTP status, used by the RFC 9457 mapping. */
|
|
60
|
+
readonly status: number;
|
|
61
|
+
readonly details?: string;
|
|
62
|
+
/** Postgres `HINT`. `raised` errors use it as an app-level error code. */
|
|
63
|
+
readonly hint?: string;
|
|
64
|
+
/** App-cased table key the operation ran against. */
|
|
65
|
+
readonly table?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A database error as plain, serializable data. Safe to send across server
|
|
69
|
+
* action and RPC boundaries.
|
|
70
|
+
*/
|
|
71
|
+
type DbError = { [K in DbErrorKind]: DbErrorBase<K> & DbErrorKinds[K]; }[DbErrorKind];
|
|
72
|
+
type DbErrorOf<K extends DbErrorKind> = Extract<DbError, {
|
|
73
|
+
kind: K;
|
|
74
|
+
}>;
|
|
75
|
+
declare function statusOf(kind: DbErrorKind): number;
|
|
76
|
+
type ExtraOf<K extends DbErrorKind> = Record<never, never> extends DbErrorKinds[K] ? [extra?: DbErrorKinds[K] & Partial<Omit<DbErrorBase<K>, "kind">>] : [extra: DbErrorKinds[K] & Partial<Omit<DbErrorBase<K>, "kind">>];
|
|
77
|
+
/** Creates a `DbError` with the default status for its kind. */
|
|
78
|
+
declare function dbError<K extends DbErrorKind>(kind: K, message: string, ...[extra]: ExtraOf<K>): DbErrorOf<K>;
|
|
79
|
+
declare function isDbError(value: unknown): value is DbError;
|
|
80
|
+
/**
|
|
81
|
+
* A unique violation, optionally for one constraint. Accepts a `DbError` or a
|
|
82
|
+
* `DbException`. Pass the generated `UniqueConstraint` type to check names:
|
|
83
|
+
* `isConflict<UniqueConstraint>(error, 'customers_organization_id_kvk_key')`.
|
|
84
|
+
*/
|
|
85
|
+
declare const isConflict: <C extends string = string>(error: unknown, constraint?: NoInfer<C>) => error is DbErrorOf<"conflict"> & {
|
|
86
|
+
readonly constraint: C;
|
|
87
|
+
};
|
|
88
|
+
/** A CHECK violation, optionally for one constraint (`CheckConstraint`). */
|
|
89
|
+
declare const isCheck: <C extends string = string>(error: unknown, constraint?: NoInfer<C>) => error is DbErrorOf<"check"> & {
|
|
90
|
+
readonly constraint: C;
|
|
91
|
+
};
|
|
92
|
+
/** A foreign key violation, optionally for one constraint (`ForeignKeyConstraint`). */
|
|
93
|
+
declare const isForeignKey: <C extends string = string>(error: unknown, constraint?: NoInfer<C>) => error is DbErrorOf<"foreign_key"> & {
|
|
94
|
+
readonly constraint: C;
|
|
95
|
+
};
|
|
96
|
+
/** Thrown by `.orThrow()`. Carries the plain `DbError` as `error`. */
|
|
97
|
+
declare class DbException extends Error {
|
|
98
|
+
override readonly name = "DbException";
|
|
99
|
+
readonly error: DbError;
|
|
100
|
+
constructor(error: DbError);
|
|
101
|
+
get kind(): DbErrorKind;
|
|
102
|
+
}
|
|
103
|
+
/** Raw error shape shared by PostgREST responses and `pg` errors. */
|
|
104
|
+
interface RawDbError {
|
|
105
|
+
readonly message?: string;
|
|
106
|
+
readonly code?: string;
|
|
107
|
+
readonly details?: string | null;
|
|
108
|
+
readonly hint?: string | null;
|
|
109
|
+
readonly constraint?: string;
|
|
110
|
+
readonly column?: string;
|
|
111
|
+
readonly table?: string;
|
|
112
|
+
readonly name?: string;
|
|
113
|
+
}
|
|
114
|
+
type ErrorMapper = (raw: RawDbError, fallback: DbError) => DbError | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* Maps a PostgREST or Postgres error to a `DbError`. Custom mappers run
|
|
117
|
+
* first; the first one that returns an error wins.
|
|
118
|
+
*/
|
|
119
|
+
declare function mapDbError(raw: RawDbError, mappers?: readonly ErrorMapper[]): DbError;
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/core/result.d.ts
|
|
122
|
+
/** Turns a `DbError` into the error `.orThrow()` throws; set with `sb.mapError()`. */
|
|
123
|
+
type ThrowMapper = (error: DbError) => unknown;
|
|
124
|
+
type Ok<T> = {
|
|
125
|
+
readonly ok: true;
|
|
126
|
+
readonly data: T;
|
|
127
|
+
readonly error: null;
|
|
128
|
+
};
|
|
129
|
+
type Err<E = DbError> = {
|
|
130
|
+
readonly ok: false;
|
|
131
|
+
readonly data: null;
|
|
132
|
+
readonly error: E;
|
|
133
|
+
};
|
|
134
|
+
type Result<T, E = DbError> = Ok<T> | Err<E>;
|
|
135
|
+
declare function ok<T>(data: T): Ok<T>;
|
|
136
|
+
declare function err<E = DbError>(error: E): Err<E>;
|
|
137
|
+
/**
|
|
138
|
+
* A lazy-free `PromiseLike<Result<T>>` with helpers. `await` gives the
|
|
139
|
+
* `Result`; `.orThrow()` gives the data or throws a `DbException`.
|
|
140
|
+
*/
|
|
141
|
+
declare class AsyncResult<T> implements PromiseLike<Result<T>> {
|
|
142
|
+
#private;
|
|
143
|
+
constructor(promise: Promise<Result<T>>);
|
|
144
|
+
static from<T>(run: () => Promise<Result<T>>): AsyncResult<T>;
|
|
145
|
+
static ok<T>(data: T): AsyncResult<T>;
|
|
146
|
+
static err<T = never>(error: DbError): AsyncResult<T>;
|
|
147
|
+
then<R1 = Result<T>, R2 = never>(onfulfilled?: ((value: Result<T>) => R1 | PromiseLike<R1>) | null, onrejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | null): Promise<R1 | R2>;
|
|
148
|
+
/**
|
|
149
|
+
* Resolves with the data, or rejects with a `DbException`. Pass `factory`
|
|
150
|
+
* to throw your own error instead, e.g. an HTTP error for your framework;
|
|
151
|
+
* without it, the mapper from `sb.mapError()` applies when one is set.
|
|
152
|
+
*/
|
|
153
|
+
orThrow(factory?: (error: DbError) => unknown): Promise<T>;
|
|
154
|
+
/** Resolves with the data, or `fallback` when the result is an error. */
|
|
155
|
+
unwrapOr<F>(fallback: F): Promise<T | F>;
|
|
156
|
+
map<U>(fn: (data: T) => U): AsyncResult<U>;
|
|
157
|
+
mapError(fn: (error: DbError) => DbError): AsyncResult<T>;
|
|
158
|
+
andThen<U>(fn: (data: T) => PromiseLike<Result<U>>): AsyncResult<U>;
|
|
159
|
+
}
|
|
160
|
+
/** What `toBetterResult` returns: the `status`/`value`/`error` fields every better-result value has. */
|
|
161
|
+
type BetterResultShape<T, E> = {
|
|
162
|
+
readonly status: "ok";
|
|
163
|
+
readonly value: T;
|
|
164
|
+
} | {
|
|
165
|
+
readonly status: "error";
|
|
166
|
+
readonly error: E;
|
|
167
|
+
};
|
|
168
|
+
/** The part of better-result's `Result` namespace `toBetterResult` calls. */
|
|
169
|
+
interface BetterResultApi<T, E> {
|
|
170
|
+
ok(value: NoInfer<T>): unknown;
|
|
171
|
+
err(error: NoInfer<E>): unknown;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Builds a better-result value with the `Result` namespace you pass, so
|
|
175
|
+
* better-result stays your dependency. Errors go through `mapError`, or, for a
|
|
176
|
+
* result from a `db` of `sb.mapError(fn)`, through `fn` (typed `unknown`).
|
|
177
|
+
* The value is a real `Ok`/`Err`: cast it (`as Result<T, E>`) for its
|
|
178
|
+
* methods in types; the cast itself is not checked against `T`.
|
|
179
|
+
*
|
|
180
|
+
* ```ts
|
|
181
|
+
* import { Result } from 'better-result';
|
|
182
|
+
* const customer = toBetterResult(await db.customers.findById(id), Result, toAppError);
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
declare function toBetterResult<T, E>(result: Result<T>, api: BetterResultApi<T, E>, mapError: (error: DbError) => E): BetterResultShape<T, E>;
|
|
186
|
+
declare function toBetterResult<T>(result: Result<T>, api: BetterResultApi<T, DbError>): BetterResultShape<T, DbError>;
|
|
187
|
+
declare function toBetterResult<T, E>(result: AsyncResult<T>, api: BetterResultApi<T, E>, mapError: (error: DbError) => E): Promise<BetterResultShape<T, E>>;
|
|
188
|
+
declare function toBetterResult<T>(result: AsyncResult<T>, api: BetterResultApi<T, unknown>): Promise<BetterResultShape<T, unknown>>;
|
|
189
|
+
/**
|
|
190
|
+
* Converts a better-result value back into a `Result`, by its `status`
|
|
191
|
+
* field, so it works across better-result versions. A `DbError`, or an
|
|
192
|
+
* error whose `cause` is one, is kept; others go through `mapError`
|
|
193
|
+
* (default `toDbError`).
|
|
194
|
+
*/
|
|
195
|
+
declare function fromBetterResult<T>(result: BetterResultShape<T, unknown>, mapError?: (error: unknown) => DbError): Result<T>;
|
|
196
|
+
declare function toDbError(cause: unknown): DbError;
|
|
197
|
+
//#endregion
|
|
198
|
+
export { isConflict as C, statusOf as D, mapDbError as E, isCheck as S, isForeignKey as T, DbException as _, Ok as a, ValidationIssue as b, err as c, toBetterResult as d, toDbError as f, DbErrorOf as g, DbErrorKinds as h, Err as i, fromBetterResult as l, DbErrorKind as m, BetterResultApi as n, Result as o, DbError as p, BetterResultShape as r, ThrowMapper as s, AsyncResult as t, ok as u, ErrorMapper as v, isDbError as w, dbError as x, RawDbError as y };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { n as dbError, r as dbErrorOf, t as DbException } from "./errors-Bl3rkOzo.js";
|
|
2
|
+
//#region src/core/result.ts
|
|
3
|
+
const throwMappers = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function inherit(from, next) {
|
|
5
|
+
const mapper = throwMappers.get(from);
|
|
6
|
+
if (mapper) throwMappers.set(next, mapper);
|
|
7
|
+
return next;
|
|
8
|
+
}
|
|
9
|
+
/** Marks `result` so its `.orThrow()` throws `mapper(error)`; returns it. */
|
|
10
|
+
function withErrorMapper(result, mapper) {
|
|
11
|
+
throwMappers.set(result, mapper);
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
function ok(data) {
|
|
15
|
+
return {
|
|
16
|
+
ok: true,
|
|
17
|
+
data,
|
|
18
|
+
error: null
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function err(error) {
|
|
22
|
+
return {
|
|
23
|
+
ok: false,
|
|
24
|
+
data: null,
|
|
25
|
+
error
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A lazy-free `PromiseLike<Result<T>>` with helpers. `await` gives the
|
|
30
|
+
* `Result`; `.orThrow()` gives the data or throws a `DbException`.
|
|
31
|
+
*/
|
|
32
|
+
var AsyncResult = class AsyncResult {
|
|
33
|
+
#promise;
|
|
34
|
+
constructor(promise) {
|
|
35
|
+
this.#promise = promise.catch((cause) => err(toDbError(cause)));
|
|
36
|
+
}
|
|
37
|
+
static from(run) {
|
|
38
|
+
return new AsyncResult(Promise.resolve().then(run));
|
|
39
|
+
}
|
|
40
|
+
static ok(data) {
|
|
41
|
+
return new AsyncResult(Promise.resolve(ok(data)));
|
|
42
|
+
}
|
|
43
|
+
static err(error) {
|
|
44
|
+
return new AsyncResult(Promise.resolve(err(error)));
|
|
45
|
+
}
|
|
46
|
+
then(onfulfilled, onrejected) {
|
|
47
|
+
return this.#promise.then(onfulfilled, onrejected);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolves with the data, or rejects with a `DbException`. Pass `factory`
|
|
51
|
+
* to throw your own error instead, e.g. an HTTP error for your framework;
|
|
52
|
+
* without it, the mapper from `sb.mapError()` applies when one is set.
|
|
53
|
+
*/
|
|
54
|
+
async orThrow(factory) {
|
|
55
|
+
const result = await this.#promise;
|
|
56
|
+
if (result.ok) return result.data;
|
|
57
|
+
const mapper = factory ?? throwMappers.get(this);
|
|
58
|
+
throw mapper ? mapper(result.error) : new DbException(result.error);
|
|
59
|
+
}
|
|
60
|
+
/** Resolves with the data, or `fallback` when the result is an error. */
|
|
61
|
+
async unwrapOr(fallback) {
|
|
62
|
+
const result = await this.#promise;
|
|
63
|
+
return result.ok ? result.data : fallback;
|
|
64
|
+
}
|
|
65
|
+
map(fn) {
|
|
66
|
+
return inherit(this, new AsyncResult(this.#promise.then((result) => result.ok ? ok(fn(result.data)) : result)));
|
|
67
|
+
}
|
|
68
|
+
mapError(fn) {
|
|
69
|
+
return inherit(this, new AsyncResult(this.#promise.then((result) => result.ok ? result : err(fn(result.error)))));
|
|
70
|
+
}
|
|
71
|
+
andThen(fn) {
|
|
72
|
+
return inherit(this, new AsyncResult(this.#promise.then((result) => result.ok ? fn(result.data) : result)));
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
function toBetterResult(result, api, mapError) {
|
|
76
|
+
const build = (settled, mapper) => settled.ok ? api.ok(settled.data) : api.err(mapper ? mapper(settled.error) : settled.error);
|
|
77
|
+
if (result instanceof AsyncResult) {
|
|
78
|
+
const mapper = mapError ?? throwMappers.get(result);
|
|
79
|
+
return result.then((settled) => build(settled, mapper));
|
|
80
|
+
}
|
|
81
|
+
return build(result, mapError);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Converts a better-result value back into a `Result`, by its `status`
|
|
85
|
+
* field, so it works across better-result versions. A `DbError`, or an
|
|
86
|
+
* error whose `cause` is one, is kept; others go through `mapError`
|
|
87
|
+
* (default `toDbError`).
|
|
88
|
+
*/
|
|
89
|
+
function fromBetterResult(result, mapError = toDbError) {
|
|
90
|
+
switch (result.status) {
|
|
91
|
+
case "ok": return ok(result.value);
|
|
92
|
+
case "error": return err(dbErrorOf(result.error) ?? mapError(result.error));
|
|
93
|
+
default: throw new TypeError(`better-supabase: fromBetterResult() expects a better-result value, got ${String(result)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function toDbError(cause) {
|
|
97
|
+
if (cause instanceof DbException) return cause.error;
|
|
98
|
+
if (cause instanceof Error && cause.name === "AbortError") return dbError("aborted", cause.message || "The operation was aborted");
|
|
99
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
100
|
+
return dbError("unexpected", message);
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
export { toBetterResult as a, ok as i, err as n, toDbError as o, fromBetterResult as r, withErrorMapper as s, AsyncResult as t };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { r as not, t as and } from "./types-6cYK9pbJ.js";
|
|
2
|
+
//#region src/ir/scope.ts
|
|
3
|
+
/**
|
|
4
|
+
* Applies `scopeFor` to every relation filter in a condition. `every(W)`
|
|
5
|
+
* becomes `none(S and not W)` so out-of-scope rows (soft-deleted, other
|
|
6
|
+
* tenants) neither satisfy nor fail it.
|
|
7
|
+
*/
|
|
8
|
+
function scopeCondition(condition, scopeFor) {
|
|
9
|
+
if (!condition) return void 0;
|
|
10
|
+
switch (condition.kind) {
|
|
11
|
+
case "and":
|
|
12
|
+
case "or": return {
|
|
13
|
+
kind: condition.kind,
|
|
14
|
+
items: condition.items.map((item) => scopeCondition(item, scopeFor) ?? item)
|
|
15
|
+
};
|
|
16
|
+
case "not": return {
|
|
17
|
+
kind: "not",
|
|
18
|
+
item: scopeCondition(condition.item, scopeFor) ?? condition.item
|
|
19
|
+
};
|
|
20
|
+
case "column": return condition;
|
|
21
|
+
case "relation": {
|
|
22
|
+
const inner = scopeCondition(condition.where, scopeFor);
|
|
23
|
+
const scope = scopeFor(condition.target);
|
|
24
|
+
if (!scope) return {
|
|
25
|
+
...condition,
|
|
26
|
+
where: inner
|
|
27
|
+
};
|
|
28
|
+
switch (condition.quantifier) {
|
|
29
|
+
case "some":
|
|
30
|
+
case "none": return {
|
|
31
|
+
...condition,
|
|
32
|
+
where: and(inner, scope)
|
|
33
|
+
};
|
|
34
|
+
case "every": return inner ? {
|
|
35
|
+
...condition,
|
|
36
|
+
quantifier: "none",
|
|
37
|
+
where: and(scope, not(inner))
|
|
38
|
+
} : {
|
|
39
|
+
...condition,
|
|
40
|
+
where: void 0
|
|
41
|
+
};
|
|
42
|
+
default: return condition.quantifier;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
default: return condition;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function scopeInclude(include, scopeFor) {
|
|
49
|
+
return {
|
|
50
|
+
...include,
|
|
51
|
+
selection: scopeSelection(include.selection, scopeFor),
|
|
52
|
+
where: and(scopeCondition(include.where, scopeFor), scopeFor(include.target))
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Applies `scopeFor` to every include and to filters inside includes. */
|
|
56
|
+
function scopeSelection(selection, scopeFor) {
|
|
57
|
+
if (selection.includes.length === 0) return selection;
|
|
58
|
+
return {
|
|
59
|
+
...selection,
|
|
60
|
+
includes: selection.includes.map((include) => scopeInclude(include, scopeFor))
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Scopes a whole operation: the root table's rows (reads, updates, deletes),
|
|
65
|
+
* relation filters, includes and returned embeds. Inserts only get their
|
|
66
|
+
* returning selection scoped.
|
|
67
|
+
*/
|
|
68
|
+
function scopeOperation(op, scopeFor, root = true) {
|
|
69
|
+
const own = root ? scopeFor(op.table) : void 0;
|
|
70
|
+
switch (op.kind) {
|
|
71
|
+
case "select": return {
|
|
72
|
+
...op,
|
|
73
|
+
selection: scopeSelection(op.selection, scopeFor),
|
|
74
|
+
where: and(scopeCondition(op.where, scopeFor), own)
|
|
75
|
+
};
|
|
76
|
+
case "update":
|
|
77
|
+
case "delete": return {
|
|
78
|
+
...op,
|
|
79
|
+
where: and(scopeCondition(op.where, scopeFor), own),
|
|
80
|
+
returning: op.returning ? scopeSelection(op.returning, scopeFor) : void 0
|
|
81
|
+
};
|
|
82
|
+
case "insert": return {
|
|
83
|
+
...op,
|
|
84
|
+
returning: op.returning ? scopeSelection(op.returning, scopeFor) : void 0
|
|
85
|
+
};
|
|
86
|
+
default: return op;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { scopeOperation as n, scopeSelection as r, scopeCondition as t };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
//#region src/testing/seed.ts
|
|
2
|
+
const SEED = Symbol.for("better-supabase.seed");
|
|
3
|
+
function isSeed(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && SEED in value;
|
|
5
|
+
}
|
|
6
|
+
const quote = (text) => `'${text.replaceAll("'", "''")}'`;
|
|
7
|
+
function arrayLiteral(values) {
|
|
8
|
+
return `{${values.map((value) => {
|
|
9
|
+
if (value === null) return "NULL";
|
|
10
|
+
if (Array.isArray(value)) return arrayLiteral(value);
|
|
11
|
+
return `"${(value instanceof Date ? value.toISOString() : String(value)).replace(/[\\"]/g, "\\$&")}"`;
|
|
12
|
+
}).join(",")}}`;
|
|
13
|
+
}
|
|
14
|
+
function literal(value, column, where) {
|
|
15
|
+
if (value === null) return "null";
|
|
16
|
+
if (column.json) return quote(JSON.stringify(value));
|
|
17
|
+
if (Array.isArray(value)) return quote(arrayLiteral(value));
|
|
18
|
+
if (value instanceof Date) return quote(value.toISOString());
|
|
19
|
+
const kind = typeof value;
|
|
20
|
+
switch (kind) {
|
|
21
|
+
case "string": return quote(value);
|
|
22
|
+
case "boolean":
|
|
23
|
+
case "bigint": return String(value);
|
|
24
|
+
case "number":
|
|
25
|
+
if (!Number.isFinite(value)) throw new TypeError(`${where}: ${String(value)} is not a finite number`);
|
|
26
|
+
return String(value);
|
|
27
|
+
case "object":
|
|
28
|
+
case "function":
|
|
29
|
+
case "symbol":
|
|
30
|
+
case "undefined": throw new TypeError(`${where}: unsupported value of type ${kind}`);
|
|
31
|
+
default: throw new TypeError(`${where}: unsupported value of type ${String(kind)}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const ident = (name) => `"${name.replaceAll("\"", "\"\"")}"`;
|
|
35
|
+
/** Parents first (by forward relations), otherwise in the order given. */
|
|
36
|
+
function order(meta, keys) {
|
|
37
|
+
const sorted = [];
|
|
38
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
39
|
+
const visit = (key) => {
|
|
40
|
+
if (sorted.includes(key) || visiting.has(key)) return;
|
|
41
|
+
visiting.add(key);
|
|
42
|
+
for (const relation of Object.values(meta.tables[key]?.relations ?? {})) if (relation.direction === "forward" && relation.table !== key && keys.includes(relation.table)) visit(relation.table);
|
|
43
|
+
visiting.delete(key);
|
|
44
|
+
sorted.push(key);
|
|
45
|
+
};
|
|
46
|
+
for (const key of keys) visit(key);
|
|
47
|
+
return sorted;
|
|
48
|
+
}
|
|
49
|
+
function statement(table, rows) {
|
|
50
|
+
const entries = Object.entries(rows);
|
|
51
|
+
if (entries.length === 0) return void 0;
|
|
52
|
+
const columns = [];
|
|
53
|
+
for (const [, row] of entries) for (const [key, value] of Object.entries(row)) {
|
|
54
|
+
if (value === void 0 || columns.includes(key)) continue;
|
|
55
|
+
const column = table.columns[key];
|
|
56
|
+
if (!column) throw new TypeError(`seed ${table.key}: unknown column "${key}"`);
|
|
57
|
+
if (column.generated) throw new TypeError(`seed ${table.key}: "${key}" is a generated column`);
|
|
58
|
+
columns.push(key);
|
|
59
|
+
}
|
|
60
|
+
const values = entries.map(([name, row]) => {
|
|
61
|
+
return ` (${columns.map((key) => row[key] === void 0 ? "default" : literal(row[key], table.columns[key], `seed ${table.key}.${name}.${key}`)).join(", ")})`;
|
|
62
|
+
});
|
|
63
|
+
return `insert into ${`${ident(table.schema)}.${ident(table.name)}`} (${columns.map((key) => ident(table.columns[key].db)).join(", ")}) values\n${values.join(",\n")}\non conflict do nothing;`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Typed fixtures shared by `supabase/seeds` and your tests. Rows use app
|
|
67
|
+
* casing and Insert types; `better-supabase seed` renders them to SQL.
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* export const seed = defineSeed(sb, {
|
|
71
|
+
* organizations: { acme: { id: ACME, name: 'Acme' } },
|
|
72
|
+
* customers: { first: { organizationId: ACME, name: 'First customer' } },
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
function defineSeed(sb, fixtures) {
|
|
77
|
+
const meta = sb.meta;
|
|
78
|
+
const statements = () => {
|
|
79
|
+
const keys = Object.keys(fixtures).filter((key) => fixtures[key] !== void 0);
|
|
80
|
+
for (const key of keys) {
|
|
81
|
+
const table = meta.tables[key];
|
|
82
|
+
if (!table) throw new TypeError(`seed: unknown table "${key}"`);
|
|
83
|
+
if (table.kind === "view") throw new TypeError(`seed: "${key}" is a view`);
|
|
84
|
+
}
|
|
85
|
+
return order(meta, keys).flatMap((key) => {
|
|
86
|
+
const sql = statement(meta.tables[key], fixtures[key]);
|
|
87
|
+
return sql ? [sql] : [];
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
return {
|
|
91
|
+
[SEED]: true,
|
|
92
|
+
rows: fixtures,
|
|
93
|
+
statements,
|
|
94
|
+
sql: () => statements().join("\n\n"),
|
|
95
|
+
async insert(sql) {
|
|
96
|
+
for (const text of statements()) await sql.queryRaw(text);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { isSeed as n, defineSeed as t };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { n as AnyModels, t as AnyFunctions } from "../types-C2fslP1z.js";
|
|
2
|
+
import { t as BetterSupabase, y as Db } from "../define-CTfWw-SS.js";
|
|
3
|
+
import { h as RequestContext } from "../plugin-HvGqCurB.js";
|
|
4
|
+
import { a as checkAal, c as impersonatorOf, i as amrOf, n as AmrEntry, o as ImpersonationOptions, r as aalOf, s as Impersonator, t as Aal } from "../mfa-TVia554c.js";
|
|
5
|
+
import { _ as readSession, a as ResolveAuthOptions, b as writeSession, c as clientIp, d as CookieOptions, f as CookieRecord, i as InvalidReason, l as resolveAuth, m as StoredSession, n as AuthResolver, o as ResolvedState, p as CookieWrite, r as AuthState, s as authContext, t as AuthResolution, u as AUTH_CACHE_HEADERS, y as sessionCookieName } from "../resolve-DW8h9NPm.js";
|
|
6
|
+
import { _ as DeleteAccountResult, a as guard, c as settle, d as ServerContext, f as ServerOptions, g as DeleteAccountOptions, h as ReplicaState, i as Settled, l as BetterServer, m as PRIMARY_COOKIE, n as GuardOptions, o as isResult, p as createServer, r as RespondOptions, s as respond, t as AuthKind, u as ContextOptions } from "../respond-PoTpy5DT.js";
|
|
7
|
+
import { a as defineResource, i as ResourceRouteOptions, n as ResourceInput, r as ResourceList, t as ResourceHandler } from "../resource-SkPTRJDD.js";
|
|
8
|
+
import { a as ProblemResponseOptions, c as problemResponse, i as ProblemOptions, l as toProblem, n as PROBLEM_TYPE_BASE, o as fromProblem, r as ProblemDetails, s as isProblem, t as PROBLEM_CONTENT_TYPE } from "../problem-DlgB0lYl.js";
|
|
9
|
+
import { n as RefreshOutcome, r as refreshSession } from "../index-cEeweTeM.js";
|
|
10
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
11
|
+
import { Middleware } from "@supabase/middleware";
|
|
12
|
+
import { AuthMode, JWTClaims, UserClaims } from "@supabase/server";
|
|
13
|
+
import { PostgresApi } from "@supabase/server/middleware/postgres";
|
|
14
|
+
//#region src/server/middleware.d.ts
|
|
15
|
+
/** The `withSupabase` context keys `withBetterSupabase` reads. */
|
|
16
|
+
interface SupabaseAuthContext {
|
|
17
|
+
readonly jwtClaims: JWTClaims | null;
|
|
18
|
+
readonly userClaims: UserClaims | null;
|
|
19
|
+
readonly authMode: AuthMode;
|
|
20
|
+
}
|
|
21
|
+
/** Repository context from a `@supabase/server` context. */
|
|
22
|
+
export declare function contextFromSupabase(ctx: SupabaseAuthContext): RequestContext;
|
|
23
|
+
/**
|
|
24
|
+
* `@supabase/middleware` entry contributing `ctx.db`: repositories bound to
|
|
25
|
+
* `ctx.supabase` (the caller-scoped client from `withSupabase`).
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* pipeline([withSupabase({ auth: 'user' }), withBetterSupabase(sb)()], (req, ctx) => ...)
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function withBetterSupabase<M extends AnyModels, D, F extends AnyFunctions, E>(sb: BetterSupabase<M, D, F, E>): Middleware<"db", void, SupabaseAuthContext & {
|
|
32
|
+
readonly supabase: SupabaseClient;
|
|
33
|
+
}, Db<M, F, E, SupabaseClient>>;
|
|
34
|
+
/**
|
|
35
|
+
* Entry contributing `ctx.sql`: repositories over `ctx.postgres` from
|
|
36
|
+
* `withPostgresClient`, which runs each query as the caller with RLS.
|
|
37
|
+
*/
|
|
38
|
+
export declare function withBetterPostgres<M extends AnyModels, D, F extends AnyFunctions, E>(sb: BetterSupabase<M, D, F, E>): Middleware<"sql", void, SupabaseAuthContext & {
|
|
39
|
+
readonly postgres: PostgresApi;
|
|
40
|
+
}, Db<M, F, E, undefined>>;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { AUTH_CACHE_HEADERS, type Aal, type AmrEntry, type AuthKind, type AuthResolution, type AuthResolver, type AuthState, type BetterServer, type ContextOptions, type CookieOptions, type CookieRecord, type CookieWrite, type DeleteAccountOptions, type DeleteAccountResult, type GuardOptions, type ImpersonationOptions, type Impersonator, type InvalidReason, PRIMARY_COOKIE, PROBLEM_CONTENT_TYPE, PROBLEM_TYPE_BASE, type ProblemDetails, type ProblemOptions, type ProblemResponseOptions, type RefreshOutcome, type ReplicaState, type ResolveAuthOptions, type ResolvedState, type ResourceHandler, type ResourceInput, type ResourceList, type ResourceRouteOptions, type RespondOptions, type ServerContext, type ServerOptions, type Settled, type StoredSession, type SupabaseAuthContext, aalOf, amrOf, authContext, checkAal, clientIp, createServer, defineResource, fromProblem, guard, impersonatorOf, isProblem, isResult, problemResponse, readSession, refreshSession, resolveAuth, respond, sessionCookieName, settle, toProblem, writeSession };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { a as problemResponse, i as isProblem, n as PROBLEM_TYPE_BASE, o as toProblem, r as fromProblem, t as PROBLEM_CONTENT_TYPE } from "../problem-DPu6Fh-t.js";
|
|
2
|
+
import { a as settle, i as respond, n as guard, o as createServer, r as isResult, u as PRIMARY_COOKIE } from "../respond-4-dhoV7x.js";
|
|
3
|
+
import { a as clientIp, f as sessionCookieName, g as impersonatorOf, i as authContext, m as refreshSession, n as amrOf, o as resolveAuth, p as writeSession, r as checkAal, s as AUTH_CACHE_HEADERS, t as aalOf, u as readSession } from "../mfa-CpogP66z.js";
|
|
4
|
+
import { n as postgresExecutor } from "../executor-Ceq60hPM.js";
|
|
5
|
+
import { t as defineResource } from "../resource-CYiu6Ygi.js";
|
|
6
|
+
import { defineMiddleware } from "@supabase/middleware";
|
|
7
|
+
//#region src/server/middleware.ts
|
|
8
|
+
/** Repository context from a `@supabase/server` context. */
|
|
9
|
+
function contextFromSupabase(ctx) {
|
|
10
|
+
switch (ctx.authMode) {
|
|
11
|
+
case "user":
|
|
12
|
+
if (!ctx.userClaims) break;
|
|
13
|
+
return {
|
|
14
|
+
actor: {
|
|
15
|
+
id: ctx.userClaims.id,
|
|
16
|
+
kind: "user",
|
|
17
|
+
...ctx.userClaims.role !== void 0 ? { role: ctx.userClaims.role } : {},
|
|
18
|
+
...ctx.userClaims.email !== void 0 ? { email: ctx.userClaims.email } : {}
|
|
19
|
+
},
|
|
20
|
+
claims: ctx.jwtClaims ?? {}
|
|
21
|
+
};
|
|
22
|
+
case "secret": return {
|
|
23
|
+
actor: {
|
|
24
|
+
id: "service",
|
|
25
|
+
kind: "service",
|
|
26
|
+
role: "service_role"
|
|
27
|
+
},
|
|
28
|
+
claims: { role: "service_role" }
|
|
29
|
+
};
|
|
30
|
+
case "publishable":
|
|
31
|
+
case "none": break;
|
|
32
|
+
default: return ctx.authMode;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
actor: {
|
|
36
|
+
id: "anon",
|
|
37
|
+
kind: "anon",
|
|
38
|
+
role: "anon"
|
|
39
|
+
},
|
|
40
|
+
claims: { role: "anon" }
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* `@supabase/middleware` entry contributing `ctx.db`: repositories bound to
|
|
45
|
+
* `ctx.supabase` (the caller-scoped client from `withSupabase`).
|
|
46
|
+
*
|
|
47
|
+
* ```ts
|
|
48
|
+
* pipeline([withSupabase({ auth: 'user' }), withBetterSupabase(sb)()], (req, ctx) => ...)
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
function withBetterSupabase(sb) {
|
|
52
|
+
return defineMiddleware({
|
|
53
|
+
key: "db",
|
|
54
|
+
run: (_config) => (_req, ctx) => Promise.resolve({ db: sb.connect(ctx.supabase, contextFromSupabase(ctx)) })
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Entry contributing `ctx.sql`: repositories over `ctx.postgres` from
|
|
59
|
+
* `withPostgresClient`, which runs each query as the caller with RLS.
|
|
60
|
+
*/
|
|
61
|
+
function withBetterPostgres(sb) {
|
|
62
|
+
return defineMiddleware({
|
|
63
|
+
key: "sql",
|
|
64
|
+
run: (_config) => (_req, ctx) => Promise.resolve({ sql: sb.connect(postgresExecutor(ctx.postgres), contextFromSupabase(ctx)) })
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { AUTH_CACHE_HEADERS, PRIMARY_COOKIE, PROBLEM_CONTENT_TYPE, PROBLEM_TYPE_BASE, aalOf, amrOf, authContext, checkAal, clientIp, contextFromSupabase, createServer, defineResource, fromProblem, guard, impersonatorOf, isProblem, isResult, problemResponse, readSession, refreshSession, resolveAuth, respond, sessionCookieName, settle, toProblem, withBetterPostgres, withBetterSupabase, writeSession };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { t as AuthSession } from "./view-B0ltUmTi.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/react/session.d.ts
|
|
4
|
+
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
|
+
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)`); `createHooks().useSession` infers it.
|
|
18
|
+
*/
|
|
19
|
+
declare function useSession<C = unknown>(): AuthSession<C>;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { SessionProviderProps as n, useSession as r, SessionProvider as t };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createContext, createElement, use, useContext } from "react";
|
|
2
|
+
//#region src/react/session.ts
|
|
3
|
+
const SessionContext = createContext(null);
|
|
4
|
+
/** Shares the server-verified session with Client Components. */
|
|
5
|
+
function SessionProvider(props) {
|
|
6
|
+
return createElement(SessionContext.Provider, { value: props.sessionPromise }, props.children);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The session from the nearest `<SessionProvider>`. Suspends until the
|
|
10
|
+
* promise resolves, so render it inside `<Suspense>`. `C` types the claims
|
|
11
|
+
* (the output of `sb.claims(schema)`); `createHooks().useSession` infers it.
|
|
12
|
+
*/
|
|
13
|
+
function useSession() {
|
|
14
|
+
const promise = useContext(SessionContext);
|
|
15
|
+
if (!promise) throw new Error("better-supabase: useSession() needs <SessionProvider sessionPromise={...}>");
|
|
16
|
+
return use(promise);
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { useSession as n, SessionProvider as t };
|