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.
Files changed (149) hide show
  1. package/README.md +34 -31
  2. package/dist/base64-CQeB1eSf.js +42 -0
  3. package/dist/claims-CoTobNC-.js +25 -0
  4. package/dist/client/index.d.ts +1 -1
  5. package/dist/client/index.js +4 -14
  6. package/dist/{compiler-DL18ukPe.d.ts → compiler-2zqGzxVZ.d.ts} +2 -2
  7. package/dist/config/index.d.ts +4 -3
  8. package/dist/config/index.js +5 -3
  9. package/dist/config-Be4GwsqI.js +129 -0
  10. package/dist/{index-BD6wKthp.d.ts → config-C1CYcm6o.d.ts} +75 -54
  11. package/dist/{config-D-aR2ZoN.js → config-DOsGYSiT.js} +14 -136
  12. package/dist/{define-QGkq04oe.js → define-DF341GDj.js} +133 -110
  13. package/dist/{define-CTfWw-SS.d.ts → define-DUbydmJa.d.ts} +32 -14
  14. package/dist/edge/index.d.ts +4 -4
  15. package/dist/edge/index.js +4 -4
  16. package/dist/entitlements-CTEBm7IB.js +20 -0
  17. package/dist/entitlements-DvJXoI02.d.ts +42 -0
  18. package/dist/env/index.js +203 -1
  19. package/dist/events/index.d.ts +1 -1
  20. package/dist/events/index.js +139 -1
  21. package/dist/{events-2OJsVG_d.d.ts → events-Do8jXh4D.d.ts} +3 -3
  22. package/dist/{executor-Bje4suQF.d.ts → executor-B26lgbHD.d.ts} +2 -2
  23. package/dist/{executor-Ceq60hPM.js → executor-C57jx2pn.js} +7 -2
  24. package/dist/{executor-Bazhgsgq.d.ts → executor-DynmIWhq.d.ts} +2 -2
  25. package/dist/guards-BnzDvFrz.js +10 -0
  26. package/dist/hono/index.d.ts +5 -5
  27. package/dist/hono/index.js +4 -4
  28. package/dist/{index-Hf8PP9sP.d.ts → index-BNsABq7P.d.ts} +17 -13
  29. package/dist/{index-JXHBuS53.d.ts → index-CADlNHK-.d.ts} +27 -14
  30. package/dist/{index-Nxo3TJcm.d.ts → index-CTTMS6_1.d.ts} +27 -8
  31. package/dist/index-Cf-D2jk1.d.ts +50 -0
  32. package/dist/{index-Dup-nSe9.d.ts → index-CriFFJ_p.d.ts} +4 -4
  33. package/dist/{index-DQVvHzjW.d.ts → index-GV77NpRP.d.ts} +5 -4
  34. package/dist/{index-Sw43J8HG.d.ts → index-UJ-LUxtI.d.ts} +6 -6
  35. package/dist/{index-cEeweTeM.d.ts → index-kpgopLNv.d.ts} +4 -3
  36. package/dist/{index-DRid0qIv.d.ts → index-qriRM9cZ.d.ts} +7 -2
  37. package/dist/index.d.ts +13 -13
  38. package/dist/index.js +18 -8
  39. package/dist/jobs/index.d.ts +25 -24
  40. package/dist/jobs/index.js +19 -12
  41. package/dist/{json-schema-BbwO2mZg.js → json-schema--aOXAGfU.js} +9 -3
  42. package/dist/lint/index.js +1 -1
  43. package/dist/list/index.d.ts +2 -2
  44. package/dist/list/index.js +128 -93
  45. package/dist/{live-6b9i72Ux.d.ts → live-QE3UPbGm.d.ts} +27 -6
  46. package/dist/logger-glM28NVN.js +21 -0
  47. package/dist/mcp/index.d.ts +59 -15
  48. package/dist/mcp/index.js +229 -67
  49. package/dist/{mfa-CpogP66z.js → mfa-BxoR1RkN.js} +97 -22
  50. package/dist/{mfa-TVia554c.d.ts → mfa-x3V3vGh-.d.ts} +1 -1
  51. package/dist/next/index.d.ts +51 -38
  52. package/dist/next/index.js +31 -25
  53. package/dist/openapi/index.d.ts +1 -1
  54. package/dist/openapi/index.js +58 -35
  55. package/dist/orpc/index.d.ts +6 -6
  56. package/dist/orpc/index.js +3 -3
  57. package/dist/otel/index.d.ts +3 -3
  58. package/dist/otel/index.js +5 -3
  59. package/dist/{template-BeOGnynM.js → permdock-sql-Bta_G0v-.js} +32 -3
  60. package/dist/permdock-sql-DImJULY-.d.ts +17 -0
  61. package/dist/{plugin-HvGqCurB.d.ts → plugin-DVRB8qNE.d.ts} +5 -4
  62. package/dist/plugins/actor/index.d.ts +1 -1
  63. package/dist/plugins/rules/index.d.ts +4 -3
  64. package/dist/plugins/rules/index.js +8 -15
  65. package/dist/plugins/soft-delete/index.d.ts +3 -3
  66. package/dist/plugins/soft-delete/index.js +2 -2
  67. package/dist/plugins/tenant/index.d.ts +10 -4
  68. package/dist/plugins/tenant/index.js +15 -13
  69. package/dist/plugins/timestamps/index.d.ts +1 -1
  70. package/dist/plugins/timestamps/index.js +1 -1
  71. package/dist/plugins/validation/index.d.ts +2 -2
  72. package/dist/pool-B9qsLyFR.d.ts +71 -0
  73. package/dist/postgres/index.d.ts +10 -5
  74. package/dist/postgres/index.js +36 -16
  75. package/dist/{postgrest-Dm-vhY6R.d.ts → postgrest-DmBlevh-.d.ts} +1 -1
  76. package/dist/{problem-DPu6Fh-t.js → problem-CGt1ADix.js} +14 -8
  77. package/dist/{problem-DlgB0lYl.d.ts → problem-Z2RTQjZD.d.ts} +6 -4
  78. package/dist/query/index.d.ts +2 -2
  79. package/dist/query/index.js +1 -1
  80. package/dist/{query-ChvDbsDE.js → query-BdKLTPlj.js} +2 -2
  81. package/dist/react/index.d.ts +7 -7
  82. package/dist/react/index.js +3 -3
  83. package/dist/react/server.d.ts +5 -5
  84. package/dist/react/server.js +1 -1
  85. package/dist/react/session.d.ts +21 -2
  86. package/dist/react/session.js +19 -1
  87. package/dist/{react-CrOvrnIP.js → react-DNBYNazu.js} +28 -23
  88. package/dist/{read-set-DhX2d04c.js → read-set-D0qBcboM.js} +3 -3
  89. package/dist/realtime/index.d.ts +4 -2
  90. package/dist/realtime/index.js +30 -14
  91. package/dist/{resolve-DW8h9NPm.d.ts → resolve-BRciX2jK.d.ts} +25 -9
  92. package/dist/{resource-SkPTRJDD.d.ts → resource-CwVgiI5q.d.ts} +16 -7
  93. package/dist/{resource-CYiu6Ygi.js → resource-D30rp0GN.js} +38 -16
  94. package/dist/{respond-4-dhoV7x.js → respond-C44EZAJo.js} +38 -19
  95. package/dist/{respond-PoTpy5DT.d.ts → respond-DAkPIdTH.d.ts} +23 -17
  96. package/dist/{result-CTkCZ6JA.d.ts → result-c2OYgCV2.d.ts} +13 -8
  97. package/dist/server/index.d.ts +35 -10
  98. package/dist/server/index.js +38 -9
  99. package/dist/{simplify-oHiDKRVQ.js → simplify-LakqK1vH.js} +22 -28
  100. package/dist/{spec-pins-t6sPaHvl.js → spec-pins-C3oc-Tdp.js} +1 -1
  101. package/dist/{spec-pins-CJPVghHy.d.ts → spec-pins-CqorWDnO.d.ts} +1 -1
  102. package/dist/sql/index.d.ts +139 -0
  103. package/dist/sql/index.js +1983 -0
  104. package/dist/{sql-M8l3fnS0.js → sql-BIgk12ew.js} +72 -16
  105. package/dist/ssr/index.d.ts +5 -5
  106. package/dist/ssr/index.js +3 -3
  107. package/dist/{standard-CyhRzctb.d.ts → standard-eudBiRk1.d.ts} +1 -1
  108. package/dist/{stats-3iy8u3_P.js → stats-D78UQ8Yu.js} +8 -7
  109. package/dist/storage/index.d.ts +4 -2
  110. package/dist/storage/index.js +530 -1
  111. package/dist/{tables-rZxRxNPW.js → tables-Dhha3BXM.js} +5 -5
  112. package/dist/temporal-BwshQk0W.js +27 -0
  113. package/dist/temporal-required-CMxeSVPo.js +19 -0
  114. package/dist/testing/index.d.ts +49 -16
  115. package/dist/testing/index.js +233 -66
  116. package/dist/{types-C2fslP1z.d.ts → types-DONv9SHN.d.ts} +68 -12
  117. package/dist/{version-Cqq1m3UY.js → version-BfpG2gks.js} +1 -1
  118. package/dist/view-3Po_PVlr.d.ts +79 -0
  119. package/dist/{view-B6F9QbG-.js → view-wZ-9qIUz.js} +12 -2
  120. package/dist/webhooks/index.d.ts +19 -17
  121. package/dist/webhooks/index.js +1 -1
  122. package/dist/{webhooks-DbMTJJX2.js → webhooks-CAIFQSTM.js} +12 -10
  123. package/package.json +30 -30
  124. package/schemas/config-v1.json +80 -5
  125. package/schemas/doctor-report-v1.json +18 -1
  126. package/schemas/snapshot-v2.json +39 -0
  127. package/skills/better-supabase/SKILL.md +23 -11
  128. package/skills/better-supabase/references/plugins.md +28 -16
  129. package/skills/better-supabase/references/troubleshooting.md +15 -15
  130. package/skills/better-supabase-api/SKILL.md +9 -9
  131. package/skills/better-supabase-api/references/adapters.md +30 -25
  132. package/skills/better-supabase-testing/SKILL.md +15 -11
  133. package/bin/better-supabase.js +0 -3
  134. package/dist/casing-da0uRTqt.js +0 -14
  135. package/dist/cli/bin.d.ts +0 -1
  136. package/dist/cli/bin.js +0 -15
  137. package/dist/cli/index.d.ts +0 -226
  138. package/dist/cli/index.js +0 -3
  139. package/dist/cli-CoByWYja.js +0 -6472
  140. package/dist/entitlements-BBg61DQZ.d.ts +0 -20
  141. package/dist/entitlements-BC_khwRy.js +0 -17
  142. package/dist/env-BEToab0I.js +0 -204
  143. package/dist/events-BuzTgn2D.js +0 -135
  144. package/dist/pool-BFeqzwQS.d.ts +0 -37
  145. package/dist/seed-CzecODcJ.js +0 -101
  146. package/dist/session-C3osL21k.d.ts +0 -21
  147. package/dist/session-CD-3orO_.js +0 -19
  148. package/dist/storage-BWXVUXGk.js +0 -461
  149. 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: `date` decodes timestamps to `Date`,
