better-supabase 0.3.0 → 0.5.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 (211) hide show
  1. package/README.md +9 -6
  2. package/bin/better-supabase.js +4 -0
  3. package/dist/{base64-CQeB1eSf.js → base64-D2gsioCY.js} +2 -2
  4. package/dist/channel-FQW-CnGR.d.ts +70 -0
  5. package/dist/claims-BAf6c7is.js +48 -0
  6. package/dist/cli/_format-Cax5EsM9.js +101 -0
  7. package/dist/cli/bin.d.ts +1 -0
  8. package/dist/cli/bin.js +48 -0
  9. package/dist/cli/codemod-DqV7612m.js +388 -0
  10. package/dist/cli/command-CK14fP91.js +502 -0
  11. package/dist/cli/compare-BmIWVEui.js +9 -0
  12. package/dist/cli/config-CPVpXP5I.js +1965 -0
  13. package/dist/cli/config-dtoekM0v.js +2 -0
  14. package/dist/cli/db-DOBPt660.js +52 -0
  15. package/dist/cli/diff-SjkO5rNr.js +752 -0
  16. package/dist/cli/dist-DBPdlPYK.js +1112 -0
  17. package/dist/cli/dist-DreZ24Sz.js +129 -0
  18. package/dist/cli/dist-xn4wlboc.js +732 -0
  19. package/dist/cli/doctor-L7Z8mYTx.js +2863 -0
  20. package/dist/cli/env-DmKv_G4A.js +108 -0
  21. package/dist/cli/env-jIFUADLY.js +511 -0
  22. package/dist/cli/errors-4v4DTtda.js +56 -0
  23. package/dist/cli/fastest-levenshtein-CFN-lNDv.js +120 -0
  24. package/dist/cli/gen-BJc9vdyu.js +2 -0
  25. package/dist/cli/gen-C2osRcr5.js +2204 -0
  26. package/dist/cli/index.d.ts +493 -0
  27. package/dist/cli/index.js +184 -0
  28. package/dist/cli/init-Saf5-R9T.js +550 -0
  29. package/dist/cli/introspect--H7oGmcd.js +81 -0
  30. package/dist/cli/io-k41_z-jT.js +24 -0
  31. package/dist/cli/json5-ChRycquj.js +787 -0
  32. package/dist/cli/jsonc-BUniUpOk.js +2 -0
  33. package/dist/cli/jsonc-D5Fu67jw.js +45 -0
  34. package/dist/cli/keys-ByKHnvP9.js +83 -0
  35. package/dist/cli/ohash-D7bG_EOb.js +277 -0
  36. package/dist/cli/openapi-Cp5Fyta-.js +66 -0
  37. package/dist/cli/project-B_GeXyHh.js +70 -0
  38. package/dist/cli/prompts-BNcNfAve.js +1142 -0
  39. package/dist/cli/prompts-BTYQGunc.js +2 -0
  40. package/dist/cli/read-sets-BfMQcKy8.js +289 -0
  41. package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
  42. package/dist/cli/run-BKR2W_79.js +351 -0
  43. package/dist/cli/seed-CUlqWh-8.js +98 -0
  44. package/dist/cli/skills-LJJIhLFR.js +137 -0
  45. package/dist/cli/sql-DzPbfngx.js +348 -0
  46. package/dist/cli/style-C0NFdJRL.js +29 -0
  47. package/dist/cli/toml-DB-MNnFs.js +424 -0
  48. package/dist/cli/version-BDJuO0UR.js +4 -0
  49. package/dist/cli/yaml-CYCbJ6et.js +2252 -0
  50. package/dist/client/index.d.ts +2 -2
  51. package/dist/client/index.js +15 -22
  52. package/dist/clone-BfgmLU90.js +21 -0
  53. package/dist/{compiler-2zqGzxVZ.d.ts → compiler-BXH_aZ7N.d.ts} +2 -2
  54. package/dist/config/index.d.ts +4 -4
  55. package/dist/config/index.js +5 -5
  56. package/dist/{config-DOsGYSiT.js → config-DreERlKo.js} +1 -1
  57. package/dist/{config-C1CYcm6o.d.ts → config-T_ejwyd3.d.ts} +176 -11
  58. package/dist/{define-DUbydmJa.d.ts → define-Bp_BZa5h.d.ts} +37 -29
  59. package/dist/{define-DF341GDj.js → define-cNKzqwL_.js} +356 -89
  60. package/dist/edge/index.d.ts +20 -13
  61. package/dist/edge/index.js +55 -26
  62. package/dist/{entitlements-DvJXoI02.d.ts → entitlements-DUxU4oHe.d.ts} +2 -2
  63. package/dist/env/index.d.ts +2 -2
  64. package/dist/env/index.js +34 -1
  65. package/dist/{errors-Bl3rkOzo.js → errors-DtwXa6b8.js} +2 -1
  66. package/dist/events/index.d.ts +3 -2
  67. package/dist/events/index.js +69 -16
  68. package/dist/events-aIO7vsIk.d.ts +230 -0
  69. package/dist/executor-BunPOO-k.d.ts +402 -0
  70. package/dist/{executor-B26lgbHD.d.ts → executor-Cghdstwu.d.ts} +1 -2
  71. package/dist/{executor-C57jx2pn.js → executor-XycESQPH.js} +3 -3
  72. package/dist/hono/index.d.ts +27 -23
  73. package/dist/hono/index.js +46 -11
  74. package/dist/impersonation-VfaGc4Q_.js +41 -0
  75. package/dist/{index-BNsABq7P.d.ts → index-BGdgBPdf.d.ts} +66 -25
  76. package/dist/{index-qriRM9cZ.d.ts → index-C7f8cOBM.d.ts} +4 -4
  77. package/dist/{index-Dy6kuF0P.d.ts → index-CLg87OBW.d.ts} +6 -1
  78. package/dist/{index-GV77NpRP.d.ts → index-DOESKG27.d.ts} +34 -9
  79. package/dist/{index-CriFFJ_p.d.ts → index-DgILJRXj.d.ts} +43 -17
  80. package/dist/{index-UJ-LUxtI.d.ts → index-DmXSxbLi.d.ts} +14 -14
  81. package/dist/{index-Cf-D2jk1.d.ts → index-Dxn2a5cw.d.ts} +2 -2
  82. package/dist/{index-CTTMS6_1.d.ts → index-SaTsEfGP.d.ts} +86 -9
  83. package/dist/{index-CADlNHK-.d.ts → index-fag8VJZ2.d.ts} +5 -6
  84. package/dist/index.d.ts +34 -17
  85. package/dist/index.js +15 -14
  86. package/dist/jobs/index.d.ts +147 -95
  87. package/dist/jobs/index.js +773 -250
  88. package/dist/{json-schema--aOXAGfU.js → json-schema-m1fiwKgN.js} +23 -2
  89. package/dist/kit-events-CTFDfSwb.js +60 -0
  90. package/dist/kit-transport-B82k1djG.d.ts +33 -0
  91. package/dist/kit-transport-DJlHQUBU.js +55 -0
  92. package/dist/{config-Be4GwsqI.js → kits-CGLLrNPd.js} +38 -10
  93. package/dist/list/index.d.ts +1 -1
  94. package/dist/list/index.js +3 -3
  95. package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
  96. package/dist/{live-QE3UPbGm.d.ts → live-D9W2M5aO.d.ts} +16 -15
  97. package/dist/lookup-BaP5bI27.js +18 -0
  98. package/dist/mcp/index.d.ts +39 -22
  99. package/dist/mcp/index.js +39 -25
  100. package/dist/{mfa-x3V3vGh-.d.ts → mfa-CusDgPaD.d.ts} +5 -1
  101. package/dist/next/image/index.js +6 -3
  102. package/dist/next/index.d.ts +60 -36
  103. package/dist/next/index.js +167 -50
  104. package/dist/notifications/index.d.ts +162 -0
  105. package/dist/notifications/index.js +264 -0
  106. package/dist/openapi/index.d.ts +1 -1
  107. package/dist/openapi/index.js +6 -6
  108. package/dist/orgs/index.d.ts +132 -0
  109. package/dist/orgs/index.js +245 -0
  110. package/dist/orpc/index.d.ts +37 -20
  111. package/dist/orpc/index.js +24 -11
  112. package/dist/otel/index.d.ts +24 -5
  113. package/dist/otel/index.js +124 -64
  114. package/dist/permdock-sql-C2Inc6Xc.d.ts +29 -0
  115. package/dist/permdock-sql-DgOfeixi.js +51 -0
  116. package/dist/plugin-DwARMuQp.js +59 -0
  117. package/dist/{plugin-DVRB8qNE.d.ts → plugin-o144f322.d.ts} +17 -5
  118. package/dist/plugins/actor/index.d.ts +5 -2
  119. package/dist/plugins/actor/index.js +22 -8
  120. package/dist/plugins/rules/index.d.ts +2 -2
  121. package/dist/plugins/rules/index.js +52 -17
  122. package/dist/plugins/soft-delete/index.d.ts +3 -3
  123. package/dist/plugins/soft-delete/index.js +14 -5
  124. package/dist/plugins/tenant/index.d.ts +3 -3
  125. package/dist/plugins/tenant/index.js +45 -21
  126. package/dist/plugins/timestamps/index.d.ts +1 -1
  127. package/dist/plugins/timestamps/index.js +4 -3
  128. package/dist/plugins/validation/index.d.ts +2 -2
  129. package/dist/plugins/validation/index.js +26 -6
  130. package/dist/{pool-B9qsLyFR.d.ts → pool-C9voM4Kw.d.ts} +24 -6
  131. package/dist/postgres/index.d.ts +5 -5
  132. package/dist/postgres/index.js +20 -10
  133. package/dist/{postgrest-DmBlevh-.d.ts → postgrest-CruYKAvV.d.ts} +1 -1
  134. package/dist/{problem-CGt1ADix.js → problem-BW1KhzSG.js} +2 -1
  135. package/dist/{problem-Z2RTQjZD.d.ts → problem-Blxe8S31.d.ts} +1 -1
  136. package/dist/query/index.d.ts +2 -2
  137. package/dist/query/index.js +3 -3
  138. package/dist/{query-BdKLTPlj.js → query-CCbo44lG.js} +18 -18
  139. package/dist/queue-BYUCjr59.d.ts +252 -0
  140. package/dist/react/index.d.ts +8 -7
  141. package/dist/react/index.js +4 -3
  142. package/dist/react/server.d.ts +16 -5
  143. package/dist/react/server.js +12 -4
  144. package/dist/react/session.d.ts +10 -4
  145. package/dist/react/session.js +11 -3
  146. package/dist/{react-DNBYNazu.js → react-C_s7kiNz.js} +138 -46
  147. package/dist/{read-set-D0qBcboM.js → read-set-DQFt1N_Y.js} +71 -15
  148. package/dist/realtime/index.d.ts +3 -3
  149. package/dist/realtime/index.js +14 -12
  150. package/dist/{index-kpgopLNv.d.ts → refresh-BTrQ_ZTp.d.ts} +6 -3
  151. package/dist/{resolve-BRciX2jK.d.ts → resolve-C15TJq77.d.ts} +22 -11
  152. package/dist/{resource-D30rp0GN.js → resource-CRxxwkQq.js} +24 -9
  153. package/dist/{resource-CwVgiI5q.d.ts → resource-D8iqWMr-.d.ts} +6 -6
  154. package/dist/respond-D2OQl62-.d.ts +371 -0
  155. package/dist/{result-DWXatkd6.js → result-BKiliPY7.js} +2 -2
  156. package/dist/server/index.d.ts +17 -15
  157. package/dist/server/index.js +16 -22
  158. package/dist/server-Csx2sRjg.js +655 -0
  159. package/dist/{shared-_6-uPL7E.js → shared-D1dRUrAg.js} +19 -4
  160. package/dist/signers-Cc6r98SW.d.ts +162 -0
  161. package/dist/{simplify-LakqK1vH.js → simplify-_0oUKqCd.js} +27 -95
  162. package/dist/sql/index.d.ts +247 -10
  163. package/dist/sql/index.js +8591 -780
  164. package/dist/{sql-BIgk12ew.js → sql-Coh6n4cC.js} +11 -3
  165. package/dist/ssr/index.d.ts +4 -4
  166. package/dist/ssr/index.js +1 -2
  167. package/dist/{standard-FUi3Z3-7.js → standard-D7r6dMUu.js} +6 -3
  168. package/dist/{standard-eudBiRk1.d.ts → standard-J4YgMOLm.d.ts} +1 -1
  169. package/dist/{stats-D78UQ8Yu.js → stats-Bqob3WqT.js} +34 -9
  170. package/dist/storage/index.d.ts +4 -4
  171. package/dist/storage/index.js +174 -27
  172. package/dist/support-DT-OhSxD.d.ts +88 -0
  173. package/dist/support-Dk6vdmEw.js +291 -0
  174. package/dist/support-view-Da5peKFg.d.ts +17 -0
  175. package/dist/support-view-g4YLBeqX.js +18 -0
  176. package/dist/{tables-Dhha3BXM.js → tables-Cb-3_VWc.js} +14 -0
  177. package/dist/{permdock-sql-Bta_G0v-.js → template-TxrGI5jR.js} +2 -31
  178. package/dist/{temporal-BwshQk0W.js → temporal-CVlIV2DZ.js} +17 -4
  179. package/dist/{temporal-required-CMxeSVPo.js → temporal-required-CAt4Dc9Z.js} +2 -2
  180. package/dist/testing/index.d.ts +113 -24
  181. package/dist/testing/index.js +375 -47
  182. package/dist/{types-DONv9SHN.d.ts → types-Dnf_wRDz.d.ts} +26 -3
  183. package/dist/user-change-CHFEUro1.js +49 -0
  184. package/dist/{webhooks-CAIFQSTM.js → verify-Ce49ETPz.js} +38 -19
  185. package/dist/{version-BfpG2gks.js → version-DM_Roffb.js} +1 -1
  186. package/dist/{view-3Po_PVlr.d.ts → view-BEf0diC5.d.ts} +10 -5
  187. package/dist/{mfa-BxoR1RkN.js → view-Bq64ki8-.js} +210 -64
  188. package/dist/webhooks/index.d.ts +136 -5
  189. package/dist/webhooks/index.js +588 -2
  190. package/dist/wire-D2dT86vi.js +35 -0
  191. package/package.json +50 -10
  192. package/schemas/config-v1.json +131 -1
  193. package/schemas/doctor-report-v1.json +10 -0
  194. package/skills/better-supabase/SKILL.md +60 -10
  195. package/skills/better-supabase/references/plugins.md +13 -14
  196. package/skills/better-supabase/references/troubleshooting.md +25 -4
  197. package/skills/better-supabase-api/SKILL.md +74 -19
  198. package/skills/better-supabase-api/references/adapters.md +48 -27
  199. package/skills/better-supabase-auth/SKILL.md +149 -0
  200. package/skills/better-supabase-auth/references/permdock.md +100 -0
  201. package/skills/better-supabase-testing/SKILL.md +58 -4
  202. package/dist/claims-CoTobNC-.js +0 -25
  203. package/dist/events-Do8jXh4D.d.ts +0 -84
  204. package/dist/executor-DynmIWhq.d.ts +0 -195
  205. package/dist/invalidate-DbxuL2jL.js +0 -18
  206. package/dist/permdock-sql-DImJULY-.d.ts +0 -17
  207. package/dist/plugin-BqR6wKMB.js +0 -23
  208. package/dist/respond-C44EZAJo.js +0 -399
  209. package/dist/respond-DAkPIdTH.d.ts +0 -175
  210. package/dist/result-c2OYgCV2.d.ts +0 -203
  211. package/dist/view-wZ-9qIUz.js +0 -45
