better-supabase 0.4.0 → 0.5.1

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 (180) hide show
  1. package/README.md +135 -16
  2. package/dist/actor-DaJjqD5R.d.ts +43 -0
  3. package/dist/channel-FQW-CnGR.d.ts +70 -0
  4. package/dist/cli/bin.js +1 -1
  5. package/dist/cli/codemod-DqV7612m.js +388 -0
  6. package/dist/cli/{config-D9R0o1LH.js → config-CPVpXP5I.js} +78 -8
  7. package/dist/cli/{config-SSKSTUl2.js → config-dtoekM0v.js} +1 -1
  8. package/dist/cli/{read-sets-CMa29t9a.js → diff-SjkO5rNr.js} +1 -220
  9. package/dist/cli/{dist-CFgGknmZ.js → dist-DBPdlPYK.js} +4 -4
  10. package/dist/cli/{dist-B1MvLv-M.js → dist-DreZ24Sz.js} +1 -1
  11. package/dist/cli/{dist-Du7VnEUG.js → dist-xn4wlboc.js} +112 -1
  12. package/dist/cli/{doctor-BOym3mbL.js → doctor-C_A-KEAz.js} +533 -50
  13. package/dist/cli/{env-BZ0uy8XK.js → env-DmKv_G4A.js} +1 -1
  14. package/dist/cli/gen-CIdSQZad.js +2 -0
  15. package/dist/cli/{gen-Ccn_p90L.js → gen-CjElD1Vw.js} +321 -88
  16. package/dist/cli/index.d.ts +1 -1
  17. package/dist/cli/index.js +4 -4
  18. package/dist/cli/{init-ClnxRYBF.js → init-DMa6M7hV.js} +2 -2
  19. package/dist/cli/{introspect-DxqfkVIv.js → introspect-BKlaIu_M.js} +2 -2
  20. package/dist/cli/{openapi-8WHjxiTJ.js → openapi-Cp5Fyta-.js} +1 -1
  21. package/dist/cli/read-sets-VQcPgxU9.js +436 -0
  22. package/dist/cli/{run-CP20LKk_.js → run-Bo_NLT5n.js} +16 -12
  23. package/dist/cli/{seed-5J6eu_Xg.js → seed-CUlqWh-8.js} +1 -1
  24. package/dist/cli/sql-CVx-1O8G.js +373 -0
  25. package/dist/cli/{version-5mW_8sY1.js → version-BCtlgDQx.js} +1 -1
  26. package/dist/client/index.d.ts +1 -1
  27. package/dist/client/index.js +3 -10
  28. package/dist/clone-BfgmLU90.js +21 -0
  29. package/dist/{compiler-DB3aSFOA.d.ts → compiler-BXH_aZ7N.d.ts} +2 -2
  30. package/dist/config/index.d.ts +4 -4
  31. package/dist/config/index.js +4 -4
  32. package/dist/{config-C1CYcm6o.d.ts → config-Bv7gvfzC.d.ts} +185 -11
  33. package/dist/{config-CbvFmGD8.js → config-DreERlKo.js} +1 -1
  34. package/dist/{define-CRS2MRV3.d.ts → define-Bp_BZa5h.d.ts} +11 -7
  35. package/dist/{define-Bh0AqTik.js → define-cNKzqwL_.js} +202 -16
  36. package/dist/edge/index.d.ts +16 -5
  37. package/dist/edge/index.js +10 -7
  38. package/dist/{entitlements-Dm-FHpNH.d.ts → entitlements-BiJZ4t49.d.ts} +1 -1
  39. package/dist/env/index.d.ts +2 -2
  40. package/dist/env/index.js +34 -1
  41. package/dist/{errors-L0xK41y_.js → errors-DtwXa6b8.js} +1 -0
  42. package/dist/events/index.d.ts +3 -2
  43. package/dist/events/index.js +65 -12
  44. package/dist/events-aIO7vsIk.d.ts +230 -0
  45. package/dist/{result-CqEsbgYs.d.ts → executor-BunPOO-k.d.ts} +200 -1
  46. package/dist/{executor-CZ7ImRiD.d.ts → executor-Cghdstwu.d.ts} +1 -2
  47. package/dist/{executor-CVt6dD0B.js → executor-XycESQPH.js} +3 -3
  48. package/dist/hono/index.d.ts +17 -6
  49. package/dist/hono/index.js +40 -5
  50. package/dist/impersonation-BgSHAYLf.js +133 -0
  51. package/dist/{resolve-BAqQcwMW.d.ts → impersonation-BmePsuxz.d.ts} +36 -6
  52. package/dist/{index-BhHEC04r.d.ts → index-C7f8cOBM.d.ts} +2 -2
  53. package/dist/{index-Dy6kuF0P.d.ts → index-CLg87OBW.d.ts} +6 -1
  54. package/dist/{index-Cf-D2jk1.d.ts → index-CWMDdEr4.d.ts} +2 -2
  55. package/dist/{index-D5IfUIDh.d.ts → index-DOESKG27.d.ts} +33 -8
  56. package/dist/{index-DFmOpBGC.d.ts → index-DgILJRXj.d.ts} +35 -9
  57. package/dist/{index-RlLXd8dL.d.ts → index-DmXSxbLi.d.ts} +4 -4
  58. package/dist/{index-BBdvo-5d.d.ts → index-Dp2VDwog.d.ts} +49 -6
  59. package/dist/{index-528Ugmyp.d.ts → index-SaTsEfGP.d.ts} +76 -8
  60. package/dist/{index-BAy4tsAP.d.ts → index-fag8VJZ2.d.ts} +3 -4
  61. package/dist/index.d.ts +30 -13
  62. package/dist/index.js +10 -9
  63. package/dist/jobs/index.d.ts +147 -101
  64. package/dist/jobs/index.js +744 -237
  65. package/dist/{json-schema-DP6V7cbr.js → json-schema-m1fiwKgN.js} +22 -1
  66. package/dist/kit-events-CTFDfSwb.js +60 -0
  67. package/dist/kit-transport-B82k1djG.d.ts +33 -0
  68. package/dist/kit-transport-DJlHQUBU.js +55 -0
  69. package/dist/{config-BpxDfnbg.js → kits-CGLLrNPd.js} +37 -9
  70. package/dist/list/index.d.ts +1 -1
  71. package/dist/{live-BHakSWWo.d.ts → live-D9W2M5aO.d.ts} +6 -5
  72. package/dist/mcp/index.d.ts +25 -8
  73. package/dist/mcp/index.js +23 -14
  74. package/dist/{mfa-C7MNQ1Ob.d.ts → mfa-Cu96oJdw.d.ts} +2 -16
  75. package/dist/next/index.d.ts +31 -10
  76. package/dist/next/index.js +136 -27
  77. package/dist/notifications/index.d.ts +162 -0
  78. package/dist/notifications/index.js +264 -0
  79. package/dist/openapi/index.d.ts +1 -1
  80. package/dist/openapi/index.js +2 -2
  81. package/dist/orgs/index.d.ts +132 -0
  82. package/dist/orgs/index.js +245 -0
  83. package/dist/orpc/index.d.ts +28 -8
  84. package/dist/orpc/index.js +16 -3
  85. package/dist/otel/index.d.ts +21 -2
  86. package/dist/otel/index.js +50 -9
  87. package/dist/permdock-sql-C2Inc6Xc.d.ts +29 -0
  88. package/dist/permdock-sql-DgOfeixi.js +51 -0
  89. package/dist/plugin-DwARMuQp.js +59 -0
  90. package/dist/{plugin-bNhvJwRh.d.ts → plugin-o144f322.d.ts} +17 -5
  91. package/dist/plugins/actor/index.d.ts +5 -2
  92. package/dist/plugins/actor/index.js +22 -8
  93. package/dist/plugins/rules/index.d.ts +2 -2
  94. package/dist/plugins/rules/index.js +15 -10
  95. package/dist/plugins/soft-delete/index.d.ts +3 -3
  96. package/dist/plugins/soft-delete/index.js +14 -5
  97. package/dist/plugins/tenant/index.d.ts +2 -2
  98. package/dist/plugins/tenant/index.js +38 -20
  99. package/dist/plugins/timestamps/index.d.ts +1 -1
  100. package/dist/plugins/timestamps/index.js +4 -3
  101. package/dist/plugins/validation/index.d.ts +2 -2
  102. package/dist/plugins/validation/index.js +26 -6
  103. package/dist/{pool-DFwEQwmN.d.ts → pool-C9voM4Kw.d.ts} +17 -6
  104. package/dist/postgres/index.d.ts +5 -5
  105. package/dist/postgres/index.js +20 -11
  106. package/dist/{postgrest-Bc-0Xw62.d.ts → postgrest-CruYKAvV.d.ts} +1 -1
  107. package/dist/{problem-BihjPR0t.js → problem-BW1KhzSG.js} +2 -1
  108. package/dist/{problem-U8UEKccv.d.ts → problem-Blxe8S31.d.ts} +1 -1
  109. package/dist/query/index.d.ts +2 -2
  110. package/dist/query/index.js +3 -3
  111. package/dist/{query-BMMSWbI7.js → query-CCbo44lG.js} +2 -2
  112. package/dist/queue-BYUCjr59.d.ts +252 -0
  113. package/dist/react/index.d.ts +8 -7
  114. package/dist/react/index.js +4 -3
  115. package/dist/react/server.d.ts +14 -3
  116. package/dist/react/server.js +10 -2
  117. package/dist/react/session.d.ts +7 -1
  118. package/dist/react/session.js +9 -1
  119. package/dist/{react-CQHMaESR.js → react-C_s7kiNz.js} +103 -11
  120. package/dist/{read-set-FWK8qQ58.js → read-set-DQFt1N_Y.js} +22 -1
  121. package/dist/realtime/index.d.ts +3 -3
  122. package/dist/realtime/index.js +5 -4
  123. package/dist/{refresh-BwYkyNOQ.d.ts → refresh-CFPX0Qft.d.ts} +1 -1
  124. package/dist/{resource-BJcaIfxi.d.ts → resource-DNRFP7KR.d.ts} +5 -5
  125. package/dist/{resource-My_y-Syh.js → resource-mqfJW4YF.js} +22 -7
  126. package/dist/respond-BR1fJWOB.d.ts +377 -0
  127. package/dist/{result-Bj6yt33D.js → result-BKiliPY7.js} +1 -1
  128. package/dist/server/index.d.ts +15 -12
  129. package/dist/server/index.js +11 -17
  130. package/dist/{server-BA75B0mT.js → server-B1mZ7CgQ.js} +259 -37
  131. package/dist/{shared-DnoCdMDr.js → shared-D1dRUrAg.js} +16 -2
  132. package/dist/signers-Cc6r98SW.d.ts +162 -0
  133. package/dist/{simplify-Cqvfr9dj.js → simplify-_0oUKqCd.js} +4 -115
  134. package/dist/sql/index.d.ts +283 -11
  135. package/dist/sql/index.js +8705 -775
  136. package/dist/{sql-B34HU2DI.js → sql-Coh6n4cC.js} +9 -2
  137. package/dist/ssr/index.d.ts +4 -4
  138. package/dist/ssr/index.js +1 -2
  139. package/dist/{standard-BRyBGTtp.js → standard-D7r6dMUu.js} +6 -3
  140. package/dist/{standard-BsaCYQJc.d.ts → standard-J4YgMOLm.d.ts} +1 -1
  141. package/dist/{stats-C_YxA2r1.js → stats-Bqob3WqT.js} +4 -4
  142. package/dist/storage/index.d.ts +4 -4
  143. package/dist/storage/index.js +155 -26
  144. package/dist/support-CEPwlw2G.d.ts +89 -0
  145. package/dist/support-view-B8SlToQX.d.ts +17 -0
  146. package/dist/support-view-g4YLBeqX.js +18 -0
  147. package/dist/support-wHnK6zp-.js +293 -0
  148. package/dist/{permdock-sql-C4KFzLc9.js → template-TxrGI5jR.js} +2 -31
  149. package/dist/{temporal-BwshQk0W.js → temporal-CVlIV2DZ.js} +17 -4
  150. package/dist/{temporal-required-CBNHT6ni.js → temporal-required-CAt4Dc9Z.js} +2 -2
  151. package/dist/testing/index.d.ts +132 -10
  152. package/dist/testing/index.js +476 -8
  153. package/dist/{types-DONv9SHN.d.ts → types-Dnf_wRDz.d.ts} +26 -3
  154. package/dist/user-change-CHFEUro1.js +49 -0
  155. package/dist/{webhooks-Bh_Jf_-l.js → verify-Ce49ETPz.js} +5 -5
  156. package/dist/{version-Bmf7_FzM.js → version-DOYTYwHP.js} +1 -1
  157. package/dist/{mfa-byfjruR9.js → view-Bn6HNKUe.js} +97 -98
  158. package/dist/{view-B64o81wp.d.ts → view-CbgObAeb.d.ts} +22 -31
  159. package/dist/webhooks/index.d.ts +135 -4
  160. package/dist/webhooks/index.js +588 -2
  161. package/dist/wire-D2dT86vi.js +35 -0
  162. package/package.json +27 -19
  163. package/schemas/config-v1.json +131 -1
  164. package/schemas/doctor-report-v1.json +11 -0
  165. package/skills/better-supabase/SKILL.md +9 -6
  166. package/skills/better-supabase/references/plugins.md +6 -3
  167. package/skills/better-supabase/references/troubleshooting.md +1 -0
  168. package/skills/better-supabase-api/SKILL.md +9 -2
  169. package/skills/better-supabase-api/references/adapters.md +11 -8
  170. package/skills/better-supabase-auth/SKILL.md +18 -7
  171. package/skills/better-supabase-auth/references/permdock.md +78 -11
  172. package/dist/cli/gen-D5cLCULx.js +0 -2
  173. package/dist/cli/sql-D4VbqmXi.js +0 -199
  174. package/dist/events-B21UOhvP.d.ts +0 -84
  175. package/dist/executor-B5IoUxLE.d.ts +0 -195
  176. package/dist/invalidate-CgxmRamI.js +0 -24
  177. package/dist/permdock-sql-DImJULY-.d.ts +0 -17
  178. package/dist/plugin-BqR6wKMB.js +0 -23
  179. package/dist/respond-DgIbdrt8.d.ts +0 -194
  180. package/dist/view-BrJI2LKp.js +0 -45
