better-supabase 0.4.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 (179) hide show
  1. package/README.md +2 -0
  2. package/dist/channel-FQW-CnGR.d.ts +70 -0
  3. package/dist/cli/bin.js +1 -1
  4. package/dist/cli/codemod-DqV7612m.js +388 -0
  5. package/dist/cli/{config-D9R0o1LH.js → config-CPVpXP5I.js} +78 -8
  6. package/dist/cli/{config-SSKSTUl2.js → config-dtoekM0v.js} +1 -1
  7. package/dist/cli/{read-sets-CMa29t9a.js → diff-SjkO5rNr.js} +1 -220
  8. package/dist/cli/{dist-CFgGknmZ.js → dist-DBPdlPYK.js} +4 -4
  9. package/dist/cli/{dist-B1MvLv-M.js → dist-DreZ24Sz.js} +1 -1
  10. package/dist/cli/{dist-Du7VnEUG.js → dist-xn4wlboc.js} +112 -1
  11. package/dist/cli/{doctor-BOym3mbL.js → doctor-L7Z8mYTx.js} +531 -50
  12. package/dist/cli/{env-BZ0uy8XK.js → env-DmKv_G4A.js} +1 -1
  13. package/dist/cli/gen-BJc9vdyu.js +2 -0
  14. package/dist/cli/{gen-Ccn_p90L.js → gen-C2osRcr5.js} +283 -87
  15. package/dist/cli/index.d.ts +1 -1
  16. package/dist/cli/index.js +4 -4
  17. package/dist/cli/{init-ClnxRYBF.js → init-Saf5-R9T.js} +2 -2
  18. package/dist/cli/{introspect-DxqfkVIv.js → introspect--H7oGmcd.js} +2 -2
  19. package/dist/cli/{openapi-8WHjxiTJ.js → openapi-Cp5Fyta-.js} +1 -1
  20. package/dist/cli/read-sets-BfMQcKy8.js +289 -0
  21. package/dist/cli/{run-CP20LKk_.js → run-BKR2W_79.js} +16 -12
  22. package/dist/cli/{seed-5J6eu_Xg.js → seed-CUlqWh-8.js} +1 -1
  23. package/dist/cli/sql-DzPbfngx.js +348 -0
  24. package/dist/cli/{version-5mW_8sY1.js → version-BDJuO0UR.js} +1 -1
  25. package/dist/client/index.d.ts +1 -1
  26. package/dist/client/index.js +3 -10
  27. package/dist/clone-BfgmLU90.js +21 -0
  28. package/dist/{compiler-DB3aSFOA.d.ts → compiler-BXH_aZ7N.d.ts} +2 -2
  29. package/dist/config/index.d.ts +4 -4
  30. package/dist/config/index.js +4 -4
  31. package/dist/{config-CbvFmGD8.js → config-DreERlKo.js} +1 -1
  32. package/dist/{config-C1CYcm6o.d.ts → config-T_ejwyd3.d.ts} +176 -11
  33. package/dist/{define-CRS2MRV3.d.ts → define-Bp_BZa5h.d.ts} +11 -7
  34. package/dist/{define-Bh0AqTik.js → define-cNKzqwL_.js} +202 -16
  35. package/dist/edge/index.d.ts +16 -5
  36. package/dist/edge/index.js +10 -7
  37. package/dist/{entitlements-Dm-FHpNH.d.ts → entitlements-DUxU4oHe.d.ts} +1 -1
  38. package/dist/env/index.d.ts +2 -2
  39. package/dist/env/index.js +34 -1
  40. package/dist/{errors-L0xK41y_.js → errors-DtwXa6b8.js} +1 -0
  41. package/dist/events/index.d.ts +3 -2
  42. package/dist/events/index.js +65 -12
  43. package/dist/events-aIO7vsIk.d.ts +230 -0
  44. package/dist/{result-CqEsbgYs.d.ts → executor-BunPOO-k.d.ts} +200 -1
  45. package/dist/{executor-CZ7ImRiD.d.ts → executor-Cghdstwu.d.ts} +1 -2
  46. package/dist/{executor-CVt6dD0B.js → executor-XycESQPH.js} +3 -3
  47. package/dist/hono/index.d.ts +17 -6
  48. package/dist/hono/index.js +40 -5
  49. package/dist/impersonation-VfaGc4Q_.js +41 -0
  50. package/dist/{index-BBdvo-5d.d.ts → index-BGdgBPdf.d.ts} +49 -6
  51. package/dist/{index-BhHEC04r.d.ts → index-C7f8cOBM.d.ts} +2 -2
  52. package/dist/{index-Dy6kuF0P.d.ts → index-CLg87OBW.d.ts} +6 -1
  53. package/dist/{index-D5IfUIDh.d.ts → index-DOESKG27.d.ts} +33 -8
  54. package/dist/{index-DFmOpBGC.d.ts → index-DgILJRXj.d.ts} +35 -9
  55. package/dist/{index-RlLXd8dL.d.ts → index-DmXSxbLi.d.ts} +4 -4
  56. package/dist/{index-Cf-D2jk1.d.ts → index-Dxn2a5cw.d.ts} +2 -2
  57. package/dist/{index-528Ugmyp.d.ts → index-SaTsEfGP.d.ts} +76 -8
  58. package/dist/{index-BAy4tsAP.d.ts → index-fag8VJZ2.d.ts} +3 -4
  59. package/dist/index.d.ts +30 -13
  60. package/dist/index.js +10 -9
  61. package/dist/jobs/index.d.ts +147 -101
  62. package/dist/jobs/index.js +744 -237
  63. package/dist/{json-schema-DP6V7cbr.js → json-schema-m1fiwKgN.js} +22 -1
  64. package/dist/kit-events-CTFDfSwb.js +60 -0
  65. package/dist/kit-transport-B82k1djG.d.ts +33 -0
  66. package/dist/kit-transport-DJlHQUBU.js +55 -0
  67. package/dist/{config-BpxDfnbg.js → kits-CGLLrNPd.js} +37 -9
  68. package/dist/list/index.d.ts +1 -1
  69. package/dist/{live-BHakSWWo.d.ts → live-D9W2M5aO.d.ts} +6 -5
  70. package/dist/mcp/index.d.ts +25 -8
  71. package/dist/mcp/index.js +23 -14
  72. package/dist/{mfa-C7MNQ1Ob.d.ts → mfa-CusDgPaD.d.ts} +5 -1
  73. package/dist/next/index.d.ts +31 -10
  74. package/dist/next/index.js +136 -27
  75. package/dist/notifications/index.d.ts +162 -0
  76. package/dist/notifications/index.js +264 -0
  77. package/dist/openapi/index.d.ts +1 -1
  78. package/dist/openapi/index.js +2 -2
  79. package/dist/orgs/index.d.ts +132 -0
  80. package/dist/orgs/index.js +245 -0
  81. package/dist/orpc/index.d.ts +28 -8
  82. package/dist/orpc/index.js +16 -3
  83. package/dist/otel/index.d.ts +21 -2
  84. package/dist/otel/index.js +50 -9
  85. package/dist/permdock-sql-C2Inc6Xc.d.ts +29 -0
  86. package/dist/permdock-sql-DgOfeixi.js +51 -0
  87. package/dist/plugin-DwARMuQp.js +59 -0
  88. package/dist/{plugin-bNhvJwRh.d.ts → plugin-o144f322.d.ts} +17 -5
  89. package/dist/plugins/actor/index.d.ts +5 -2
  90. package/dist/plugins/actor/index.js +22 -8
  91. package/dist/plugins/rules/index.d.ts +2 -2
  92. package/dist/plugins/rules/index.js +15 -10
  93. package/dist/plugins/soft-delete/index.d.ts +3 -3
  94. package/dist/plugins/soft-delete/index.js +14 -5
  95. package/dist/plugins/tenant/index.d.ts +2 -2
  96. package/dist/plugins/tenant/index.js +38 -20
  97. package/dist/plugins/timestamps/index.d.ts +1 -1
  98. package/dist/plugins/timestamps/index.js +4 -3
  99. package/dist/plugins/validation/index.d.ts +2 -2
  100. package/dist/plugins/validation/index.js +26 -6
  101. package/dist/{pool-DFwEQwmN.d.ts → pool-C9voM4Kw.d.ts} +17 -6
  102. package/dist/postgres/index.d.ts +5 -5
  103. package/dist/postgres/index.js +20 -11
  104. package/dist/{postgrest-Bc-0Xw62.d.ts → postgrest-CruYKAvV.d.ts} +1 -1
  105. package/dist/{problem-BihjPR0t.js → problem-BW1KhzSG.js} +2 -1
  106. package/dist/{problem-U8UEKccv.d.ts → problem-Blxe8S31.d.ts} +1 -1
  107. package/dist/query/index.d.ts +2 -2
  108. package/dist/query/index.js +3 -3
  109. package/dist/{query-BMMSWbI7.js → query-CCbo44lG.js} +2 -2
  110. package/dist/queue-BYUCjr59.d.ts +252 -0
  111. package/dist/react/index.d.ts +8 -7
  112. package/dist/react/index.js +4 -3
  113. package/dist/react/server.d.ts +14 -3
  114. package/dist/react/server.js +10 -2
  115. package/dist/react/session.d.ts +7 -1
  116. package/dist/react/session.js +9 -1
  117. package/dist/{react-CQHMaESR.js → react-C_s7kiNz.js} +103 -11
  118. package/dist/{read-set-FWK8qQ58.js → read-set-DQFt1N_Y.js} +22 -1
  119. package/dist/realtime/index.d.ts +3 -3
  120. package/dist/realtime/index.js +5 -4
  121. package/dist/{refresh-BwYkyNOQ.d.ts → refresh-BTrQ_ZTp.d.ts} +1 -1
  122. package/dist/{resolve-BAqQcwMW.d.ts → resolve-C15TJq77.d.ts} +11 -5
  123. package/dist/{resource-My_y-Syh.js → resource-CRxxwkQq.js} +22 -7
  124. package/dist/{resource-BJcaIfxi.d.ts → resource-D8iqWMr-.d.ts} +5 -5
  125. package/dist/respond-D2OQl62-.d.ts +371 -0
  126. package/dist/{result-Bj6yt33D.js → result-BKiliPY7.js} +1 -1
  127. package/dist/server/index.d.ts +14 -12
  128. package/dist/server/index.js +11 -17
  129. package/dist/{server-BA75B0mT.js → server-Csx2sRjg.js} +251 -34
  130. package/dist/{shared-DnoCdMDr.js → shared-D1dRUrAg.js} +16 -2
  131. package/dist/signers-Cc6r98SW.d.ts +162 -0
  132. package/dist/{simplify-Cqvfr9dj.js → simplify-_0oUKqCd.js} +4 -115
  133. package/dist/sql/index.d.ts +247 -10
  134. package/dist/sql/index.js +8590 -779
  135. package/dist/{sql-B34HU2DI.js → sql-Coh6n4cC.js} +9 -2
  136. package/dist/ssr/index.d.ts +4 -4
  137. package/dist/ssr/index.js +1 -2
  138. package/dist/{standard-BRyBGTtp.js → standard-D7r6dMUu.js} +6 -3
  139. package/dist/{standard-BsaCYQJc.d.ts → standard-J4YgMOLm.d.ts} +1 -1
  140. package/dist/{stats-C_YxA2r1.js → stats-Bqob3WqT.js} +4 -4
  141. package/dist/storage/index.d.ts +4 -4
  142. package/dist/storage/index.js +155 -26
  143. package/dist/support-DT-OhSxD.d.ts +88 -0
  144. package/dist/support-Dk6vdmEw.js +291 -0
  145. package/dist/support-view-Da5peKFg.d.ts +17 -0
  146. package/dist/support-view-g4YLBeqX.js +18 -0
  147. package/dist/{permdock-sql-C4KFzLc9.js → template-TxrGI5jR.js} +2 -31
  148. package/dist/{temporal-BwshQk0W.js → temporal-CVlIV2DZ.js} +17 -4
  149. package/dist/{temporal-required-CBNHT6ni.js → temporal-required-CAt4Dc9Z.js} +2 -2
  150. package/dist/testing/index.d.ts +100 -10
  151. package/dist/testing/index.js +336 -8
  152. package/dist/{types-DONv9SHN.d.ts → types-Dnf_wRDz.d.ts} +26 -3
  153. package/dist/user-change-CHFEUro1.js +49 -0
  154. package/dist/{webhooks-Bh_Jf_-l.js → verify-Ce49ETPz.js} +5 -5
  155. package/dist/{version-Bmf7_FzM.js → version-DM_Roffb.js} +1 -1
  156. package/dist/{view-B64o81wp.d.ts → view-BEf0diC5.d.ts} +8 -3
  157. package/dist/{mfa-byfjruR9.js → view-Bq64ki8-.js} +95 -38
  158. package/dist/webhooks/index.d.ts +135 -4
  159. package/dist/webhooks/index.js +588 -2
  160. package/dist/wire-D2dT86vi.js +35 -0
  161. package/package.json +16 -8
  162. package/schemas/config-v1.json +131 -1
  163. package/schemas/doctor-report-v1.json +10 -0
  164. package/skills/better-supabase/SKILL.md +9 -6
  165. package/skills/better-supabase/references/plugins.md +6 -3
  166. package/skills/better-supabase/references/troubleshooting.md +1 -0
  167. package/skills/better-supabase-api/SKILL.md +9 -2
  168. package/skills/better-supabase-api/references/adapters.md +11 -8
  169. package/skills/better-supabase-auth/SKILL.md +3 -0
  170. package/skills/better-supabase-auth/references/permdock.md +56 -11
  171. package/dist/cli/gen-D5cLCULx.js +0 -2
  172. package/dist/cli/sql-D4VbqmXi.js +0 -199
  173. package/dist/events-B21UOhvP.d.ts +0 -84
  174. package/dist/executor-B5IoUxLE.d.ts +0 -195
  175. package/dist/invalidate-CgxmRamI.js +0 -24
  176. package/dist/permdock-sql-DImJULY-.d.ts +0 -17
  177. package/dist/plugin-BqR6wKMB.js +0 -23
  178. package/dist/respond-DgIbdrt8.d.ts +0 -194
  179. package/dist/view-BrJI2LKp.js +0 -45
