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.
- package/README.md +37 -33
- package/dist/base64-D2gsioCY.js +42 -0
- package/dist/claims-BAf6c7is.js +48 -0
- package/dist/cli/_format-Cax5EsM9.js +101 -0
- package/dist/cli/bin.js +39 -6
- package/dist/cli/command-CK14fP91.js +502 -0
- package/dist/cli/compare-BmIWVEui.js +9 -0
- package/dist/cli/config-D9R0o1LH.js +1895 -0
- package/dist/cli/config-SSKSTUl2.js +2 -0
- package/dist/cli/db-DOBPt660.js +52 -0
- package/dist/cli/dist-B1MvLv-M.js +129 -0
- package/dist/cli/dist-CFgGknmZ.js +1112 -0
- package/dist/cli/dist-Du7VnEUG.js +621 -0
- package/dist/cli/doctor-BOym3mbL.js +2382 -0
- package/dist/cli/env-BZ0uy8XK.js +108 -0
- package/dist/cli/env-jIFUADLY.js +511 -0
- package/dist/cli/errors-4v4DTtda.js +56 -0
- package/dist/cli/fastest-levenshtein-CFN-lNDv.js +120 -0
- package/dist/cli/gen-Ccn_p90L.js +2008 -0
- package/dist/cli/gen-D5cLCULx.js +2 -0
- package/dist/cli/index.d.ts +295 -28
- package/dist/cli/index.js +184 -3
- package/dist/cli/init-ClnxRYBF.js +550 -0
- package/dist/cli/introspect-DxqfkVIv.js +81 -0
- package/dist/cli/io-k41_z-jT.js +24 -0
- package/dist/cli/json5-ChRycquj.js +787 -0
- package/dist/cli/jsonc-BUniUpOk.js +2 -0
- package/dist/cli/jsonc-D5Fu67jw.js +45 -0
- package/dist/cli/keys-ByKHnvP9.js +83 -0
- package/dist/cli/ohash-D7bG_EOb.js +277 -0
- package/dist/cli/openapi-8WHjxiTJ.js +66 -0
- package/dist/cli/project-B_GeXyHh.js +70 -0
- package/dist/cli/prompts-BNcNfAve.js +1142 -0
- package/dist/cli/prompts-BTYQGunc.js +2 -0
- package/dist/cli/read-sets-CMa29t9a.js +971 -0
- package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
- package/dist/cli/run-CP20LKk_.js +347 -0
- package/dist/cli/seed-5J6eu_Xg.js +98 -0
- package/dist/cli/skills-LJJIhLFR.js +137 -0
- package/dist/cli/sql-D4VbqmXi.js +199 -0
- package/dist/cli/style-C0NFdJRL.js +29 -0
- package/dist/cli/toml-DB-MNnFs.js +424 -0
- package/dist/{version-Cqq1m3UY.js → cli/version-5mW_8sY1.js} +1 -1
- package/dist/cli/yaml-CYCbJ6et.js +2252 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +15 -25
- package/dist/{compiler-CZ9nIuqy.d.ts → compiler-DB3aSFOA.d.ts} +2 -2
- package/dist/config/index.d.ts +4 -3
- package/dist/config/index.js +5 -3
- package/dist/config-BpxDfnbg.js +129 -0
- package/dist/{index-DOsjFvMf.d.ts → config-C1CYcm6o.d.ts} +49 -49
- package/dist/{config-ClDXmVtY.js → config-CbvFmGD8.js} +14 -137
- package/dist/{define-BXMYD9AY.js → define-Bh0AqTik.js} +221 -120
- package/dist/{define-e3zI4_4g.d.ts → define-CRS2MRV3.d.ts} +36 -31
- package/dist/edge/index.d.ts +9 -13
- package/dist/edge/index.js +51 -25
- package/dist/{entitlements-Dng-ctuT.d.ts → entitlements-Dm-FHpNH.d.ts} +2 -2
- package/dist/env/index.js +203 -1
- package/dist/{errors-Bl3rkOzo.js → errors-L0xK41y_.js} +1 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.js +139 -1
- package/dist/{events-DOt3nSO-.d.ts → events-B21UOhvP.d.ts} +4 -4
- package/dist/{executor-CGdNQ27g.d.ts → executor-B5IoUxLE.d.ts} +2 -2
- package/dist/{executor-DeppvirK.js → executor-CVt6dD0B.js} +9 -4
- package/dist/{executor-BYXQ9AGn.d.ts → executor-CZ7ImRiD.d.ts} +2 -2
- package/dist/hono/index.d.ts +17 -24
- package/dist/hono/index.js +11 -11
- package/dist/{index-DuP14VHo.d.ts → index-528Ugmyp.d.ts} +30 -10
- package/dist/{index-Bw1bwtC0.d.ts → index-BAy4tsAP.d.ts} +28 -15
- package/dist/{index-CBDufH1M.d.ts → index-BBdvo-5d.d.ts} +24 -26
- package/dist/{index-DbxFr7XG.d.ts → index-BhHEC04r.d.ts} +9 -4
- package/dist/index-Cf-D2jk1.d.ts +50 -0
- package/dist/{index-Ciu5Xlml.d.ts → index-D5IfUIDh.d.ts} +6 -5
- package/dist/{index-K-3WM2Hp.d.ts → index-DFmOpBGC.d.ts} +13 -13
- package/dist/{index-D4v7sncu.d.ts → index-RlLXd8dL.d.ts} +13 -13
- package/dist/index.d.ts +17 -17
- package/dist/index.js +23 -14
- package/dist/{invalidate-DbxuL2jL.js → invalidate-CgxmRamI.js} +7 -1
- package/dist/jobs/index.d.ts +33 -26
- package/dist/jobs/index.js +44 -22
- package/dist/{json-schema-BpYqkCKf.js → json-schema-DP6V7cbr.js} +8 -3
- package/dist/lint/index.js +1 -1
- package/dist/list/index.d.ts +2 -2
- package/dist/list/index.js +131 -96
- package/dist/{live-DJyZMD6w.d.ts → live-BHakSWWo.d.ts} +26 -16
- package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
- package/dist/lookup-BaP5bI27.js +18 -0
- package/dist/mcp/index.d.ts +34 -27
- package/dist/mcp/index.js +59 -25
- package/dist/{mfa-TVia554c.d.ts → mfa-C7MNQ1Ob.d.ts} +1 -1
- package/dist/{mfa-CpLfJSde.js → mfa-byfjruR9.js} +190 -46
- package/dist/next/image/index.js +6 -3
- package/dist/next/index.d.ts +64 -48
- package/dist/next/index.js +63 -50
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +61 -38
- package/dist/orpc/index.d.ts +18 -21
- package/dist/orpc/index.js +12 -12
- package/dist/otel/index.d.ts +5 -5
- package/dist/otel/index.js +84 -63
- package/dist/{permdock-sql-CghlHPuH.js → permdock-sql-C4KFzLc9.js} +12 -7
- package/dist/permdock-sql-DImJULY-.d.ts +17 -0
- package/dist/{plugin-C4TR9J0Z.d.ts → plugin-bNhvJwRh.d.ts} +5 -4
- package/dist/plugins/actor/index.d.ts +1 -1
- package/dist/plugins/actor/index.js +1 -1
- package/dist/plugins/rules/index.d.ts +2 -2
- package/dist/plugins/rules/index.js +46 -16
- package/dist/plugins/soft-delete/index.d.ts +3 -3
- package/dist/plugins/soft-delete/index.js +4 -4
- package/dist/plugins/tenant/index.d.ts +3 -3
- package/dist/plugins/tenant/index.js +10 -4
- package/dist/plugins/timestamps/index.d.ts +1 -1
- package/dist/plugins/timestamps/index.js +2 -2
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/plugins/validation/index.js +3 -3
- package/dist/pool-DFwEQwmN.d.ts +78 -0
- package/dist/postgres/index.d.ts +10 -5
- package/dist/postgres/index.js +37 -16
- package/dist/{postgrest-cAEQ_IQN.d.ts → postgrest-Bc-0Xw62.d.ts} +1 -1
- package/dist/{problem-BTkTtRV9.js → problem-BihjPR0t.js} +11 -5
- package/dist/{problem-DlgB0lYl.d.ts → problem-U8UEKccv.d.ts} +6 -4
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +2 -2
- package/dist/{query-ChvDbsDE.js → query-BMMSWbI7.js} +19 -19
- package/dist/react/index.d.ts +7 -7
- package/dist/react/index.js +2 -2
- package/dist/react/server.d.ts +6 -6
- package/dist/react/server.js +3 -3
- package/dist/react/session.d.ts +21 -2
- package/dist/react/session.js +19 -1
- package/dist/{react-C83BdBGt.js → react-CQHMaESR.js} +59 -55
- package/dist/{read-set-4lI3W_gZ.js → read-set-FWK8qQ58.js} +51 -16
- package/dist/realtime/index.d.ts +4 -3
- package/dist/realtime/index.js +19 -17
- package/dist/{index-CG69s15v.d.ts → refresh-BwYkyNOQ.d.ts} +7 -3
- package/dist/{resolve-CjHILk2w.d.ts → resolve-BAqQcwMW.d.ts} +17 -11
- package/dist/{resource-CgZa3YG_.d.ts → resource-BJcaIfxi.d.ts} +17 -8
- package/dist/{resource-BHEWmQJK.js → resource-My_y-Syh.js} +43 -21
- package/dist/{respond-Dne1ARSa.d.ts → respond-DgIbdrt8.d.ts} +39 -14
- package/dist/{result-DWXatkd6.js → result-Bj6yt33D.js} +2 -2
- package/dist/{result-CTkCZ6JA.d.ts → result-CqEsbgYs.d.ts} +16 -11
- package/dist/server/index.d.ts +38 -13
- package/dist/server/index.js +43 -14
- package/dist/{respond-DMcbQwfN.js → server-BA75B0mT.js} +151 -96
- package/dist/{shared-_6-uPL7E.js → shared-DnoCdMDr.js} +4 -3
- package/dist/{simplify-bwJpLnaS.js → simplify-Cqvfr9dj.js} +76 -39
- package/dist/sql/index.d.ts +139 -0
- package/dist/sql/index.js +1983 -0
- package/dist/{sql-DTjA1LPj.js → sql-B34HU2DI.js} +74 -17
- package/dist/ssr/index.d.ts +4 -4
- package/dist/ssr/index.js +2 -2
- package/dist/{standard-FUi3Z3-7.js → standard-BRyBGTtp.js} +2 -2
- package/dist/{standard-CyhRzctb.d.ts → standard-BsaCYQJc.d.ts} +1 -1
- package/dist/{stats-C5W-rBfR.js → stats-C_YxA2r1.js} +40 -14
- package/dist/storage/index.d.ts +4 -3
- package/dist/storage/index.js +548 -1
- package/dist/{tables-rZxRxNPW.js → tables-Cb-3_VWc.js} +19 -5
- package/dist/temporal-BwshQk0W.js +27 -0
- package/dist/temporal-required-CBNHT6ni.js +19 -0
- package/dist/testing/index.d.ts +25 -24
- package/dist/testing/index.js +165 -66
- package/dist/{types-C83v5SQz.d.ts → types-DONv9SHN.d.ts} +14 -11
- package/dist/version-Bmf7_FzM.js +4 -0
- package/dist/{view-D1s0wa0T.d.ts → view-B64o81wp.d.ts} +36 -6
- package/dist/{view-aOYizTeE.js → view-BrJI2LKp.js} +11 -2
- package/dist/webhooks/index.d.ts +19 -17
- package/dist/webhooks/index.js +1 -1
- package/dist/{webhooks-DMipjhSP.js → webhooks-Bh_Jf_-l.js} +45 -24
- package/package.json +50 -22
- package/schemas/config-v1.json +31 -1
- package/schemas/doctor-report-v1.json +17 -1
- package/schemas/snapshot-v2.json +35 -0
- package/skills/better-supabase/SKILL.md +77 -18
- package/skills/better-supabase/references/plugins.md +21 -22
- package/skills/better-supabase/references/troubleshooting.md +38 -18
- package/skills/better-supabase-api/SKILL.md +66 -18
- package/skills/better-supabase-api/references/adapters.md +64 -41
- package/skills/better-supabase-auth/SKILL.md +146 -0
- package/skills/better-supabase-auth/references/permdock.md +55 -0
- package/skills/better-supabase-testing/SKILL.md +68 -11
- package/dist/casing-da0uRTqt.js +0 -14
- package/dist/claims-CoTobNC-.js +0 -25
- package/dist/cli-DrSgDOQC.js +0 -6646
- package/dist/env-BEToab0I.js +0 -204
- package/dist/events-BuzTgn2D.js +0 -135
- package/dist/pool-R2m_DkXi.d.ts +0 -37
- package/dist/seed-CzecODcJ.js +0 -101
- package/dist/session-C3LxnQ0e.d.ts +0 -22
- package/dist/session-CqEwzVup.js +0 -20
- package/dist/storage-DuGn38fr.js +0 -527
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { n as dbError, t as DbException } from "./errors-
|
|
2
|
-
import { a as invalidRequest, c as needsDecoding, o as decodeRows, r as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
1
|
+
import { n as dbError, t as DbException } from "./errors-L0xK41y_.js";
|
|
2
|
+
import { a as invalidRequest, c as needsDecoding, o as decodeRows, r as builderFor, s as encodeValue } from "./simplify-Cqvfr9dj.js";
|
|
3
|
+
import { t as lookupOf } from "./lookup-BaP5bI27.js";
|
|
4
|
+
import { n as nowInstant } from "./temporal-BwshQk0W.js";
|
|
5
|
+
import { i as or, n as column, r as not, t as and } from "./types-6cYK9pbJ.js";
|
|
6
|
+
import { i as ok, n as err, o as toDbError, s as withErrorMapper, t as AsyncResult } from "./result-Bj6yt33D.js";
|
|
7
|
+
import { t as invalidationTargets } from "./tables-Cb-3_VWc.js";
|
|
6
8
|
import { t as consoleLogger } from "./logger-glM28NVN.js";
|
|
7
9
|
import { r as orderPlugins } from "./plugin-BqR6wKMB.js";
|
|
8
|
-
import { a as postgrestExecutor, n as StatsRecorder, r as recordStats } from "./stats-
|
|
9
|
-
import { d as isQuerySpec, f as specTables, n as checkParams, o as isReadSet, r as containsPlaceholder, t as bindParams, u as createSpecs } from "./read-set-
|
|
10
|
-
import { t as
|
|
10
|
+
import { a as postgrestExecutor, n as StatsRecorder, r as recordStats } from "./stats-C_YxA2r1.js";
|
|
11
|
+
import { d as isQuerySpec, f as specTables, n as checkParams, o as isReadSet, r as containsPlaceholder, t as bindParams, u as createSpecs } from "./read-set-FWK8qQ58.js";
|
|
12
|
+
import { a as toBase64Url, t as base64ToText } from "./base64-D2gsioCY.js";
|
|
13
|
+
import { t as validate } from "./standard-BRyBGTtp.js";
|
|
11
14
|
//#region src/core/batch.ts
|
|
12
15
|
/**
|
|
13
16
|
* Holds operations until each of `readers` has either submitted one or
|
|
@@ -93,12 +96,18 @@ function memoryCache() {
|
|
|
93
96
|
}
|
|
94
97
|
//#endregion
|
|
95
98
|
//#region src/core/events.ts
|
|
99
|
+
/** More handlers than this for one event usually means a missing unsubscribe. */
|
|
100
|
+
const HANDLER_WARNING = 50;
|
|
101
|
+
function isDevelopment() {
|
|
102
|
+
return typeof process !== "undefined" && process.env["NODE_ENV"] !== "production";
|
|
103
|
+
}
|
|
96
104
|
/**
|
|
97
105
|
* Observers only: a handler that throws is reported to the logger and never
|
|
98
106
|
* changes a result.
|
|
99
107
|
*/
|
|
100
108
|
var EventHub = class {
|
|
101
109
|
#handlers = /* @__PURE__ */ new Map();
|
|
110
|
+
#warned = /* @__PURE__ */ new Set();
|
|
102
111
|
logger;
|
|
103
112
|
constructor(logger = consoleLogger) {
|
|
104
113
|
this.logger = logger;
|
|
@@ -110,6 +119,10 @@ var EventHub = class {
|
|
|
110
119
|
this.#handlers.set(name, set);
|
|
111
120
|
}
|
|
112
121
|
set.add(handler);
|
|
122
|
+
if (set.size > HANDLER_WARNING && !this.#warned.has(name) && isDevelopment()) {
|
|
123
|
+
this.#warned.add(name);
|
|
124
|
+
this.logger.warn(`${set.size} "${name}" handlers are registered; call the function on() returns to remove one you no longer need`);
|
|
125
|
+
}
|
|
113
126
|
return () => {
|
|
114
127
|
set.delete(handler);
|
|
115
128
|
};
|
|
@@ -129,27 +142,13 @@ var EventHub = class {
|
|
|
129
142
|
};
|
|
130
143
|
//#endregion
|
|
131
144
|
//#region src/core/cursor.ts
|
|
132
|
-
const encoder = new TextEncoder();
|
|
133
|
-
const decoder = new TextDecoder();
|
|
134
|
-
function toBase64Url(bytes) {
|
|
135
|
-
let binary = "";
|
|
136
|
-
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
137
|
-
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
138
|
-
}
|
|
139
|
-
function fromBase64Url(text) {
|
|
140
|
-
const base64 = text.replace(/-/g, "+").replace(/_/g, "/");
|
|
141
|
-
const binary = atob(base64 + "=".repeat((4 - base64.length % 4) % 4));
|
|
142
|
-
const bytes = new Uint8Array(binary.length);
|
|
143
|
-
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
144
|
-
return bytes;
|
|
145
|
-
}
|
|
146
145
|
/** Opaque, URL-safe keyset cursor. */
|
|
147
146
|
function encodeCursor(values) {
|
|
148
|
-
return toBase64Url(
|
|
147
|
+
return toBase64Url(JSON.stringify(values));
|
|
149
148
|
}
|
|
150
149
|
function decodeCursor(cursor) {
|
|
151
150
|
try {
|
|
152
|
-
const parsed = JSON.parse(
|
|
151
|
+
const parsed = JSON.parse(base64ToText(cursor));
|
|
153
152
|
return Array.isArray(parsed) ? parsed : void 0;
|
|
154
153
|
} catch {
|
|
155
154
|
return;
|
|
@@ -182,11 +181,28 @@ const KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
|
182
181
|
"_min",
|
|
183
182
|
"_max"
|
|
184
183
|
]);
|
|
184
|
+
const NO_OPTIONS = Object.freeze({});
|
|
185
185
|
function optionsOf(args) {
|
|
186
|
-
if (!args) return
|
|
187
|
-
|
|
188
|
-
for (const
|
|
189
|
-
return options;
|
|
186
|
+
if (!args) return NO_OPTIONS;
|
|
187
|
+
let options;
|
|
188
|
+
for (const key in args) if (!KNOWN_KEYS.has(key) && Object.hasOwn(args, key)) (options ??= {})[key] = args[key];
|
|
189
|
+
return options ?? NO_OPTIONS;
|
|
190
|
+
}
|
|
191
|
+
const hooksByPlugins = /* @__PURE__ */ new WeakMap();
|
|
192
|
+
function hooksOf(plugins) {
|
|
193
|
+
let hooks = hooksByPlugins.get(plugins);
|
|
194
|
+
if (!hooks) {
|
|
195
|
+
hooks = {
|
|
196
|
+
transformQuery: plugins.filter((plugin) => plugin.transformQuery),
|
|
197
|
+
beforeMutation: plugins.filter((plugin) => plugin.beforeMutation),
|
|
198
|
+
afterMutation: plugins.filter((plugin) => plugin.afterMutation)
|
|
199
|
+
};
|
|
200
|
+
hooksByPlugins.set(plugins, hooks);
|
|
201
|
+
}
|
|
202
|
+
return hooks;
|
|
203
|
+
}
|
|
204
|
+
function isThenable(value) {
|
|
205
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
190
206
|
}
|
|
191
207
|
function signalOf(args) {
|
|
192
208
|
const signal = args?.["signal"];
|
|
@@ -199,8 +215,10 @@ function mutationKind(op) {
|
|
|
199
215
|
/** Runs operations through plugins, the executor and the event hub. */
|
|
200
216
|
var OperationRunner = class {
|
|
201
217
|
runtime;
|
|
218
|
+
#hooks;
|
|
202
219
|
constructor(runtime) {
|
|
203
220
|
this.runtime = runtime;
|
|
221
|
+
this.#hooks = hooksOf(runtime.plugins);
|
|
204
222
|
}
|
|
205
223
|
hookArgs(table, options) {
|
|
206
224
|
return {
|
|
@@ -213,30 +231,43 @@ var OperationRunner = class {
|
|
|
213
231
|
}
|
|
214
232
|
async run(op, options, signal) {
|
|
215
233
|
const { runtime } = this;
|
|
216
|
-
const
|
|
234
|
+
const hooks = this.#hooks;
|
|
217
235
|
let current = op;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
236
|
+
if (hooks.transformQuery.length > 0 || hooks.beforeMutation.length > 0) {
|
|
237
|
+
const hook = this.hookArgs(op.table, options);
|
|
238
|
+
try {
|
|
239
|
+
for (const plugin of hooks.transformQuery) current = plugin.transformQuery(current, hook);
|
|
240
|
+
if (current.kind !== "select") {
|
|
241
|
+
let mutation = current;
|
|
242
|
+
for (const plugin of hooks.beforeMutation) {
|
|
243
|
+
const next = plugin.beforeMutation(mutation, hook);
|
|
244
|
+
mutation = isThenable(next) ? await next : next;
|
|
245
|
+
}
|
|
246
|
+
current = mutation;
|
|
247
|
+
}
|
|
248
|
+
} catch (cause) {
|
|
249
|
+
if (cause instanceof DbException) return this.fail(op.table, cause.error);
|
|
250
|
+
throw cause;
|
|
224
251
|
}
|
|
225
|
-
} catch (cause) {
|
|
226
|
-
if (cause instanceof DbException) return this.fail(op.table, cause.error);
|
|
227
|
-
throw cause;
|
|
228
252
|
}
|
|
229
|
-
const
|
|
253
|
+
const timed = runtime.events.has("query");
|
|
254
|
+
const started = timed ? performance.now() : 0;
|
|
230
255
|
const context = signal ? {
|
|
231
256
|
signal,
|
|
232
257
|
errorMappers: runtime.errorMappers
|
|
233
258
|
} : { errorMappers: runtime.errorMappers };
|
|
234
259
|
const executed = await runtime.executor.execute(current, context);
|
|
235
260
|
const selection = current.kind === "select" ? current.selection : current.returning;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
261
|
+
let result = executed;
|
|
262
|
+
if (executed.ok && selection && needsDecoding(selection)) try {
|
|
263
|
+
result = ok({
|
|
264
|
+
...executed.data,
|
|
265
|
+
rows: decodeRows(selection, executed.data.rows, true)
|
|
266
|
+
});
|
|
267
|
+
} catch (cause) {
|
|
268
|
+
if (cause instanceof DbException) return this.fail(op.table, cause.error);
|
|
269
|
+
throw cause;
|
|
270
|
+
}
|
|
240
271
|
const rows = result.ok ? result.data.rows.length : 0;
|
|
241
272
|
const truncated = current.kind === "select" && current.limit === void 0 && current.single === void 0 && !current.head && rows >= runtime.maxRows;
|
|
242
273
|
if (truncated && !runtime.truncatedTables.has(op.table.key)) {
|
|
@@ -246,7 +277,7 @@ var OperationRunner = class {
|
|
|
246
277
|
maxRows: runtime.maxRows
|
|
247
278
|
});
|
|
248
279
|
}
|
|
249
|
-
if (
|
|
280
|
+
if (timed) runtime.events.emit("query", {
|
|
250
281
|
table: op.table.key,
|
|
251
282
|
operation: current.kind,
|
|
252
283
|
ok: result.ok,
|
|
@@ -260,21 +291,22 @@ var OperationRunner = class {
|
|
|
260
291
|
}
|
|
261
292
|
async afterMutation(op, data) {
|
|
262
293
|
const { runtime } = this;
|
|
294
|
+
const plugins = this.#hooks.afterMutation;
|
|
295
|
+
const listening = runtime.events.has("mutation");
|
|
296
|
+
if (plugins.length === 0 && !listening) return;
|
|
263
297
|
const event = {
|
|
264
298
|
table: op.table,
|
|
265
299
|
kind: mutationKind(op),
|
|
266
300
|
rows: data.rows,
|
|
267
301
|
context: runtime.context
|
|
268
302
|
};
|
|
269
|
-
for (const plugin of
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
runtime.events.logger.error(`plugin "${plugin.name}" afterMutation threw`, { cause });
|
|
275
|
-
}
|
|
303
|
+
for (const plugin of plugins) try {
|
|
304
|
+
const pending = plugin.afterMutation(event);
|
|
305
|
+
if (isThenable(pending)) await pending;
|
|
306
|
+
} catch (cause) {
|
|
307
|
+
runtime.events.logger.error(`plugin "${plugin.name}" afterMutation threw`, { cause });
|
|
276
308
|
}
|
|
277
|
-
runtime.events.emit("mutation", {
|
|
309
|
+
if (listening) runtime.events.emit("mutation", {
|
|
278
310
|
table: op.table.key,
|
|
279
311
|
kind: event.kind,
|
|
280
312
|
rows: event.rows,
|
|
@@ -286,7 +318,7 @@ var OperationRunner = class {
|
|
|
286
318
|
...error,
|
|
287
319
|
table: table.key
|
|
288
320
|
};
|
|
289
|
-
this.runtime.events.emit("error", {
|
|
321
|
+
if (this.runtime.events.has("error")) this.runtime.events.emit("error", {
|
|
290
322
|
table: table.key,
|
|
291
323
|
error: withTable
|
|
292
324
|
});
|
|
@@ -312,19 +344,22 @@ function createRepository(runner, table) {
|
|
|
312
344
|
});
|
|
313
345
|
const returning = (args) => args?.["returning"] === false ? void 0 : selection(args);
|
|
314
346
|
const run = (op, args) => runner.run(op, optionsOf(args), signalOf(args));
|
|
347
|
+
let primaryOrder;
|
|
348
|
+
/** `primaryKey` holds app names; order terms take database names. */
|
|
349
|
+
const defaultOrder = () => primaryOrder ??= table.primaryKey.map((name) => ({
|
|
350
|
+
column: builder.column(table, name),
|
|
351
|
+
direction: "asc"
|
|
352
|
+
}));
|
|
315
353
|
const notFound = () => runner.fail(table, dbError("not_found", `No ${table.key} row matched`));
|
|
316
354
|
const base = {
|
|
317
|
-
$
|
|
355
|
+
$tableName: table.key,
|
|
318
356
|
$meta: table,
|
|
319
357
|
findMany(args) {
|
|
320
358
|
return AsyncResult.from(async () => {
|
|
321
359
|
const op = selectOp(args);
|
|
322
360
|
const ordered = op.orderBy.length > 0 || table.primaryKey.length === 0 ? op : {
|
|
323
361
|
...op,
|
|
324
|
-
orderBy:
|
|
325
|
-
column,
|
|
326
|
-
direction: "asc"
|
|
327
|
-
}))
|
|
362
|
+
orderBy: defaultOrder()
|
|
328
363
|
};
|
|
329
364
|
const result = await run(ordered, args);
|
|
330
365
|
return result.ok ? ok(result.data.rows) : result;
|
|
@@ -515,10 +550,11 @@ function createRepository(runner, table) {
|
|
|
515
550
|
}
|
|
516
551
|
};
|
|
517
552
|
function insertOp(rows, args, conflict) {
|
|
553
|
+
const built = rows.map((row) => builder.row(table, row));
|
|
518
554
|
return {
|
|
519
555
|
kind: "insert",
|
|
520
556
|
table,
|
|
521
|
-
rows:
|
|
557
|
+
rows: conflict && built.length > 1 ? byKey(built, conflict) : built,
|
|
522
558
|
returning: returning(args),
|
|
523
559
|
onConflict: conflict ? {
|
|
524
560
|
columns: conflict,
|
|
@@ -572,7 +608,8 @@ function createRepository(runner, table) {
|
|
|
572
608
|
if (typeof args["after"] === "string") {
|
|
573
609
|
const values = decodeCursor(args["after"]);
|
|
574
610
|
if (!values || values.length !== orderBy.length) return runner.fail(table, dbError("invalid_request", "Invalid cursor"));
|
|
575
|
-
|
|
611
|
+
const { byDb } = lookupOf(table);
|
|
612
|
+
after = keysetCondition(orderBy, values, (name) => byDb.get(name)?.[1].nullable ?? true);
|
|
576
613
|
}
|
|
577
614
|
const op = selectOp(args, {
|
|
578
615
|
selection: withSort,
|
|
@@ -586,7 +623,8 @@ function createRepository(runner, table) {
|
|
|
586
623
|
const rows = result.data.rows.slice(0, size);
|
|
587
624
|
const hasMore = result.data.rows.length > size;
|
|
588
625
|
const last = rows.at(-1);
|
|
589
|
-
const
|
|
626
|
+
const aliases = new Map(withSort.columns.map((entry) => [entry.column, entry.alias]));
|
|
627
|
+
const nextCursor = hasMore && last ? encodeCursor(orderBy.map((term) => encodeValue(last[aliases.get(term.column) ?? term.column]))) : null;
|
|
590
628
|
return ok({
|
|
591
629
|
items: added.length > 0 ? rows.map((row) => strip(row, added)) : rows,
|
|
592
630
|
nextCursor,
|
|
@@ -606,14 +644,17 @@ function createRepository(runner, table) {
|
|
|
606
644
|
}
|
|
607
645
|
function ensureColumns(base, orderBy) {
|
|
608
646
|
const columns = [...base.columns];
|
|
647
|
+
const selected = new Set(columns.map((entry) => entry.column));
|
|
648
|
+
const { byDb } = lookupOf(table);
|
|
609
649
|
const added = [];
|
|
610
650
|
for (const term of orderBy) {
|
|
611
|
-
if (
|
|
612
|
-
const alias =
|
|
651
|
+
if (selected.has(term.column)) continue;
|
|
652
|
+
const alias = byDb.get(term.column)?.[0] ?? term.column;
|
|
613
653
|
columns.push({
|
|
614
654
|
alias,
|
|
615
655
|
column: term.column
|
|
616
656
|
});
|
|
657
|
+
selected.add(term.column);
|
|
617
658
|
added.push(alias);
|
|
618
659
|
}
|
|
619
660
|
return {
|
|
@@ -626,32 +667,60 @@ function createRepository(runner, table) {
|
|
|
626
667
|
}
|
|
627
668
|
return base;
|
|
628
669
|
}
|
|
629
|
-
function aliasOf(selection, column) {
|
|
630
|
-
return selection.columns.find((entry) => entry.column === column)?.alias ?? column;
|
|
631
|
-
}
|
|
632
670
|
function strip(row, keys) {
|
|
633
|
-
const copy = {
|
|
634
|
-
for (const key
|
|
671
|
+
const copy = {};
|
|
672
|
+
for (const key in row) if (!keys.includes(key) && Object.hasOwn(row, key)) copy[key] = row[key];
|
|
635
673
|
return copy;
|
|
636
674
|
}
|
|
637
|
-
/**
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
675
|
+
/**
|
|
676
|
+
* Rows in conflict-key order, so concurrent upserts lock the same rows in
|
|
677
|
+
* the same order instead of deadlocking.
|
|
678
|
+
*/
|
|
679
|
+
function byKey(rows, columns) {
|
|
680
|
+
const compare = (left, right) => {
|
|
681
|
+
if (left === right) return 0;
|
|
682
|
+
if (left === null || left === void 0) return 1;
|
|
683
|
+
if (right === null || right === void 0) return -1;
|
|
684
|
+
if (typeof left === "number" && typeof right === "number") return left - right;
|
|
685
|
+
if (typeof left === "bigint" && typeof right === "bigint") return left < right ? -1 : 1;
|
|
686
|
+
const a = String(left);
|
|
687
|
+
const b = String(right);
|
|
688
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
689
|
+
};
|
|
690
|
+
const keyed = rows.map((row) => ({
|
|
691
|
+
row,
|
|
692
|
+
key: columns.map((column) => {
|
|
693
|
+
const value = row[column];
|
|
694
|
+
return typeof value === "object" && value !== null ? String(value) : value;
|
|
695
|
+
})
|
|
696
|
+
}));
|
|
697
|
+
keyed.sort((left, right) => {
|
|
698
|
+
for (let index = 0; index < columns.length; index++) {
|
|
699
|
+
const order = compare(left.key[index], right.key[index]);
|
|
700
|
+
if (order !== 0) return order;
|
|
701
|
+
}
|
|
702
|
+
return 0;
|
|
703
|
+
});
|
|
704
|
+
return keyed.map((entry) => entry.row);
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* The rows after the cursor `values` in `orderBy` order, as an OR of ANDs:
|
|
708
|
+
* `a > x or (a = x and b > y)`. The SQL compiler sends that shape as the row
|
|
709
|
+
* comparison `(a, b) > (x, y)`. Nulls sort where Postgres puts them: last
|
|
710
|
+
* for `asc`, first for `desc`, unless the term says otherwise.
|
|
711
|
+
*/
|
|
712
|
+
function keysetCondition(orderBy, values, nullable) {
|
|
713
|
+
const isNull = (name) => column(name, "is", null);
|
|
714
|
+
const branches = orderBy.flatMap((term, index) => {
|
|
715
|
+
const value = values[index];
|
|
716
|
+
const nullsFirst = (term.nulls ?? (term.direction === "desc" ? "first" : "last")) === "first";
|
|
717
|
+
const after = column(term.column, term.direction === "asc" ? "gt" : "lt", value);
|
|
718
|
+
const step = value === null ? nullsFirst ? not(isNull(term.column)) : void 0 : nullsFirst || !nullable(term.column) ? after : or(after, isNull(term.column));
|
|
719
|
+
if (!step) return [];
|
|
720
|
+
const equal = orderBy.slice(0, index).map((prev, prevIndex) => values[prevIndex] === null ? isNull(prev.column) : column(prev.column, "eq", values[prevIndex]));
|
|
721
|
+
return [and(...equal, step) ?? step];
|
|
653
722
|
});
|
|
654
|
-
return or(...branches);
|
|
723
|
+
return branches.length > 0 ? or(...branches) : column(orderBy[0]?.column ?? "", "in", []);
|
|
655
724
|
}
|
|
656
725
|
//#endregion
|
|
657
726
|
//#region src/core/search.ts
|
|
@@ -698,7 +767,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
698
767
|
* A token that fails it resolves to `{ kind: 'invalid', reason: 'claims' }`.
|
|
699
768
|
*
|
|
700
769
|
* ```ts
|
|
701
|
-
* const
|
|
770
|
+
* const betterSupabase = defineSupabase(schema).claims(z.object({ tenant_id: z.uuid() }));
|
|
702
771
|
* ```
|
|
703
772
|
*/
|
|
704
773
|
claims(schema) {
|
|
@@ -716,7 +785,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
716
785
|
* the verified claims, never from `profile`.
|
|
717
786
|
*
|
|
718
787
|
* ```ts
|
|
719
|
-
* const
|
|
788
|
+
* const betterSupabase = defineSupabase(schema).userMetadata(z.object({ display_name: z.string() }));
|
|
720
789
|
* ```
|
|
721
790
|
*/
|
|
722
791
|
userMetadata(schema) {
|
|
@@ -731,7 +800,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
731
800
|
* Results themselves keep their `DbError`.
|
|
732
801
|
*
|
|
733
802
|
* ```ts
|
|
734
|
-
* const
|
|
803
|
+
* const betterSupabase = defineSupabase(schema).mapError((error) => new AppError(error));
|
|
735
804
|
* ```
|
|
736
805
|
*/
|
|
737
806
|
mapError(mapper) {
|
|
@@ -742,9 +811,14 @@ var BetterSupabase = class BetterSupabase {
|
|
|
742
811
|
}
|
|
743
812
|
#specs;
|
|
744
813
|
#truncatedTables = /* @__PURE__ */ new Set();
|
|
814
|
+
/** A hub without listeners, for decoding read-set results. */
|
|
815
|
+
#decodeEvents;
|
|
816
|
+
/** One getter per table, shared by every db this instance connects. */
|
|
817
|
+
#tables;
|
|
818
|
+
#errorMappers = /* @__PURE__ */ new WeakMap();
|
|
745
819
|
/**
|
|
746
820
|
* Builds serializable `QuerySpec`s with the same arguments and result types
|
|
747
|
-
* as the repository: `
|
|
821
|
+
* as the repository: `betterSupabase.spec.customers.findMany({ select: ['id'] })`.
|
|
748
822
|
*/
|
|
749
823
|
get spec() {
|
|
750
824
|
this.#specs ??= createSpecs(this.meta);
|
|
@@ -765,7 +839,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
765
839
|
* invalidate them after it succeeds.
|
|
766
840
|
*
|
|
767
841
|
* ```ts
|
|
768
|
-
*
|
|
842
|
+
* betterSupabase.defineRpc('archive_customer', { invalidates: ['customers', 'notes'] });
|
|
769
843
|
* ```
|
|
770
844
|
*/
|
|
771
845
|
defineRpc(name, options) {
|
|
@@ -796,7 +870,9 @@ var BetterSupabase = class BetterSupabase {
|
|
|
796
870
|
const invalidate = (target) => {
|
|
797
871
|
try {
|
|
798
872
|
const pending = adapter.invalidate(target);
|
|
799
|
-
if (pending) pending.catch((cause) =>
|
|
873
|
+
if (pending) pending.catch((cause) => {
|
|
874
|
+
report(cause, target.table);
|
|
875
|
+
});
|
|
800
876
|
} catch (cause) {
|
|
801
877
|
report(cause, target.table);
|
|
802
878
|
}
|
|
@@ -822,20 +898,26 @@ var BetterSupabase = class BetterSupabase {
|
|
|
822
898
|
let executor = base;
|
|
823
899
|
for (const plugin of plugins) if (plugin.wrapExecutor) executor = plugin.wrapExecutor(executor);
|
|
824
900
|
executor = recordStats(executor, recorder);
|
|
825
|
-
const errorMappers =
|
|
901
|
+
const errorMappers = this.#errorMappersFor(plugins);
|
|
826
902
|
const runner = new OperationRunner({
|
|
827
903
|
meta: this.meta,
|
|
828
|
-
builder:
|
|
904
|
+
builder: builderFor(this.meta),
|
|
829
905
|
executor,
|
|
830
906
|
plugins,
|
|
831
907
|
context,
|
|
832
908
|
events,
|
|
833
909
|
errorMappers,
|
|
834
|
-
now: this.options.now ??
|
|
910
|
+
now: this.options.now ?? nowInstant,
|
|
835
911
|
maxRows: this.options.maxRows ?? 1e3,
|
|
836
912
|
truncatedTables: this.#truncatedTables
|
|
837
913
|
});
|
|
838
|
-
const db =
|
|
914
|
+
const db = Object.create(this.#tablePrototype());
|
|
915
|
+
dbStates.set(db, {
|
|
916
|
+
runner,
|
|
917
|
+
plugins,
|
|
918
|
+
repositories: /* @__PURE__ */ new Map()
|
|
919
|
+
});
|
|
920
|
+
Object.assign(db, {
|
|
839
921
|
$client: client,
|
|
840
922
|
$executor: executor,
|
|
841
923
|
$context: context,
|
|
@@ -903,10 +985,10 @@ var BetterSupabase = class BetterSupabase {
|
|
|
903
985
|
hint: `Add "${table.schema}.${table.name}" to vectorSearch in better-supabase.config.ts and run \`better-supabase sql sync\`.`
|
|
904
986
|
}) : result;
|
|
905
987
|
})
|
|
906
|
-
};
|
|
988
|
+
});
|
|
907
989
|
const many = (specs, signal, usePlugins) => AsyncResult.from(async () => {
|
|
908
990
|
const invalid = specs.findIndex((spec) => !isQuerySpec(spec));
|
|
909
|
-
if (invalid !== -1) return err(dbError("invalid_request", `db.$many() entry ${invalid} is not a QuerySpec from
|
|
991
|
+
if (invalid !== -1) return err(dbError("invalid_request", `db.$many() entry ${invalid} is not a QuerySpec from betterSupabase.spec`));
|
|
910
992
|
const active = usePlugins ? plugins : [];
|
|
911
993
|
const batch = base.batch?.bind(base);
|
|
912
994
|
const batching = batch && specs.length > 1 ? batchingExecutor({
|
|
@@ -954,21 +1036,6 @@ var BetterSupabase = class BetterSupabase {
|
|
|
954
1036
|
"$many",
|
|
955
1037
|
"$search"
|
|
956
1038
|
]) db[name] = mapThrows(db[name], throwAs);
|
|
957
|
-
for (const [key, table] of Object.entries(this.meta.tables)) {
|
|
958
|
-
let repository;
|
|
959
|
-
Object.defineProperty(db, key, {
|
|
960
|
-
enumerable: true,
|
|
961
|
-
get: () => {
|
|
962
|
-
if (!repository) {
|
|
963
|
-
repository = this.#repository(runner, key, table, plugins);
|
|
964
|
-
if (throwAs) {
|
|
965
|
-
for (const [name, method] of Object.entries(repository)) if (typeof method === "function" && name !== "extend") repository[name] = mapThrows(method, throwAs);
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
return repository;
|
|
969
|
-
}
|
|
970
|
-
});
|
|
971
|
-
}
|
|
972
1039
|
return db;
|
|
973
1040
|
}
|
|
974
1041
|
/**
|
|
@@ -985,22 +1052,55 @@ var BetterSupabase = class BetterSupabase {
|
|
|
985
1052
|
const rows = entry.rows ?? [];
|
|
986
1053
|
const result = await runSpec(this.#db(client, {
|
|
987
1054
|
name: "read-set",
|
|
988
|
-
execute:
|
|
1055
|
+
execute: (op) => {
|
|
989
1056
|
if (op.kind === "select" && op.single) {
|
|
990
|
-
if (rows.length > 1) return err(dbError("multiple_rows", `Expected one ${op.table.key} row`));
|
|
991
|
-
if (rows.length === 0 && op.single === "one") return err(dbError("not_found", `No ${op.table.key} row matched`));
|
|
1057
|
+
if (rows.length > 1) return Promise.resolve(err(dbError("multiple_rows", `Expected one ${op.table.key} row`)));
|
|
1058
|
+
if (rows.length === 0 && op.single === "one") return Promise.resolve(err(dbError("not_found", `No ${op.table.key} row matched`)));
|
|
992
1059
|
}
|
|
993
|
-
return ok({
|
|
1060
|
+
return Promise.resolve(ok({
|
|
994
1061
|
rows,
|
|
995
1062
|
count: entry.count ?? null
|
|
996
|
-
});
|
|
1063
|
+
}));
|
|
997
1064
|
}
|
|
998
|
-
}, context, [], new StatsRecorder(), new EventHub(this.events.logger)), spec, void 0);
|
|
1065
|
+
}, context, [], new StatsRecorder(), this.#decodeEvents ??= new EventHub(this.events.logger)), spec, void 0);
|
|
999
1066
|
if (!result.ok) return result;
|
|
1000
1067
|
out[key] = result.data;
|
|
1001
1068
|
}
|
|
1002
1069
|
return ok(out);
|
|
1003
1070
|
}
|
|
1071
|
+
#errorMappersFor(plugins) {
|
|
1072
|
+
let mappers = this.#errorMappers.get(plugins);
|
|
1073
|
+
if (!mappers) {
|
|
1074
|
+
mappers = [...this.options.errors ?? [], ...plugins.flatMap((plugin) => plugin.mapError ? [plugin.mapError] : [])];
|
|
1075
|
+
this.#errorMappers.set(plugins, mappers);
|
|
1076
|
+
}
|
|
1077
|
+
return mappers;
|
|
1078
|
+
}
|
|
1079
|
+
#tablePrototype() {
|
|
1080
|
+
if (this.#tables) return this.#tables;
|
|
1081
|
+
const tables = {};
|
|
1082
|
+
const throwAs = this.options.throwAs;
|
|
1083
|
+
const build = (state, key) => {
|
|
1084
|
+
let repository = state.repositories.get(key);
|
|
1085
|
+
if (repository) return repository;
|
|
1086
|
+
const table = this.meta.tables[key];
|
|
1087
|
+
repository = this.#repository(state.runner, key, table, state.plugins);
|
|
1088
|
+
if (throwAs) {
|
|
1089
|
+
for (const [name, method] of Object.entries(repository)) if (typeof method === "function" && name !== "extend") repository[name] = mapThrows(method, throwAs);
|
|
1090
|
+
}
|
|
1091
|
+
state.repositories.set(key, repository);
|
|
1092
|
+
return repository;
|
|
1093
|
+
};
|
|
1094
|
+
for (const key of Object.keys(this.meta.tables)) Object.defineProperty(tables, key, {
|
|
1095
|
+
enumerable: true,
|
|
1096
|
+
get() {
|
|
1097
|
+
const state = dbStates.get(this);
|
|
1098
|
+
return state ? build(state, key) : void 0;
|
|
1099
|
+
}
|
|
1100
|
+
});
|
|
1101
|
+
this.#tables = tables;
|
|
1102
|
+
return tables;
|
|
1103
|
+
}
|
|
1004
1104
|
#repository(runner, key, table, plugins) {
|
|
1005
1105
|
const repository = createRepository(runner, table);
|
|
1006
1106
|
for (const plugin of plugins) {
|
|
@@ -1021,6 +1121,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
1021
1121
|
return repository;
|
|
1022
1122
|
}
|
|
1023
1123
|
};
|
|
1124
|
+
const dbStates = /* @__PURE__ */ new WeakMap();
|
|
1024
1125
|
function mapThrows(method, throwAs) {
|
|
1025
1126
|
return function(...args) {
|
|
1026
1127
|
const value = method.apply(this, args);
|
|
@@ -1028,7 +1129,7 @@ function mapThrows(method, throwAs) {
|
|
|
1028
1129
|
};
|
|
1029
1130
|
}
|
|
1030
1131
|
function runSpec(db, spec, signal) {
|
|
1031
|
-
if (!isQuerySpec(spec)) return AsyncResult.err(dbError("invalid_request", "db.$run() expects a QuerySpec from
|
|
1132
|
+
if (!isQuerySpec(spec)) return AsyncResult.err(dbError("invalid_request", "db.$run() expects a QuerySpec from betterSupabase.spec"));
|
|
1032
1133
|
const method = db[spec.table]?.[spec.method];
|
|
1033
1134
|
if (!method) return AsyncResult.err(dbError("invalid_request", `Unknown table "${spec.table}" in QuerySpec`));
|
|
1034
1135
|
if (containsPlaceholder(spec.args)) return AsyncResult.err(dbError("invalid_request", "This spec comes from a read set and still holds placeholders; run it with db.$many(readSet, params)"));
|
|
@@ -1061,7 +1162,7 @@ function rpc(executor, errorMappers, name, rest) {
|
|
|
1061
1162
|
* Creates the data-layer definition from the generated `schema`.
|
|
1062
1163
|
*
|
|
1063
1164
|
* ```ts
|
|
1064
|
-
* export const
|
|
1165
|
+
* export const betterSupabase = defineSupabase(schema).use(timestamps()).use(softDelete());
|
|
1065
1166
|
* ```
|
|
1066
1167
|
*/
|
|
1067
1168
|
function defineSupabase(schema, options) {
|