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
package/dist/jobs/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { c as mapDbError, n as dbError, t as DbException } from "../errors-
|
|
2
|
-
import {
|
|
3
|
-
import { t as
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
7
|
-
|
|
1
|
+
import { c as mapDbError, n as dbError, t as DbException } from "../errors-L0xK41y_.js";
|
|
2
|
+
import { n as nowInstant } from "../temporal-BwshQk0W.js";
|
|
3
|
+
import { t as temporal } from "../temporal-required-CBNHT6ni.js";
|
|
4
|
+
import { i as ok, n as err, o as toDbError, t as AsyncResult } from "../result-Bj6yt33D.js";
|
|
5
|
+
import { t as validate } from "../standard-BRyBGTtp.js";
|
|
6
|
+
import { a as problemResponse } from "../problem-BihjPR0t.js";
|
|
7
|
+
import { t as fromPgError } from "../executor-CVt6dD0B.js";
|
|
8
|
+
import { c as verifyWebhook } from "../webhooks-Bh_Jf_-l.js";
|
|
9
|
+
//#region src/jobs/jobs.ts
|
|
8
10
|
function run(fn) {
|
|
9
11
|
return AsyncResult.from(async () => {
|
|
10
12
|
try {
|
|
@@ -22,7 +24,10 @@ function workerId() {
|
|
|
22
24
|
return `worker-${crypto.randomUUID().slice(0, 8)}`;
|
|
23
25
|
}
|
|
24
26
|
const sleep = (ms, signal) => new Promise((resolve) => {
|
|
25
|
-
if (signal?.aborted)
|
|
27
|
+
if (signal?.aborted) {
|
|
28
|
+
resolve();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
26
31
|
const timer = setTimeout(done, ms);
|
|
27
32
|
function done() {
|
|
28
33
|
clearTimeout(timer);
|
|
@@ -149,7 +154,8 @@ function postgrestTransport(client) {
|
|
|
149
154
|
unschedule: () => sqlOnly("unschedule")
|
|
150
155
|
};
|
|
151
156
|
}
|
|
152
|
-
|
|
157
|
+
/** pgmq and the inbox return `timestamptz` as text over RPC and as `Date` from `pg`. */
|
|
158
|
+
const toInstant = (value) => value instanceof Date ? temporal().Instant.fromEpochMilliseconds(value.getTime()) : temporal().Instant.from(value);
|
|
153
159
|
function toJob(queue, row) {
|
|
154
160
|
const message = row.message ?? {};
|
|
155
161
|
return {
|
|
@@ -158,8 +164,8 @@ function toJob(queue, row) {
|
|
|
158
164
|
payload: message.payload,
|
|
159
165
|
attempts: row.attempts,
|
|
160
166
|
maxAttempts: message.max_attempts ?? 5,
|
|
161
|
-
enqueuedAt:
|
|
162
|
-
visibleUntil:
|
|
167
|
+
enqueuedAt: toInstant(row.enqueued_at),
|
|
168
|
+
visibleUntil: toInstant(row.visible_until),
|
|
163
169
|
lastError: message.last_error ?? null
|
|
164
170
|
};
|
|
165
171
|
}
|
|
@@ -194,12 +200,15 @@ function createJobs(source, queues) {
|
|
|
194
200
|
schemaOf(queue);
|
|
195
201
|
return (await transport.read(queue, claimOptions.lease ?? 300, claimOptions.batch ?? 1)).map((row) => toJob(queue, row));
|
|
196
202
|
});
|
|
203
|
+
/**
|
|
204
|
+
* Extends the lease of every job in `held` at half the lease, so jobs
|
|
205
|
+
* waiting their turn in a claimed batch don't expire before they run.
|
|
206
|
+
*/
|
|
207
|
+
const heartbeat = (held, lease) => transport.name === "sql" ? setInterval(() => {
|
|
208
|
+
for (const job of held) run(() => transport.extend(job, lease));
|
|
209
|
+
}, Math.max(1e3, lease * 1e3 / 2)) : void 0;
|
|
197
210
|
const handle = async (job, handler, workOptions) => {
|
|
198
211
|
const controller = new AbortController();
|
|
199
|
-
const lease = workOptions.lease ?? 300;
|
|
200
|
-
const heartbeat = transport.name === "sql" ? setInterval(() => {
|
|
201
|
-
run(() => transport.extend(job, lease));
|
|
202
|
-
}, Math.max(1e3, lease * 1e3 / 2)) : void 0;
|
|
203
212
|
try {
|
|
204
213
|
const payload = await validate(schemaOf(job.queue), job.payload, "payload");
|
|
205
214
|
if (!payload.ok) {
|
|
@@ -219,15 +228,17 @@ function createJobs(source, queues) {
|
|
|
219
228
|
await fail(job, cause);
|
|
220
229
|
workOptions.onError?.(typeof cause === "object" && cause !== null && "kind" in cause ? cause : toDbError(cause), job);
|
|
221
230
|
return false;
|
|
222
|
-
} finally {
|
|
223
|
-
clearInterval(heartbeat);
|
|
224
231
|
}
|
|
225
232
|
};
|
|
226
233
|
const loop = async (queue, handler, workOptions, forever) => {
|
|
227
234
|
const concurrency = Math.max(1, workOptions.concurrency ?? 1);
|
|
235
|
+
const lease = workOptions.lease ?? 300;
|
|
236
|
+
const firstWait = workOptions.pollInterval ?? 1e3;
|
|
237
|
+
const maxWait = Math.max(firstWait, workOptions.maxPollInterval ?? 3e4);
|
|
228
238
|
let succeeded = 0;
|
|
229
239
|
let failed = 0;
|
|
230
240
|
const lanes = Array.from({ length: concurrency }, async () => {
|
|
241
|
+
let wait = firstWait;
|
|
231
242
|
while (!workOptions.signal?.aborted) {
|
|
232
243
|
const claimed = await claim(queue, {
|
|
233
244
|
...workOptions,
|
|
@@ -236,11 +247,22 @@ function createJobs(source, queues) {
|
|
|
236
247
|
if (!claimed.ok) throw new TypeError(claimed.error.message, { cause: claimed.error });
|
|
237
248
|
if (claimed.data.length === 0) {
|
|
238
249
|
if (!forever) return;
|
|
239
|
-
await sleep(
|
|
250
|
+
await sleep(wait, workOptions.signal);
|
|
251
|
+
wait = Math.min(maxWait, wait * 2);
|
|
240
252
|
continue;
|
|
241
253
|
}
|
|
242
|
-
|
|
243
|
-
|
|
254
|
+
wait = firstWait;
|
|
255
|
+
const held = new Set(claimed.data);
|
|
256
|
+
const timer = heartbeat(held, lease);
|
|
257
|
+
try {
|
|
258
|
+
for (const job of claimed.data) {
|
|
259
|
+
if (await handle(job, handler, workOptions)) succeeded += 1;
|
|
260
|
+
else failed += 1;
|
|
261
|
+
held.delete(job);
|
|
262
|
+
}
|
|
263
|
+
} finally {
|
|
264
|
+
clearInterval(timer);
|
|
265
|
+
}
|
|
244
266
|
}
|
|
245
267
|
});
|
|
246
268
|
await Promise.all(lanes);
|
|
@@ -254,7 +276,7 @@ function createJobs(source, queues) {
|
|
|
254
276
|
return AsyncResult.from(async () => {
|
|
255
277
|
const valid = await validate(schemaOf(queue), payload, "payload");
|
|
256
278
|
if (!valid.ok) return valid;
|
|
257
|
-
const delay = enqueueOptions.delay ?? (enqueueOptions.runAt ? Math.max(0, Math.ceil((enqueueOptions.runAt.
|
|
279
|
+
const delay = enqueueOptions.delay ?? (enqueueOptions.runAt ? Math.max(0, Math.ceil((enqueueOptions.runAt.epochMilliseconds - nowInstant().epochMilliseconds) / 1e3)) : 0);
|
|
258
280
|
return run(() => transport.send(queue, valid.data, delay, enqueueOptions.maxAttempts ?? 5, enqueueOptions.dedupeKey));
|
|
259
281
|
});
|
|
260
282
|
},
|
|
@@ -435,7 +457,7 @@ function createInbox(sql, options) {
|
|
|
435
457
|
payload: row.payload,
|
|
436
458
|
headers: row.headers,
|
|
437
459
|
attempts: row.attempts,
|
|
438
|
-
receivedAt:
|
|
460
|
+
receivedAt: toInstant(row.received_at)
|
|
439
461
|
};
|
|
440
462
|
try {
|
|
441
463
|
const outcome = await handler(message);
|
|
@@ -19,7 +19,8 @@ function scalarKind(column) {
|
|
|
19
19
|
values: column.enum
|
|
20
20
|
};
|
|
21
21
|
if (column.json) return { kind: "json" };
|
|
22
|
-
if (column.codec === "
|
|
22
|
+
if (column.codec === "instant") return { kind: "instant" };
|
|
23
|
+
if (column.codec === "plainDateTime") return { kind: "plainDateTime" };
|
|
23
24
|
if (column.codec === "bigint") return { kind: "bigint" };
|
|
24
25
|
if (column.codec === "string") return { kind: "string" };
|
|
25
26
|
if (column.type === "uuid") return { kind: "uuid" };
|
|
@@ -64,7 +65,7 @@ function variantsFor(table) {
|
|
|
64
65
|
];
|
|
65
66
|
}
|
|
66
67
|
function tableEntries(input) {
|
|
67
|
-
return Object.entries(input.meta.tables).sort(([a], [b]) => a
|
|
68
|
+
return Object.entries(input.meta.tables).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
68
69
|
}
|
|
69
70
|
function propertyKey(name) {
|
|
70
71
|
return /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name);
|
|
@@ -107,10 +108,14 @@ function scalar(kind) {
|
|
|
107
108
|
type: "string",
|
|
108
109
|
format: "date"
|
|
109
110
|
};
|
|
110
|
-
case "
|
|
111
|
+
case "instant": return {
|
|
111
112
|
type: "string",
|
|
112
113
|
format: "date-time"
|
|
113
114
|
};
|
|
115
|
+
case "plainDateTime": return {
|
|
116
|
+
type: "string",
|
|
117
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$"
|
|
118
|
+
};
|
|
114
119
|
case "bigint": return {
|
|
115
120
|
type: "string",
|
|
116
121
|
pattern: "^-?\\d+$"
|
package/dist/lint/index.js
CHANGED
|
@@ -16,7 +16,7 @@ function receiverName(node) {
|
|
|
16
16
|
return receiver.property.name;
|
|
17
17
|
}
|
|
18
18
|
/** Matches `order_items`, `orderItems` and `public.order_items` alike. */
|
|
19
|
-
const tableKey = (name) => (name.split(".").at(-1) ?? name).
|
|
19
|
+
const tableKey = (name) => (name.split(".").at(-1) ?? name).replaceAll("_", "").toLowerCase();
|
|
20
20
|
function keyName(property) {
|
|
21
21
|
if (property.computed) return void 0;
|
|
22
22
|
if (property.key.type === "Identifier") return property.key.name;
|
package/dist/list/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ListPage, c as
|
|
2
|
-
export { FacetCounts, FacetInfo, ListDefinition, ListExtra, ListPage, ListParseResult, ListParsers, ListQuery, ListQueryConfig, ListQueryInput, ListSearchParams, OpenApiParameter, ParserSpec, UNSET, defineListQuery };
|
|
1
|
+
import { a as ListPage, c as ListParsers, d as ListQueryInput, f as ListSearchParams, g as defineListQuery, h as UNSET, i as ListExtra, l as ListQuery, m as ParserSpec, n as FacetInfo, o as ListPagination, p as OpenApiParameter, r as ListDefinition, s as ListParseResult, t as FacetCounts, u as ListQueryConfig } from "../index-BAy4tsAP.js";
|
|
2
|
+
export { type FacetCounts, type FacetInfo, type ListDefinition, type ListExtra, type ListPage, type ListPagination, type ListParseResult, type ListParsers, type ListQuery, type ListQueryConfig, type ListQueryInput, type ListSearchParams, type OpenApiParameter, type ParserSpec, UNSET, defineListQuery };
|
package/dist/list/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
//#region src/list/
|
|
1
|
+
//#region src/list/list-query.ts
|
|
2
2
|
/** Facet value meaning "not set": filters with `is null`. */
|
|
3
3
|
const UNSET = "__unset__";
|
|
4
4
|
const RESERVED = /* @__PURE__ */ new Set([
|
|
5
5
|
"q",
|
|
6
6
|
"sort",
|
|
7
7
|
"page",
|
|
8
|
+
"after",
|
|
8
9
|
"size"
|
|
9
10
|
]);
|
|
10
11
|
function first(value) {
|
|
@@ -13,8 +14,9 @@ function first(value) {
|
|
|
13
14
|
function all(value) {
|
|
14
15
|
return (typeof value === "string" ? [value] : [...value ?? []]).flatMap((entry) => entry.split(",")).map((entry) => entry.trim()).filter(Boolean);
|
|
15
16
|
}
|
|
17
|
+
const isParamValue = (value) => value === void 0 || typeof value === "string" || Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
16
18
|
function isSearchParams(value) {
|
|
17
|
-
return value instanceof URLSearchParams || !("facets" in value && typeof value.facets === "object");
|
|
19
|
+
return value instanceof URLSearchParams || !("facets" in value && typeof value.facets === "object") && Object.values(value).every(isParamValue);
|
|
18
20
|
}
|
|
19
21
|
function readRecord(input) {
|
|
20
22
|
if (!(input instanceof URLSearchParams)) return input;
|
|
@@ -33,7 +35,7 @@ function toInt(raw) {
|
|
|
33
35
|
* OpenAPI parameters and a JSON Schema derived from the same definition.
|
|
34
36
|
*
|
|
35
37
|
* ```ts
|
|
36
|
-
* export const customerList = defineListQuery(
|
|
38
|
+
* export const customerList = defineListQuery(betterSupabase, 'customers', {
|
|
37
39
|
* search: ['name', 'kvk'],
|
|
38
40
|
* facets: { status: 'status' },
|
|
39
41
|
* sorts: { name: { name: 'asc' }, newest: [{ createdAt: 'desc' }, { id: 'asc' }] },
|
|
@@ -41,12 +43,13 @@ function toInt(raw) {
|
|
|
41
43
|
* });
|
|
42
44
|
* ```
|
|
43
45
|
*/
|
|
44
|
-
function defineListQuery(
|
|
45
|
-
const meta =
|
|
46
|
+
function defineListQuery(betterSupabase, table, config) {
|
|
47
|
+
const meta = betterSupabase.meta.tables[table];
|
|
46
48
|
if (!meta) throw new TypeError(`defineListQuery: unknown table "${table}"`);
|
|
47
49
|
const pageSize = config.pageSize ?? 50;
|
|
48
50
|
const maxPageSize = config.maxPageSize ?? 200;
|
|
49
51
|
const maxSearch = config.maxSearchLength ?? 200;
|
|
52
|
+
const cursor = config.pagination === "cursor";
|
|
50
53
|
const sortKeys = Object.keys(config.sorts);
|
|
51
54
|
const facetEntries = Object.entries(config.facets ?? {});
|
|
52
55
|
for (const [key, column] of facetEntries) {
|
|
@@ -96,6 +99,18 @@ function defineListQuery(sb, table, config) {
|
|
|
96
99
|
message: "Must be a whole number of at least 1",
|
|
97
100
|
path: ["page"]
|
|
98
101
|
});
|
|
102
|
+
else if (cursor && page !== 1) issues.push({
|
|
103
|
+
message: "This list pages with `after`, not `page`",
|
|
104
|
+
path: ["page"]
|
|
105
|
+
});
|
|
106
|
+
let after;
|
|
107
|
+
if (raw.after !== void 0 && raw.after !== "") {
|
|
108
|
+
if (cursor && typeof raw.after === "string") after = raw.after;
|
|
109
|
+
else issues.push({
|
|
110
|
+
message: cursor ? "Must be text" : "This list pages with `page`, not `after`",
|
|
111
|
+
path: ["after"]
|
|
112
|
+
});
|
|
113
|
+
}
|
|
99
114
|
const size = raw.size === void 0 || raw.size === "" ? pageSize : toInt(raw.size);
|
|
100
115
|
if (size === void 0 || !Number.isInteger(size) || size < 1 || size > maxPageSize) issues.push({
|
|
101
116
|
message: `Must be a whole number from 1 to ${String(maxPageSize)}`,
|
|
@@ -121,6 +136,7 @@ function defineListQuery(sb, table, config) {
|
|
|
121
136
|
...q ? { q } : {},
|
|
122
137
|
sort,
|
|
123
138
|
page: page ?? 1,
|
|
139
|
+
...after ? { after } : {},
|
|
124
140
|
size: size ?? pageSize,
|
|
125
141
|
facets: facetValues
|
|
126
142
|
}
|
|
@@ -143,6 +159,7 @@ function defineListQuery(sb, table, config) {
|
|
|
143
159
|
q: first(record["q"]),
|
|
144
160
|
sort: first(record["sort"]),
|
|
145
161
|
page: first(record["page"]),
|
|
162
|
+
after: first(record["after"]),
|
|
146
163
|
size: first(record["size"]),
|
|
147
164
|
facets: facetValues
|
|
148
165
|
});
|
|
@@ -160,6 +177,7 @@ function defineListQuery(sb, table, config) {
|
|
|
160
177
|
q: typed.q,
|
|
161
178
|
sort: typed.sort,
|
|
162
179
|
page: typed.page,
|
|
180
|
+
after: typed.after,
|
|
163
181
|
size: typed.size,
|
|
164
182
|
facets: rawFacets
|
|
165
183
|
});
|
|
@@ -195,12 +213,15 @@ function defineListQuery(sb, table, config) {
|
|
|
195
213
|
}
|
|
196
214
|
function args(query) {
|
|
197
215
|
const filter = where(query);
|
|
216
|
+
const paging = cursor ? { after: query.after ?? null } : {
|
|
217
|
+
page: query.page,
|
|
218
|
+
count: config.count ?? "exact"
|
|
219
|
+
};
|
|
198
220
|
return {
|
|
199
221
|
...filter ? { where: filter } : {},
|
|
200
222
|
orderBy: config.sorts[query.sort],
|
|
201
|
-
page: query.page,
|
|
202
223
|
size: query.size,
|
|
203
|
-
|
|
224
|
+
...paging
|
|
204
225
|
};
|
|
205
226
|
}
|
|
206
227
|
/** Whether a group's value passes the facet's selected values. */
|
|
@@ -249,6 +270,10 @@ function defineListQuery(sb, table, config) {
|
|
|
249
270
|
serialize: (value) => value
|
|
250
271
|
},
|
|
251
272
|
page: intParser,
|
|
273
|
+
after: {
|
|
274
|
+
parse: (value) => value || null,
|
|
275
|
+
serialize: (value) => value
|
|
276
|
+
},
|
|
252
277
|
size: intParser,
|
|
253
278
|
...Object.fromEntries(facets.map((facet) => [facet.key, listParser]))
|
|
254
279
|
};
|
|
@@ -261,8 +286,102 @@ function defineListQuery(sb, table, config) {
|
|
|
261
286
|
uniqueItems: true
|
|
262
287
|
});
|
|
263
288
|
const searchDescription = config.search ? Array.isArray(config.search) ? `Case-insensitive search in ${config.search.join(", ")}.` : "Full-text search (web search syntax)." : void 0;
|
|
289
|
+
const openapi = [
|
|
290
|
+
...searchDescription ? [{
|
|
291
|
+
name: "q",
|
|
292
|
+
in: "query",
|
|
293
|
+
required: false,
|
|
294
|
+
description: searchDescription,
|
|
295
|
+
schema: {
|
|
296
|
+
type: "string",
|
|
297
|
+
maxLength: maxSearch
|
|
298
|
+
}
|
|
299
|
+
}] : [],
|
|
300
|
+
{
|
|
301
|
+
name: "sort",
|
|
302
|
+
in: "query",
|
|
303
|
+
required: false,
|
|
304
|
+
description: `Ordering. Default \`${config.defaultSort}\`.`,
|
|
305
|
+
schema: {
|
|
306
|
+
type: "string",
|
|
307
|
+
enum: sortKeys,
|
|
308
|
+
default: config.defaultSort
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
cursor ? {
|
|
312
|
+
name: "after",
|
|
313
|
+
in: "query",
|
|
314
|
+
required: false,
|
|
315
|
+
description: "`nextCursor` of the previous page. Leave it out for the first page.",
|
|
316
|
+
schema: { type: "string" }
|
|
317
|
+
} : {
|
|
318
|
+
name: "page",
|
|
319
|
+
in: "query",
|
|
320
|
+
required: false,
|
|
321
|
+
description: "1-based page number.",
|
|
322
|
+
schema: {
|
|
323
|
+
type: "integer",
|
|
324
|
+
minimum: 1,
|
|
325
|
+
default: 1
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
name: "size",
|
|
330
|
+
in: "query",
|
|
331
|
+
required: false,
|
|
332
|
+
description: "Page size.",
|
|
333
|
+
schema: {
|
|
334
|
+
type: "integer",
|
|
335
|
+
minimum: 1,
|
|
336
|
+
maximum: maxPageSize,
|
|
337
|
+
default: pageSize
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
...facets.map((facet) => ({
|
|
341
|
+
name: facet.key,
|
|
342
|
+
in: "query",
|
|
343
|
+
required: false,
|
|
344
|
+
description: `Filter on ${facet.column}. Comma-separated; any value matches.${facet.nullable ? ` \`${UNSET}\` matches empty.` : ""}`,
|
|
345
|
+
schema: facetSchema(facet),
|
|
346
|
+
style: "form",
|
|
347
|
+
explode: false
|
|
348
|
+
}))
|
|
349
|
+
];
|
|
350
|
+
const jsonSchema = {
|
|
351
|
+
type: "object",
|
|
352
|
+
additionalProperties: false,
|
|
353
|
+
properties: {
|
|
354
|
+
...searchDescription ? { q: {
|
|
355
|
+
type: "string",
|
|
356
|
+
maxLength: maxSearch,
|
|
357
|
+
description: searchDescription
|
|
358
|
+
} } : {},
|
|
359
|
+
sort: {
|
|
360
|
+
type: "string",
|
|
361
|
+
enum: sortKeys,
|
|
362
|
+
default: config.defaultSort
|
|
363
|
+
},
|
|
364
|
+
...cursor ? { after: { type: "string" } } : { page: {
|
|
365
|
+
type: "integer",
|
|
366
|
+
minimum: 1,
|
|
367
|
+
default: 1
|
|
368
|
+
} },
|
|
369
|
+
size: {
|
|
370
|
+
type: "integer",
|
|
371
|
+
minimum: 1,
|
|
372
|
+
maximum: maxPageSize,
|
|
373
|
+
default: pageSize
|
|
374
|
+
},
|
|
375
|
+
...facets.length > 0 ? { facets: {
|
|
376
|
+
type: "object",
|
|
377
|
+
additionalProperties: false,
|
|
378
|
+
properties: Object.fromEntries(facets.map((facet) => [facet.key, facetSchema(facet)]))
|
|
379
|
+
} } : {}
|
|
380
|
+
}
|
|
381
|
+
};
|
|
264
382
|
return {
|
|
265
383
|
table,
|
|
384
|
+
pagination: config.pagination ?? "offset",
|
|
266
385
|
defaults,
|
|
267
386
|
facets,
|
|
268
387
|
parse,
|
|
@@ -279,7 +398,8 @@ function defineListQuery(sb, table, config) {
|
|
|
279
398
|
if (query.q) params.set("q", query.q);
|
|
280
399
|
if (query.sort && query.sort !== config.defaultSort) params.set("sort", query.sort);
|
|
281
400
|
if (query.page && query.page !== 1) params.set("page", String(query.page));
|
|
282
|
-
if (query.
|
|
401
|
+
if (query.after) params.set("after", query.after);
|
|
402
|
+
if (query.size !== void 0 && query.size > 0 && query.size !== pageSize) params.set("size", String(query.size));
|
|
283
403
|
for (const facet of facets) {
|
|
284
404
|
const values = query.facets?.[facet.key];
|
|
285
405
|
if (values && values.length > 0) params.set(facet.key, values.join(","));
|
|
@@ -297,7 +417,7 @@ function defineListQuery(sb, table, config) {
|
|
|
297
417
|
const page = repository.paginate({
|
|
298
418
|
...extra,
|
|
299
419
|
...base,
|
|
300
|
-
count: count ?? base["count"],
|
|
420
|
+
...cursor ? {} : { count: count ?? base["count"] },
|
|
301
421
|
...combined ? { where: combined } : {}
|
|
302
422
|
});
|
|
303
423
|
if (!config.facetCounts) return page;
|
|
@@ -317,93 +437,8 @@ function defineListQuery(sb, table, config) {
|
|
|
317
437
|
facetCounts: marginals(rows, query)
|
|
318
438
|
})));
|
|
319
439
|
},
|
|
320
|
-
openapi
|
|
321
|
-
|
|
322
|
-
name: "q",
|
|
323
|
-
in: "query",
|
|
324
|
-
required: false,
|
|
325
|
-
description: searchDescription,
|
|
326
|
-
schema: {
|
|
327
|
-
type: "string",
|
|
328
|
-
maxLength: maxSearch
|
|
329
|
-
}
|
|
330
|
-
}] : [],
|
|
331
|
-
{
|
|
332
|
-
name: "sort",
|
|
333
|
-
in: "query",
|
|
334
|
-
required: false,
|
|
335
|
-
description: `Ordering. Default \`${config.defaultSort}\`.`,
|
|
336
|
-
schema: {
|
|
337
|
-
type: "string",
|
|
338
|
-
enum: sortKeys,
|
|
339
|
-
default: config.defaultSort
|
|
340
|
-
}
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
name: "page",
|
|
344
|
-
in: "query",
|
|
345
|
-
required: false,
|
|
346
|
-
description: "1-based page number.",
|
|
347
|
-
schema: {
|
|
348
|
-
type: "integer",
|
|
349
|
-
minimum: 1,
|
|
350
|
-
default: 1
|
|
351
|
-
}
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
name: "size",
|
|
355
|
-
in: "query",
|
|
356
|
-
required: false,
|
|
357
|
-
description: "Page size.",
|
|
358
|
-
schema: {
|
|
359
|
-
type: "integer",
|
|
360
|
-
minimum: 1,
|
|
361
|
-
maximum: maxPageSize,
|
|
362
|
-
default: pageSize
|
|
363
|
-
}
|
|
364
|
-
},
|
|
365
|
-
...facets.map((facet) => ({
|
|
366
|
-
name: facet.key,
|
|
367
|
-
in: "query",
|
|
368
|
-
required: false,
|
|
369
|
-
description: `Filter on ${facet.column}. Comma-separated; any value matches.${facet.nullable ? ` \`${UNSET}\` matches empty.` : ""}`,
|
|
370
|
-
schema: facetSchema(facet),
|
|
371
|
-
style: "form",
|
|
372
|
-
explode: false
|
|
373
|
-
}))
|
|
374
|
-
],
|
|
375
|
-
jsonSchema: {
|
|
376
|
-
type: "object",
|
|
377
|
-
additionalProperties: false,
|
|
378
|
-
properties: {
|
|
379
|
-
...searchDescription ? { q: {
|
|
380
|
-
type: "string",
|
|
381
|
-
maxLength: maxSearch,
|
|
382
|
-
description: searchDescription
|
|
383
|
-
} } : {},
|
|
384
|
-
sort: {
|
|
385
|
-
type: "string",
|
|
386
|
-
enum: sortKeys,
|
|
387
|
-
default: config.defaultSort
|
|
388
|
-
},
|
|
389
|
-
page: {
|
|
390
|
-
type: "integer",
|
|
391
|
-
minimum: 1,
|
|
392
|
-
default: 1
|
|
393
|
-
},
|
|
394
|
-
size: {
|
|
395
|
-
type: "integer",
|
|
396
|
-
minimum: 1,
|
|
397
|
-
maximum: maxPageSize,
|
|
398
|
-
default: pageSize
|
|
399
|
-
},
|
|
400
|
-
...facets.length > 0 ? { facets: {
|
|
401
|
-
type: "object",
|
|
402
|
-
additionalProperties: false,
|
|
403
|
-
properties: Object.fromEntries(facets.map((facet) => [facet.key, facetSchema(facet)]))
|
|
404
|
-
} } : {}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
440
|
+
openapi,
|
|
441
|
+
jsonSchema
|
|
407
442
|
};
|
|
408
443
|
}
|
|
409
444
|
//#endregion
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { A as SchemaMeta, N as TableKey, O as Row, n as AnyModels, t as AnyFunctions, x as PermdockTopicPolicy } from "./types-
|
|
2
|
-
import { b as ValidationIssue, o as Result, p as DbError, t as AsyncResult } from "./result-
|
|
3
|
-
import { Z as QuerySpec, t as BetterSupabase } from "./define-
|
|
1
|
+
import { A as SchemaMeta, N as TableKey, O as Row, n as AnyModels, t as AnyFunctions, x as PermdockTopicPolicy } from "./types-DONv9SHN.js";
|
|
2
|
+
import { b as ValidationIssue, o as Result, p as DbError, t as AsyncResult } from "./result-CqEsbgYs.js";
|
|
3
|
+
import { Z as QuerySpec, t as BetterSupabase } from "./define-CRS2MRV3.js";
|
|
4
|
+
import { t as PermdockCatalog } from "./permdock-sql-DImJULY-.js";
|
|
4
5
|
import { n as TemplateValues, t as TemplateParams } from "./template-mbvlysOo.js";
|
|
5
6
|
import { RealtimeChannel, SupabaseClient } from "@supabase/supabase-js";
|
|
6
7
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
7
|
-
//#region src/realtime/
|
|
8
|
+
//#region src/realtime/topic.d.ts
|
|
8
9
|
type EventSchemas = Readonly<Record<string, StandardSchemaV1>>;
|
|
9
10
|
interface TopicOptions<E extends EventSchemas> {
|
|
10
11
|
/** Name used for generated policies and functions. Defaults to the template's literal parts. */
|
|
@@ -34,9 +35,15 @@ interface TopicOptions<E extends EventSchemas> {
|
|
|
34
35
|
* The helpers check role and scope only. Use this just for permissions
|
|
35
36
|
* whose grants have no row conditions beyond the scope: for a permission
|
|
36
37
|
* with row conditions (e.g. `authorId = principal.id`) every member of the
|
|
37
|
-
* scope
|
|
38
|
+
* scope could join. Pass `catalog` to refuse those keys here;
|
|
39
|
+
* `better-supabase doctor` (BS214) refuses them from the catalog file.
|
|
38
40
|
*/
|
|
39
41
|
readonly permdock?: PermdockTopicPolicy;
|
|
42
|
+
/**
|
|
43
|
+
* PermDock's `permissions.catalog.json`. With it, a `permdock` policy
|
|
44
|
+
* naming a permission with `rowConditions: true` throws.
|
|
45
|
+
*/
|
|
46
|
+
readonly catalog?: PermdockCatalog;
|
|
40
47
|
/** Let clients broadcast on the topic, not only receive. Defaults to `false`. */
|
|
41
48
|
readonly send?: boolean;
|
|
42
49
|
/** Also authorize presence. Defaults to `false`. */
|
|
@@ -71,13 +78,16 @@ interface Subscription extends Disposable, AsyncDisposable {
|
|
|
71
78
|
readonly ready: Promise<void>;
|
|
72
79
|
unsubscribe(): Promise<void>;
|
|
73
80
|
}
|
|
74
|
-
type RealtimeClient = Pick<SupabaseClient, "channel" | "removeChannel" | "realtime">;
|
|
81
|
+
type RealtimeClient = Pick<SupabaseClient, "channel" | "getChannels" | "removeChannel" | "realtime">;
|
|
75
82
|
interface TriggerOptions<M extends AnyModels, T extends keyof M, P extends string> {
|
|
76
83
|
/** Column that fills each placeholder. */
|
|
77
84
|
readonly values: { readonly [K in TemplateParams<P>]: Extract<keyof Row<M, T>, string>; };
|
|
78
85
|
/** Defaults to all three. */
|
|
79
86
|
readonly events?: readonly ("insert" | "update" | "delete")[];
|
|
80
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Schema for the generated function. Defaults to `better_supabase`, which
|
|
89
|
+
* the Data API does not expose.
|
|
90
|
+
*/
|
|
81
91
|
readonly functionSchema?: string;
|
|
82
92
|
}
|
|
83
93
|
interface RowChange<R> {
|
|
@@ -96,7 +106,7 @@ interface Topic<P extends string, E extends EventSchemas> {
|
|
|
96
106
|
/** `realtime.messages` policies for this topic. Idempotent. */
|
|
97
107
|
sql(): string;
|
|
98
108
|
/** A trigger that broadcasts row changes (`realtime.broadcast_changes`) to this topic. */
|
|
99
|
-
triggerSql<M extends AnyModels, D, F extends AnyFunctions, X, T extends TableKey<M>>(
|
|
109
|
+
triggerSql<M extends AnyModels, D, F extends AnyFunctions, X, T extends TableKey<M>>(betterSupabase: BetterSupabase<M, D, F, X>, table: T, options: TriggerOptions<M, T, P>): string;
|
|
100
110
|
subscribe(client: RealtimeClient, values: TemplateValues<P>, handlers: TopicHandlers<E>, options?: SubscribeOptions): Subscription;
|
|
101
111
|
/** Sends over HTTP, without joining the channel. */
|
|
102
112
|
send<K extends TopicEvent<E>>(client: RealtimeClient, values: TemplateValues<P>, event: K, payload: TopicPayload<E, K>): AsyncResult<void>;
|
|
@@ -117,10 +127,10 @@ declare function defineTopic<const P extends string, const E extends EventSchema
|
|
|
117
127
|
* Reads a `realtime.broadcast_changes` message as an app-cased row change.
|
|
118
128
|
* Returns `null` for messages about other tables.
|
|
119
129
|
*/
|
|
120
|
-
declare function rowChange<M extends AnyModels, D, F extends AnyFunctions, X, T extends TableKey<M>>(
|
|
130
|
+
declare function rowChange<M extends AnyModels, D, F extends AnyFunctions, X, T extends TableKey<M>>(betterSupabase: BetterSupabase<M, D, F, X>, table: T, message: TopicMessage): RowChange<Row<M, T>> | null;
|
|
121
131
|
//#endregion
|
|
122
132
|
//#region src/realtime/live.d.ts
|
|
123
|
-
/** What `liveQuery` needs from `
|
|
133
|
+
/** What `liveQuery` needs from `betterSupabase`: metadata and the tables a spec reads. */
|
|
124
134
|
interface LiveSource {
|
|
125
135
|
readonly meta: SchemaMeta;
|
|
126
136
|
tablesOf(spec: QuerySpec): string[];
|
|
@@ -144,7 +154,7 @@ interface LiveSubscription extends Disposable, AsyncDisposable {
|
|
|
144
154
|
}
|
|
145
155
|
/**
|
|
146
156
|
* A count from the server plus the spec to keep it live on the client:
|
|
147
|
-
* `
|
|
157
|
+
* `bs.liveCount(spec)` makes one, `useLiveCount(seed)` reads it. `count`
|
|
148
158
|
* is `null` when the server read failed; the client then fetches it.
|
|
149
159
|
*/
|
|
150
160
|
interface LiveCountSeed<T extends string = string> {
|
|
@@ -160,11 +170,11 @@ declare function liveTopic(meta: SchemaMeta, table: string, tenant?: string): st
|
|
|
160
170
|
* table, so any number of them can run at once.
|
|
161
171
|
*
|
|
162
172
|
* ```ts
|
|
163
|
-
* using live = liveQuery(
|
|
173
|
+
* using live = liveQuery(betterSupabase, supabase, spec, { onChange: () => refetch() });
|
|
164
174
|
* ```
|
|
165
175
|
*/
|
|
166
|
-
declare function liveQuery(
|
|
167
|
-
/** What `liveCount` runs the spec with: a `db` from `
|
|
176
|
+
declare function liveQuery(betterSupabase: LiveSource, client: RealtimeClient, spec: QuerySpec | readonly string[], options: LiveQueryOptions): LiveSubscription;
|
|
177
|
+
/** What `liveCount` runs the spec with: a `db` from `betterSupabase.connect()` or `createClient()`. */
|
|
168
178
|
interface CountRunner {
|
|
169
179
|
$run(spec: QuerySpec): PromiseLike<Result<unknown>>;
|
|
170
180
|
}
|
|
@@ -181,11 +191,11 @@ interface LiveCountOptions extends Omit<LiveQueryOptions, "onChange"> {
|
|
|
181
191
|
* Responses that arrive out of order are dropped.
|
|
182
192
|
*
|
|
183
193
|
* ```ts
|
|
184
|
-
* using live = liveCount(
|
|
194
|
+
* using live = liveCount(betterSupabase, supabase, db, betterSupabase.spec.notes.count(), {
|
|
185
195
|
* onCount: (count) => render(count),
|
|
186
196
|
* });
|
|
187
197
|
* ```
|
|
188
198
|
*/
|
|
189
|
-
declare function liveCount(
|
|
199
|
+
declare function liveCount(betterSupabase: LiveSource, client: RealtimeClient, db: CountRunner, spec: QuerySpec<string, "count", number>, options: LiveCountOptions): LiveSubscription;
|
|
190
200
|
//#endregion
|
|
191
201
|
export { defineTopic as C, TriggerOptions as S, TopicEvent as _, LiveSource as a, TopicOptions as b, liveQuery as c, RealtimeClient as d, RowChange as f, Topic as g, SubscriptionStatus as h, LiveQueryOptions as i, liveTopic as l, Subscription as m, LiveCountOptions as n, LiveSubscription as o, SubscribeOptions as p, LiveCountSeed as r, liveCount as s, CountRunner as t, EventSchemas as u, TopicHandlers as v, rowChange as w, TopicPayload as x, TopicMessage as y };
|