better-supabase 0.3.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 +7 -6
- package/bin/better-supabase.js +4 -0
- package/dist/{base64-CQeB1eSf.js → base64-D2gsioCY.js} +2 -2
- package/dist/claims-BAf6c7is.js +48 -0
- package/dist/cli/_format-Cax5EsM9.js +101 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +48 -0
- 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 +493 -0
- package/dist/cli/index.js +184 -0
- 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/cli/version-5mW_8sY1.js +4 -0
- package/dist/cli/yaml-CYCbJ6et.js +2252 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +13 -13
- package/dist/{compiler-2zqGzxVZ.d.ts → compiler-DB3aSFOA.d.ts} +2 -2
- package/dist/config/index.js +4 -4
- package/dist/{config-Be4GwsqI.js → config-BpxDfnbg.js} +1 -1
- package/dist/{config-DOsGYSiT.js → config-CbvFmGD8.js} +1 -1
- package/dist/{define-DF341GDj.js → define-Bh0AqTik.js} +160 -79
- package/dist/{define-DUbydmJa.d.ts → define-CRS2MRV3.d.ts} +32 -28
- package/dist/edge/index.d.ts +8 -12
- package/dist/edge/index.js +50 -24
- package/dist/{entitlements-DvJXoI02.d.ts → entitlements-Dm-FHpNH.d.ts} +2 -2
- package/dist/{errors-Bl3rkOzo.js → errors-L0xK41y_.js} +1 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.js +4 -4
- package/dist/{events-Do8jXh4D.d.ts → events-B21UOhvP.d.ts} +4 -4
- package/dist/{executor-DynmIWhq.d.ts → executor-B5IoUxLE.d.ts} +1 -1
- package/dist/{executor-C57jx2pn.js → executor-CVt6dD0B.js} +3 -3
- package/dist/{executor-B26lgbHD.d.ts → executor-CZ7ImRiD.d.ts} +2 -2
- package/dist/hono/index.d.ts +16 -23
- package/dist/hono/index.js +10 -10
- package/dist/{index-CTTMS6_1.d.ts → index-528Ugmyp.d.ts} +12 -3
- package/dist/{index-CADlNHK-.d.ts → index-BAy4tsAP.d.ts} +5 -5
- package/dist/{index-BNsABq7P.d.ts → index-BBdvo-5d.d.ts} +23 -25
- package/dist/{index-qriRM9cZ.d.ts → index-BhHEC04r.d.ts} +3 -3
- package/dist/{index-GV77NpRP.d.ts → index-D5IfUIDh.d.ts} +3 -3
- package/dist/{index-CriFFJ_p.d.ts → index-DFmOpBGC.d.ts} +11 -11
- package/dist/{index-UJ-LUxtI.d.ts → index-RlLXd8dL.d.ts} +12 -12
- package/dist/index.d.ts +15 -15
- package/dist/index.js +13 -13
- package/dist/{invalidate-DbxuL2jL.js → invalidate-CgxmRamI.js} +7 -1
- package/dist/jobs/index.d.ts +10 -4
- package/dist/jobs/index.js +32 -16
- package/dist/{json-schema--aOXAGfU.js → json-schema-DP6V7cbr.js} +1 -1
- package/dist/list/index.d.ts +1 -1
- package/dist/list/index.js +3 -3
- package/dist/{live-QE3UPbGm.d.ts → live-BHakSWWo.d.ts} +12 -12
- package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
- package/dist/lookup-BaP5bI27.js +18 -0
- package/dist/mcp/index.d.ts +18 -18
- package/dist/mcp/index.js +23 -18
- package/dist/{mfa-x3V3vGh-.d.ts → mfa-C7MNQ1Ob.d.ts} +1 -1
- package/dist/{mfa-BxoR1RkN.js → mfa-byfjruR9.js} +118 -29
- package/dist/next/image/index.js +6 -3
- package/dist/next/index.d.ts +38 -35
- package/dist/next/index.js +41 -33
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +6 -6
- package/dist/orpc/index.d.ts +17 -20
- package/dist/orpc/index.js +11 -11
- package/dist/otel/index.d.ts +5 -5
- package/dist/otel/index.js +81 -62
- package/dist/{permdock-sql-Bta_G0v-.js → permdock-sql-C4KFzLc9.js} +1 -1
- package/dist/{plugin-DVRB8qNE.d.ts → plugin-bNhvJwRh.d.ts} +2 -2
- 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 +42 -12
- package/dist/plugins/soft-delete/index.d.ts +2 -2
- package/dist/plugins/soft-delete/index.js +2 -2
- package/dist/plugins/tenant/index.d.ts +2 -2
- package/dist/plugins/tenant/index.js +10 -4
- package/dist/plugins/timestamps/index.d.ts +1 -1
- package/dist/plugins/timestamps/index.js +1 -1
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/plugins/validation/index.js +3 -3
- package/dist/{pool-B9qsLyFR.d.ts → pool-DFwEQwmN.d.ts} +11 -4
- package/dist/postgres/index.d.ts +5 -5
- package/dist/postgres/index.js +3 -2
- package/dist/{postgrest-DmBlevh-.d.ts → postgrest-Bc-0Xw62.d.ts} +1 -1
- package/dist/{problem-CGt1ADix.js → problem-BihjPR0t.js} +1 -1
- package/dist/{problem-Z2RTQjZD.d.ts → problem-U8UEKccv.d.ts} +1 -1
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +2 -2
- package/dist/{query-BdKLTPlj.js → query-BMMSWbI7.js} +18 -18
- package/dist/react/index.d.ts +6 -6
- package/dist/react/index.js +1 -1
- package/dist/react/server.d.ts +5 -5
- package/dist/react/server.js +3 -3
- package/dist/react/session.d.ts +4 -4
- package/dist/react/session.js +2 -2
- package/dist/{react-DNBYNazu.js → react-CQHMaESR.js} +39 -39
- package/dist/{read-set-D0qBcboM.js → read-set-FWK8qQ58.js} +50 -15
- package/dist/realtime/index.d.ts +1 -1
- package/dist/realtime/index.js +13 -12
- package/dist/{index-kpgopLNv.d.ts → refresh-BwYkyNOQ.d.ts} +6 -3
- package/dist/{resolve-BRciX2jK.d.ts → resolve-BAqQcwMW.d.ts} +15 -10
- package/dist/{resource-CwVgiI5q.d.ts → resource-BJcaIfxi.d.ts} +5 -5
- package/dist/{resource-D30rp0GN.js → resource-My_y-Syh.js} +6 -6
- package/dist/{respond-DAkPIdTH.d.ts → respond-DgIbdrt8.d.ts} +31 -12
- package/dist/{result-DWXatkd6.js → result-Bj6yt33D.js} +2 -2
- package/dist/{result-c2OYgCV2.d.ts → result-CqEsbgYs.d.ts} +3 -3
- package/dist/server/index.d.ts +14 -14
- package/dist/server/index.js +12 -12
- package/dist/{respond-C44EZAJo.js → server-BA75B0mT.js} +139 -100
- package/dist/{shared-_6-uPL7E.js → shared-DnoCdMDr.js} +4 -3
- package/dist/{simplify-LakqK1vH.js → simplify-Cqvfr9dj.js} +67 -24
- package/dist/sql/index.d.ts +1 -1
- package/dist/sql/index.js +7 -7
- package/dist/{sql-BIgk12ew.js → sql-B34HU2DI.js} +3 -2
- 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-eudBiRk1.d.ts → standard-BsaCYQJc.d.ts} +1 -1
- package/dist/{stats-D78UQ8Yu.js → stats-C_YxA2r1.js} +33 -8
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +26 -8
- package/dist/{tables-Dhha3BXM.js → tables-Cb-3_VWc.js} +14 -0
- package/dist/{temporal-required-CMxeSVPo.js → temporal-required-CBNHT6ni.js} +1 -1
- package/dist/testing/index.d.ts +20 -21
- package/dist/testing/index.js +45 -45
- package/dist/{version-BfpG2gks.js → version-Bmf7_FzM.js} +1 -1
- package/dist/{view-3Po_PVlr.d.ts → view-B64o81wp.d.ts} +5 -5
- package/dist/{view-wZ-9qIUz.js → view-BrJI2LKp.js} +1 -1
- package/dist/webhooks/index.d.ts +3 -3
- package/dist/webhooks/index.js +1 -1
- package/dist/{webhooks-CAIFQSTM.js → webhooks-Bh_Jf_-l.js} +37 -18
- package/package.json +36 -4
- package/skills/better-supabase/SKILL.md +57 -10
- package/skills/better-supabase/references/plugins.md +7 -11
- package/skills/better-supabase/references/troubleshooting.md +24 -4
- package/skills/better-supabase-api/SKILL.md +66 -18
- package/skills/better-supabase-api/references/adapters.md +44 -26
- 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 +58 -4
- package/dist/claims-CoTobNC-.js +0 -25
package/dist/client/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { AuthSnapshot, AuthUser,
|
|
1
|
+
import { a as ClientOptions, i as ClientAuth, n as AuthUser, o as createClient, r as BetterClient, t as AuthSnapshot } from "../index-RlLXd8dL.js";
|
|
2
|
+
export { AuthSnapshot, AuthUser, BetterClient, ClientAuth, ClientOptions, createClient };
|
package/dist/client/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { n as decodeJwtPayload } from "../base64-
|
|
1
|
+
import { n as decodeJwtPayload } from "../base64-D2gsioCY.js";
|
|
2
2
|
import { EnvValidationError, parseEnv } from "../env/index.js";
|
|
3
|
-
import { t as createQueries } from "../query-
|
|
3
|
+
import { t as createQueries } from "../query-BMMSWbI7.js";
|
|
4
4
|
import { createBrowserClient } from "@supabase/ssr";
|
|
5
|
-
import { createClient } from "@supabase/supabase-js";
|
|
5
|
+
import { createClient as createClient$1 } from "@supabase/supabase-js";
|
|
6
6
|
//#region src/client/index.ts
|
|
7
7
|
const LOADING = {
|
|
8
8
|
status: "loading",
|
|
@@ -49,13 +49,13 @@ function contextOf(snapshot) {
|
|
|
49
49
|
}
|
|
50
50
|
function clientFor(options) {
|
|
51
51
|
if (options.client) return options.client;
|
|
52
|
-
if (!options.env) throw new TypeError("
|
|
52
|
+
if (!options.env) throw new TypeError("createClient needs `env` ({ url, publishableKey }) or `client`");
|
|
53
53
|
const checked = parseEnv({
|
|
54
54
|
SUPABASE_URL: options.env.url,
|
|
55
55
|
SUPABASE_PUBLISHABLE_KEY: options.env.publishableKey
|
|
56
56
|
});
|
|
57
57
|
if (!checked.ok) throw new EnvValidationError(checked.issues);
|
|
58
|
-
if (options.storage === "local") return createClient(checked.env.url, checked.env.publishableKey);
|
|
58
|
+
if (options.storage === "local") return createClient$1(checked.env.url, checked.env.publishableKey);
|
|
59
59
|
return createBrowserClient(checked.env.url, checked.env.publishableKey);
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
@@ -63,10 +63,10 @@ function clientFor(options) {
|
|
|
63
63
|
* session, TanStack Query options and an auth store for UI state.
|
|
64
64
|
*
|
|
65
65
|
* ```ts
|
|
66
|
-
* export const
|
|
66
|
+
* export const bs = createClient(betterSupabase, { env: { url, publishableKey } });
|
|
67
67
|
* ```
|
|
68
68
|
*/
|
|
69
|
-
function
|
|
69
|
+
function createClient(betterSupabase, options = {}) {
|
|
70
70
|
const supabase = clientFor(options);
|
|
71
71
|
let snapshot = LOADING;
|
|
72
72
|
let db;
|
|
@@ -78,14 +78,14 @@ function createBrowser(sb, options = {}) {
|
|
|
78
78
|
db = void 0;
|
|
79
79
|
for (const listener of listeners) listener();
|
|
80
80
|
});
|
|
81
|
-
const
|
|
82
|
-
|
|
81
|
+
const client = {
|
|
82
|
+
betterSupabase,
|
|
83
83
|
supabase,
|
|
84
84
|
get db() {
|
|
85
|
-
db ??=
|
|
85
|
+
db ??= betterSupabase.connect(supabase, contextOf(snapshot));
|
|
86
86
|
return db;
|
|
87
87
|
},
|
|
88
|
-
queries: createQueries(
|
|
88
|
+
queries: createQueries(betterSupabase, () => client.db),
|
|
89
89
|
auth: {
|
|
90
90
|
current: () => snapshot,
|
|
91
91
|
subscribe: (listener) => {
|
|
@@ -96,7 +96,7 @@ function createBrowser(sb, options = {}) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
};
|
|
99
|
-
return
|
|
99
|
+
return client;
|
|
100
100
|
}
|
|
101
101
|
//#endregion
|
|
102
|
-
export {
|
|
102
|
+
export { createClient };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as Operation } from "./executor-
|
|
2
|
-
import { i as PostgrestPlan } from "./postgrest-
|
|
1
|
+
import { g as Operation } from "./executor-B5IoUxLE.js";
|
|
2
|
+
import { i as PostgrestPlan } from "./postgrest-Bc-0Xw62.js";
|
|
3
3
|
//#region src/core/compiler.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Turns an IR operation into something a backend runs. An `Executor` for a
|
package/dist/config/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as tenantClaimPaths, t as DEFAULT_CLAIMS } from "../claims-
|
|
2
|
-
import { i as resolveJsonSchema, n as defineConfig, r as resolveConfig, t as CONFIG_SCHEMA_URL } from "../config-
|
|
3
|
-
import { n as jsonSchema, t as buildJsonSchema } from "../json-schema
|
|
4
|
-
import { n as valibot, t as zod } from "../config-
|
|
1
|
+
import { i as tenantClaimPaths, t as DEFAULT_CLAIMS } from "../claims-BAf6c7is.js";
|
|
2
|
+
import { i as resolveJsonSchema, n as defineConfig, r as resolveConfig, t as CONFIG_SCHEMA_URL } from "../config-BpxDfnbg.js";
|
|
3
|
+
import { n as jsonSchema, t as buildJsonSchema } from "../json-schema-DP6V7cbr.js";
|
|
4
|
+
import { n as valibot, t as zod } from "../config-CbvFmGD8.js";
|
|
5
5
|
export { CONFIG_SCHEMA_URL, DEFAULT_CLAIMS, buildJsonSchema, defineConfig, jsonSchema, resolveConfig, resolveJsonSchema, tenantClaimPaths, valibot, zod };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as parseImport, c as schemaName, d as variantsFor, i as fieldsFor, l as siblingPath, o as propertyKey, r as HEADER, s as rowType, u as tableEntries } from "./json-schema
|
|
1
|
+
import { a as parseImport, c as schemaName, d as variantsFor, i as fieldsFor, l as siblingPath, o as propertyKey, r as HEADER, s as rowType, u as tableEntries } from "./json-schema-DP6V7cbr.js";
|
|
2
2
|
//#region src/generators/valibot.ts
|
|
3
3
|
function scalar$1(kind) {
|
|
4
4
|
switch (kind.kind) {
|
|
@@ -1,15 +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
|
|
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";
|
|
3
4
|
import { n as nowInstant } from "./temporal-BwshQk0W.js";
|
|
4
5
|
import { i as or, n as column, r as not, t as and } from "./types-6cYK9pbJ.js";
|
|
5
|
-
import { i as ok, n as err, o as toDbError, s as withErrorMapper, t as AsyncResult } from "./result-
|
|
6
|
-
import { t as invalidationTargets } from "./tables-
|
|
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";
|
|
7
8
|
import { t as consoleLogger } from "./logger-glM28NVN.js";
|
|
8
9
|
import { r as orderPlugins } from "./plugin-BqR6wKMB.js";
|
|
9
|
-
import { a as postgrestExecutor, n as StatsRecorder, r as recordStats } from "./stats-
|
|
10
|
-
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-
|
|
11
|
-
import { a as toBase64Url, t as base64ToText } from "./base64-
|
|
12
|
-
import { t as validate } from "./standard-
|
|
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";
|
|
13
14
|
//#region src/core/batch.ts
|
|
14
15
|
/**
|
|
15
16
|
* Holds operations until each of `readers` has either submitted one or
|
|
@@ -95,12 +96,18 @@ function memoryCache() {
|
|
|
95
96
|
}
|
|
96
97
|
//#endregion
|
|
97
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
|
+
}
|
|
98
104
|
/**
|
|
99
105
|
* Observers only: a handler that throws is reported to the logger and never
|
|
100
106
|
* changes a result.
|
|
101
107
|
*/
|
|
102
108
|
var EventHub = class {
|
|
103
109
|
#handlers = /* @__PURE__ */ new Map();
|
|
110
|
+
#warned = /* @__PURE__ */ new Set();
|
|
104
111
|
logger;
|
|
105
112
|
constructor(logger = consoleLogger) {
|
|
106
113
|
this.logger = logger;
|
|
@@ -112,6 +119,10 @@ var EventHub = class {
|
|
|
112
119
|
this.#handlers.set(name, set);
|
|
113
120
|
}
|
|
114
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
|
+
}
|
|
115
126
|
return () => {
|
|
116
127
|
set.delete(handler);
|
|
117
128
|
};
|
|
@@ -170,11 +181,28 @@ const KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
|
170
181
|
"_min",
|
|
171
182
|
"_max"
|
|
172
183
|
]);
|
|
184
|
+
const NO_OPTIONS = Object.freeze({});
|
|
173
185
|
function optionsOf(args) {
|
|
174
|
-
if (!args) return
|
|
175
|
-
|
|
176
|
-
for (const
|
|
177
|
-
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";
|
|
178
206
|
}
|
|
179
207
|
function signalOf(args) {
|
|
180
208
|
const signal = args?.["signal"];
|
|
@@ -187,8 +215,10 @@ function mutationKind(op) {
|
|
|
187
215
|
/** Runs operations through plugins, the executor and the event hub. */
|
|
188
216
|
var OperationRunner = class {
|
|
189
217
|
runtime;
|
|
218
|
+
#hooks;
|
|
190
219
|
constructor(runtime) {
|
|
191
220
|
this.runtime = runtime;
|
|
221
|
+
this.#hooks = hooksOf(runtime.plugins);
|
|
192
222
|
}
|
|
193
223
|
hookArgs(table, options) {
|
|
194
224
|
return {
|
|
@@ -201,20 +231,27 @@ var OperationRunner = class {
|
|
|
201
231
|
}
|
|
202
232
|
async run(op, options, signal) {
|
|
203
233
|
const { runtime } = this;
|
|
204
|
-
const
|
|
234
|
+
const hooks = this.#hooks;
|
|
205
235
|
let current = op;
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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;
|
|
212
251
|
}
|
|
213
|
-
} catch (cause) {
|
|
214
|
-
if (cause instanceof DbException) return this.fail(op.table, cause.error);
|
|
215
|
-
throw cause;
|
|
216
252
|
}
|
|
217
|
-
const
|
|
253
|
+
const timed = runtime.events.has("query");
|
|
254
|
+
const started = timed ? performance.now() : 0;
|
|
218
255
|
const context = signal ? {
|
|
219
256
|
signal,
|
|
220
257
|
errorMappers: runtime.errorMappers
|
|
@@ -225,7 +262,7 @@ var OperationRunner = class {
|
|
|
225
262
|
if (executed.ok && selection && needsDecoding(selection)) try {
|
|
226
263
|
result = ok({
|
|
227
264
|
...executed.data,
|
|
228
|
-
rows: decodeRows(selection, executed.data.rows)
|
|
265
|
+
rows: decodeRows(selection, executed.data.rows, true)
|
|
229
266
|
});
|
|
230
267
|
} catch (cause) {
|
|
231
268
|
if (cause instanceof DbException) return this.fail(op.table, cause.error);
|
|
@@ -240,7 +277,7 @@ var OperationRunner = class {
|
|
|
240
277
|
maxRows: runtime.maxRows
|
|
241
278
|
});
|
|
242
279
|
}
|
|
243
|
-
if (
|
|
280
|
+
if (timed) runtime.events.emit("query", {
|
|
244
281
|
table: op.table.key,
|
|
245
282
|
operation: current.kind,
|
|
246
283
|
ok: result.ok,
|
|
@@ -254,21 +291,22 @@ var OperationRunner = class {
|
|
|
254
291
|
}
|
|
255
292
|
async afterMutation(op, data) {
|
|
256
293
|
const { runtime } = this;
|
|
294
|
+
const plugins = this.#hooks.afterMutation;
|
|
295
|
+
const listening = runtime.events.has("mutation");
|
|
296
|
+
if (plugins.length === 0 && !listening) return;
|
|
257
297
|
const event = {
|
|
258
298
|
table: op.table,
|
|
259
299
|
kind: mutationKind(op),
|
|
260
300
|
rows: data.rows,
|
|
261
301
|
context: runtime.context
|
|
262
302
|
};
|
|
263
|
-
for (const plugin of
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
runtime.events.logger.error(`plugin "${plugin.name}" afterMutation threw`, { cause });
|
|
269
|
-
}
|
|
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 });
|
|
270
308
|
}
|
|
271
|
-
runtime.events.emit("mutation", {
|
|
309
|
+
if (listening) runtime.events.emit("mutation", {
|
|
272
310
|
table: op.table.key,
|
|
273
311
|
kind: event.kind,
|
|
274
312
|
rows: event.rows,
|
|
@@ -280,7 +318,7 @@ var OperationRunner = class {
|
|
|
280
318
|
...error,
|
|
281
319
|
table: table.key
|
|
282
320
|
};
|
|
283
|
-
this.runtime.events.emit("error", {
|
|
321
|
+
if (this.runtime.events.has("error")) this.runtime.events.emit("error", {
|
|
284
322
|
table: table.key,
|
|
285
323
|
error: withTable
|
|
286
324
|
});
|
|
@@ -306,19 +344,22 @@ function createRepository(runner, table) {
|
|
|
306
344
|
});
|
|
307
345
|
const returning = (args) => args?.["returning"] === false ? void 0 : selection(args);
|
|
308
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
|
+
}));
|
|
309
353
|
const notFound = () => runner.fail(table, dbError("not_found", `No ${table.key} row matched`));
|
|
310
354
|
const base = {
|
|
311
|
-
$
|
|
355
|
+
$tableName: table.key,
|
|
312
356
|
$meta: table,
|
|
313
357
|
findMany(args) {
|
|
314
358
|
return AsyncResult.from(async () => {
|
|
315
359
|
const op = selectOp(args);
|
|
316
360
|
const ordered = op.orderBy.length > 0 || table.primaryKey.length === 0 ? op : {
|
|
317
361
|
...op,
|
|
318
|
-
orderBy:
|
|
319
|
-
column,
|
|
320
|
-
direction: "asc"
|
|
321
|
-
}))
|
|
362
|
+
orderBy: defaultOrder()
|
|
322
363
|
};
|
|
323
364
|
const result = await run(ordered, args);
|
|
324
365
|
return result.ok ? ok(result.data.rows) : result;
|
|
@@ -567,7 +608,8 @@ function createRepository(runner, table) {
|
|
|
567
608
|
if (typeof args["after"] === "string") {
|
|
568
609
|
const values = decodeCursor(args["after"]);
|
|
569
610
|
if (!values || values.length !== orderBy.length) return runner.fail(table, dbError("invalid_request", "Invalid cursor"));
|
|
570
|
-
|
|
611
|
+
const { byDb } = lookupOf(table);
|
|
612
|
+
after = keysetCondition(orderBy, values, (name) => byDb.get(name)?.[1].nullable ?? true);
|
|
571
613
|
}
|
|
572
614
|
const op = selectOp(args, {
|
|
573
615
|
selection: withSort,
|
|
@@ -581,7 +623,8 @@ function createRepository(runner, table) {
|
|
|
581
623
|
const rows = result.data.rows.slice(0, size);
|
|
582
624
|
const hasMore = result.data.rows.length > size;
|
|
583
625
|
const last = rows.at(-1);
|
|
584
|
-
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;
|
|
585
628
|
return ok({
|
|
586
629
|
items: added.length > 0 ? rows.map((row) => strip(row, added)) : rows,
|
|
587
630
|
nextCursor,
|
|
@@ -601,14 +644,17 @@ function createRepository(runner, table) {
|
|
|
601
644
|
}
|
|
602
645
|
function ensureColumns(base, orderBy) {
|
|
603
646
|
const columns = [...base.columns];
|
|
647
|
+
const selected = new Set(columns.map((entry) => entry.column));
|
|
648
|
+
const { byDb } = lookupOf(table);
|
|
604
649
|
const added = [];
|
|
605
650
|
for (const term of orderBy) {
|
|
606
|
-
if (
|
|
607
|
-
const alias =
|
|
651
|
+
if (selected.has(term.column)) continue;
|
|
652
|
+
const alias = byDb.get(term.column)?.[0] ?? term.column;
|
|
608
653
|
columns.push({
|
|
609
654
|
alias,
|
|
610
655
|
column: term.column
|
|
611
656
|
});
|
|
657
|
+
selected.add(term.column);
|
|
612
658
|
added.push(alias);
|
|
613
659
|
}
|
|
614
660
|
return {
|
|
@@ -621,12 +667,9 @@ function createRepository(runner, table) {
|
|
|
621
667
|
}
|
|
622
668
|
return base;
|
|
623
669
|
}
|
|
624
|
-
function aliasOf(selection, column) {
|
|
625
|
-
return selection.columns.find((entry) => entry.column === column)?.alias ?? column;
|
|
626
|
-
}
|
|
627
670
|
function strip(row, keys) {
|
|
628
|
-
const copy = {
|
|
629
|
-
for (const key
|
|
671
|
+
const copy = {};
|
|
672
|
+
for (const key in row) if (!keys.includes(key) && Object.hasOwn(row, key)) copy[key] = row[key];
|
|
630
673
|
return copy;
|
|
631
674
|
}
|
|
632
675
|
/**
|
|
@@ -644,13 +687,21 @@ function byKey(rows, columns) {
|
|
|
644
687
|
const b = String(right);
|
|
645
688
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
646
689
|
};
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
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]);
|
|
650
700
|
if (order !== 0) return order;
|
|
651
701
|
}
|
|
652
702
|
return 0;
|
|
653
703
|
});
|
|
704
|
+
return keyed.map((entry) => entry.row);
|
|
654
705
|
}
|
|
655
706
|
/**
|
|
656
707
|
* The rows after the cursor `values` in `orderBy` order, as an OR of ANDs:
|
|
@@ -716,7 +767,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
716
767
|
* A token that fails it resolves to `{ kind: 'invalid', reason: 'claims' }`.
|
|
717
768
|
*
|
|
718
769
|
* ```ts
|
|
719
|
-
* const
|
|
770
|
+
* const betterSupabase = defineSupabase(schema).claims(z.object({ tenant_id: z.uuid() }));
|
|
720
771
|
* ```
|
|
721
772
|
*/
|
|
722
773
|
claims(schema) {
|
|
@@ -734,7 +785,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
734
785
|
* the verified claims, never from `profile`.
|
|
735
786
|
*
|
|
736
787
|
* ```ts
|
|
737
|
-
* const
|
|
788
|
+
* const betterSupabase = defineSupabase(schema).userMetadata(z.object({ display_name: z.string() }));
|
|
738
789
|
* ```
|
|
739
790
|
*/
|
|
740
791
|
userMetadata(schema) {
|
|
@@ -749,7 +800,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
749
800
|
* Results themselves keep their `DbError`.
|
|
750
801
|
*
|
|
751
802
|
* ```ts
|
|
752
|
-
* const
|
|
803
|
+
* const betterSupabase = defineSupabase(schema).mapError((error) => new AppError(error));
|
|
753
804
|
* ```
|
|
754
805
|
*/
|
|
755
806
|
mapError(mapper) {
|
|
@@ -760,9 +811,14 @@ var BetterSupabase = class BetterSupabase {
|
|
|
760
811
|
}
|
|
761
812
|
#specs;
|
|
762
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();
|
|
763
819
|
/**
|
|
764
820
|
* Builds serializable `QuerySpec`s with the same arguments and result types
|
|
765
|
-
* as the repository: `
|
|
821
|
+
* as the repository: `betterSupabase.spec.customers.findMany({ select: ['id'] })`.
|
|
766
822
|
*/
|
|
767
823
|
get spec() {
|
|
768
824
|
this.#specs ??= createSpecs(this.meta);
|
|
@@ -783,7 +839,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
783
839
|
* invalidate them after it succeeds.
|
|
784
840
|
*
|
|
785
841
|
* ```ts
|
|
786
|
-
*
|
|
842
|
+
* betterSupabase.defineRpc('archive_customer', { invalidates: ['customers', 'notes'] });
|
|
787
843
|
* ```
|
|
788
844
|
*/
|
|
789
845
|
defineRpc(name, options) {
|
|
@@ -842,10 +898,10 @@ var BetterSupabase = class BetterSupabase {
|
|
|
842
898
|
let executor = base;
|
|
843
899
|
for (const plugin of plugins) if (plugin.wrapExecutor) executor = plugin.wrapExecutor(executor);
|
|
844
900
|
executor = recordStats(executor, recorder);
|
|
845
|
-
const errorMappers =
|
|
901
|
+
const errorMappers = this.#errorMappersFor(plugins);
|
|
846
902
|
const runner = new OperationRunner({
|
|
847
903
|
meta: this.meta,
|
|
848
|
-
builder:
|
|
904
|
+
builder: builderFor(this.meta),
|
|
849
905
|
executor,
|
|
850
906
|
plugins,
|
|
851
907
|
context,
|
|
@@ -855,7 +911,13 @@ var BetterSupabase = class BetterSupabase {
|
|
|
855
911
|
maxRows: this.options.maxRows ?? 1e3,
|
|
856
912
|
truncatedTables: this.#truncatedTables
|
|
857
913
|
});
|
|
858
|
-
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, {
|
|
859
921
|
$client: client,
|
|
860
922
|
$executor: executor,
|
|
861
923
|
$context: context,
|
|
@@ -923,10 +985,10 @@ var BetterSupabase = class BetterSupabase {
|
|
|
923
985
|
hint: `Add "${table.schema}.${table.name}" to vectorSearch in better-supabase.config.ts and run \`better-supabase sql sync\`.`
|
|
924
986
|
}) : result;
|
|
925
987
|
})
|
|
926
|
-
};
|
|
988
|
+
});
|
|
927
989
|
const many = (specs, signal, usePlugins) => AsyncResult.from(async () => {
|
|
928
990
|
const invalid = specs.findIndex((spec) => !isQuerySpec(spec));
|
|
929
|
-
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`));
|
|
930
992
|
const active = usePlugins ? plugins : [];
|
|
931
993
|
const batch = base.batch?.bind(base);
|
|
932
994
|
const batching = batch && specs.length > 1 ? batchingExecutor({
|
|
@@ -974,21 +1036,6 @@ var BetterSupabase = class BetterSupabase {
|
|
|
974
1036
|
"$many",
|
|
975
1037
|
"$search"
|
|
976
1038
|
]) db[name] = mapThrows(db[name], throwAs);
|
|
977
|
-
for (const [key, table] of Object.entries(this.meta.tables)) {
|
|
978
|
-
let repository;
|
|
979
|
-
Object.defineProperty(db, key, {
|
|
980
|
-
enumerable: true,
|
|
981
|
-
get: () => {
|
|
982
|
-
if (!repository) {
|
|
983
|
-
repository = this.#repository(runner, key, table, plugins);
|
|
984
|
-
if (throwAs) {
|
|
985
|
-
for (const [name, method] of Object.entries(repository)) if (typeof method === "function" && name !== "extend") repository[name] = mapThrows(method, throwAs);
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
return repository;
|
|
989
|
-
}
|
|
990
|
-
});
|
|
991
|
-
}
|
|
992
1039
|
return db;
|
|
993
1040
|
}
|
|
994
1041
|
/**
|
|
@@ -1015,12 +1062,45 @@ var BetterSupabase = class BetterSupabase {
|
|
|
1015
1062
|
count: entry.count ?? null
|
|
1016
1063
|
}));
|
|
1017
1064
|
}
|
|
1018
|
-
}, 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);
|
|
1019
1066
|
if (!result.ok) return result;
|
|
1020
1067
|
out[key] = result.data;
|
|
1021
1068
|
}
|
|
1022
1069
|
return ok(out);
|
|
1023
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
|
+
}
|
|
1024
1104
|
#repository(runner, key, table, plugins) {
|
|
1025
1105
|
const repository = createRepository(runner, table);
|
|
1026
1106
|
for (const plugin of plugins) {
|
|
@@ -1041,6 +1121,7 @@ var BetterSupabase = class BetterSupabase {
|
|
|
1041
1121
|
return repository;
|
|
1042
1122
|
}
|
|
1043
1123
|
};
|
|
1124
|
+
const dbStates = /* @__PURE__ */ new WeakMap();
|
|
1044
1125
|
function mapThrows(method, throwAs) {
|
|
1045
1126
|
return function(...args) {
|
|
1046
1127
|
const value = method.apply(this, args);
|
|
@@ -1048,7 +1129,7 @@ function mapThrows(method, throwAs) {
|
|
|
1048
1129
|
};
|
|
1049
1130
|
}
|
|
1050
1131
|
function runSpec(db, spec, signal) {
|
|
1051
|
-
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"));
|
|
1052
1133
|
const method = db[spec.table]?.[spec.method];
|
|
1053
1134
|
if (!method) return AsyncResult.err(dbError("invalid_request", `Unknown table "${spec.table}" in QuerySpec`));
|
|
1054
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)"));
|
|
@@ -1081,7 +1162,7 @@ function rpc(executor, errorMappers, name, rest) {
|
|
|
1081
1162
|
* Creates the data-layer definition from the generated `schema`.
|
|
1082
1163
|
*
|
|
1083
1164
|
* ```ts
|
|
1084
|
-
* export const
|
|
1165
|
+
* export const betterSupabase = defineSupabase(schema).use(timestamps()).use(softDelete());
|
|
1085
1166
|
* ```
|
|
1086
1167
|
*/
|
|
1087
1168
|
function defineSupabase(schema, options) {
|