@@ -1,3 +1,163 @@
1
+ import { E as RelationMeta, F as TableMeta, l as Codec } from "./types-Dnf_wRDz.js";
2
+ //#region src/ir/types.d.ts
3
+ /**
4
+ * The query IR. Every repository call becomes one of these operations; the
5
+ * executor compiles it to PostgREST or SQL. Column names in the IR are
6
+ * database names; `Selection` carries the app aliases.
7
+ */
8
+ type ColumnOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "is" | "like" | "ilike" | "contains" | "containedBy" | "overlaps" | "fts";
9
+ type Quantifier = "some" | "none" | "every";
10
+ type Condition = {
11
+ readonly kind: "and";
12
+ readonly items: readonly Condition[];
13
+ } | {
14
+ readonly kind: "or";
15
+ readonly items: readonly Condition[];
16
+ } | {
17
+ readonly kind: "not";
18
+ readonly item: Condition;
19
+ } | {
20
+ readonly kind: "column";
21
+ readonly column: string;
22
+ readonly op: ColumnOp;
23
+ readonly value: unknown;
24
+ /** Full-text search configuration for `fts`. */
25
+ readonly config?: string;
26
+ } | {
27
+ readonly kind: "relation";
28
+ readonly name: string;
29
+ readonly relation: RelationMeta;
30
+ readonly target: TableMeta;
31
+ readonly quantifier: Quantifier;
32
+ readonly where: Condition | undefined;
33
+ };
34
+ interface SelectColumn {
35
+ /** Key in the returned row. */
36
+ readonly alias: string;
37
+ /** Database column name. */
38
+ readonly column: string;
39
+ /** Read the column as text, so exact `int8`/`numeric` values survive JSON. */
40
+ readonly cast?: "text";
41
+ /** Decodes the returned value (see `ColumnMeta.codec`). */
42
+ readonly codec?: Codec;
43
+ }
44
+ interface OrderTerm {
45
+ readonly column: string;
46
+ readonly direction: "asc" | "desc";
47
+ readonly nulls?: "first" | "last";
48
+ }
49
+ interface Include {
50
+ readonly alias: string;
51
+ readonly relation: RelationMeta;
52
+ readonly target: TableMeta;
53
+ readonly selection: Selection;
54
+ readonly where: Condition | undefined;
55
+ readonly orderBy: readonly OrderTerm[];
56
+ readonly limit: number | undefined;
57
+ /** Drop parent rows without a match (`!inner`). */
58
+ readonly required: boolean;
59
+ /**
60
+ * `_count` include: returns the number of matching related rows instead of
61
+ * rows, folded into `row._count[count]` when decoded.
62
+ */
63
+ readonly count?: string;
64
+ /**
65
+ * `_sum`/`_avg`/`_min`/`_max` include: `selection.aggregate` holds the
66
+ * measures, folded into `row[`_${fn}`][name]` when decoded.
67
+ */
68
+ readonly aggregate?: {
69
+ readonly fn: AggregateFn;
70
+ readonly name: string;
71
+ };
72
+ }
73
+ type AggregateFn = "sum" | "avg" | "min" | "max";
74
+ interface Measure {
75
+ readonly fn: AggregateFn;
76
+ /** Key in the returned row (`_sum_amount`, or the column alias in an include). */
77
+ readonly key: string;
78
+ /** App column name, the key under `_sum` in the decoded row. */
79
+ readonly alias: string;
80
+ /** Database column name. */
81
+ readonly column: string;
82
+ /** Read the result as text, so exact `int8`/`numeric` values survive JSON. */
83
+ readonly cast?: "text";
84
+ readonly codec?: Codec;
85
+ }
86
+ /**
87
+ * Aggregates instead of rows. `Selection.columns` become the grouping
88
+ * columns; without any, the result is exactly one row.
89
+ */
90
+ interface Aggregation {
91
+ /** Also return `_count`, the number of rows in each group. */
92
+ readonly count: boolean;
93
+ readonly measures: readonly Measure[];
94
+ }
95
+ interface Selection {
96
+ readonly columns: readonly SelectColumn[];
97
+ readonly includes: readonly Include[];
98
+ readonly aggregate?: Aggregation;
99
+ }
100
+ type CountMode = "exact" | "planned" | "estimated";
101
+ interface SelectOp {
102
+ readonly kind: "select";
103
+ readonly table: TableMeta;
104
+ readonly selection: Selection;
105
+ readonly where: Condition | undefined;
106
+ readonly orderBy: readonly OrderTerm[];
107
+ readonly limit: number | undefined;
108
+ readonly offset: number | undefined;
109
+ readonly count: CountMode | undefined;
110
+ /** Only count, return no rows. */
111
+ readonly head: boolean;
112
+ readonly single: "one" | "maybe" | undefined;
113
+ /** `limit` includes one row past the page, which `paginate()` reads to set `hasMore`. */
114
+ readonly lookAhead?: boolean;
115
+ /**
116
+ * Read from this set-returning function instead of the table (`db.$search`).
117
+ * Only executors with `functionSources` honor it.
118
+ */
119
+ readonly source?: FunctionSource;
120
+ }
121
+ /** A function returning `setof <table>`, called with named arguments. */
122
+ interface FunctionSource {
123
+ readonly schema: string;
124
+ readonly name: string;
125
+ readonly args: Readonly<Record<string, unknown>>;
126
+ }
127
+ interface InsertOp {
128
+ readonly kind: "insert";
129
+ readonly table: TableMeta;
130
+ /** Rows keyed by database column names. */
131
+ readonly rows: readonly Readonly<Record<string, unknown>>[];
132
+ readonly returning: Selection | undefined;
133
+ readonly onConflict: {
134
+ readonly columns: readonly string[];
135
+ readonly action: "update" | "ignore";
136
+ } | undefined;
137
+ /** Missing columns become `null` instead of their default in bulk inserts. */
138
+ readonly defaultToNull: boolean;
139
+ }
140
+ interface UpdateOp {
141
+ readonly kind: "update";
142
+ readonly table: TableMeta;
143
+ /** Keyed by database column names. */
144
+ readonly set: Readonly<Record<string, unknown>>;
145
+ readonly where: Condition | undefined;
146
+ readonly returning: Selection | undefined;
147
+ }
148
+ interface DeleteOp {
149
+ readonly kind: "delete";
150
+ readonly table: TableMeta;
151
+ readonly where: Condition | undefined;
152
+ readonly returning: Selection | undefined;
153
+ }
154
+ type Operation = SelectOp | InsertOp | UpdateOp | DeleteOp;
155
+ type MutationOp = InsertOp | UpdateOp | DeleteOp;
156
+ declare const and: (...items: (Condition | undefined)[]) => Condition | undefined;
157
+ declare const or: (...items: Condition[]) => Condition;
158
+ declare const not: (item: Condition) => Condition;
159
+ declare const column: (name: string, op: ColumnOp, value: unknown) => Condition;
160
+ //#endregion
1
161
  //#region src/core/errors.d.ts