@@ -1,7 +1,7 @@
1
- import { N as TableKey, n as AnyModels, t as AnyFunctions } from "../types-DONv9SHN.js";
2
- import { t as BetterSupabase } from "../define-DUbydmJa.js";
3
- import { d as ServerContext, f as ServerOptions, l as BetterServer, n as GuardOptions } from "../respond-DAkPIdTH.js";
4
- import { a as ResourceRouteOptions } from "../resource-CwVgiI5q.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 { f as ServerContext, n as GuardOptions, p as ServerOptions, r as MiddlewareOptions, u as BetterServer } from "../respond-D2OQl62-.js";
4
+ import { a as ResourceRouteOptions } from "../resource-D8iqWMr-.js";
5
5
  //#region src/edge/index.d.ts
6
6
  export interface CorsOptions {
7
7
  /** Allowed origins, or `*`. Defaults to `*`. */
@@ -16,28 +16,35 @@ export interface EdgeOptions extends ServerOptions {
16
16
  readonly cors?: boolean | CorsOptions;
17
17
  /** Include error details in problem responses. Defaults to `NODE_ENV === 'development'`. */
18
18
  readonly exposeErrors?: boolean;
19
+ /**
20
+ * Keeps the invocation alive for event sink sends a handler started, e.g.
21
+ * `EdgeRuntime.waitUntil` on Supabase. On Workers the `ctx` the runtime
22
+ * passes to `fetch` is used when this is unset.
23
+ */
24
+ readonly waitUntil?: (promise: Promise<unknown>) => void;
19
25
  }
20
- export interface HandlerOptions extends GuardOptions {
21
- /** Refresh an expired cookie session and send the new cookies. */
22
- readonly refresh?: boolean;
26
+ /** The platform context Workers pass as the third `fetch` argument. */
27
+ export interface EdgeExecutionContext {
28
+ waitUntil(promise: Promise<unknown>): void;
23
29
  }
24
- export type EdgeHandler = (request: Request) => Promise<Response>;
30
+ /** `Deno.serve` passes `(request, info)`, Workers `fetch` passes `(request, env, ctx)`. */
31
+ export type EdgeHandler = (request: Request, env?: unknown, executionContext?: EdgeExecutionContext) => Promise<Response>;
25
32
  export type ResourceMap<M extends AnyModels> = { readonly [T in TableKey<M>]?: ResourceRouteOptions<M, T> | true; };
26
- export interface ResourcesOptions extends HandlerOptions {
33
+ export interface ResourcesOptions extends MiddlewareOptions {
27
34
  /** Path before the resources, e.g. `/api` (Supabase: `/<function-name>`). */
28
35
  readonly basePath?: string;
29
36
  }
30
- export interface BetterEdge<M extends AnyModels, F extends AnyFunctions, E> extends BetterServer<M, F, E> {
37
+ export interface BetterEdge<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> extends BetterServer<M, F, E, C, P> {
31
38
  /**
32
39
  * A fetch handler (`Deno.serve`, Workers `fetch`) running as the caller.
33
40
  * `Result`s become JSON or Problem Details; `undefined` becomes 204.
34
41
  */
35
- handler(fn: (request: Request, ctx: ServerContext<M, F, E>) => unknown, options?: HandlerOptions): EdgeHandler;
42
+ handler(fn: (request: Request, ctx: ServerContext<M, F, E, C, P>) => unknown, options?: MiddlewareOptions): EdgeHandler;
36
43
  /** REST resources matching `createOpenApi`, e.g. `Deno.serve(bs.resources({ customers: true }))`. */
37
44
  resources(map: ResourceMap<M>, options?: ResourcesOptions): EdgeHandler;
38
45
  }
39
46
  export declare const SUPABASE_CORS_HEADERS: readonly string[];
40
47
  /** Fetch-handler integration for Supabase Edge Functions, Deno, Bun and Workers. */
41
- export declare function createEdge<M extends AnyModels, D, F extends AnyFunctions, E>(sb: BetterSupabase<M, D, F, E>, options?: EdgeOptions): BetterEdge<M, F, E>;
48
+ export declare function createEdge<M extends AnyModels, D, F extends AnyFunctions, E, C = unknown, P = unknown>(betterSupabase: BetterSupabase<M, D, F, E, C, P>, options?: EdgeOptions): BetterEdge<M, F, E, C, P>;
42
49
  //#endregion
43
- export type { GuardOptions, ResourceRouteOptions };
50
+ export type { GuardOptions, MiddlewareOptions, ResourceRouteOptions };
@@ -1,7 +1,7 @@
1
- import { n as dbError } from "../errors-Bl3rkOzo.js";
2
- import { a as problemResponse } from "../problem-CGt1ADix.js";
3
- import { i as respond, n as guard, o as createServer, s as extendServer, t as defaultExpose } from "../respond-C44EZAJo.js";
4
- import { t as defineResource } from "../resource-D30rp0GN.js";
1
+ import { n as dbError } from "../errors-DtwXa6b8.js";
2
+ import { a as problemResponse } from "../problem-BW1KhzSG.js";
3
+ import { d as guard, n as createServer, p as respond, r as extendServer, u as defaultExpose } from "../server-Csx2sRjg.js";
4
+ import { t as defineResource } from "../resource-CRxxwkQq.js";
5
5
  //#region src/edge/index.ts
6
6
  const SUPABASE_CORS_HEADERS = [
7
7
  "authorization",
@@ -9,15 +9,11 @@ const SUPABASE_CORS_HEADERS = [
9
9
  "apikey",
10
10
  "content-type"
11
11
  ];
12
- function corsHeaders(request, cors) {
13
- const origin = request.headers.get("origin");
12
+ /** The CORS headers for a request's origin; the fixed ones are joined once. */
13
+ function corsFor(cors) {
14
14
  const allowed = cors.origin ?? "*";
15
- let value;
16
- if (allowed === "*") value = "*";
17
- else if (origin && (typeof allowed === "string" ? [allowed] : allowed).includes(origin)) value = origin;
18
- if (!value) return void 0;
19
- return {
20
- "access-control-allow-origin": value,
15
+ const origins = new Set(typeof allowed === "string" ? [allowed] : allowed);
16
+ const fixed = {
21
17
  "access-control-allow-headers": (cors.headers ?? SUPABASE_CORS_HEADERS).join(", "),
22
18
  "access-control-allow-methods": (cors.methods ?? [
23
19
  "GET",
@@ -26,8 +22,21 @@ function corsHeaders(request, cors) {
26
22
  "DELETE",
27
23
  "OPTIONS"
28
24
  ]).join(", "),
29
- ...cors.maxAge === void 0 ? {} : { "access-control-max-age": String(cors.maxAge) },
30
- ...value === "*" ? {} : { vary: "origin" }
25
+ ...cors.maxAge === void 0 ? {} : { "access-control-max-age": String(cors.maxAge) }
26
+ };
27
+ const any = {
28
+ "access-control-allow-origin": "*",
29
+ ...fixed
30
+ };
31
+ return (request) => {
32
+ if (allowed === "*") return any;
33
+ const origin = request.headers.get("origin");
34
+ if (!origin || !origins.has(origin)) return;
35
+ return {
36
+ "access-control-allow-origin": origin,
37
+ ...fixed,
38
+ vary: "origin"
39
+ };
31
40
  };
32
41
  }
33
42
  function withHeaders(response, headers) {
@@ -41,17 +50,20 @@ function withHeaders(response, headers) {
41
50
  return target;
42
51
  }
43
52
  /** Fetch-handler integration for Supabase Edge Functions, Deno, Bun and Workers. */
44
- function createEdge(sb, options = {}) {
45
- const server = createServer(sb, options);
53
+ function createEdge(betterSupabase, options = {}) {
54
+ const server = createServer(betterSupabase, options);
46
55
  const expose = options.exposeErrors ?? defaultExpose();
47
56
  const cors = options.cors === true ? {} : options.cors === false ? void 0 : options.cors;
48
- const serve = (run, handlerOptions) => {
49
- return async (request) => {
50
- const extra = cors ? corsHeaders(request, cors) : void 0;
57
+ const corsHeaders = cors ? corsFor(cors) : void 0;
58
+ const serve = (run, handlerOptions, early) => {
59
+ return async (request, _env, executionContext) => {
60
+ const extra = corsHeaders?.(request);
51
61
  if (cors && request.method === "OPTIONS") return new Response(null, {
52
62
  status: 204,
53
63
  headers: extra ?? {}
54
64
  });
65
+ const answered = early?.(request);
66
+ if (answered) return extra ? withHeaders(answered, extra) : answered;
55
67
  const ctx = await server.context(request, { refresh: handlerOptions.refresh ?? false });
56
68
  const instance = new URL(request.url).pathname;
57
69
  const denied = guard(ctx.auth, handlerOptions.allow, handlerOptions.aal, handlerOptions.scopes);
@@ -67,7 +79,10 @@ function createEdge(sb, options = {}) {
67
79
  expose
68
80
  });
69
81
  }
70
- response = ctx.resolution.apply(response);
82
+ response = ctx.apply(response);
83
+ const { events } = betterSupabase;
84
+ const waitUntil = options.waitUntil ?? executionContext?.waitUntil.bind(executionContext);
85
+ if (events.pending && waitUntil) waitUntil(events.settled());
71
86
  return extra ? withHeaders(response, extra) : response;
72
87
  };
73
88
  };
@@ -83,19 +98,33 @@ function createEdge(sb, options = {}) {
83
98
  const handlers = /* @__PURE__ */ new Map();
84
99
  for (const [table, resource] of Object.entries(map)) {
85
100
  if (!resource) continue;
86
- handlers.set(table, defineResource(sb, table, resource === true ? {} : resource));
101
+ handlers.set(table, defineResource(betterSupabase, table, resource === true ? {} : resource));
87
102
  }
88
- return serve(async (request, ctx) => {
103
+ const routes = /* @__PURE__ */ new WeakMap();
104
+ const notFound = (request) => {
89
105
  const { pathname } = new URL(request.url);
90
- const instance = pathname;
91
106
  const [table, id, extra] = (pathname.startsWith(`${base}/`) ? pathname.slice(base.length + 1) : void 0)?.split("/") ?? [];
92
107
  const handler = table ? handlers.get(table) : void 0;
93
- if (!handler || extra !== void 0 || id !== void 0 && !handler.keyParam) return problemResponse(dbError("not_found", `No route for ${pathname}`), { instance });
94
- return handler.handle(request, ctx.db, id === void 0 || id === "" ? void 0 : decodeURIComponent(id), {
108
+ if (!handler || extra !== void 0 || id !== void 0 && !handler.keyParam) return problemResponse(dbError("not_found", `No route for ${pathname}`), { instance: pathname });
109
+ let key;
110
+ try {
111
+ key = id === void 0 || id === "" ? void 0 : decodeURIComponent(id);
112
+ } catch {
113
+ return problemResponse(dbError("invalid_input", `Malformed id in ${pathname}`), { instance: pathname });
114
+ }
115
+ routes.set(request, {
116
+ handler,
117
+ id: key,
118
+ instance: pathname
119
+ });
120
+ };
121
+ return serve((request, ctx) => {
122
+ const { handler, id, instance } = routes.get(request);
123
+ return handler.handle(request, ctx.db, id, {
95
124
  instance,
96
125
  expose
97
126
  });
98
- }, resourcesOptions);
127
+ }, resourcesOptions, notFound);
99
128
  }
100
129
  });
101
130
  }
@@ -1,4 +1,4 @@
1
- import { t as AuthSession } from "./view-3Po_PVlr.js";
1
+ import { t as AuthSession } from "./view-BEf0diC5.js";
2
2
  //#region src/auth/entitlements.d.ts
3
3
  /**
4
4
  * One entry of the `memberships` claim, in PermDock's shape. PermDock strips
@@ -25,7 +25,7 @@ interface MembershipClaim {
25
25
  }
26
26
  /**
27
27
  * Entitlement keys of the `features` claim: the literal union when
28
- * `sb.claims(schema)` declares one (`z.enum([...])`), otherwise `string`.
28
+ * `betterSupabase.claims(schema)` declares one (`z.enum([...])`), otherwise `string`.
29
29
  */
30
30
  type EntitlementKey<C> = C extends {
31
31
  readonly features?: infer F;
@@ -1,2 +1,2 @@
1
- import { a as EnvResult, c as PublicEnv, d as parseEnv, f as publicEnv, i as EnvOptions, l as envSchema, n as ENV_VARIABLES, o as EnvSource, p as toServerEnv, r as EnvIssue, s as EnvValidationError, t as BetterSupabaseEnv, u as loadEnv } from "../index-Dy6kuF0P.js";
2
- export { BetterSupabaseEnv, ENV_VARIABLES, EnvIssue, EnvOptions, EnvResult, EnvSource, EnvValidationError, PublicEnv, envSchema, loadEnv, parseEnv, publicEnv, toServerEnv };
1
+ import { a as EnvResult, c as InlineJwks, d as loadEnv, f as parseEnv, i as EnvOptions, l as PublicEnv, m as toServerEnv, n as ENV_VARIABLES, o as EnvSource, p as publicEnv, r as EnvIssue, s as EnvValidationError, t as BetterSupabaseEnv, u as envSchema } from "../index-CLg87OBW.js";
2
+ export { BetterSupabaseEnv, ENV_VARIABLES, EnvIssue, EnvOptions, EnvResult, EnvSource, EnvValidationError, InlineJwks, PublicEnv, envSchema, loadEnv, parseEnv, publicEnv, toServerEnv };
package/dist/env/index.js CHANGED
@@ -13,6 +13,7 @@ const ENV_VARIABLES = {
13
13
  secretKey: ["SUPABASE_SECRET_KEY"],
14
14
  dbUrl: ["SUPABASE_DB_URL", "DATABASE_URL"],
15
15
  jwksUrl: ["SUPABASE_JWKS_URL"],
16
+ jwks: ["SUPABASE_JWKS"],
16
17
  readUrl: ["SUPABASE_READ_URL"]
17
18
  };
18
19
  const LOOPBACK = /^(localhost|127(?:\.\d{1,3}){3}|\[::1\])$/;
@@ -57,6 +58,35 @@ function preferred(keys) {
57
58
  if (!keys) return void 0;
58
59
  return keys["default"] ?? Object.values(keys)[0];
59
60
  }
61
+ function isJwk(value) {
62
+ return typeof value === "object" && value !== null && "kty" in value && typeof value.kty === "string";
63
+ }
64
+ /** At least one key, each an object with a string `kty`, the shape the verifier reads. */
65
+ function isJwkList(value) {
66
+ return Array.isArray(value) && value.length > 0 && value.every(isJwk);
67
+ }
68
+ /** `SUPABASE_JWKS` as `@supabase/server` reads it: `{"keys":[...]}` or `[...]`. */
69
+ function checkJwks(raw, issues) {
70
+ let parsed;
71
+ try {
72
+ parsed = JSON.parse(raw);
73
+ } catch {
74
+ issues.push({
75
+ variables: ENV_VARIABLES.jwks,
76
+ message: "must be JSON: {\"keys\":[...]} or [...]"
77
+ });
78
+ return;
79
+ }
80
+ const keys = typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? "keys" in parsed ? parsed.keys : void 0 : parsed;
81
+ if (!isJwkList(keys)) {
82
+ issues.push({
83
+ variables: ENV_VARIABLES.jwks,
84
+ message: "must hold at least one JSON Web Key with a kty"
85
+ });
86
+ return;
87
+ }
88
+ return { keys };
89
+ }
60
90
  function checkUrl(value, variables, issues) {
61
91
  let url;
62
92
  try {
@@ -132,6 +162,8 @@ function parseEnv(source, options = {}) {
132
162
  });
133
163
  const rawJwks = first(source, ENV_VARIABLES.jwksUrl);
134
164
  const jwksOverride = rawJwks ? checkUrl(rawJwks, ENV_VARIABLES.jwksUrl, issues) : void 0;
165
+ const rawInline = first(source, ENV_VARIABLES.jwks);
166
+ const jwks = rawInline ? checkJwks(rawInline, issues) : void 0;
135
167
  const rawRead = first(source, ENV_VARIABLES.readUrl);
136
168
  const readUrl = rawRead ? checkUrl(rawRead, ENV_VARIABLES.readUrl, issues) : void 0;
137
169
  if (issues.length > 0 || !url || !publishableKey) return {
@@ -146,6 +178,7 @@ function parseEnv(source, options = {}) {
146
178
  url: base,
147
179
  publishableKey,
148
180
  jwksUrl: jwksOverride ?? new URL(`${base}/auth/v1/.well-known/jwks.json`),
181
+ ...jwks ? { jwks } : {},
149
182
  ...secretKey ? {
150
183
  secretKey,
151
184
  secretKeys: {
@@ -197,7 +230,7 @@ function toServerEnv(env) {
197
230
  url: env.url,
198
231
  publishableKeys: { default: env.publishableKey },
199
232
  secretKeys: env.secretKeys ?? (env.secretKey ? { default: env.secretKey } : {}),
200
- jwks: env.jwksUrl
233
+ jwks: env.jwks ?? env.jwksUrl
201
234
  };
202
235
  }
203
236
  //#endregion
@@ -9,6 +9,7 @@ const STATUS = {
9
9
  not_null: 422,
10
10
  exclusion: 409,
11
11
  invalid_input: 400,
12
+ invalid_value: 500,
12
13
  raised: 400,
13
14
  timeout: 504,
14
15
  serialization: 409,
@@ -41,7 +42,7 @@ function isDbError(value) {
41
42
  }
42
43
  /**
43
44
  * The `DbError` in a `DbError`, a `DbException`, or an error whose `cause`
44
- * is a `DbError` (what `sb.mapError()` mappers should set).
45
+ * is a `DbError` (what `betterSupabase.mapError()` mappers should set).
45
46
  */
46
47
  function dbErrorOf(value) {
47
48
  if (value instanceof DbException) return value.error;
@@ -1,2 +1,3 @@
1
- import { a as HttpMode, c as RowEventData, d as httpSink, f as isCloudEvent, i as ForwardOptions, l as forwardMutations, m as toHttp, n as CloudEventOptions, o as HttpSinkOptions, p as toCloudEvents, r as EventSink, s as ROW_EVENT_TYPES, t as CloudEvent, u as fromHttp } from "../index-GV77NpRP.js";
2
- export { CloudEvent, CloudEventOptions, EventSink, ForwardOptions, HttpMode, HttpSinkOptions, ROW_EVENT_TYPES, RowEventData, forwardMutations, fromHttp, httpSink, isCloudEvent, toCloudEvents, toHttp };
1
+ import { C as kitEventAttributes, S as WebhookEventData, _ as KitEventType, b as OrgEventData, d as InvitationEventData, f as KIT_ATTRIBUTES, g as KitEventPattern, h as KitEventMeta, m as KitEventMap, p as KitEvent, v as KitEventsMatching, w as onKitEvent, x as SupportEventData, y as NotificationEventData } from "../events-aIO7vsIk.js";
2
+ import { _ as toHttp, a as ForwardOptions, c as ROW_EVENT_TYPES, d as forwardMutations, f as fromHttp, g as toCloudEvents, h as kitCloudEvent, i as ForwardKitOptions, l as RowEventData, m as isCloudEvent, n as CloudEventOptions, o as HttpMode, p as httpSink, r as EventSink, s as HttpSinkOptions, t as CloudEvent, u as forwardKitEvents } from "../index-DOESKG27.js";
3
+ export { CloudEvent, CloudEventOptions, EventSink, ForwardKitOptions, ForwardOptions, HttpMode, HttpSinkOptions, type InvitationEventData, KIT_ATTRIBUTES, type KitEvent, type KitEventMap, type KitEventMeta, type KitEventPattern, type KitEventType, type KitEventsMatching, type NotificationEventData, type OrgEventData, ROW_EVENT_TYPES, RowEventData, type SupportEventData, type WebhookEventData, forwardKitEvents, forwardMutations, fromHttp, httpSink, isCloudEvent, kitCloudEvent, kitEventAttributes, onKitEvent, toCloudEvents, toHttp };
@@ -1,10 +1,12 @@
1
- import { n as nowInstant } from "../temporal-BwshQk0W.js";
1
+ import { n as nowInstant } from "../temporal-CVlIV2DZ.js";
2
+ import { i as onKitEvent, r as kitEventAttributes, t as KIT_ATTRIBUTES } from "../kit-events-CTFDfSwb.js";
2
3
  //#region src/events/index.ts
3
4
  const ROW_EVENT_TYPES = {
4
5
  insert: "dev.better-supabase.row.created",
5
6
  upsert: "dev.better-supabase.row.upserted",
6
7
  update: "dev.better-supabase.row.updated",
7
- delete: "dev.better-supabase.row.deleted"
8
+ delete: "dev.better-supabase.row.deleted",
9
+ softDelete: "dev.better-supabase.row.softdeleted"
8
10
  };
9
11
  function subjectOf(meta, table, row) {
10
12
  const key = meta?.tables[table]?.primaryKey;
@@ -15,13 +17,19 @@ function subjectOf(meta, table, row) {
15
17
  }
16
18
  /**
17
19
  * One CloudEvent per mutated row: `dev.better-supabase.row.created` with the
18
- * app-cased row as `data`, the primary key as `subject`, the tenant as
19
- * `partitionkey` and the actor as `actorid`.
20
+ * app-cased row and the actor in `data`, the primary key as `subject` and the
21
+ * tenant as `partitionkey`. Writes that return no rows (soft
22
+ * deletes, `returning: false`) send one event per known primary key, with the
23
+ * key as `row`.
20
24
  */
21
25
  function toCloudEvents(notice, options) {
22
- const type = options.typePrefix ? `${options.typePrefix}.row.${ROW_EVENT_TYPES[notice.kind].split(".").at(-1)}` : ROW_EVENT_TYPES[notice.kind];
26
+ const intent = notice.intent ?? notice.kind;
27
+ const type = options.typePrefix ? `${options.typePrefix}.row.${ROW_EVENT_TYPES[intent].split(".").at(-1)}` : ROW_EVENT_TYPES[intent];
23
28
  const time = (options.now ?? nowInstant)().toString();
24
- return notice.rows.map((row) => {
29
+ const tenant = notice.tenant ?? notice.context.tenant;
30
+ const rows = notice.rows.length > 0 ? notice.rows : notice.keys ?? [];
31
+ const actorId = notice.context.actor?.id;
32
+ return rows.map((row) => {
25
33
  const subject = subjectOf(options.meta, notice.table, row);
26
34
  return {
27
35
  specversion: "1.0",
@@ -33,32 +41,77 @@ function toCloudEvents(notice, options) {
33
41
  datacontenttype: "application/json",
34
42
  data: {
35
43
  table: notice.table,
36
- row
44
+ row,
45
+ ...actorId ? { actorId } : {}
37
46
  },
38
- ...notice.context.tenant ? { partitionkey: notice.context.tenant } : {},
39
- ...notice.context.actor?.id ? { actorid: notice.context.actor.id } : {}
47
+ ...tenant ? { partitionkey: tenant } : {}
40
48
  };
41
49
  });
42
50
  }
43
51
  /**
44
52
  * Sends a CloudEvent for every mutation to `sink`. Returns a function that
45
- * stops forwarding. Use an outbox (SQL kit) when events must not be lost.
53
+ * stops forwarding. Sends in flight are tracked on `betterSupabase.events`
54
+ * (`settled()`), which the Next adapter hands to `after()` and the edge
55
+ * entry to `waitUntil`. Use an outbox (SQL kit) when events must not be lost.
46
56
  */
47
- function forwardMutations(sb, sink, options) {
48
- return sb.events.on("mutation", (notice) => {
57
+ function forwardMutations(betterSupabase, sink, options) {
58
+ return betterSupabase.events.on("mutation", (notice) => {
49
59
  if (options.filter && !options.filter(notice)) return;
50
60
  const events = toCloudEvents(notice, {
51
61
  ...options,
52
- meta: sb.meta
62
+ meta: betterSupabase.meta
53
63
  });
54
64
  if (events.length === 0) return;
55
65
  const report = (error) => {
56
66
  (options.onError ?? ((cause) => {
57
- sb.events.logger.error("event sink failed", { cause });
67
+ betterSupabase.events.logger.error("event sink failed", { cause });
58
68
  }))(error, events);
59
69
  };
60
70
  try {
61
- Promise.resolve(sink.send(events)).catch(report);
71
+ betterSupabase.events.track(Promise.resolve(sink.send(events)).catch(report));
72
+ } catch (error) {
73
+ report(error);
74
+ }
75
+ });
76
+ }
77
+ /**
78
+ * A kit event as a CloudEvent: `dev.better-supabase.support.started` with
79
+ * the event data and the actor (`actorId`) as `data` and the tenant as
80
+ * `partitionkey`.
81
+ */
82
+ function kitCloudEvent(event, options) {
83
+ return {
84
+ specversion: "1.0",
85
+ id: options.id?.() ?? crypto.randomUUID(),
86
+ source: options.source,
87
+ type: `${options.typePrefix ?? "dev.better-supabase"}.${event.type}`,
88
+ ...event.subject ? { subject: event.subject } : {},
89
+ time: (options.now?.() ?? event.time).toString(),
90
+ datacontenttype: "application/json",
91
+ data: event.actorId ? {
92
+ ...event.data,
93
+ actorId: event.actorId
94
+ } : event.data,
95
+ ...event.tenant ? { partitionkey: event.tenant } : {}
96
+ };
97
+ }
98
+ /**
99
+ * Sends a CloudEvent for every kit event (`support.*`, `org.*`, ...) to
100
+ * `sink`. Returns a function that stops forwarding. Like
101
+ * `forwardMutations`, sends are tracked on `betterSupabase.events`.
102
+ */
103
+ function forwardKitEvents(betterSupabase, sink, options) {
104
+ const types = options.types;
105
+ return betterSupabase.events.on("kit", (event) => {
106
+ if (types && !types.some((pattern) => pattern.endsWith(".*") ? event.type.startsWith(pattern.slice(0, -1)) : pattern === event.type)) return;
107
+ const events = [kitCloudEvent(event, options)];
108
+ const report = (error) => {
109
+ (options.onError ?? ((cause) => {
110
+ betterSupabase.events.logger.error("event sink failed", { cause });
111
+ }))(error, events);
112
+ };
113
+ try {
114
+ betterSupabase.events.track(Promise.resolve(sink.send(events)).catch(report));
62
115
  } catch (error) {
63
116
  report(error);
64
117
  }
@@ -137,4 +190,4 @@ function httpSink(url, options = {}) {
137
190
  } };
138
191
  }
139
192
  //#endregion
140
- export { ROW_EVENT_TYPES, forwardMutations, fromHttp, httpSink, isCloudEvent, toCloudEvents, toHttp };
193
+ export { KIT_ATTRIBUTES, ROW_EVENT_TYPES, forwardKitEvents, forwardMutations, fromHttp, httpSink, isCloudEvent, kitCloudEvent, kitEventAttributes, onKitEvent, toCloudEvents, toHttp };