@@ -1,7 +1,7 @@
1
- import { n as dbError } 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 } 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",
@@ -56,7 +56,7 @@ function createEdge(betterSupabase, options = {}) {
56
56
  const cors = options.cors === true ? {} : options.cors === false ? void 0 : options.cors;
57
57
  const corsHeaders = cors ? corsFor(cors) : void 0;
58
58
  const serve = (run, handlerOptions, early) => {
59
- return async (request) => {
59
+ return async (request, _env, executionContext) => {
60
60
  const extra = corsHeaders?.(request);
61
61
  if (cors && request.method === "OPTIONS") return new Response(null, {
62
62
  status: 204,
@@ -79,7 +79,10 @@ function createEdge(betterSupabase, options = {}) {
79
79
  expose
80
80
  });
81
81
  }
82
- 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());
83
86
  return extra ? withHeaders(response, extra) : response;
84
87
  };
85
88
  };
@@ -107,7 +110,7 @@ function createEdge(betterSupabase, options = {}) {
107
110
  try {
108
111
  key = id === void 0 || id === "" ? void 0 : decodeURIComponent(id);
109
112
  } catch {
110
- return problemResponse(dbError("invalid_request", `Malformed id in ${pathname}`), { instance: pathname });
113
+ return problemResponse(dbError("invalid_input", `Malformed id in ${pathname}`), { instance: pathname });
111
114
  }
112
115
  routes.set(request, {
113
116
  handler,
@@ -1,4 +1,4 @@
1
- import { t as AuthSession } from "./view-B64o81wp.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
@@ -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,
@@ -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-D5IfUIDh.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,16 +41,18 @@ 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
57
  function forwardMutations(betterSupabase, sink, options) {
48
58
  return betterSupabase.events.on("mutation", (notice) => {
@@ -58,7 +68,50 @@ function forwardMutations(betterSupabase, sink, options) {
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 };
@@ -0,0 +1,230 @@
1
+ /// <reference lib="esnext.temporal" />
2
+ import { U as Operation, _ as DbError } from "./executor-BunPOO-k.js";
3
+ import { g as RequestContext, l as MutationIntent, u as MutationKind } from "./plugin-o144f322.js";
4
+ //#region src/core/logger.d.ts
5
+ type LogFields = Readonly<Record<string, unknown>>;
6
+ /**
7
+ * Where better-supabase reports problems it swallows on purpose: event
8
+ * handlers, `afterMutation` hooks, sinks and cache adapters that throw.
9
+ * Structured loggers (pino, consola, OpenTelemetry logs) fit directly.
10
+ */
11
+ interface Logger {
12
+ debug(message: string, fields?: LogFields): void;
13
+ info(message: string, fields?: LogFields): void;
14
+ warn(message: string, fields?: LogFields): void;
15
+ error(message: string, fields?: LogFields): void;
16
+ }
17
+ /** The default: `console`, with a `better-supabase:` prefix. */
18
+ declare const consoleLogger: Logger;
19
+ declare const silentLogger: Logger;
20
+ //#endregion
21
+ //#region src/core/kit-events.d.ts
22
+ /** `support.*`: support sessions, where a platform admin views the app as a user. */
23
+ interface SupportEventData {
24
+ /** Absent on `support.denied`. */
25
+ readonly sessionId?: string;
26
+ readonly adminId: string;
27
+ readonly targetUserId: string;
28
+ readonly reason?: string;
29
+ readonly readOnly?: boolean;
30
+ readonly expiresAt?: Temporal.Instant;
31
+ /** `support.denied`: which check refused it. */
32
+ readonly denial?: "authorize" | "permission" | "policy" | "store";
33
+ /** `support.ended`: who or what ended it. */
34
+ readonly endedBy?: "admin" | "expired" | "revoked";
35
+ }
36
+ /** `org.*`: organizations and their members. */
37
+ interface OrgEventData {
38
+ readonly organizationId: string;
39
+ /** The member the event is about. */
40
+ readonly userId?: string;
41
+ readonly role?: string;
42
+ readonly previousRole?: string;
43
+ }
44
+ /** `invitation.*`. The token is never part of the event. */
45
+ interface InvitationEventData {
46
+ readonly invitationId: string;
47
+ /** Absent for a platform-scope invitation. */
48
+ readonly organizationId?: string;
49
+ readonly email?: string;
50
+ readonly role?: string;
51
+ }
52
+ /** `notification.*`. */
53
+ interface NotificationEventData {
54
+ readonly notificationId: string;
55
+ readonly type: string;
56
+ readonly recipientIds?: readonly string[];
57
+ readonly channel?: string;
58
+ readonly error?: string;
59
+ }
60
+ /** `webhook.*`: outgoing webhooks. */
61
+ interface WebhookEventData {
62
+ readonly endpointId: string;
63
+ readonly deliveryId?: string;
64
+ readonly eventType?: string;
65
+ /** The HTTP status of the attempt, when there was a response. */
66
+ readonly status?: number;
67
+ readonly attempt?: number;
68
+ readonly error?: string;
69
+ }
70
+ /** Every kit event type and its data. */
71
+ interface KitEventMap {
72
+ "support.started": SupportEventData;
73
+ "support.ended": SupportEventData;
74
+ "support.denied": SupportEventData;
75
+ "org.created": OrgEventData;
76
+ "org.updated": OrgEventData;
77
+ "org.deleted": OrgEventData;
78
+ "org.member_added": OrgEventData;
79
+ "org.member_removed": OrgEventData;
80
+ "org.member_left": OrgEventData;
81
+ "org.role_changed": OrgEventData;
82
+ "org.ownership_transferred": OrgEventData;
83
+ "org.switched": OrgEventData;
84
+ "invitation.created": InvitationEventData;
85
+ "invitation.resent": InvitationEventData;
86
+ "invitation.accepted": InvitationEventData;
87
+ "invitation.declined": InvitationEventData;
88
+ "invitation.revoked": InvitationEventData;
89
+ "notification.created": NotificationEventData;
90
+ "notification.delivered": NotificationEventData;
91
+ "notification.failed": NotificationEventData;
92
+ "webhook.delivered": WebhookEventData;
93
+ "webhook.failed": WebhookEventData;
94
+ "webhook.disabled": WebhookEventData;
95
+ }
96
+ type KitEventType = keyof KitEventMap;
97
+ /** Where an event came from, beyond its data. */
98
+ interface KitEventMeta {
99
+ /** e.g. `organizations/<id>`; becomes the CloudEvents `subject`. */
100
+ readonly subject?: string;
101
+ readonly tenant?: string;
102
+ /** The user who caused it. */
103
+ readonly actorId?: string;
104
+ readonly context?: RequestContext;
105
+ }
106
+ /** A kit event as `betterSupabase.on('kit', handler)` receives it. */
107
+ type KitEvent<K extends KitEventType = KitEventType> = { readonly [T in K]: KitEventMeta & {
108
+ readonly type: T;
109
+ /** A copy: changing it never changes what the kit does (invariant 5). */
110
+ readonly data: KitEventMap[T];
111
+ readonly time: Temporal.Instant;
112
+ }; }[K];
113
+ /** A type, or a `prefix.*` pattern such as `support.*`. */
114
+ type KitEventPattern = KitEventType | `${KitEventType extends `${infer P}.${string}` ? P : never}.*`;
115
+ /** The event types a pattern matches. */
116
+ type KitEventsMatching<P extends KitEventPattern> = P extends `${infer Prefix}.*` ? Extract<KitEventType, `${Prefix}.${string}`> : Extract<P, KitEventType>;
117
+ /**
118
+ * Fixed OpenTelemetry attribute names for kit work, so dashboards and
119
+ * queries can rely on them.
120
+ */
121
+ declare const KIT_ATTRIBUTES: {
122
+ readonly event: "better_supabase.kit.event";
123
+ readonly tenant: "better_supabase.tenant";
124
+ readonly actor: "better_supabase.actor.id";
125
+ readonly supportSessionId: "better_supabase.support.session_id";
126
+ readonly orgId: "better_supabase.org.id";
127
+ readonly invitationId: "better_supabase.invitation.id";
128
+ readonly notificationType: "better_supabase.notification.type";
129
+ readonly webhookEndpointId: "better_supabase.webhook.endpoint_id";
130
+ };
131
+ /** The `KIT_ATTRIBUTES` an event carries. */
132
+ declare function kitEventAttributes(event: KitEvent): Record<string, string>;
133
+ /**
134
+ * Listens to the kit events that match `pattern` (`'support.started'` or
135
+ * `'support.*'`). Returns a function that stops listening.
136
+ */
137
+ declare function onKitEvent<P extends KitEventPattern>(betterSupabase: {
138
+ readonly events: EventHub;
139
+ }, pattern: P, handler: (event: KitEvent<KitEventsMatching<P>>) => void): () => void;
140
+ //#endregion
141
+ //#region src/core/events.d.ts
142
+ interface QueryEvent {
143
+ readonly table: string;
144
+ readonly operation: Operation["kind"];
145
+ readonly ok: boolean;
146
+ readonly durationMs: number;
147
+ readonly rows: number;
148
+ /**
149
+ * An unbounded read returned `maxRows` rows: PostgREST's `db-max-rows`
150
+ * probably cut it short. Add `limit` or use `paginate`.
151
+ */
152
+ readonly truncated: boolean;
153
+ }
154
+ interface MutationNotice {
155
+ readonly table: string;
156
+ readonly kind: MutationKind;
157
+ /** See `MutationEvent.intent`. */
158
+ readonly intent?: MutationIntent;
159
+ /** A copy of the returned rows: changing it never changes the result. */
160
+ readonly rows: readonly Readonly<Record<string, unknown>>[];
161
+ /** See `MutationEvent.keys`. */
162
+ readonly keys?: readonly Readonly<Record<string, unknown>>[];
163
+ /** See `MutationEvent.tenant`. */
164
+ readonly tenant?: string;
165
+ readonly context: RequestContext;
166
+ }
167
+ /** A successful RPC registered with `betterSupabase.defineRpc(name, { invalidates })`. */
168
+ interface RpcNotice {
169
+ readonly name: string;
170
+ /** App keys of the tables the function changes. */
171
+ readonly invalidates: readonly string[];
172
+ readonly context: RequestContext;
173
+ }
174
+ interface ErrorEvent {
175
+ readonly table?: string;
176
+ readonly error: DbError;
177
+ }
178
+ interface AuthEvent {
179
+ readonly source: "bearer" | "cookie" | "none";
180
+ readonly ok: boolean;
181
+ readonly userId?: string;
182
+ /**
183
+ * Why there is no user: the anon reason (`expired`, `signed_out`, ...) or
184
+ * the invalid reason (`token`, `claims`, `actor`).
185
+ */
186
+ readonly reason?: "none" | "expired" | "signed_out" | "refresh_failed" | "token" | "claims" | "actor";
187
+ /** The user's `source` as the resolver set it, e.g. a custom resolver's name. */
188
+ readonly rawSource?: string;
189
+ }
190
+ interface RefreshEvent {
191
+ readonly ok: boolean;
192
+ readonly shared: boolean;
193
+ readonly durationMs: number;
194
+ }
195
+ interface BetterSupabaseEvents {
196
+ query: QueryEvent;
197
+ mutation: MutationNotice;
198
+ rpc: RpcNotice;
199
+ error: ErrorEvent;
200
+ auth: AuthEvent;
201
+ refresh: RefreshEvent;
202
+ /** Support sessions, organizations, invitations, notifications and webhooks. */
203
+ kit: KitEvent;
204
+ }
205
+ type EventName = keyof BetterSupabaseEvents;
206
+ type EventHandler<K extends EventName> = (event: BetterSupabaseEvents[K]) => void;
207
+ /**
208
+ * Observers only: a handler that throws is reported to the logger and never
209
+ * changes a result.
210
+ */
211
+ declare class EventHub {
212
+ #private;
213
+ readonly logger: Logger;
214
+ constructor(logger?: Logger);
215
+ on<K extends EventName>(name: K, handler: EventHandler<K>): () => void;
216
+ has(name: EventName): boolean;
217
+ /**
218
+ * Keeps async work a handler started (a sink send) until it settles, so
219
+ * adapters can hand it to `after()` or `waitUntil`. Its outcome is ignored:
220
+ * handlers report their own failures.
221
+ */
222
+ track(work: PromiseLike<unknown>): void;
223
+ /** Whether tracked work is still running. */
224
+ get pending(): boolean;
225
+ /** Resolves once the work tracked so far has settled. Never rejects. */
226
+ settled(): Promise<void>;
227
+ emit<K extends EventName>(name: K, event: BetterSupabaseEvents[K]): void;
228
+ }
229
+ //#endregion
230
+ export { kitEventAttributes as C, consoleLogger as D, Logger as E, silentLogger as O, WebhookEventData as S, LogFields as T, KitEventType as _, EventHub as a, OrgEventData as b, QueryEvent as c, InvitationEventData as d, KIT_ATTRIBUTES as f, KitEventPattern as g, KitEventMeta as h, EventHandler as i, RefreshEvent as l, KitEventMap as m, BetterSupabaseEvents as n, EventName as o, KitEvent as p, ErrorEvent as r, MutationNotice as s, AuthEvent as t, RpcNotice as u, KitEventsMatching as v, onKitEvent as w, SupportEventData as x, NotificationEventData as y };