better-supabase 0.2.0 → 0.4.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 (190) hide show
  1. package/README.md +37 -33
  2. package/dist/base64-D2gsioCY.js +42 -0
  3. package/dist/claims-BAf6c7is.js +48 -0
  4. package/dist/cli/_format-Cax5EsM9.js +101 -0
  5. package/dist/cli/bin.js +39 -6
  6. package/dist/cli/command-CK14fP91.js +502 -0
  7. package/dist/cli/compare-BmIWVEui.js +9 -0
  8. package/dist/cli/config-D9R0o1LH.js +1895 -0
  9. package/dist/cli/config-SSKSTUl2.js +2 -0
  10. package/dist/cli/db-DOBPt660.js +52 -0
  11. package/dist/cli/dist-B1MvLv-M.js +129 -0
  12. package/dist/cli/dist-CFgGknmZ.js +1112 -0
  13. package/dist/cli/dist-Du7VnEUG.js +621 -0
  14. package/dist/cli/doctor-BOym3mbL.js +2382 -0
  15. package/dist/cli/env-BZ0uy8XK.js +108 -0
  16. package/dist/cli/env-jIFUADLY.js +511 -0
  17. package/dist/cli/errors-4v4DTtda.js +56 -0
  18. package/dist/cli/fastest-levenshtein-CFN-lNDv.js +120 -0
  19. package/dist/cli/gen-Ccn_p90L.js +2008 -0
  20. package/dist/cli/gen-D5cLCULx.js +2 -0
  21. package/dist/cli/index.d.ts +295 -28
  22. package/dist/cli/index.js +184 -3
  23. package/dist/cli/init-ClnxRYBF.js +550 -0
  24. package/dist/cli/introspect-DxqfkVIv.js +81 -0
  25. package/dist/cli/io-k41_z-jT.js +24 -0
  26. package/dist/cli/json5-ChRycquj.js +787 -0
  27. package/dist/cli/jsonc-BUniUpOk.js +2 -0
  28. package/dist/cli/jsonc-D5Fu67jw.js +45 -0
  29. package/dist/cli/keys-ByKHnvP9.js +83 -0
  30. package/dist/cli/ohash-D7bG_EOb.js +277 -0
  31. package/dist/cli/openapi-8WHjxiTJ.js +66 -0
  32. package/dist/cli/project-B_GeXyHh.js +70 -0
  33. package/dist/cli/prompts-BNcNfAve.js +1142 -0
  34. package/dist/cli/prompts-BTYQGunc.js +2 -0
  35. package/dist/cli/read-sets-CMa29t9a.js +971 -0
  36. package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
  37. package/dist/cli/run-CP20LKk_.js +347 -0
  38. package/dist/cli/seed-5J6eu_Xg.js +98 -0
  39. package/dist/cli/skills-LJJIhLFR.js +137 -0
  40. package/dist/cli/sql-D4VbqmXi.js +199 -0
  41. package/dist/cli/style-C0NFdJRL.js +29 -0
  42. package/dist/cli/toml-DB-MNnFs.js +424 -0
  43. package/dist/{version-Cqq1m3UY.js → cli/version-5mW_8sY1.js} +1 -1
  44. package/dist/cli/yaml-CYCbJ6et.js +2252 -0
  45. package/dist/client/index.d.ts +2 -2
  46. package/dist/client/index.js +15 -25
  47. package/dist/{compiler-CZ9nIuqy.d.ts → compiler-DB3aSFOA.d.ts} +2 -2
  48. package/dist/config/index.d.ts +4 -3
  49. package/dist/config/index.js +5 -3
  50. package/dist/config-BpxDfnbg.js +129 -0
  51. package/dist/{index-DOsjFvMf.d.ts → config-C1CYcm6o.d.ts} +49 -49
  52. package/dist/{config-ClDXmVtY.js → config-CbvFmGD8.js} +14 -137
  53. package/dist/{define-BXMYD9AY.js → define-Bh0AqTik.js} +221 -120
  54. package/dist/{define-e3zI4_4g.d.ts → define-CRS2MRV3.d.ts} +36 -31
  55. package/dist/edge/index.d.ts +9 -13
  56. package/dist/edge/index.js +51 -25
  57. package/dist/{entitlements-Dng-ctuT.d.ts → entitlements-Dm-FHpNH.d.ts} +2 -2
  58. package/dist/env/index.js +203 -1
  59. package/dist/{errors-Bl3rkOzo.js → errors-L0xK41y_.js} +1 -1
  60. package/dist/events/index.d.ts +1 -1
  61. package/dist/events/index.js +139 -1
  62. package/dist/{events-DOt3nSO-.d.ts → events-B21UOhvP.d.ts} +4 -4
  63. package/dist/{executor-CGdNQ27g.d.ts → executor-B5IoUxLE.d.ts} +2 -2
  64. package/dist/{executor-DeppvirK.js → executor-CVt6dD0B.js} +9 -4
  65. package/dist/{executor-BYXQ9AGn.d.ts → executor-CZ7ImRiD.d.ts} +2 -2
  66. package/dist/hono/index.d.ts +17 -24
  67. package/dist/hono/index.js +11 -11
  68. package/dist/{index-DuP14VHo.d.ts → index-528Ugmyp.d.ts} +30 -10
  69. package/dist/{index-Bw1bwtC0.d.ts → index-BAy4tsAP.d.ts} +28 -15
  70. package/dist/{index-CBDufH1M.d.ts → index-BBdvo-5d.d.ts} +24 -26
  71. package/dist/{index-DbxFr7XG.d.ts → index-BhHEC04r.d.ts} +9 -4
  72. package/dist/index-Cf-D2jk1.d.ts +50 -0
  73. package/dist/{index-Ciu5Xlml.d.ts → index-D5IfUIDh.d.ts} +6 -5
  74. package/dist/{index-K-3WM2Hp.d.ts → index-DFmOpBGC.d.ts} +13 -13
  75. package/dist/{index-D4v7sncu.d.ts → index-RlLXd8dL.d.ts} +13 -13
  76. package/dist/index.d.ts +17 -17
  77. package/dist/index.js +23 -14
  78. package/dist/{invalidate-DbxuL2jL.js → invalidate-CgxmRamI.js} +7 -1
  79. package/dist/jobs/index.d.ts +33 -26
  80. package/dist/jobs/index.js +44 -22
  81. package/dist/{json-schema-BpYqkCKf.js → json-schema-DP6V7cbr.js} +8 -3
  82. package/dist/lint/index.js +1 -1
  83. package/dist/list/index.d.ts +2 -2
  84. package/dist/list/index.js +131 -96
  85. package/dist/{live-DJyZMD6w.d.ts → live-BHakSWWo.d.ts} +26 -16
  86. package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
  87. package/dist/lookup-BaP5bI27.js +18 -0
  88. package/dist/mcp/index.d.ts +34 -27
  89. package/dist/mcp/index.js +59 -25
  90. package/dist/{mfa-TVia554c.d.ts → mfa-C7MNQ1Ob.d.ts} +1 -1
  91. package/dist/{mfa-CpLfJSde.js → mfa-byfjruR9.js} +190 -46
  92. package/dist/next/image/index.js +6 -3
  93. package/dist/next/index.d.ts +64 -48
  94. package/dist/next/index.js +63 -50
  95. package/dist/openapi/index.d.ts +1 -1
  96. package/dist/openapi/index.js +61 -38
  97. package/dist/orpc/index.d.ts +18 -21
  98. package/dist/orpc/index.js +12 -12
  99. package/dist/otel/index.d.ts +5 -5
  100. package/dist/otel/index.js +84 -63
  101. package/dist/{permdock-sql-CghlHPuH.js → permdock-sql-C4KFzLc9.js} +12 -7
  102. package/dist/permdock-sql-DImJULY-.d.ts +17 -0
  103. package/dist/{plugin-C4TR9J0Z.d.ts → plugin-bNhvJwRh.d.ts} +5 -4
  104. package/dist/plugins/actor/index.d.ts +1 -1
  105. package/dist/plugins/actor/index.js +1 -1
  106. package/dist/plugins/rules/index.d.ts +2 -2
  107. package/dist/plugins/rules/index.js +46 -16
  108. package/dist/plugins/soft-delete/index.d.ts +3 -3
  109. package/dist/plugins/soft-delete/index.js +4 -4
  110. package/dist/plugins/tenant/index.d.ts +3 -3
  111. package/dist/plugins/tenant/index.js +10 -4
  112. package/dist/plugins/timestamps/index.d.ts +1 -1
  113. package/dist/plugins/timestamps/index.js +2 -2
  114. package/dist/plugins/validation/index.d.ts +2 -2
  115. package/dist/plugins/validation/index.js +3 -3
  116. package/dist/pool-DFwEQwmN.d.ts +78 -0
  117. package/dist/postgres/index.d.ts +10 -5
  118. package/dist/postgres/index.js +37 -16
  119. package/dist/{postgrest-cAEQ_IQN.d.ts → postgrest-Bc-0Xw62.d.ts} +1 -1
  120. package/dist/{problem-BTkTtRV9.js → problem-BihjPR0t.js} +11 -5
  121. package/dist/{problem-DlgB0lYl.d.ts → problem-U8UEKccv.d.ts} +6 -4
  122. package/dist/query/index.d.ts +2 -2
  123. package/dist/query/index.js +2 -2
  124. package/dist/{query-ChvDbsDE.js → query-BMMSWbI7.js} +19 -19
  125. package/dist/react/index.d.ts +7 -7
  126. package/dist/react/index.js +2 -2
  127. package/dist/react/server.d.ts +6 -6
  128. package/dist/react/server.js +3 -3
  129. package/dist/react/session.d.ts +21 -2
  130. package/dist/react/session.js +19 -1
  131. package/dist/{react-C83BdBGt.js → react-CQHMaESR.js} +59 -55
  132. package/dist/{read-set-4lI3W_gZ.js → read-set-FWK8qQ58.js} +51 -16
  133. package/dist/realtime/index.d.ts +4 -3
  134. package/dist/realtime/index.js +19 -17
  135. package/dist/{index-CG69s15v.d.ts → refresh-BwYkyNOQ.d.ts} +7 -3
  136. package/dist/{resolve-CjHILk2w.d.ts → resolve-BAqQcwMW.d.ts} +17 -11
  137. package/dist/{resource-CgZa3YG_.d.ts → resource-BJcaIfxi.d.ts} +17 -8
  138. package/dist/{resource-BHEWmQJK.js → resource-My_y-Syh.js} +43 -21
  139. package/dist/{respond-Dne1ARSa.d.ts → respond-DgIbdrt8.d.ts} +39 -14
  140. package/dist/{result-DWXatkd6.js → result-Bj6yt33D.js} +2 -2
  141. package/dist/{result-CTkCZ6JA.d.ts → result-CqEsbgYs.d.ts} +16 -11
  142. package/dist/server/index.d.ts +38 -13
  143. package/dist/server/index.js +43 -14
  144. package/dist/{respond-DMcbQwfN.js → server-BA75B0mT.js} +151 -96
  145. package/dist/{shared-_6-uPL7E.js → shared-DnoCdMDr.js} +4 -3
  146. package/dist/{simplify-bwJpLnaS.js → simplify-Cqvfr9dj.js} +76 -39
  147. package/dist/sql/index.d.ts +139 -0
  148. package/dist/sql/index.js +1983 -0
  149. package/dist/{sql-DTjA1LPj.js → sql-B34HU2DI.js} +74 -17
  150. package/dist/ssr/index.d.ts +4 -4
  151. package/dist/ssr/index.js +2 -2
  152. package/dist/{standard-FUi3Z3-7.js → standard-BRyBGTtp.js} +2 -2
  153. package/dist/{standard-CyhRzctb.d.ts → standard-BsaCYQJc.d.ts} +1 -1
  154. package/dist/{stats-C5W-rBfR.js → stats-C_YxA2r1.js} +40 -14
  155. package/dist/storage/index.d.ts +4 -3
  156. package/dist/storage/index.js +548 -1
  157. package/dist/{tables-rZxRxNPW.js → tables-Cb-3_VWc.js} +19 -5
  158. package/dist/temporal-BwshQk0W.js +27 -0
  159. package/dist/temporal-required-CBNHT6ni.js +19 -0
  160. package/dist/testing/index.d.ts +25 -24
  161. package/dist/testing/index.js +165 -66
  162. package/dist/{types-C83v5SQz.d.ts → types-DONv9SHN.d.ts} +14 -11
  163. package/dist/version-Bmf7_FzM.js +4 -0
  164. package/dist/{view-D1s0wa0T.d.ts → view-B64o81wp.d.ts} +36 -6
  165. package/dist/{view-aOYizTeE.js → view-BrJI2LKp.js} +11 -2
  166. package/dist/webhooks/index.d.ts +19 -17
  167. package/dist/webhooks/index.js +1 -1
  168. package/dist/{webhooks-DMipjhSP.js → webhooks-Bh_Jf_-l.js} +45 -24
  169. package/package.json +50 -22
  170. package/schemas/config-v1.json +31 -1
  171. package/schemas/doctor-report-v1.json +17 -1
  172. package/schemas/snapshot-v2.json +35 -0
  173. package/skills/better-supabase/SKILL.md +77 -18
  174. package/skills/better-supabase/references/plugins.md +21 -22
  175. package/skills/better-supabase/references/troubleshooting.md +38 -18
  176. package/skills/better-supabase-api/SKILL.md +66 -18
  177. package/skills/better-supabase-api/references/adapters.md +64 -41
  178. package/skills/better-supabase-auth/SKILL.md +146 -0
  179. package/skills/better-supabase-auth/references/permdock.md +55 -0
  180. package/skills/better-supabase-testing/SKILL.md +68 -11
  181. package/dist/casing-da0uRTqt.js +0 -14
  182. package/dist/claims-CoTobNC-.js +0 -25
  183. package/dist/cli-DrSgDOQC.js +0 -6646
  184. package/dist/env-BEToab0I.js +0 -204
  185. package/dist/events-BuzTgn2D.js +0 -135
  186. package/dist/pool-R2m_DkXi.d.ts +0 -37
  187. package/dist/seed-CzecODcJ.js +0 -101
  188. package/dist/session-C3LxnQ0e.d.ts +0 -22
  189. package/dist/session-CqEwzVup.js +0 -20
  190. package/dist/storage-DuGn38fr.js +0 -527