2
162
  /**
3
163
  * Extra fields carried by each error kind. Plugins can add kinds through the
@@ -34,6 +194,10 @@ interface DbErrorKinds {
34
194
  constraint?: string;
35
195
  };
36
196
  invalid_input: Record<never, never>;
197
+ /** A stored value the app type can't hold, e.g. `infinity` for a Temporal timestamp. */
198
+ invalid_value: {
199
+ column?: string;
200
+ };
37
201
  raised: Record<never, never>;
38
202
  timeout: Record<never, never>;
39
203
  serialization: Record<never, never>;
@@ -200,4 +364,39 @@ declare function toBetterResult<T>(result: AsyncResult<T>, api: BetterResultApi<
200
364
  declare function fromBetterResult<T>(result: BetterResultValue<T, unknown>, mapError?: (error: unknown) => DbError): Result<T>;
201
365
  declare function toDbError(cause: unknown): DbError;
202
366
  //#endregion
203
- 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, BetterResultValue as r, ThrowMapper as s, AsyncResult as t, ok as u, ErrorMapper as v, isDbError as w, dbError as x, RawDbError as y };
367
+ //#region src/core/executor.d.ts
368
+ interface ExecuteContext {
369
+ readonly signal?: AbortSignal;
370
+ readonly errorMappers: readonly ErrorMapper[];
371
+ }
372
+ interface ExecuteResult {
373
+ /** Rows keyed by the aliases in the operation's selection. */
374
+ readonly rows: readonly Record<string, unknown>[];
375
+ readonly count: number | null;
376
+ }
377
+ /**
378
+ * Runs IR operations. PostgREST (`postgrestExecutor`) and SQL
379
+ * (`better-supabase/postgres`) are built in; any other backend can implement
380
+ * this interface and prove it with `testExecutor` from `better-supabase/testing`.
381
+ */
382
+ interface Executor {
383
+ readonly name: string;
384
+ /** Honors `SelectOp.source`. `db.$search` fails on executors without it. */
385
+ readonly functionSources?: boolean;
386
+ execute(op: Operation, context: ExecuteContext): Promise<Result<ExecuteResult>>;
387
+ /** Calls a database function. Optional; `db.$rpc` fails without it. */
388
+ rpc?(name: string, args: Readonly<Record<string, unknown>>, context: RpcContext): Promise<Result<unknown>>;
389
+ /**
390
+ * Runs several reads together, for `db.$many`: one transaction on a SQL
391
+ * connection. Returns one result per operation, in order. Optional;
392
+ * without it `db.$many` runs the operations in parallel.
393
+ */
394
+ batch?(ops: readonly Operation[], context: ExecuteContext): Promise<readonly Result<ExecuteResult>[]>;
395
+ }
396
+ interface RpcContext extends ExecuteContext {
397
+ readonly schema: string;
398
+ /** The function is `stable`: send it as a GET, so read replicas can serve it. */
399
+ readonly get?: boolean;
400
+ }
401
+ //#endregion
402
+ export { or as $, mapDbError as A, InsertOp as B, RawDbError as C, isConflict as D, isCheck as E, Condition as F, Quantifier as G, MutationOp as H, CountMode as I, Selection as J, SelectColumn as K, DeleteOp as L, AggregateFn as M, Aggregation as N, isDbError as O, ColumnOp as P, not as Q, FunctionSource as R, ErrorMapper as S, dbError as T, Operation as U, Measure as V, OrderTerm as W, and as X, UpdateOp as Y, column as Z, DbError as _, AsyncResult as a, DbErrorOf as b, Err as c, ThrowMapper as d, err as f, toDbError as g, toBetterResult as h, RpcContext as i, statusOf as j, isForeignKey as k, Ok as l, ok as m, ExecuteResult as n, BetterResultApi as o, fromBetterResult as p, SelectOp as q, Executor as r, BetterResultValue as s, ExecuteContext as t, Result as u, DbErrorKind as v, ValidationIssue as w, DbException as x, DbErrorKinds as y, Include as z };
@@ -1,5 +1,4 @@
1
- import { r as Executor } from "./executor-B5IoUxLE.js";
2
- import { y as RawDbError } from "./result-CqEsbgYs.js";
1
+ import { C as RawDbError, r as Executor } from "./executor-BunPOO-k.js";
3
2
  //#region src/postgres/executor.d.ts