31
- * `bigint` and `string` read the exact text of `int8`/`numeric` values.
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 = "date" | "bigint" | "string";
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?: "tenant" | "owner" | "public" | "none";
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 RelationShape {
171
+ interface RelationTypes {
116
172
  readonly table: string;
117
173
  readonly kind: "one" | "many";
118
174
  readonly nullable: boolean;
119
175
  }
120
- interface FlagsShape {
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 ModelShape {
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: FlagsShape;
194
+ readonly Flags: ModelFlags;
139
195
  }
140
196
  type AnyModels = {
141
- readonly [table: string]: ModelShape;
197
+ readonly [table: string]: ModelTypes;
142
198
  };
143
- type FunctionShape = {
199
+ type FunctionTypes = {
144
200
  readonly Args: object;
145
201
  readonly Returns: unknown;
146
202
  };
147
203
  type AnyFunctions = {
148
- readonly [name: string]: FunctionShape;
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 { TableMeta as A, Relations as C, Simplify as D, SchemaMeta as E, UniqueKeyName as M, UniqueWhere as N, TableFlags as O, Update as P, RelationShape as S, Schema as T, ModelsOf as _, CheckConstraint as a, RealtimeTableMeta as b, DatabaseOf as c, ForeignKeyConstraint as d, FunctionMeta as f, ModelShape as g, Insert as h, Casing as i, UniqueConstraint as j, TableKey as k, Flags as l, FunctionsOf as m, AnyModels as n, Codec as o, FunctionShape as p, BucketMeta as r, ColumnMeta as s, AnyFunctions as t, FlagsShape as u, PrimaryKeyColumn as v, Row as w, RelationMeta as x, PrimaryKeyValue as y };
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 };
@@ -1,4 +1,4 @@
1
- //#region src/cli/version.ts
1
+ //#region src/core/version.ts
2
2
  const VERSION = "0.0.0";
3
3
  //#endregion
4
4
  export { VERSION as t };
@@ -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 impersonatorOf, n as amrOf, t as aalOf } from "./mfa-CpogP66z.js";
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 {
@@ -1,19 +1,20 @@
1
- import { k as TableKey, n as AnyModels, t as AnyFunctions, w as Row } from "../types-C2fslP1z.js";
2
- import { o as Result } from "../result-CTkCZ6JA.js";
3
- import { t as BetterSupabase } from "../define-CTfWw-SS.js";
4
- //#region src/webhooks/index.d.ts
5
- export interface VerifiedWebhook<T = unknown> {
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: Date;
8
+ readonly timestamp: Temporal.Instant;
8
9
  readonly payload: T;
9
10
  readonly body: string;
10
11
  }
11
- export interface VerifyOptions {
12
+ interface VerifyOptions {
12
13
  /** Allowed clock skew in seconds. Defaults to 300. */
13
14
  readonly tolerance?: number;
14
- readonly now?: () => number;
15
+ readonly now?: () => Temporal.Instant;
15
16
  }
16
- export type WebhookInput = Request | {
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?: Date;
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
- export interface AuthHookError {
45
+ interface AuthHookError {
45
46
  readonly error: {
46
47
  readonly http_code: number;
47
48
  readonly message: string;
48
49
  };
49
50
  }
50
- export interface AuthHooks {
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
- export type AuthHookKind = keyof AuthHooks;
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, org_id: await orgFor(user_id) },
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
- export interface DatabaseWebhookPayload {
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
- export interface DatabaseChange<R> {
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 };
@@ -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-DbMTJJX2.js";
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/index.ts
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 Uint8Array.from(atob(raw), (char) => char.charCodeAt(0));
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
- const mac = new Uint8Array(await crypto.subtle.sign("HMAC", key, encoder.encode(content)));
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 ?? /* @__PURE__ */ new Date()).getTime() / 1e3));
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 now = (options.now?.() ?? Date.now()) / 1e3;
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: /* @__PURE__ */ new Date(seconds * 1e3),
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, org_id: await orgFor(user_id) },
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.1.0",
4
- "description": "Strongly typed Supabase: generated schema, typed repositories, plugins, auth glue and framework integrations, with a CLI from day one.",
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.6.0",
181
- "@supabase/postgrest-typegen": "0.2.2",
182
- "@supabase/server": "1.8.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": "26.6.3",
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
- "@vitest/coverage-v8": "5.0.2",
200
- "effect": "4.0.0-rc.117",
201
- "hono": "4.13.10",
202
- "next": "16.3.6",
203
- "oxfmt": "0.71.0",
204
- "pg": "8.23.0",
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.2",
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 src/next/next.bench.ts",
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
- "typecheck": "tsc --noEmit --checkers 4"
258
+ "transit": "true",
259
+ "typecheck": "tsc --noEmit"
260
260
  }
261
261
  }