@@ -1,6 +1,6 @@
1
1
  import { n as definePlugin } from "../plugin-BqR6wKMB.js";
2
2
  import { t as SPEC_PINS } from "../spec-pins-C3oc-Tdp.js";
3
- import "../version-Cqq1m3UY.js";
3
+ import "../version-Bmf7_FzM.js";
4
4
  import { SpanKind, SpanStatusCode, context, metrics, propagation, trace } from "@opentelemetry/api";
5
5
  //#region src/otel/index.ts
6
6
  const INSTRUMENTATION_NAME = "better-supabase";
@@ -26,13 +26,13 @@ function systemOf(executor) {
26
26
  * never recorded; `db.query.summary` is `SELECT customers`.
27
27
  *
28
28
  * ```ts
29
- * const sb = defineSupabase(schema).use(otel());
29
+ * const betterSupabase = defineSupabase(schema).use(otel());
30
30
  * ```
31
31
  */
32
32
  function otel(options = {}) {
33
- const tracer = options.tracer ?? trace.getTracer("better-supabase", "0.0.0");
33
+ const tracer = options.tracer ?? trace.getTracer("better-supabase", "0.4.0");
34
34
  let histogram;
35
- if (options.metrics !== false) histogram = (options.meter ?? metrics.getMeter("better-supabase", "0.0.0")).createHistogram("db.client.operation.duration", {
35
+ if (options.metrics !== false) histogram = (options.meter ?? metrics.getMeter("better-supabase", "0.4.0")).createHistogram("db.client.operation.duration", {
36
36
  unit: "s",
37
37
  description: "Duration of database client operations.",
38
38
  advice: { explicitBucketBoundaries: [
@@ -50,76 +50,95 @@ function otel(options = {}) {
50
50
  return definePlugin({
51
51
  name: "otel",
52
52
  enforce: "post",
53
- wrapExecutor: (executor) => ({
54
- ...executor,
55
- name: executor.name,
56
- execute(op, executeContext) {
53
+ wrapExecutor: (executor) => {
54
+ const system = systemOf(executor);
55
+ /** Span and metric attributes per table and operation, built once. */
56
+ const described = /* @__PURE__ */ new Map();
57
+ const describe = (op) => {
57
58
  const operation = operationName(op);
58
- const summary = `${operation} ${op.table.name}`;
59
- const attributes = {
60
- ...options.attributes,
61
- "db.system.name": systemOf(executor),
62
- "db.namespace": op.table.schema,
63
- "db.collection.name": op.table.name,
64
- "db.operation.name": operation,
65
- "db.query.summary": summary,
66
- "better_supabase.executor": executor.name
67
- };
68
- const started = performance.now();
69
- return tracer.startActiveSpan(summary, {
70
- kind: SpanKind.CLIENT,
71
- attributes
72
- }, async (span) => {
73
- const finish = (errorType) => {
74
- const metricAttributes = {
75
- "db.system.name": attributes["db.system.name"],
59
+ const key = `${op.table.key}:${operation}`;
60
+ let entry = described.get(key);
61
+ if (!entry) {
62
+ const summary = `${operation} ${op.table.name}`;
63
+ entry = {
64
+ summary,
65
+ attributes: {
66
+ ...options.attributes,
67
+ "db.system.name": system,
68
+ "db.namespace": op.table.schema,
76
69
  "db.collection.name": op.table.name,
77
70
  "db.operation.name": operation,
78
- ...errorType ? { "error.type": errorType } : {}
79
- };
80
- histogram?.record((performance.now() - started) / 1e3, metricAttributes);
81
- span.end();
71
+ "db.query.summary": summary,
72
+ "better_supabase.executor": executor.name
73
+ },
74
+ metric: {
75
+ "db.system.name": system,
76
+ "db.collection.name": op.table.name,
77
+ "db.operation.name": operation
78
+ }
82
79
  };
83
- try {
84
- const result = await executor.execute(op, executeContext);
85
- if (result.ok) {
86
- span.setAttribute("db.response.returned_rows", result.data.rows.length);
87
- finish();
88
- } else {
89
- span.setAttributes({
90
- "error.type": result.error.kind,
91
- ...result.error.code ? { "db.response.status_code": result.error.code } : {}
92
- });
80
+ described.set(key, entry);
81
+ }
82
+ return entry;
83
+ };
84
+ return {
85
+ ...executor,
86
+ name: executor.name,
87
+ execute(op, executeContext) {
88
+ const { summary, attributes, metric } = describe(op);
89
+ const started = performance.now();
90
+ return tracer.startActiveSpan(summary, {
91
+ kind: SpanKind.CLIENT,
92
+ attributes
93
+ }, async (span) => {
94
+ const finish = (errorType) => {
95
+ histogram?.record((performance.now() - started) / 1e3, errorType ? {
96
+ ...metric,
97
+ "error.type": errorType
98
+ } : metric);
99
+ span.end();
100
+ };
101
+ try {
102
+ const result = await executor.execute(op, executeContext);
103
+ if (result.ok) {
104
+ if (span.isRecording()) span.setAttribute("db.response.returned_rows", result.data.rows.length);
105
+ finish();
106
+ } else {
107
+ span.setAttributes({
108
+ "error.type": result.error.kind,
109
+ ...result.error.code ? { "db.response.status_code": result.error.code } : {}
110
+ });
111
+ span.setStatus({
112
+ code: SpanStatusCode.ERROR,
113
+ message: result.error.message
114
+ });
115
+ finish(result.error.kind);
116
+ }
117
+ return result;
118
+ } catch (cause) {
119
+ const error = cause instanceof Error ? cause : new Error(String(cause));
120
+ span.recordException(error);
121
+ span.setAttribute("error.type", error.name);
93
122
  span.setStatus({
94
123
  code: SpanStatusCode.ERROR,
95
- message: result.error.message
124
+ message: error.message
96
125
  });
97
- finish(result.error.kind);
126
+ finish(error.name);
127
+ throw cause;
98
128
  }
99
- return result;
100
- } catch (cause) {
101
- const error = cause instanceof Error ? cause : new Error(String(cause));
102
- span.recordException(error);
103
- span.setAttribute("error.type", error.name);
104
- span.setStatus({
105
- code: SpanStatusCode.ERROR,
106
- message: error.message
107
- });
108
- finish(error.name);
109
- throw cause;
110
- }
111
- });
112
- }
113
- })
129
+ });
130
+ }
131
+ };
132
+ }
114
133
  });
115
134
  }
116
135
  /**
117
- * Spans for auth resolution and session refreshes, from `sb.events`.
136
+ * Spans for auth resolution and session refreshes, from `betterSupabase.events`.
118
137
  * Returns a function that stops listening.
119
138
  */
120
- function traceAuth(sb, options = {}) {
121
- const tracer = options.tracer ?? trace.getTracer("better-supabase", "0.0.0");
122
- const offAuth = sb.events.on("auth", (event) => {
139
+ function traceAuth(betterSupabase, options = {}) {
140
+ const tracer = options.tracer ?? trace.getTracer("better-supabase", "0.4.0");
141
+ const offAuth = betterSupabase.events.on("auth", (event) => {
123
142
  const span = tracer.startSpan("auth.resolve", {
124
143
  kind: SpanKind.INTERNAL,
125
144
  attributes: {
@@ -131,7 +150,7 @@ function traceAuth(sb, options = {}) {
131
150
  if (!event.ok) span.setStatus({ code: SpanStatusCode.ERROR });
132
151
  span.end();
133
152
  });
134
- const offRefresh = sb.events.on("refresh", (event) => {
153
+ const offRefresh = betterSupabase.events.on("refresh", (event) => {
135
154
  const end = Date.now();
136
155
  const span = tracer.startSpan("auth.refresh", {
137
156
  kind: SpanKind.CLIENT,
@@ -157,7 +176,9 @@ function traceAuth(sb, options = {}) {
157
176
  function tracedFetch(base = fetch) {
158
177
  return (input, init) => {
159
178
  const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
160
- propagation.inject(context.active(), headers, { set: (carrier, key, value) => carrier.set(key, value) });
179
+ propagation.inject(context.active(), headers, { set: (carrier, key, value) => {
180
+ carrier.set(key, value);
181
+ } });
161
182
  return base(input, {
162
183
  ...init,
163
184
  headers
@@ -1,4 +1,4 @@
1
- import { n as dbError, t as DbException } from "./errors-Bl3rkOzo.js";
1
+ import { n as dbError, t as DbException } from "./errors-L0xK41y_.js";
2
2
  //#region src/core/template.ts
3
3
  const PLACEHOLDER = /\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
4
4
  function parseSegment(segment) {
@@ -21,7 +21,7 @@ function parseSegment(segment) {
21
21
  });
22
22
  return parts;
23
23
  }
24
- const escapeRegex = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
24
+ const escapeRegex = (text) => text.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
25
25
  function parseTemplate(source, separator, validate) {
26
26
  const segments = source.split(separator).map(parseSegment);
27
27
  const params = [];
@@ -87,7 +87,7 @@ function sqlIdent(value) {
87
87
  }
88
88
  /** Postgres identifier-safe name part: `customer-logos` → `customer_logos`. */
89
89
  function slug(value) {
90
- return value.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_|_$/g, "").toLowerCase();
90
+ return value.replaceAll(/[^A-Za-z0-9]+/g, "_").replaceAll(/^_|_$/g, "").toLowerCase();
91
91
  }
92
92
  //#endregion
93
93
  //#region src/core/permdock-sql.ts
@@ -101,17 +101,22 @@ const SPLIT_KEY = /#\d+$/;
101
101
  *
102
102
  * The helpers check role and scope, not a permission's row conditions, so
103
103
  * the condition is only correct for permissions whose grants have none
104
- * beyond the scope. `#n` keys are refused; other row-conditioned keys can't
105
- * be detected here.
104
+ * beyond the scope. `#n` keys are refused, and so are keys the catalog marks
105
+ * with `rowConditions: true` when one is passed.
106
106
  */
107
- function permdockCheck(where, target, key, id) {
107
+ function permdockCheck(where, target, key, id, catalog) {
108
108
  if (key === "") throw new TypeError(`${where}: a PermDock permission key is empty`);
109
109
  if (SPLIT_KEY.test(key)) throw new TypeError(`${where}: "${key}" is one part of a permission PermDock splits by row condition. Use PermDock's generated policies for it.`);
110
+ if (catalog?.permissions.some((permission) => permission.key === key && permission.rowConditions === true)) throw new TypeError(`${where}: "${key}" has row conditions in PermDock's catalog (rowConditions: true), which the SQL helpers don't check. Use PermDock's generated policies for it.`);
110
111
  const schema = sqlIdent(target.schema ?? "public");
111
112
  if (target.scope === "global") return `(select ${schema}.permdock_has(${sqlString(key)}))`;
112
113
  if (!SCOPE.test(target.scope)) throw new TypeError(`${where}: invalid PermDock scope "${target.scope}"`);
113
114
  if (id === void 0) throw new TypeError(`${where}: scope "${target.scope}" needs a segment`);
114
115
  return `${id} in (select t.id::text from ${schema}.${sqlIdent(`permitted_${target.scope}_ids`)}(${sqlString(key)}) as t(id))`;
115
116
  }
117
+ /** The keys a bucket or topic PermDock policy names. */
118
+ function permdockKeys(policy) {
119
+ return Object.values(policy.permdock).filter((key) => typeof key === "string");
120
+ }
116
121
  //#endregion
117
- export { sqlString as a, sqlIdent as i, parseTemplate as n, slug as r, permdockCheck as t };
122
+ export { sqlIdent as a, slug as i, permdockKeys as n, sqlString as o, parseTemplate as r, permdockCheck as t };
@@ -0,0 +1,17 @@
1
+ //#region src/core/permdock-sql.d.ts
2
+ /**
3
+ * The part of PermDock's `permissions.catalog.json` the Storage and Realtime
4
+ * builders read: `import catalog from './permissions.catalog.json'`.
5
+ */
6
+ interface PermdockCatalog {
7
+ readonly permissions: readonly {
8
+ readonly key: string;
9
+ readonly rowConditions?: boolean;
10
+ }[];
11
+ }
12
+ /** The keys a bucket or topic PermDock policy names. */
13
+ declare function permdockKeys(policy: {
14
+ readonly permdock: object;
15
+ }): string[];
16
+ //#endregion
17
+ export { permdockKeys as n, PermdockCatalog as t };
@@ -1,6 +1,7 @@
1
- import { A as SchemaMeta, P as TableMeta, n as AnyModels } from "./types-C83v5SQz.js";
2
- import { g as Operation, h as MutationOp, r as Executor } from "./executor-CGdNQ27g.js";
3
- import { v as ErrorMapper } from "./result-CTkCZ6JA.js";
1
+ /// <reference lib="esnext.temporal" />
2
+ import { A as SchemaMeta, P as TableMeta, n as AnyModels } from "./types-DONv9SHN.js";
3
+ import { g as Operation, h as MutationOp, r as Executor } from "./executor-B5IoUxLE.js";
4
+ import { v as ErrorMapper } from "./result-CqEsbgYs.js";
4
5
  //#region src/core/plugin.d.ts
5
6
  /** Who is making the request. */
6
7
  interface Actor {
@@ -28,7 +29,7 @@ interface HookArgs {
28
29
  readonly schema: SchemaMeta;
29
30
  readonly context: RequestContext;
30
31
  readonly options: CallOptions;
31
- readonly now: () => Date;
32
+ readonly now: () => Temporal.Instant;
32
33
  }
33
34
  type MutationKind = "insert" | "upsert" | "update" | "delete";
34
35
  interface MutationEvent {
@@ -1,4 +1,4 @@
1
- import { f as Plugin, h as RequestContext } from "../../plugin-C4TR9J0Z.js";
1
+ import { f as Plugin, h as RequestContext } from "../../plugin-bNhvJwRh.js";
2
2
  //#region src/plugins/actor/index.d.ts
3
3
  export interface ActorOptions {
4
4
  /** Custom actor id resolution. Defaults to `context.actor.id` for users and services. */
@@ -1,5 +1,5 @@
1
1
  import { n as definePlugin } from "../../plugin-BqR6wKMB.js";
2
- import { i as insertsOnly, l as withDefault, t as dbName } from "../../shared-_6-uPL7E.js";
2
+ import { i as insertsOnly, l as withDefault, t as dbName } from "../../shared-DnoCdMDr.js";
3
3
  //#region src/plugins/actor/index.ts
4
4
  function defaultActor(context) {
5
5
  const actor = context.actor;
@@ -1,5 +1,5 @@
1
- import { g as Operation } from "../../executor-CGdNQ27g.js";
2
- import { f as Plugin, m as RepositoryExtension } from "../../plugin-C4TR9J0Z.js";
1
+ import { g as Operation } from "../../executor-B5IoUxLE.js";
2
+ import { f as Plugin, m as RepositoryExtension } from "../../plugin-bNhvJwRh.js";
3
3
  //#region src/plugins/rules/index.d.ts
4
4
  export type RuleLevel = "off" | "warn" | "error";
5
5
  /** A level, or a level with the rule's option: `['error', 500]`. */
@@ -1,6 +1,7 @@
1
- import { n as dbError, t as DbException } from "../../errors-Bl3rkOzo.js";
1
+ import { n as dbError, t as DbException } from "../../errors-L0xK41y_.js";
2
+ import { t as lookupOf } from "../../lookup-BaP5bI27.js";
2
3
  import { n as definePlugin } from "../../plugin-BqR6wKMB.js";
3
- import { n as claimAt, r as claimsOf } from "../../claims-CoTobNC-.js";
4
+ import { n as claimAt, r as claimsOf } from "../../claims-BAf6c7is.js";
4
5
  //#region src/plugins/rules/index.ts
5
6
  /** Catches data-exposure and correctness mistakes; everything else off. */
6
7
  function safe() {
@@ -40,22 +41,42 @@ function levelOf(setting) {
40
41
  function optionOf(setting, fallback) {
41
42
  return Array.isArray(setting) ? setting[1] : fallback;
42
43
  }
44
+ const depths = /* @__PURE__ */ new WeakMap();
43
45
  function includeDepth(selection) {
46
+ let depth = depths.get(selection);
47
+ if (depth === void 0) {
48
+ depth = computeIncludeDepth(selection);
49
+ depths.set(selection, depth);
50
+ }
51
+ return depth;
52
+ }
53
+ function computeIncludeDepth(selection) {
44
54
  let depth = 0;
45
55
  for (const include of selection.includes) if (include.count !== void 0 || include.aggregate !== void 0) depth = Math.max(depth, 1);
46
56
  else depth = Math.max(depth, 1 + includeDepth(include.selection));
47
57
  return depth;
48
58
  }
59
+ const sensitiveByTable = /* @__PURE__ */ new WeakMap();
60
+ function sensitiveOf(table) {
61
+ let sensitive = sensitiveByTable.get(table);
62
+ if (!sensitive) {
63
+ sensitive = new Set(lookupOf(table).entries.filter(([, column]) => column.sensitive).map(([, column]) => column.db));
64
+ sensitiveByTable.set(table, sensitive);
65
+ }
66
+ return sensitive;
67
+ }
49
68
  function sensitiveColumns(selection, table) {
50
69
  const found = [];
51
- const sensitive = new Set(Object.values(table.columns).filter((column) => column.sensitive).map((column) => column.db));
52
- const columns = [...selection.columns, ...selection.aggregate?.measures ?? []];
53
- for (const column of columns) if (sensitive.has(column.column)) found.push(`${table.key}.${column.column}`);
70
+ const sensitive = sensitiveOf(table);
71
+ if (sensitive.size > 0) {
72
+ for (const column of selection.columns) if (sensitive.has(column.column)) found.push(`${table.key}.${column.column}`);
73
+ for (const measure of selection.aggregate?.measures ?? []) if (sensitive.has(measure.column)) found.push(`${table.key}.${measure.column}`);
74
+ }
54
75
  for (const include of selection.includes) found.push(...sensitiveColumns(include.selection, include.target));
55
76
  return found;
56
77
  }
57
78
  function isBrowser() {
58
- return typeof globalThis.window !== "undefined" && typeof globalThis.document !== "undefined";
79
+ return globalThis.window !== void 0 && globalThis.document !== void 0;
59
80
  }
60
81
  const TEXT_TYPES = /* @__PURE__ */ new Set([
61
82
  "text",
@@ -68,16 +89,26 @@ const templatesBySchema = /* @__PURE__ */ new WeakMap();
68
89
  function bucketTemplates(schema) {
69
90
  let templates = templatesBySchema.get(schema);
70
91
  if (!templates) {
71
- templates = Object.values(schema.buckets ?? {}).filter((bucket) => bucket.path.replace(/\{[^}]*\}|\//g, "").length > 0).map((bucket) => new RegExp(`^${bucket.path.split(/\{[^}]*\}/).map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("[^/]+")}$`));
92
+ templates = Object.values(schema.buckets ?? {}).filter((bucket) => bucket.path.replaceAll(/\{[^}]*\}|\//g, "").length > 0).map((bucket) => new RegExp(`^${bucket.path.split(/\{[^}]*\}/).map((part) => part.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("[^/]+")}$`));
72
93
  templatesBySchema.set(schema, templates);
73
94
  }
74
95
  return templates;
75
96
  }
97
+ const urlColumnsByTable = /* @__PURE__ */ new WeakMap();
98
+ /** Scalar text columns named `*_url`, the only ones the rule inspects. */
99
+ function urlColumns(table) {
100
+ let columns = urlColumnsByTable.get(table);
101
+ if (!columns) {
102
+ columns = lookupOf(table).entries.map(([, column]) => column).filter((column) => column.db.endsWith("_url") && !column.array && TEXT_TYPES.has(column.type));
103
+ urlColumnsByTable.set(table, columns);
104
+ }
105
+ return columns;
106
+ }
76
107
  function storedObjectColumn(op, schema) {
77
108
  const rows = op.kind === "insert" ? op.rows : op.kind === "update" ? [op.set] : [];
78
109
  if (rows.length === 0) return void 0;
79
- for (const column of Object.values(op.table.columns)) {
80
- if (!rows.some((row) => column.db in row) || !column.db.endsWith("_url") || column.array || !TEXT_TYPES.has(column.type)) continue;
110
+ for (const column of urlColumns(op.table)) {
111
+ if (!rows.some((row) => column.db in row)) continue;
81
112
  const path = `${column.db.slice(0, -4)}_path`;
82
113
  if (column.storage !== void 0) return `"${column.db}" holds paths in bucket "${column.storage}"; name it "${path}"`;
83
114
  if (rows.some((row) => {
@@ -87,27 +118,26 @@ function storedObjectColumn(op, schema) {
87
118
  }
88
119
  }
89
120
  function checks(rules) {
121
+ const maxLimit = optionOf(rules.maxLimit, 1e3);
122
+ const maxDepth = optionOf(rules.maxIncludeDepth, 3);
90
123
  return {
91
124
  noUnboundedFindMany: (op) => op.kind === "select" && op.single === void 0 && !op.head && op.limit === void 0 ? "findMany without limit reads every visible row" : void 0,
92
- maxLimit: (op) => {
93
- const max = optionOf(rules.maxLimit, 1e3);
94
- return op.kind === "select" && op.limit !== void 0 && op.limit > max ? `limit ${op.limit} is above the maximum of ${max}` : void 0;
95
- },
125
+ maxLimit: (op) => op.kind === "select" && op.limit !== void 0 && op.limit > maxLimit ? `limit ${op.limit} is above the maximum of ${maxLimit}` : void 0,
96
126
  requireOrderByForCursor: (op) => op.kind === "select" && !op.head && op.orderBy.length === 0 && (op.offset !== void 0 || op.limit !== void 0 && op.limit > 1) ? "paging without orderBy returns rows in no stable order" : void 0,
97
127
  maxIncludeDepth: (op) => {
98
- const max = optionOf(rules.maxIncludeDepth, 3);
128
+ const max = maxDepth;
99
129
  const selection = op.kind === "select" ? op.selection : op.returning;
100
130
  const depth = selection ? includeDepth(selection) : 0;
101
131
  return depth > max ? `includes nest ${depth} levels deep (maximum ${max})` : void 0;
102
132
  },
103
133
  requireTenantContext: (op, { context, schema }) => {
104
- if (!op.table.flags.tenant || context.actor?.kind === "service") return void 0;
134
+ if (!op.table.flags.tenant || context.actor?.kind === "service") return;
105
135
  const claim = optionOf(rules.requireTenantContext, claimsOf(schema).tenant);
106
136
  return context.tenant === void 0 && claimAt(context.claims, claim) === void 0 ? `"${op.table.key}" is tenant-scoped but the request has no tenant (context.tenant or claim "${claim}")` : void 0;
107
137
  },
108
138
  noAdminInBrowser: (_op, { context }) => context.actor?.kind === "service" && isBrowser() ? "a service-role connection is running in a browser" : void 0,
109
139
  noSensitiveSelect: (op, { options }) => {
110
- if (options["sensitive"] === true) return void 0;
140
+ if (options["sensitive"] === true) return;
111
141
  const selection = op.kind === "select" ? op.selection : op.returning;
112
142
  const columns = selection ? sensitiveColumns(selection, op.table) : [];
113
143
  return columns.length > 0 ? `reads sensitive column(s) ${columns.join(", ")}; pass { sensitive: true } to allow` : void 0;
@@ -1,6 +1,6 @@
1
- import { C as PrimaryKeyValue } from "../../types-C83v5SQz.js";
2
- import { t as AsyncResult } from "../../result-CTkCZ6JA.js";
3
- import { f as Plugin, m as RepositoryExtension, o as HasFlag } from "../../plugin-C4TR9J0Z.js";
1
+ import { C as PrimaryKeyValue } from "../../types-DONv9SHN.js";
2
+ import { t as AsyncResult } from "../../result-CqEsbgYs.js";
3
+ import { f as Plugin, m as RepositoryExtension, o as HasFlag } from "../../plugin-bNhvJwRh.js";
4
4
  //#region src/plugins/soft-delete/index.d.ts
5
5
  export interface SoftDeleteFindArgs {
6
6
  /** Include soft-deleted rows of the queried table. */
@@ -1,8 +1,8 @@
1
1
  import { t as and } from "../../types-6cYK9pbJ.js";
2
- import { i as ok, t as AsyncResult } from "../../result-DWXatkd6.js";
2
+ import { i as ok, t as AsyncResult } from "../../result-Bj6yt33D.js";
3
3
  import { n as definePlugin } from "../../plugin-BqR6wKMB.js";
4
4
  import { n as scopeOperation } from "../../scope-CDHcS7dE.js";
5
- import { a as isNotNull, o as isNull, t as dbName } from "../../shared-_6-uPL7E.js";
5
+ import { a as isNotNull, o as isNull, t as dbName } from "../../shared-DnoCdMDr.js";
6
6
  //#region src/plugins/soft-delete/index.ts
7
7
  function deletedColumn(table) {
8
8
  return dbName(table, table.flags.softDelete);
@@ -45,14 +45,14 @@ function softDelete() {
45
45
  return {
46
46
  kind: "update",
47
47
  table,
48
- set: { [column]: now().toISOString() },
48
+ set: { [column]: now().toString() },
49
49
  where: op.where,
50
50
  returning: void 0
51
51
  };
52
52
  },
53
53
  repository({ table, base }) {
54
54
  const flag = table.flags.softDelete;
55
- if (!flag) return void 0;
55
+ if (!flag) return;
56
56
  const update = base["update"];
57
57
  return { restore: (key, args) => AsyncResult.from(async () => {
58
58
  const result = await update(key, { [flag]: null }, {
@@ -1,5 +1,5 @@
1
- import { A as SchemaMeta } from "../../types-C83v5SQz.js";
2
- import { f as Plugin, h as RequestContext, m as RepositoryExtension, o as HasFlag } from "../../plugin-C4TR9J0Z.js";
1
+ import { A as SchemaMeta } from "../../types-DONv9SHN.js";
2
+ import { f as Plugin, h as RequestContext, m as RepositoryExtension, o as HasFlag } from "../../plugin-bNhvJwRh.js";
3
3
  //#region src/plugins/tenant/index.d.ts
4
4
  /**
5
5
  * Dotted paths to the string claims of `C` (up to three levels), e.g.
@@ -7,7 +7,7 @@ import { f as Plugin, h as RequestContext, m as RepositoryExtension, o as HasFla
7
7
  */
8
8
  export type ClaimPath<C> = unknown extends C ? string : StringPaths<C, [1, 2, 3]>;
9
9
  type StringPaths<T, Depth extends readonly unknown[]> = T extends object ? T extends readonly unknown[] ? never : { [K in keyof T & string]-?: (NonNullable<T[K]> extends string ? K : never) | (Depth extends readonly [unknown, ...infer Rest] ? `${K}.${StringPaths<NonNullable<T[K]>, Rest>}` : never); }[keyof T & string] : never;
10
- /** `C` is the claims type (`sb.claims(schema)`'s output); it types `claim`. */
10
+ /** `C` is the claims type (`betterSupabase.claims(schema)`'s output); it types `claim`. */
11
11
  export interface TenantOptions<C = unknown> {
12
12
  /**
13
13
  * JWT claim path(s) holding the tenant id when `context.tenant` is not set.
@@ -1,8 +1,8 @@
1
- import { n as dbError, t as DbException } from "../../errors-Bl3rkOzo.js";
1
+ import { n as dbError, t as DbException } from "../../errors-L0xK41y_.js";
2
2
  import { n as definePlugin } from "../../plugin-BqR6wKMB.js";
3
3
  import { n as scopeOperation } from "../../scope-CDHcS7dE.js";
4
- import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "../../claims-CoTobNC-.js";
5
- import { n as equals, r as forbidden, t as dbName } from "../../shared-_6-uPL7E.js";
4
+ import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "../../claims-BAf6c7is.js";
5
+ import { n as equals, r as forbidden, t as dbName } from "../../shared-DnoCdMDr.js";
6
6
  //#region src/plugins/tenant/index.ts
7
7
  /**
8
8
  * The tenant for a request: `context.tenant`, then the configured claim.
@@ -30,8 +30,14 @@ function tenantColumn(table) {
30
30
  */
31
31
  function tenant(options = {}) {
32
32
  const onMissing = options.onMissing ?? "error";
33
+ /** A context is fixed for a connection, so its tenant is resolved once. */
34
+ const resolved = /* @__PURE__ */ new WeakMap();
33
35
  const current = (table, context, schema) => {
34
- const id = resolveTenant(context, options, schema);
36
+ let id = resolved.get(context);
37
+ if (id === void 0 && !resolved.has(context)) {
38
+ id = resolveTenant(context, options, schema);
39
+ resolved.set(context, id);
40
+ }
35
41
  if (id === void 0 && onMissing === "error" && tenantColumn(table)) throw new DbException(dbError("forbidden", `No tenant in the request context for "${table.key}"`));
36
42
  return id;
37
43
  };
@@ -1,4 +1,4 @@
1
- import { f as Plugin } from "../../plugin-C4TR9J0Z.js";
1
+ import { f as Plugin } from "../../plugin-bNhvJwRh.js";
2
2
  //#region src/plugins/timestamps/index.d.ts
3
3
  /**
4
4
  * Stamps the columns generated as `Flags.timestamps`: `createdAt` on insert,
@@ -1,5 +1,5 @@
1
1
  import { n as definePlugin } from "../../plugin-BqR6wKMB.js";
2
- import { i as insertsOnly, l as withDefault, t as dbName } from "../../shared-_6-uPL7E.js";
2
+ import { i as insertsOnly, l as withDefault, t as dbName } from "../../shared-DnoCdMDr.js";
3
3
  //#region src/plugins/timestamps/index.ts
4
4
  /**
5
5
  * Stamps the columns generated as `Flags.timestamps`: `createdAt` on insert,
@@ -14,7 +14,7 @@ function timestamps() {
14
14
  if (!flags) return op;
15
15
  const created = dbName(table, flags.createdAt);
16
16
  const updated = dbName(table, flags.updatedAt);
17
- const stamp = now().toISOString();
17
+ const stamp = now().toString();
18
18
  switch (op.kind) {
19
19
  case "insert": {
20
20
  const stampCreated = insertsOnly(op);
@@ -1,5 +1,5 @@
1
- import { f as Plugin } from "../../plugin-C4TR9J0Z.js";
2
- import { t as StandardSchemaV1 } from "../../standard-CyhRzctb.js";
1
+ import { f as Plugin } from "../../plugin-bNhvJwRh.js";
2
+ import { t as StandardSchemaV1 } from "../../standard-BsaCYQJc.js";
3
3
  //#region src/plugins/validation/index.d.ts
4
4
  export interface TableValidators {
5
5
  /** Validates inserts and upserts, with app-cased keys. */
@@ -1,7 +1,7 @@
1
- import { n as dbError, t as DbException } from "../../errors-Bl3rkOzo.js";
1
+ import { n as dbError, t as DbException } from "../../errors-L0xK41y_.js";
2
2
  import { n as definePlugin } from "../../plugin-BqR6wKMB.js";
3
- import { t as validate } from "../../standard-FUi3Z3-7.js";
4
- import { c as toDb, s as toApp } from "../../shared-_6-uPL7E.js";
3
+ import { t as validate } from "../../standard-BRyBGTtp.js";
4
+ import { c as toDb, s as toApp } from "../../shared-DnoCdMDr.js";
5
5
  //#region src/plugins/validation/index.ts
6
6
  async function check(schema, table, row, label, index) {
7
7
  const result = await validate(schema, toApp(table, row), label);
@@ -0,0 +1,78 @@
1
+ import { r as Executor } from "./executor-B5IoUxLE.js";
2
+ import { t as SqlClient } from "./executor-CZ7ImRiD.js";
3
+ //#region src/postgres/pool.d.ts
4
+ /** The part of a `pg` pool client `createPostgres` uses. */
5
+ interface PgPoolClient {
6
+ query(text: string, values?: unknown[]): Promise<{
7
+ rows: unknown[];
8
+ }>;
9
+ release(): void;
10
+ }
11
+ /** The part of a `pg.Pool` `createPostgres` uses. */
12
+ interface PgPool {
13
+ connect(): Promise<PgPoolClient>;
14
+ end(): Promise<void>;
15
+ }
16
+ /** Statement timeouts in milliseconds by the role a transaction runs as. */
17
+ interface PostgresTimeouts {
18
+ /** The connection-string role (`admin` and `transaction` without claims). Unset by default. */
19
+ readonly admin?: number;
20
+ /** Defaults to 8000, Supabase's setting for the role. */
21
+ readonly authenticated?: number;
22
+ /** Defaults to 3000, Supabase's setting for the role. */
23
+ readonly anon?: number;
24
+ }
25
+ interface PostgresOptions {
26
+ /** Defaults to `$SUPABASE_DB_URL`, then `$DATABASE_URL`. */
27
+ readonly connectionString?: string;
28
+ /** An existing pool to run on instead of opening one. `end()` ends it. */
29
+ readonly pool?: PgPool;
30
+ readonly max?: number;
31
+ /**
32
+ * Statement timeout in milliseconds, applied per transaction: one value
33
+ * for every role, or one per role. `set role` doesn't apply the role's own
34
+ * `statement_timeout`, so `authenticated` and `anon` get Supabase's 8 s
35
+ * and 3 s unless you set them.
36
+ */
37
+ readonly statementTimeout?: number | PostgresTimeouts;
38
+ /** Ends a session that stays idle inside a transaction this long, in milliseconds. */
39
+ readonly idleInTransactionTimeout?: number;
40
+ /** How long `connect` waits for a connection, in milliseconds. Defaults to 10000. */
41
+ readonly connectionTimeout?: number;
42
+ /** How long an unused connection stays open, in milliseconds. Defaults to 10000. */
43
+ readonly idleTimeout?: number;
44
+ }
45
+ /** JWT claims to run as. `role` must be `authenticated` or `anon`. */
46
+ interface SqlClaims {
47
+ readonly sub?: string;
48
+ readonly role?: string;
49
+ readonly [claim: string]: unknown;
50
+ }
51
+ interface BetterPostgres {
52
+ /** Connects as the connection-string role. On Supabase that bypasses RLS. */
53
+ readonly admin: SqlClient;
54
+ /** Runs every query as the given user, with RLS, like PostgREST does. */
55
+ asUser(claims: SqlClaims): SqlClient;
56
+ /** Runs every query as `anon`. */
57
+ readonly anon: SqlClient;
58
+ /**
59
+ * Repositories' executor as the given user (`postgresExecutor(asUser(claims))`).
60
+ * `createServer` calls it for `ctx.sql`, so only apps that pass `postgres`
61
+ * bundle the SQL compiler.
62
+ */
63
+ executorFor(claims: SqlClaims): Executor;
64
+ /** Runs `fn` in one transaction. Pass claims to run it as a user. */
65
+ transaction<T>(fn: (client: SqlClient) => Promise<T>, options?: {
66
+ readonly claims?: SqlClaims;
67
+ }): Promise<T>;
68
+ end(): Promise<void>;
69
+ [Symbol.asyncDispose](): Promise<void>;
70
+ }
71
+ /**
72
+ * A pooled Postgres connection for jobs, scripts and tests. Each query (or
73
+ * transaction) runs in its own transaction; claims and role are
74
+ * transaction-local, so nothing leaks back into the pool.
75
+ */
76
+ declare function createPostgres(options?: PostgresOptions): BetterPostgres;
77
+ //#endregion
78
+ export { PostgresTimeouts as a, PostgresOptions as i, PgPool as n, SqlClaims as o, PgPoolClient as r, createPostgres as s, BetterPostgres as t };