4
3
  /**
5
4
  * Anything that runs parameterized SQL: `ctx.postgres` from
@@ -1,6 +1,6 @@
1
- import { c as mapDbError, n as dbError } from "./errors-L0xK41y_.js";
2
- import { i as ok, n as err, o as toDbError } from "./result-Bj6yt33D.js";
3
- import { t as compileSql } from "./sql-B34HU2DI.js";
1
+ import { c as mapDbError, n as dbError } from "./errors-DtwXa6b8.js";
2
+ import { i as ok, n as err, o as toDbError } from "./result-BKiliPY7.js";
3
+ import { t as compileSql } from "./sql-Coh6n4cC.js";
4
4
  //#region src/postgres/executor.ts
5
5
  function isPgError(value) {
6
6
  return typeof value === "object" && value !== null && typeof value.code === "string";
@@ -1,8 +1,8 @@
1
- import { N as TableKey, n as AnyModels, t as AnyFunctions } from "../types-DONv9SHN.js";
2
- import { t as BetterSupabase } from "../define-CRS2MRV3.js";
3
- import { r as AuthState } from "../resolve-BAqQcwMW.js";
4
- import { f as ServerContext, n as GuardOptions, p as ServerOptions, r as MiddlewareOptions, u as BetterServer } from "../respond-DgIbdrt8.js";
5
- import { a as ResourceRouteOptions } from "../resource-BJcaIfxi.js";
1
+ import { P as TableKey, n as AnyFunctions, r as AnyModels } from "../types-Dnf_wRDz.js";
2
+ import { t as BetterSupabase } from "../define-Bp_BZa5h.js";
3
+ import { o as AuthState } from "../impersonation-BmePsuxz.js";
4
+ import { f as ServerContext, n as GuardOptions, p as ServerOptions, r as MiddlewareOptions, u as BetterServer } from "../respond-BR1fJWOB.js";
5
+ import { a as ResourceRouteOptions } from "../resource-DNRFP7KR.js";
6
6
  import { Context, ErrorHandler, Hono, MiddlewareHandler } from "hono";
7
7
  //#region src/hono/index.d.ts
8
8
  /** Hono `Env` with the request's better-supabase context in `c.var`. */
