better-supabase 0.1.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/claims-CoTobNC-.js +25 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +4 -14
- package/dist/{compiler-DL18ukPe.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-BD6wKthp.d.ts → config-C1CYcm6o.d.ts} +75 -54
- package/dist/{config-D-aR2ZoN.js → config-DOsGYSiT.js} +14 -136
- package/dist/{define-QGkq04oe.js → define-DF341GDj.js} +133 -110
- package/dist/{define-CTfWw-SS.d.ts → define-DUbydmJa.d.ts} +32 -14
- package/dist/edge/index.d.ts +4 -4
- package/dist/edge/index.js +4 -4
- package/dist/entitlements-CTEBm7IB.js +20 -0
- package/dist/entitlements-DvJXoI02.d.ts +42 -0
- 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-2OJsVG_d.d.ts → events-Do8jXh4D.d.ts} +3 -3
- package/dist/{executor-Bje4suQF.d.ts → executor-B26lgbHD.d.ts} +2 -2
- package/dist/{executor-Ceq60hPM.js → executor-C57jx2pn.js} +7 -2
- package/dist/{executor-Bazhgsgq.d.ts → executor-DynmIWhq.d.ts} +2 -2
- package/dist/guards-BnzDvFrz.js +10 -0
- package/dist/hono/index.d.ts +5 -5
- package/dist/hono/index.js +4 -4
- package/dist/{index-Hf8PP9sP.d.ts → index-BNsABq7P.d.ts} +17 -13
- package/dist/{index-JXHBuS53.d.ts → index-CADlNHK-.d.ts} +27 -14
- package/dist/{index-Nxo3TJcm.d.ts → index-CTTMS6_1.d.ts} +27 -8
- package/dist/index-Cf-D2jk1.d.ts +50 -0
- package/dist/{index-Dup-nSe9.d.ts → index-CriFFJ_p.d.ts} +4 -4
- package/dist/{index-DQVvHzjW.d.ts → index-GV77NpRP.d.ts} +5 -4
- package/dist/{index-Sw43J8HG.d.ts → index-UJ-LUxtI.d.ts} +6 -6
- package/dist/{index-cEeweTeM.d.ts → index-kpgopLNv.d.ts} +4 -3
- package/dist/{index-DRid0qIv.d.ts → index-qriRM9cZ.d.ts} +7 -2
- package/dist/index.d.ts +13 -13
- package/dist/index.js +18 -8
- package/dist/jobs/index.d.ts +25 -24
- package/dist/jobs/index.js +19 -12
- package/dist/{json-schema-BbwO2mZg.js → json-schema--aOXAGfU.js} +9 -3
- 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-6b9i72Ux.d.ts → live-QE3UPbGm.d.ts} +27 -6
- package/dist/logger-glM28NVN.js +21 -0
- package/dist/mcp/index.d.ts +59 -15
- package/dist/mcp/index.js +229 -67
- package/dist/{mfa-CpogP66z.js → mfa-BxoR1RkN.js} +97 -22
- package/dist/{mfa-TVia554c.d.ts → mfa-x3V3vGh-.d.ts} +1 -1
- package/dist/next/index.d.ts +51 -38
- package/dist/next/index.js +31 -25
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +58 -35
- package/dist/orpc/index.d.ts +6 -6
- package/dist/orpc/index.js +3 -3
- package/dist/otel/index.d.ts +3 -3
- package/dist/otel/index.js +5 -3
- package/dist/{template-BeOGnynM.js → permdock-sql-Bta_G0v-.js} +32 -3
- package/dist/permdock-sql-DImJULY-.d.ts +17 -0
- package/dist/{plugin-HvGqCurB.d.ts → plugin-DVRB8qNE.d.ts} +5 -4
- package/dist/plugins/actor/index.d.ts +1 -1
- package/dist/plugins/rules/index.d.ts +4 -3
- package/dist/plugins/rules/index.js +8 -15
- 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 +10 -4
- package/dist/plugins/tenant/index.js +15 -13
- 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-Dm-vhY6R.d.ts → postgrest-DmBlevh-.d.ts} +1 -1
- package/dist/{problem-DPu6Fh-t.js → problem-CGt1ADix.js} +14 -8
- 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 +3 -3
- package/dist/react/server.d.ts +5 -5
- 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-CrOvrnIP.js → react-DNBYNazu.js} +28 -23
- package/dist/{read-set-DhX2d04c.js → read-set-D0qBcboM.js} +3 -3
- package/dist/realtime/index.d.ts +4 -2
- package/dist/realtime/index.js +30 -14
- package/dist/{resolve-DW8h9NPm.d.ts → resolve-BRciX2jK.d.ts} +25 -9
- package/dist/{resource-SkPTRJDD.d.ts → resource-CwVgiI5q.d.ts} +16 -7
- package/dist/{resource-CYiu6Ygi.js → resource-D30rp0GN.js} +38 -16
- package/dist/{respond-4-dhoV7x.js → respond-C44EZAJo.js} +38 -19
- package/dist/{respond-PoTpy5DT.d.ts → respond-DAkPIdTH.d.ts} +23 -17
- 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-oHiDKRVQ.js → simplify-LakqK1vH.js} +22 -28
- package/dist/{spec-pins-t6sPaHvl.js → spec-pins-C3oc-Tdp.js} +1 -1
- package/dist/{spec-pins-CJPVghHy.d.ts → spec-pins-CqorWDnO.d.ts} +1 -1
- package/dist/sql/index.d.ts +139 -0
- package/dist/sql/index.js +1983 -0
- package/dist/{sql-M8l3fnS0.js → sql-BIgk12ew.js} +72 -16
- package/dist/ssr/index.d.ts +5 -5
- package/dist/ssr/index.js +3 -3
- package/dist/{standard-CyhRzctb.d.ts → standard-eudBiRk1.d.ts} +1 -1
- package/dist/{stats-3iy8u3_P.js → stats-D78UQ8Yu.js} +8 -7
- package/dist/storage/index.d.ts +4 -2
- 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 +49 -16
- package/dist/testing/index.js +233 -66
- package/dist/{types-C2fslP1z.d.ts → types-DONv9SHN.d.ts} +68 -12
- package/dist/{version-Cqq1m3UY.js → version-BfpG2gks.js} +1 -1
- package/dist/view-3Po_PVlr.d.ts +79 -0
- package/dist/{view-B6F9QbG-.js → view-wZ-9qIUz.js} +12 -2
- package/dist/webhooks/index.d.ts +19 -17
- package/dist/webhooks/index.js +1 -1
- package/dist/{webhooks-DbMTJJX2.js → webhooks-CAIFQSTM.js} +12 -10
- package/package.json +30 -30
- package/schemas/config-v1.json +80 -5
- package/schemas/doctor-report-v1.json +18 -1
- package/schemas/snapshot-v2.json +39 -0
- package/skills/better-supabase/SKILL.md +23 -11
- package/skills/better-supabase/references/plugins.md +28 -16
- package/skills/better-supabase/references/troubleshooting.md +15 -15
- package/skills/better-supabase-api/SKILL.md +9 -9
- package/skills/better-supabase-api/references/adapters.md +30 -25
- package/skills/better-supabase-testing/SKILL.md +15 -11
- package/bin/better-supabase.js +0 -3
- 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-CoByWYja.js +0 -6472
- package/dist/entitlements-BBg61DQZ.d.ts +0 -20
- package/dist/entitlements-BC_khwRy.js +0 -17
- package/dist/env-BEToab0I.js +0 -204
- package/dist/events-BuzTgn2D.js +0 -135
- package/dist/pool-BFeqzwQS.d.ts +0 -37
- package/dist/seed-CzecODcJ.js +0 -101
- package/dist/session-C3osL21k.d.ts +0 -21
- package/dist/session-CD-3orO_.js +0 -19
- package/dist/storage-BWXVUXGk.js +0 -461
- package/dist/view-B0ltUmTi.d.ts +0 -43
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="esnext.temporal" />
|
|
1
2
|
//#region src/schema/types.d.ts
|
|
2
3
|
type Casing = "snake" | "camel";
|
|
3
4
|
/** Runtime metadata for one column. Keyed by the app (cased) column name. */
|
|
@@ -27,10 +28,12 @@ interface ColumnMeta {
|
|
|
27
28
|
readonly storage?: string;
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
30
|
-
* Runtime representation for a column: `
|
|
31
|
-
* `
|
|
31
|
+
* Runtime representation for a column: `instant` decodes `timestamptz` to
|
|
32
|
+
* `Temporal.Instant`, `plainDateTime` decodes `timestamp` to
|
|
33
|
+
* `Temporal.PlainDateTime`, and `bigint` and `string` read the exact text of
|
|
34
|
+
* `int8`/`numeric` values.
|
|
32
35
|
*/
|
|
33
|
-
type Codec = "
|
|
36
|
+
type Codec = "instant" | "plainDateTime" | "bigint" | "string";
|
|
34
37
|
interface RelationMeta {
|
|
35
38
|
/** App key of the target table. */
|
|
36
39
|
readonly table: string;
|
|
@@ -99,32 +102,85 @@ interface SchemaMeta {
|
|
|
99
102
|
readonly topics?: Readonly<Record<string, string>>;
|
|
100
103
|
/** Tables that broadcast change signals (`config.realtime.tables`), keyed by app key. */
|
|
101
104
|
readonly realtime?: Readonly<Record<string, RealtimeTableMeta>>;
|
|
105
|
+
/** Claim names from `config.claims` that differ from the defaults. */
|
|
106
|
+
readonly claims?: Partial<ClaimsMeta>;
|
|
107
|
+
}
|
|
108
|
+
/** The claim names the SQL kit, codegen and runtime defaults agree on. */
|
|
109
|
+
interface ClaimsMeta {
|
|
110
|
+
/** Top-level claim holding the active tenant id. Defaults to `tenant_id`. */
|
|
111
|
+
readonly tenant: string;
|
|
112
|
+
/** `scope` of the tenant entries in the `memberships` claim. Defaults to `tenant`. */
|
|
113
|
+
readonly scope: string;
|
|
114
|
+
/** Claim holding plan features per tenant (`{ [tenantId]: string[] }`). Defaults to `features`. */
|
|
115
|
+
readonly features: string;
|
|
102
116
|
}
|
|
103
117
|
interface RealtimeTableMeta {
|
|
104
118
|
/** App column whose value scopes the broadcast topic. */
|
|
105
119
|
readonly tenant?: string;
|
|
106
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Storage policies that call PermDock's generated SQL helpers:
|
|
123
|
+
* `<schema>.permitted_<scope>_ids(key)` for a scope keyed by a path segment,
|
|
124
|
+
* `<schema>.permdock_has(key)` for `scope: 'global'`. Only for permissions
|
|
125
|
+
* whose grants have no row conditions beyond the scope.
|
|
126
|
+
*/
|
|
127
|
+
interface PermdockBucketPolicy {
|
|
128
|
+
readonly permdock: {
|
|
129
|
+
/** Downloads, signed URLs, renders and metadata reads. */
|
|
130
|
+
readonly read: string;
|
|
131
|
+
/** Listing; without it `read` covers listing too. */
|
|
132
|
+
readonly list?: string;
|
|
133
|
+
/** Uploads, updates and moves; also deletes unless `delete` is set. */
|
|
134
|
+
readonly write: string;
|
|
135
|
+
readonly delete?: string;
|
|
136
|
+
};
|
|
137
|
+
/** A PermDock scope such as `organization`, or `global`. */
|
|
138
|
+
readonly scope: string;
|
|
139
|
+
/** 1-based path segment holding the scope id. Defaults to the `{orgId}` segment. */
|
|
140
|
+
readonly segment?: number;
|
|
141
|
+
/**
|
|
142
|
+
* Schema of the helpers `permdock rls generate` writes: PermDock's
|
|
143
|
+
* `rls.schema`. Defaults to `public`.
|
|
144
|
+
*/
|
|
145
|
+
readonly schema?: string;
|
|
146
|
+
}
|
|
147
|
+
/** A PermDock topic policy: `select` (receive) and `insert` (send) on `realtime.messages`. */
|
|
148
|
+
interface PermdockTopicPolicy {
|
|
149
|
+
readonly receive: string;
|
|
150
|
+
/** Lets clients send on the topic with this permission. */
|
|
151
|
+
readonly send?: string;
|
|
152
|
+
/** A PermDock scope such as `organization`, or `global`. */
|
|
153
|
+
readonly scope: string;
|
|
154
|
+
/** 1-based `:`-separated topic segment holding the scope id. Defaults to the `{orgId}` segment. */
|
|
155
|
+
readonly segment?: number;
|
|
156
|
+
readonly schema?: string;
|
|
157
|
+
}
|
|
158
|
+
type BucketPolicyName = "tenant" | "owner" | "public" | "none";
|
|
107
159
|
interface BucketMeta {
|
|
108
160
|
readonly id: string;
|
|
109
161
|
readonly public: boolean;
|
|
110
162
|
readonly path: string;
|
|
111
|
-
readonly policy?:
|
|
163
|
+
readonly policy?: BucketPolicyName | PermdockBucketPolicy;
|
|
164
|
+
/** Claim paths for the tenant policy, when `config.claims.tenant` is not the default. */
|
|
165
|
+
readonly tenant?: {
|
|
166
|
+
readonly claim: readonly string[];
|
|
167
|
+
};
|
|
112
168
|
readonly fileSizeLimit?: string;
|
|
113
169
|
readonly allowedMimeTypes?: readonly string[];
|
|
114
170
|
}
|
|
115
|
-
interface
|
|
171
|
+
interface RelationTypes {
|
|
116
172
|
readonly table: string;
|
|
117
173
|
readonly kind: "one" | "many";
|
|
118
174
|
readonly nullable: boolean;
|
|
119
175
|
}
|
|
120
|
-
interface
|
|
176
|
+
interface ModelFlags {
|
|
121
177
|
readonly softDelete?: string;
|
|
122
178
|
readonly timestamps?: true;
|
|
123
179
|
readonly tenant?: string;
|
|
124
180
|
readonly actor?: true;
|
|
125
181
|
readonly version?: string;
|
|
126
182
|
}
|
|
127
|
-
interface
|
|
183
|
+
interface ModelTypes {
|
|
128
184
|
readonly Row: object;
|
|
129
185
|
readonly Insert: object;
|
|
130
186
|
readonly Update: object;
|
|
@@ -135,17 +191,17 @@ interface ModelShape {
|
|
|
135
191
|
readonly Checks?: string;
|
|
136
192
|
/** Foreign key constraint names on this table. */
|
|
137
193
|
readonly ForeignKeys?: string;
|
|
138
|
-
readonly Flags:
|
|
194
|
+
readonly Flags: ModelFlags;
|
|
139
195
|
}
|
|
140
196
|
type AnyModels = {
|
|
141
|
-
readonly [table: string]:
|
|
197
|
+
readonly [table: string]: ModelTypes;
|
|
142
198
|
};
|
|
143
|
-
type
|
|
199
|
+
type FunctionTypes = {
|
|
144
200
|
readonly Args: object;
|
|
145
201
|
readonly Returns: unknown;
|
|
146
202
|
};
|
|
147
203
|
type AnyFunctions = {
|
|
148
|
-
readonly [name: string]:
|
|
204
|
+
readonly [name: string]: FunctionTypes;
|
|
149
205
|
};
|
|
150
206
|
/**
|
|
151
207
|
* Carries the model types next to the runtime metadata. Created by
|
|
@@ -192,4 +248,4 @@ type IsUnion<T, U = T> = T extends unknown ? [U] extends [T] ? false : true : ne
|
|
|
192
248
|
type PrimaryKeyValue<M extends AnyModels, T extends keyof M> = true extends IsUnion<PrimaryKeyColumn<M, T>> ? { readonly [K in PrimaryKeyColumn<M, T>]: Row<M, T>[K]; } : Row<M, T>[PrimaryKeyColumn<M, T>];
|
|
193
249
|
type Simplify<T> = { [K in keyof T]: T[K]; } & {};
|
|
194
250
|
//#endregion
|
|
195
|
-
export {
|
|
251
|
+
export { SchemaMeta as A, PrimaryKeyValue as C, Relations as D, RelationTypes as E, UniqueConstraint as F, UniqueKeyName as I, UniqueWhere as L, TableFlags as M, TableKey as N, Row as O, TableMeta as P, Update as R, PrimaryKeyColumn as S, RelationMeta as T, ModelFlags as _, Casing as a, PermdockBucketPolicy as b, Codec as c, Flags as d, ForeignKeyConstraint as f, Insert as g, FunctionsOf as h, BucketPolicyName as i, Simplify as j, Schema as k, ColumnMeta as l, FunctionTypes as m, AnyModels as n, CheckConstraint as o, FunctionMeta as p, BucketMeta as r, ClaimsMeta as s, AnyFunctions as t, DatabaseOf as u, ModelTypes as v, RealtimeTableMeta as w, PermdockTopicPolicy as x, ModelsOf as y };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { p as DbError } from "./result-c2OYgCV2.js";
|
|
2
|
+
import { n as AmrEntry, s as Impersonator, t as Aal } from "./mfa-x3V3vGh-.js";
|
|
3
|
+
import { i as InvalidReason, r as AuthState } from "./resolve-BRciX2jK.js";
|
|
4
|
+
import { JWTClaims, UserClaims } from "@supabase/server";
|
|
5
|
+
//#region src/auth/actor.d.ts
|
|
6
|
+
/** One level of an RFC 8693 `act` chain: who acts, and who acted before it. */
|
|
7
|
+
interface ActClaim {
|
|
8
|
+
readonly sub: string;
|
|
9
|
+
readonly act?: ActClaim;
|
|
10
|
+
readonly [claim: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The app acting for the user: the outermost `sub` of an RFC 8693 `act`
|
|
14
|
+
* chain (prior actors stay on `chain`), else the OAuth `client_id` of a
|
|
15
|
+
* Supabase OAuth server token.
|
|
16
|
+
*/
|
|
17
|
+
interface SessionActor {
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly kind: "oauth-client";
|
|
20
|
+
readonly chain?: ActClaim;
|
|
21
|
+
}
|
|
22
|
+
/** What the user delegated to the actor: the token's OAuth `scope`. */
|
|
23
|
+
interface SessionDelegation {
|
|
24
|
+
readonly scopes: readonly string[];
|
|
25
|
+
readonly chain?: ActClaim;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/auth/view.d.ts
|
|
29
|
+
/**
|
|
30
|
+
* The verified caller as plain data: no token, no clients. Safe to return
|
|
31
|
+
* from a `'use cache: private'` function and to pass to Client Components.
|
|
32
|
+
*/
|
|
33
|
+
type AuthSession<C = unknown, P = unknown> = {
|
|
34
|
+
readonly kind: "user";
|
|
35
|
+
readonly user: UserClaims;
|
|
36
|
+
/**
|
|
37
|
+
* The verified JWT payload, including custom access token hook claims,
|
|
38
|
+
* typed and validated by `sb.claims(schema)`.
|
|
39
|
+
*/
|
|
40
|
+
readonly claims: JWTClaims & C;
|
|
41
|
+
/** Seconds since epoch, from the token's `exp`. */
|
|
42
|
+
readonly expiresAt: number | null;
|
|
43
|
+
/**
|
|
44
|
+
* `user_metadata` parsed by `sb.userMetadata(schema)`, for display.
|
|
45
|
+
* Absent without a schema or when the metadata fails it. Users
|
|
46
|
+
* write this data with `auth.updateUser()`: never base access on it.
|
|
47
|
+
*/
|
|
48
|
+
readonly profile?: P;
|
|
49
|
+
/** `aal2` once the user verified a second factor in this session. */
|
|
50
|
+
readonly aal: Aal;
|
|
51
|
+
/** How the user signed in (`password`, `totp`, `sso/saml`, ...). */
|
|
52
|
+
readonly amr: readonly AmrEntry[];
|
|
53
|
+
/** Set when an admin acts as this user (the `act` claim), for a banner. */
|
|
54
|
+
readonly impersonator?: Impersonator;
|
|
55
|
+
/**
|
|
56
|
+
* The OAuth client or agent acting for the user (`client_id`, or the
|
|
57
|
+
* outermost `sub` of the `act` chain), as PermDock's `actorOf` reads it.
|
|
58
|
+
*/
|
|
59
|
+
readonly actor?: SessionActor;
|
|
60
|
+
/** The scopes the user granted `actor`, plus its `act` chain. Set only with `actor`. */
|
|
61
|
+
readonly delegation?: SessionDelegation;
|
|
62
|
+
} | {
|
|
63
|
+
readonly kind: "service";
|
|
64
|
+
readonly keyName: string;
|
|
65
|
+
} | {
|
|
66
|
+
readonly kind: "anon";
|
|
67
|
+
readonly reason: AnonReason;
|
|
68
|
+
} | {
|
|
69
|
+
readonly kind: "invalid";
|
|
70
|
+
readonly reason: InvalidReason;
|
|
71
|
+
readonly error: DbError;
|
|
72
|
+
};
|
|
73
|
+
type AnonReason = Extract<AuthState, {
|
|
74
|
+
kind: "anon";
|
|
75
|
+
}>["reason"];
|
|
76
|
+
/** Drops the token from an `AuthState`, leaving only serializable fields. */
|
|
77
|
+
declare function toSession<C, P>(auth: AuthState<C, P>): AuthSession<C, P>;
|
|
78
|
+
//#endregion
|
|
79
|
+
export { SessionDelegation as a, SessionActor as i, toSession as n, ActClaim as r, AuthSession as t };
|
|
@@ -1,18 +1,28 @@
|
|
|
1
|
-
import { g as
|
|
1
|
+
import { g as delegationOf, h as actorOf, n as amrOf, t as aalOf, v as impersonatorOf } from "./mfa-BxoR1RkN.js";
|
|
2
2
|
//#region src/auth/view.ts
|
|
3
3
|
/** Drops the token from an `AuthState`, leaving only serializable fields. */
|
|
4
4
|
function toSession(auth) {
|
|
5
5
|
switch (auth.kind) {
|
|
6
6
|
case "user": {
|
|
7
7
|
const impersonator = impersonatorOf(auth.claims);
|
|
8
|
+
const outcome = actorOf(auth.claims);
|
|
9
|
+
const actor = outcome.ok ? outcome.actor : void 0;
|
|
10
|
+
const scopes = actor ? delegationOf(auth.claims)?.scopes : void 0;
|
|
11
|
+
const delegation = actor && (scopes || actor.chain) ? {
|
|
12
|
+
scopes: scopes ?? [],
|
|
13
|
+
...actor.chain ? { chain: actor.chain } : {}
|
|
14
|
+
} : void 0;
|
|
8
15
|
return {
|
|
9
16
|
kind: "user",
|
|
10
17
|
user: auth.user,
|
|
11
18
|
claims: auth.claims,
|
|
12
19
|
expiresAt: auth.expiresAt,
|
|
20
|
+
...auth.profile === void 0 ? {} : { profile: auth.profile },
|
|
13
21
|
aal: aalOf(auth.claims),
|
|
14
22
|
amr: amrOf(auth.claims),
|
|
15
|
-
...impersonator ? { impersonator } : {}
|
|
23
|
+
...impersonator ? { impersonator } : {},
|
|
24
|
+
...actor ? { actor } : {},
|
|
25
|
+
...delegation ? { delegation } : {}
|
|
16
26
|
};
|
|
17
27
|
}
|
|
18
28
|
case "service": return {
|
package/dist/webhooks/index.d.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/// <reference lib="esnext.temporal" />
|
|
2
|
+
import { N as TableKey, O as Row, n as AnyModels, t as AnyFunctions } from "../types-DONv9SHN.js";
|
|
3
|
+
import { o as Result } from "../result-c2OYgCV2.js";
|
|
4
|
+
import { t as BetterSupabase } from "../define-DUbydmJa.js";
|
|
5
|
+
//#region src/webhooks/verify.d.ts
|
|
6
|
+
interface VerifiedWebhook<T = unknown> {
|
|
6
7
|
readonly id: string;
|
|
7
|
-
readonly timestamp:
|
|
8
|
+
readonly timestamp: Temporal.Instant;
|
|
8
9
|
readonly payload: T;
|
|
9
10
|
readonly body: string;
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
+
interface VerifyOptions {
|
|
12
13
|
/** Allowed clock skew in seconds. Defaults to 300. */
|
|
13
14
|
readonly tolerance?: number;
|
|
14
|
-
readonly now?: () =>
|
|
15
|
+
readonly now?: () => Temporal.Instant;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
type WebhookInput = Request | {
|
|
17
18
|
readonly headers: Headers | Readonly<Record<string, string>>;
|
|
18
19
|
readonly body: string;
|
|
19
20
|
};
|
|
@@ -23,7 +24,7 @@ export declare function timingSafeEqual(a: string, b: string): boolean;
|
|
|
23
24
|
export declare function signWebhook(secret: string, message: {
|
|
24
25
|
readonly id: string;
|
|
25
26
|
readonly body: string;
|
|
26
|
-
readonly timestamp?:
|
|
27
|
+
readonly timestamp?: Temporal.Instant;
|
|
27
28
|
}): Promise<Record<string, string>>;
|
|
28
29
|
/**
|
|
29
30
|
* Verifies a Standard Webhooks signature (`webhook-id`, `webhook-timestamp`,
|
|
@@ -41,13 +42,13 @@ interface HookUser {
|
|
|
41
42
|
readonly user_metadata?: Readonly<Record<string, unknown>>;
|
|
42
43
|
readonly [key: string]: unknown;
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
+
interface AuthHookError {
|
|
45
46
|
readonly error: {
|
|
46
47
|
readonly http_code: number;
|
|
47
48
|
readonly message: string;
|
|
48
49
|
};
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
+
interface AuthHooks {
|
|
51
52
|
custom_access_token: {
|
|
52
53
|
input: {
|
|
53
54
|
readonly user_id: string;
|
|
@@ -116,7 +117,7 @@ export interface AuthHooks {
|
|
|
116
117
|
output: Record<never, never>;
|
|
117
118
|
};
|
|
118
119
|
}
|
|
119
|
-
|
|
120
|
+
type AuthHookKind = keyof AuthHooks;
|
|
120
121
|
/** Rejects a hook with a status and message Supabase Auth passes to the client. */
|
|
121
122
|
export declare function hookError(status: number, message: string): AuthHookError;
|
|
122
123
|
/**
|
|
@@ -125,19 +126,19 @@ export declare function hookError(status: number, message: string): AuthHookErro
|
|
|
125
126
|
*
|
|
126
127
|
* ```ts
|
|
127
128
|
* export const POST = authHook('custom_access_token', env.AUTH_HOOK_SECRET, async ({ claims, user_id }) => ({
|
|
128
|
-
* claims: { ...claims,
|
|
129
|
+
* claims: { ...claims, tenant_id: await orgFor(user_id) },
|
|
129
130
|
* }));
|
|
130
131
|
* ```
|
|
131
132
|
*/
|
|
132
133
|
export declare function authHook<K extends AuthHookKind>(_kind: K, secret: string | readonly string[], handler: (payload: AuthHooks[K]["input"], webhook: VerifiedWebhook<AuthHooks[K]["input"]>) => AuthHooks[K]["output"] | AuthHookError | Promise<AuthHooks[K]["output"] | AuthHookError>, options?: VerifyOptions): (request: Request) => Promise<Response>;
|
|
133
|
-
|
|
134
|
+
interface DatabaseWebhookPayload {
|
|
134
135
|
readonly type: "INSERT" | "UPDATE" | "DELETE";
|
|
135
136
|
readonly table: string;
|
|
136
137
|
readonly schema: string;
|
|
137
138
|
readonly record: Readonly<Record<string, unknown>> | null;
|
|
138
139
|
readonly old_record: Readonly<Record<string, unknown>> | null;
|
|
139
140
|
}
|
|
140
|
-
|
|
141
|
+
interface DatabaseChange<R> {
|
|
141
142
|
readonly type: "INSERT" | "UPDATE" | "DELETE";
|
|
142
143
|
readonly table: string;
|
|
143
144
|
readonly record: R | null;
|
|
@@ -149,4 +150,5 @@ export declare function isDatabaseWebhook(value: unknown): value is DatabaseWebh
|
|
|
149
150
|
* Returns `null` for other tables or payloads that aren't database webhooks.
|
|
150
151
|
*/
|
|
151
152
|
export declare function databaseChange<M extends AnyModels, D, F extends AnyFunctions, E, T extends TableKey<M>>(sb: BetterSupabase<M, D, F, E>, table: T, payload: unknown): DatabaseChange<Row<M, T>> | null;
|
|
152
|
-
//#endregion
|
|
153
|
+
//#endregion
|
|
154
|
+
export type { AuthHookError, AuthHookKind, AuthHooks, DatabaseChange, DatabaseWebhookPayload, VerifiedWebhook, VerifyOptions, WebhookInput };
|
package/dist/webhooks/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as signWebhook, c as verifyWebhook, i as isDatabaseWebhook, n as databaseChange, o as timingSafeEqual, r as hookError, s as verifySharedSecret, t as authHook } from "../webhooks-
|
|
1
|
+
import { a as signWebhook, c as verifyWebhook, i as isDatabaseWebhook, n as databaseChange, o as timingSafeEqual, r as hookError, s as verifySharedSecret, t as authHook } from "../webhooks-CAIFQSTM.js";
|
|
2
2
|
export { authHook, databaseChange, hookError, isDatabaseWebhook, signWebhook, timingSafeEqual, verifySharedSecret, verifyWebhook };
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { n as dbError } from "./errors-Bl3rkOzo.js";
|
|
2
|
+
import { n as nowInstant, r as optionalTemporal } from "./temporal-BwshQk0W.js";
|
|
3
|
+
import { n as temporalMissing } from "./temporal-required-CMxeSVPo.js";
|
|
2
4
|
import { i as ok, n as err } from "./result-DWXatkd6.js";
|
|
5
|
+
import { i as toBase64, r as fromBase64 } from "./base64-CQeB1eSf.js";
|
|
3
6
|
import { s as toApp } from "./shared-_6-uPL7E.js";
|
|
4
|
-
//#region src/webhooks/
|
|
7
|
+
//#region src/webhooks/verify.ts
|
|
5
8
|
const encoder = new TextEncoder();
|
|
6
9
|
/** Accepts `whsec_…`, `v1,whsec_…` (Supabase Auth hooks) or raw base64. */
|
|
7
10
|
function secretBytes(secret) {
|
|
8
11
|
const raw = secret.replace(/^v1,/, "").replace(/^whsec_/, "");
|
|
9
12
|
try {
|
|
10
|
-
return
|
|
13
|
+
return fromBase64(raw);
|
|
11
14
|
} catch {
|
|
12
15
|
throw new TypeError("Webhook secret is not valid base64");
|
|
13
16
|
}
|
|
@@ -17,10 +20,7 @@ async function signature(secret, content) {
|
|
|
17
20
|
name: "HMAC",
|
|
18
21
|
hash: "SHA-256"
|
|
19
22
|
}, false, ["sign"]);
|
|
20
|
-
|
|
21
|
-
let binary = "";
|
|
22
|
-
for (const byte of mac) binary += String.fromCharCode(byte);
|
|
23
|
-
return btoa(binary);
|
|
23
|
+
return toBase64(new Uint8Array(await crypto.subtle.sign("HMAC", key, encoder.encode(content))));
|
|
24
24
|
}
|
|
25
25
|
/** Constant-time string comparison. */
|
|
26
26
|
function timingSafeEqual(a, b) {
|
|
@@ -37,7 +37,7 @@ function header(headers, name) {
|
|
|
37
37
|
const unauthorized = (code, message) => dbError("unauthorized", message, { code });
|
|
38
38
|
/** Headers for a signed Standard Webhooks request. */
|
|
39
39
|
async function signWebhook(secret, message) {
|
|
40
|
-
const timestamp = String(Math.floor((message.timestamp ??
|
|
40
|
+
const timestamp = String(Math.floor((message.timestamp ?? nowInstant()).epochMilliseconds / 1e3));
|
|
41
41
|
return {
|
|
42
42
|
"webhook-id": message.id,
|
|
43
43
|
"webhook-timestamp": timestamp,
|
|
@@ -58,7 +58,9 @@ async function verifyWebhook(input, secrets, options = {}) {
|
|
|
58
58
|
if (!id || !timestamp || !signatures) return err(unauthorized("WEBHOOK_MISSING_HEADERS", "Missing webhook signature headers"));
|
|
59
59
|
const seconds = Number(timestamp);
|
|
60
60
|
if (!/^\d+$/.test(timestamp)) return err(unauthorized("WEBHOOK_INVALID_TIMESTAMP", "Invalid webhook timestamp"));
|
|
61
|
-
const
|
|
61
|
+
const namespace = optionalTemporal();
|
|
62
|
+
if (namespace === void 0) return err(temporalMissing());
|
|
63
|
+
const now = (options.now?.() ?? namespace.Now.instant()).epochMilliseconds / 1e3;
|
|
62
64
|
const tolerance = options.tolerance ?? 300;
|
|
63
65
|
if (seconds < now - tolerance) return err(unauthorized("WEBHOOK_TIMESTAMP_TOO_OLD", "Webhook timestamp is too old"));
|
|
64
66
|
if (seconds > now + tolerance) return err(unauthorized("WEBHOOK_TIMESTAMP_TOO_NEW", "Webhook timestamp is in the future"));
|
|
@@ -73,7 +75,7 @@ async function verifyWebhook(input, secrets, options = {}) {
|
|
|
73
75
|
try {
|
|
74
76
|
return ok({
|
|
75
77
|
id,
|
|
76
|
-
timestamp:
|
|
78
|
+
timestamp: namespace.Instant.fromEpochMilliseconds(seconds * 1e3),
|
|
77
79
|
payload: JSON.parse(body),
|
|
78
80
|
body
|
|
79
81
|
});
|
|
@@ -98,7 +100,7 @@ function hookError(status, message) {
|
|
|
98
100
|
*
|
|
99
101
|
* ```ts
|
|
100
102
|
* export const POST = authHook('custom_access_token', env.AUTH_HOOK_SECRET, async ({ claims, user_id }) => ({
|
|
101
|
-
* claims: { ...claims,
|
|
103
|
+
* claims: { ...claims, tenant_id: await orgFor(user_id) },
|
|
102
104
|
* }));
|
|
103
105
|
* ```
|
|
104
106
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-supabase",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Strongly typed Supabase: generated schema, typed repositories, plugins, auth glue and framework integrations
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Strongly typed Supabase: generated schema, typed repositories, plugins, auth glue and framework integrations. The CLI ships as @better-supabase/cli.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hono",
|
|
7
7
|
"mcp",
|
|
@@ -25,11 +25,7 @@
|
|
|
25
25
|
"url": "git+https://github.com/ScaleDockHQ/better-supabase.git",
|
|
26
26
|
"directory": "packages/better-supabase"
|
|
27
27
|
},
|
|
28
|
-
"bin": {
|
|
29
|
-
"better-supabase": "./bin/better-supabase.js"
|
|
30
|
-
},
|
|
31
28
|
"files": [
|
|
32
|
-
"bin",
|
|
33
29
|
"dist",
|
|
34
30
|
"schemas",
|
|
35
31
|
"skills",
|
|
@@ -160,14 +156,14 @@
|
|
|
160
156
|
"types": "./dist/plugins/validation/index.d.ts",
|
|
161
157
|
"default": "./dist/plugins/validation/index.js"
|
|
162
158
|
},
|
|
159
|
+
"./sql": {
|
|
160
|
+
"types": "./dist/sql/index.d.ts",
|
|
161
|
+
"default": "./dist/sql/index.js"
|
|
162
|
+
},
|
|
163
163
|
"./testing": {
|
|
164
164
|
"types": "./dist/testing/index.d.ts",
|
|
165
165
|
"default": "./dist/testing/index.js"
|
|
166
166
|
},
|
|
167
|
-
"./cli": {
|
|
168
|
-
"types": "./dist/cli/index.d.ts",
|
|
169
|
-
"default": "./dist/cli/index.js"
|
|
170
|
-
},
|
|
171
167
|
"./schemas/*.json": "./schemas/*.json",
|
|
172
168
|
"./package.json": "./package.json"
|
|
173
169
|
},
|
|
@@ -177,50 +173,52 @@
|
|
|
177
173
|
},
|
|
178
174
|
"dependencies": {
|
|
179
175
|
"@standard-schema/spec": "1.1.0",
|
|
180
|
-
"@supabase/middleware": "0.
|
|
181
|
-
"@supabase/postgrest-typegen": "0.
|
|
182
|
-
"@supabase/server": "1.
|
|
176
|
+
"@supabase/middleware": "1.0.0",
|
|
177
|
+
"@supabase/postgrest-typegen": "0.3.1",
|
|
178
|
+
"@supabase/server": "1.9.0",
|
|
183
179
|
"@supabase/ssr": "0.12.7"
|
|
184
180
|
},
|
|
185
181
|
"devDependencies": {
|
|
186
182
|
"@arethetypeswrong/cli": "0.18.5",
|
|
183
|
+
"@better-supabase/ox-config": "0.0.0",
|
|
187
184
|
"@better-supabase/typescript-config": "0.0.0",
|
|
188
|
-
"@effect/platform-node": "4.0.0-rc.117",
|
|
189
185
|
"@opentelemetry/api": "1.9.1",
|
|
190
186
|
"@orpc/server": "2.0.0-beta.40",
|
|
191
|
-
"@supabase/config": "0.10.0",
|
|
192
187
|
"@supabase/supabase-js": "2.117.2",
|
|
193
188
|
"@tanstack/query-core": "5.104.0",
|
|
194
189
|
"@tanstack/react-query": "5.104.0",
|
|
195
|
-
"@types/node": "
|
|
190
|
+
"@types/node": "24.19.0",
|
|
196
191
|
"@types/pg": "8.23.1",
|
|
197
192
|
"@types/react": "19.3.0",
|
|
198
193
|
"@types/react-dom": "19.3.0",
|
|
199
|
-
"@
|
|
200
|
-
"
|
|
201
|
-
"
|
|
202
|
-
"
|
|
203
|
-
"
|
|
204
|
-
"
|
|
194
|
+
"@valibot/to-json-schema": "1.8.0",
|
|
195
|
+
"@vitest/coverage-v8": "5.0.3",
|
|
196
|
+
"ajv": "8.20.0",
|
|
197
|
+
"ajv-formats": "3.0.1",
|
|
198
|
+
"hono": "4.13.12",
|
|
199
|
+
"next": "16.3.8",
|
|
200
|
+
"oxlint": "1.86.0",
|
|
201
|
+
"pg": "8.23.1",
|
|
205
202
|
"publint": "0.3.24",
|
|
206
203
|
"react": "19.3.0",
|
|
207
204
|
"react-dom": "19.3.0",
|
|
205
|
+
"temporal-polyfill": "1.0.5",
|
|
208
206
|
"tsdown": "0.23.0",
|
|
209
207
|
"typescript": "7.0.2",
|
|
210
208
|
"valibot": "1.5.0",
|
|
211
|
-
"vitest": "5.0.
|
|
209
|
+
"vitest": "5.0.3",
|
|
212
210
|
"zod": "4.6.5"
|
|
213
211
|
},
|
|
214
212
|
"peerDependencies": {
|
|
215
213
|
"@opentelemetry/api": ">=1.9",
|
|
216
214
|
"@orpc/server": ">=2.0.0-0",
|
|
217
|
-
"@supabase/config": ">=0.9.0 <0.11",
|
|
218
215
|
"@supabase/supabase-js": "^2.116.0",
|
|
219
216
|
"@tanstack/query-core": "^5",
|
|
220
217
|
"hono": ">=4",
|
|
221
218
|
"next": ">=16",
|
|
222
219
|
"pg": ">=8",
|
|
223
|
-
"react": "^19"
|
|
220
|
+
"react": "^19",
|
|
221
|
+
"temporal-polyfill": ">=1"
|
|
224
222
|
},
|
|
225
223
|
"peerDependenciesMeta": {
|
|
226
224
|
"@opentelemetry/api": {
|
|
@@ -229,9 +227,6 @@
|
|
|
229
227
|
"@orpc/server": {
|
|
230
228
|
"optional": true
|
|
231
229
|
},
|
|
232
|
-
"@supabase/config": {
|
|
233
|
-
"optional": true
|
|
234
|
-
},
|
|
235
230
|
"@tanstack/query-core": {
|
|
236
231
|
"optional": true
|
|
237
232
|
},
|
|
@@ -246,16 +241,21 @@
|
|
|
246
241
|
},
|
|
247
242
|
"react": {
|
|
248
243
|
"optional": true
|
|
244
|
+
},
|
|
245
|
+
"temporal-polyfill": {
|
|
246
|
+
"optional": true
|
|
249
247
|
}
|
|
250
248
|
},
|
|
251
249
|
"engines": {
|
|
252
250
|
"node": ">=24"
|
|
253
251
|
},
|
|
254
252
|
"scripts": {
|
|
255
|
-
"bench": "node
|
|
253
|
+
"bench": "node tests/next/next.bench.ts",
|
|
256
254
|
"build": "tsdown",
|
|
257
255
|
"check:publish": "publint && pnpm pack --out pack.tgz && attw --profile esm-only pack.tgz && rm -f pack.tgz",
|
|
256
|
+
"lint": "oxlint",
|
|
258
257
|
"test": "vitest run --coverage",
|
|
259
|
-
"
|
|
258
|
+
"transit": "true",
|
|
259
|
+
"typecheck": "tsc --noEmit"
|
|
260
260
|
}
|
|
261
261
|
}
|