@@ -18,13 +18,24 @@ export interface HonoOptions extends ServerOptions {
18
18
  readonly exposeErrors?: boolean;
19
19
  }
20
20
  export interface BetterHono<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> extends BetterServer<M, F, E, C, P> {
21
+ /**
22
+ * The app's Hono `Env`, for `new Hono<typeof bs.Env>()` and
23
+ * `Context<typeof bs.Env>`. Type only: `undefined` at runtime.
24
+ */
25
+ readonly Env: HonoEnv<M, F, E, C, P>;
26
+ /** `new Hono<typeof bs.Env>()` with `onError(bs.onError)` installed. */
27
+ app(): Hono<HonoEnv<M, F, E, C, P>>;
21
28
  /** Resolves the caller, enforces `allow` and sets `c.var.bs`, `c.var.db`, `c.var.auth`. */
22
29
  middleware(options?: MiddlewareOptions): MiddlewareHandler<HonoEnv<M, F, E, C, P>>;
23
30
  /** Wraps a handler: `Result`s become JSON or Problem Details, `undefined` becomes 204. */
24
31
  handler(fn: (c: Context<HonoEnv<M, F, E, C, P>>, ctx: ServerContext<M, F, E, C, P>) => unknown, options?: {
25
32
  readonly status?: number;
26
33
  }): (c: Context<HonoEnv<M, F, E, C, P>>) => Promise<Response>;
27
- /** `app.onError(bs.onError)`: `DbException`s (and errors caused by a `DbError`) become Problem Details, others a 500. */
34
+ /**
35
+ * `app.onError(bs.onError)`: `DbException`s (and errors caused by a `DbError`)
36
+ * become Problem Details, Hono's `HTTPException`s keep their own response,
37
+ * and anything else is a 500.
38
+ */
28
39
  readonly onError: ErrorHandler<HonoEnv<M, F, E, C, P>>;
29
40
  /**
30
41
  * REST routes for a table matching `createOpenApi`. Mount with
@@ -1,19 +1,48 @@
1
- import { n as dbError, r as dbErrorOf } from "../errors-L0xK41y_.js";
2
- import { a as problemResponse } from "../problem-BihjPR0t.js";
3
- import { a as guard, i as defaultExpose, n as extendServer, s as respond, t as createServer } from "../server-BA75B0mT.js";
4
- import { t as defineResource } from "../resource-My_y-Syh.js";
1
+ import { n as dbError, r as dbErrorOf } from "../errors-DtwXa6b8.js";
2
+ import { a as problemResponse } from "../problem-BW1KhzSG.js";
3
+ import { d as guard, i as rememberVerifiedFor, n as createServer, p as respond, r as extendServer, u as defaultExpose } from "../server-B1mZ7CgQ.js";
4
+ import { t as defineResource } from "../resource-mqfJW4YF.js";
5
5
  import { Hono } from "hono";
6
+ import { HTTPException } from "hono/http-exception";
6
7
  //#region src/hono/index.ts
7
8
  function contextOf(c) {
8
9
  const ctx = c.get("bs");
9
10
  if (!ctx) throw new TypeError("better-supabase: no context on this request; add app.use(bs.middleware()) first");
10
11
  return ctx;
11
12
  }
13
+ function isRecord(value) {
14
+ return typeof value === "object" && value !== null;
15
+ }
16
+ function isJwtClaims(value) {
17
+ return isRecord(value) && typeof value["sub"] === "string";
18
+ }
19
+ function isUserClaims(value) {
20
+ return isRecord(value) && typeof value["id"] === "string";
21
+ }
22
+ /**
23
+ * The bearer token `withSupabase` from `@supabase/server/adapters/hono`
24
+ * verified for this request, with the claims it stored in
25
+ * `c.var.supabaseContext`.
26
+ */
27
+ function verifiedBySupabase(c) {
28
+ const supabase = c.var["supabaseContext"];
29
+ if (!isRecord(supabase) || supabase["authMode"] !== "user") return void 0;
30
+ const { jwtClaims, userClaims } = supabase;
31
+ const header = c.req.header("authorization");
32
+ const token = header?.startsWith("Bearer ") ? header.slice(7) : "";
33
+ if (!token || !isJwtClaims(jwtClaims) || !isUserClaims(userClaims)) return void 0;
34
+ return {
35
+ token,
36
+ claims: jwtClaims,
37
+ user: userClaims
38
+ };
39
+ }
12
40
  /** Hono integration: a server plus middleware, handlers and REST resources. */
13
41
  function createHono(betterSupabase, options = {}) {
14
42
  const server = createServer(betterSupabase, options);
15
43
  const expose = options.exposeErrors ?? defaultExpose();
16
44
  const onError = (cause, c) => {
45
+ if (cause instanceof HTTPException) return cause.getResponse();
17
46
  const instance = new URL(c.req.url).pathname;
18
47
  const thrown = dbErrorOf(cause);
19
48
  if (thrown) return problemResponse(thrown, {
@@ -27,9 +56,15 @@ function createHono(betterSupabase, options = {}) {
27
56
  });
28
57
  };
29
58
  return extendServer(server, {
59
+ Env: void 0,
30
60
  onError,
61
+ app() {
62
+ return new Hono().onError(onError);
63
+ },
31
64
  middleware(middlewareOptions = {}) {
32
65
  return async (c, next) => {
66
+ const verified = verifiedBySupabase(c);
67
+ if (verified) rememberVerifiedFor(server, verified);
33
68
  const ctx = await server.context(c.req.raw, { refresh: middlewareOptions.refresh ?? false });
34
69
  const denied = guard(ctx.auth, middlewareOptions.allow, middlewareOptions.aal, middlewareOptions.scopes);
35
70
  if (denied) return ctx.resolution.apply(problemResponse(denied, {
@@ -40,7 +75,7 @@ function createHono(betterSupabase, options = {}) {
40
75
  c.set("db", ctx.db);
41
76
  c.set("auth", ctx.auth);
42
77
  await next();
43
- c.res = ctx.resolution.apply(c.res);
78
+ c.res = ctx.apply(c.res);
44
79
  };
45
80
  },
46
81
  handler(fn, handlerOptions = {}) {
@@ -0,0 +1,133 @@
1
+ //#region src/auth/actor.ts
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ function copyAct(level) {
6
+ const entries = Object.entries(level).map(([key, value]) => [key, key === "act" && isRecord(value) ? copyAct(value) : value]);
7
+ return Object.fromEntries(entries);
8
+ }
9
+ const INVALID = {
10
+ ok: false,
11
+ reason: "invalid-chain"
12
+ };
13
+ function actorAt(outer, id) {
14
+ const kind = outer["kind"];
15
+ const sessionId = outer["session_id"];
16
+ const readOnly = outer["read_only"];
17
+ const reason = outer["reason"];
18
+ if (kind === "support" || kind === void 0 && sessionId !== void 0) {
19
+ if (typeof sessionId !== "string" || sessionId === "") return INVALID;
20
+ if (readOnly !== void 0 && typeof readOnly !== "boolean") return INVALID;
21
+ return {
22
+ ok: true,
23
+ actor: {
24
+ kind: "support",
25
+ id,
26
+ sessionId,
27
+ readOnly: readOnly ?? true,
28
+ ...typeof reason === "string" ? { reason } : {}
29
+ }
30
+ };
31
+ }
32
+ if (kind === "impersonation") return {
33
+ ok: true,
34
+ actor: {
35
+ kind: "impersonation",
36
+ id,
37
+ ...typeof reason === "string" ? { reason } : {}
38
+ }
39
+ };
40
+ if (kind !== void 0) return INVALID;
41
+ return {
42
+ ok: true,
43
+ actor: {
44
+ kind: "oauth-client",
45
+ id,
46
+ chain: copyAct(outer)
47
+ }
48
+ };
49
+ }
50
+ /**
51
+ * Reads only `act` and `client_id`, the way PermDock's `actorOf` does. An
52
+ * `act` that is not a chain of objects each with a non-empty `sub`, a
53
+ * `kind` other than `support` or `impersonation`, or a support level without
54
+ * a `session_id` is `{ ok: false }`: the session must not pass as the user
55
+ * alone.
56
+ */
57
+ function actorOf(claims) {
58
+ const outer = claims["act"];
59
+ if (outer !== void 0) {
60
+ if (!isRecord(outer)) return INVALID;
61
+ const id = outer["sub"];
62
+ if (typeof id !== "string" || id === "") return INVALID;
63
+ let level = outer["act"];
64
+ while (level !== void 0) {
65
+ if (!isRecord(level)) return INVALID;
66
+ const sub = level["sub"];
67
+ if (typeof sub !== "string" || sub === "") return INVALID;
68
+ level = level["act"];
69
+ }
70
+ return actorAt(outer, id);
71
+ }
72
+ const client = claims["client_id"];
73
+ if (typeof client === "string" && client !== "") return {
74
+ ok: true,
75
+ actor: {
76
+ id: client,
77
+ kind: "oauth-client"
78
+ }
79
+ };
80
+ return { ok: true };
81
+ }
82
+ /** The OAuth `scope` claim (a space-separated string or a list); `undefined` when empty. */
83
+ function delegationOf(claims) {
84
+ const scope = claims["scope"];
85
+ const scopes = typeof scope === "string" ? scope.split(/\s+/u).filter(Boolean) : Array.isArray(scope) ? scope.filter((item) => typeof item === "string") : [];
86
+ return scopes.length > 0 ? { scopes } : void 0;
87
+ }
88
+ //#endregion
89
+ //#region src/auth/impersonation.ts
90
+ /** The `act` claim for an impersonated session. */
91
+ function actClaim(options) {
92
+ return {
93
+ kind: "impersonation",
94
+ sub: options.actor,
95
+ reason: options.reason
96
+ };
97
+ }
98
+ /**
99
+ * The admin in `claims.act`: a support session or an impersonated session
100
+ * (`actorOf` reads the same level, so the two always agree). `undefined`
101
+ * for a normal session, an OAuth client or agent chain, and an invalid `act`.
102
+ */
103
+ function impersonatorOf(claims) {
104
+ const outcome = actorOf(claims);
105
+ const actor = outcome.ok ? outcome.actor : void 0;
106
+ if (actor === void 0) return void 0;
107
+ switch (actor.kind) {
108
+ case "oauth-client": return;
109
+ case "support":
110
+ case "impersonation": return { ...actor };
111
+ default: return actor;
112
+ }
113
+ }
114
+ /**
115
+ * The repository context of a signed-in user: the actor, with the
116
+ * impersonator from `act`, and the claims. Every adapter builds it here, so
117
+ * plugins see the same actor on the server, in middleware and in the browser.
118
+ */
119
+ function userContext(user, claims) {
120
+ const impersonator = impersonatorOf(claims);
121
+ return {
122
+ actor: {
123
+ id: user.id,
124
+ kind: "user",
125
+ ...user.role ? { role: user.role } : {},
126
+ ...user.email ? { email: user.email } : {},
127
+ ...impersonator ? { impersonator: impersonator.id } : {}
128
+ },
129
+ claims
130
+ };
131
+ }
132
+ //#endregion
133
+ export { delegationOf as a, actorOf as i, impersonatorOf as n, userContext as r, actClaim as t };
@@ -1,8 +1,8 @@
1
- import { p as DbError } from "./result-CqEsbgYs.js";
2
- import { f as Logger, l as RefreshEvent } from "./events-B21UOhvP.js";
3
- import { h as RequestContext } from "./plugin-bNhvJwRh.js";
4
- import { t as StandardSchemaV1 } from "./standard-BsaCYQJc.js";
5
- import { t as BetterSupabaseEnv } from "./index-Dy6kuF0P.js";
1
+ import { _ as DbError } from "./executor-BunPOO-k.js";
2
+ import { E as Logger, l as RefreshEvent } from "./events-aIO7vsIk.js";
3
+ import { g as RequestContext } from "./plugin-o144f322.js";
4
+ import { t as StandardSchemaV1 } from "./standard-J4YgMOLm.js";
5
+ import { t as BetterSupabaseEnv } from "./index-CLg87OBW.js";
6
6
  import { CookieOptions } from "@supabase/ssr";
7
7
  import { JWTClaims, SupabaseEnv, UserClaims } from "@supabase/server";
8
8
  //#region src/auth/session.d.ts
@@ -119,6 +119,12 @@ interface ResolveAuthOptions {
119
119
  readonly name?: string;
120
120
  readonly options?: CookieOptions;
121
121
  };
122
+ /**
123
+ * Read the session cookie. Defaults to true. `false` suits endpoints only
124
+ * bearer clients call (MCP): a browser's cookie then can't authorize a
125
+ * request another site makes it send.
126
+ */
127
+ readonly cookies?: boolean;
122
128
  /** Inline JWKS instead of fetching `env.jwksUrl` (tests, air-gapped). */
123
129
  readonly jwks?: SupabaseEnv["jwks"];
124
130
  /**
@@ -173,4 +179,28 @@ declare function resolveAuth(request: Request, options: ResolveAuthOptions): Pro
173
179
  /** The repository context (`actor`, `claims`) for an auth state. */
174
180
  declare function authContext(auth: AuthState): RequestContext;
175
181
  //#endregion
176
- export { readSession as _, ResolveAuthOptions as a, writeSession as b, clientIp as c, CookieOptions as d, CookieRecord as f, parseCookies as g, applyCookieWrites as h, InvalidReason as i, resolveAuth as l, StoredSession as m, AuthResolver as n, ResolvedState as o, CookieWrite as p, AuthState as r, authContext as s, AuthResolution as t, AUTH_CACHE_HEADERS as u, serializeCookie as v, sessionCookieName as y };
182
+ //#region src/auth/impersonation.d.ts
183
+ /** The admin acting as the user, from the RFC 8693 `act` claim. */
184
+ interface Impersonator {
185
+ /** `act.kind`: a support session or an impersonated session. */
186
+ readonly kind: "support" | "impersonation";
187
+ readonly id: string;
188
+ readonly reason?: string;
189
+ /** The support session, when the admin started one (`act.session_id`). */
190
+ readonly sessionId?: string;
191
+ /** Whether the support session blocks writes (`act.read_only`). */
192
+ readonly readOnly?: boolean;
193
+ }
194
+ /** `actingAs(userId, claims, { actor, reason })`: who acts, and why (recorded by the audit module). */
195
+ interface ImpersonationOptions {
196
+ readonly actor: string;
197
+ readonly reason: string;
198
+ }
199
+ /**
200
+ * The admin in `claims.act`: a support session or an impersonated session
201
+ * (`actorOf` reads the same level, so the two always agree). `undefined`
202
+ * for a normal session, an OAuth client or agent chain, and an invalid `act`.
203
+ */
204
+ declare function impersonatorOf(claims: Readonly<Record<string, unknown>>): Impersonator | undefined;
205
+ //#endregion
206
+ export { writeSession as C, sessionCookieName as S, StoredSession as _, AuthResolver as a, readSession as b, ResolveAuthOptions as c, clientIp as d, resolveAuth as f, CookieWrite as g, CookieRecord as h, AuthResolution as i, ResolvedState as l, CookieOptions as m, Impersonator as n, AuthState as o, AUTH_CACHE_HEADERS as p, impersonatorOf as r, InvalidReason as s, ImpersonationOptions as t, authContext as u, applyCookieWrites as v, serializeCookie as x, parseCookies as y };
@@ -1,5 +1,5 @@
1
- import { A as SchemaMeta } from "./types-DONv9SHN.js";
2
- import { p as OpenApiParameter } from "./index-BAy4tsAP.js";
1
+ import { j as SchemaMeta } from "./types-Dnf_wRDz.js";
2
+ import { p as OpenApiParameter } from "./index-fag8VJZ2.js";
3
3
  //#region src/openapi/index.d.ts
4
4
  type Json = Record<string, unknown>;
5
5
  type ResourceOperation = "list" | "get" | "create" | "update" | "delete";
@@ -10,6 +10,8 @@ interface BetterSupabaseEnv {
10
10
  readonly secretKeys?: Readonly<Record<string, string>>;
11
11
  /** `SUPABASE_JWKS_URL`, or `<url>/auth/v1/.well-known/jwks.json`. */
12
12
  readonly jwksUrl: URL;
13
+ /** `SUPABASE_JWKS`: inline keys, used instead of fetching `jwksUrl`. */
14
+ readonly jwks?: InlineJwks;
13
15
  /** Direct Postgres connection string (`SUPABASE_DB_URL` / `DATABASE_URL`). */
14
16
  readonly dbUrl?: string;
15
17
  /** Project ref for hosted projects (`<ref>.supabase.co`). */
@@ -17,6 +19,8 @@ interface BetterSupabaseEnv {
17
19
  /** `SUPABASE_READ_URL`: a read replica or the `<ref>-all` load balancer, for reads. */
18
20
  readonly readUrl?: string;
19
21
  }
22
+ /** A JSON Web Key Set, as `@supabase/server` verifies with it. */
23
+ type InlineJwks = Exclude<SupabaseEnv["jwks"], URL | null>;
20
24
  interface PublicEnv {
21
25
  readonly url: string;
22
26
  readonly publishableKey: string;
@@ -46,6 +50,7 @@ declare const ENV_VARIABLES: {
46
50
  readonly secretKey: readonly string[];
47
51
  readonly dbUrl: readonly string[];
48
52
  readonly jwksUrl: readonly string[];
53
+ readonly jwks: readonly string[];
49
54
  readonly readUrl: readonly string[];
50
55
  };
51
56
  declare class EnvValidationError extends Error {
@@ -68,4 +73,4 @@ declare function publicEnv(env: BetterSupabaseEnv): PublicEnv;
68
73
  /** Converts to `@supabase/server`'s `SupabaseEnv` (the `env` option of `withSupabase`). */
69
74
  declare function toServerEnv(env: BetterSupabaseEnv): SupabaseEnv;
70
75
  //#endregion
71
- export { EnvResult as a, PublicEnv as c, parseEnv as d, publicEnv as f, EnvOptions as i, envSchema as l, ENV_VARIABLES as n, EnvSource as o, toServerEnv as p, EnvIssue as r, EnvValidationError as s, BetterSupabaseEnv as t, loadEnv as u };
76
+ export { EnvResult as a, InlineJwks as c, loadEnv as d, parseEnv as f, EnvOptions as i, PublicEnv as l, toServerEnv as m, ENV_VARIABLES as n, EnvSource as o, publicEnv as p, EnvIssue as r, EnvValidationError as s, BetterSupabaseEnv as t, envSchema as u };
@@ -1,5 +1,5 @@
1
- import { A as SchemaMeta, s as ClaimsMeta } from "./types-DONv9SHN.js";
2
- import { d as Generator } from "./config-C1CYcm6o.js";
1
+ import { c as ClaimsMeta, j as SchemaMeta } from "./types-Dnf_wRDz.js";
2
+ import { d as Generator } from "./config-Bv7gvfzC.js";
3
3
  //#region src/core/claims.d.ts
4
4
  declare const DEFAULT_CLAIMS: ClaimsMeta;
5
5
  /** Where the active tenant is read from: the top-level claim, then `app_metadata`. */