better-supabase 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/bin/better-supabase.js +4 -0
- package/dist/{base64-CQeB1eSf.js → base64-D2gsioCY.js} +2 -2
- package/dist/channel-FQW-CnGR.d.ts +70 -0
- 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/codemod-DqV7612m.js +388 -0
- package/dist/cli/command-CK14fP91.js +502 -0
- package/dist/cli/compare-BmIWVEui.js +9 -0
- package/dist/cli/config-CPVpXP5I.js +1965 -0
- package/dist/cli/config-dtoekM0v.js +2 -0
- package/dist/cli/db-DOBPt660.js +52 -0
- package/dist/cli/diff-SjkO5rNr.js +752 -0
- package/dist/cli/dist-DBPdlPYK.js +1112 -0
- package/dist/cli/dist-DreZ24Sz.js +129 -0
- package/dist/cli/dist-xn4wlboc.js +732 -0
- package/dist/cli/doctor-L7Z8mYTx.js +2863 -0
- package/dist/cli/env-DmKv_G4A.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-BJc9vdyu.js +2 -0
- package/dist/cli/gen-C2osRcr5.js +2204 -0
- package/dist/cli/index.d.ts +493 -0
- package/dist/cli/index.js +184 -0
- package/dist/cli/init-Saf5-R9T.js +550 -0
- package/dist/cli/introspect--H7oGmcd.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-Cp5Fyta-.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-BfMQcKy8.js +289 -0
- package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
- package/dist/cli/run-BKR2W_79.js +351 -0
- package/dist/cli/seed-CUlqWh-8.js +98 -0
- package/dist/cli/skills-LJJIhLFR.js +137 -0
- package/dist/cli/sql-DzPbfngx.js +348 -0
- package/dist/cli/style-C0NFdJRL.js +29 -0
- package/dist/cli/toml-DB-MNnFs.js +424 -0
- package/dist/cli/version-BDJuO0UR.js +4 -0
- package/dist/cli/yaml-CYCbJ6et.js +2252 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +15 -22
- package/dist/clone-BfgmLU90.js +21 -0
- package/dist/{compiler-2zqGzxVZ.d.ts → compiler-BXH_aZ7N.d.ts} +2 -2
- package/dist/config/index.d.ts +4 -4
- package/dist/config/index.js +5 -5
- package/dist/{config-DOsGYSiT.js → config-DreERlKo.js} +1 -1
- package/dist/{config-C1CYcm6o.d.ts → config-T_ejwyd3.d.ts} +176 -11
- package/dist/{define-DUbydmJa.d.ts → define-Bp_BZa5h.d.ts} +37 -29
- package/dist/{define-DF341GDj.js → define-cNKzqwL_.js} +356 -89
- package/dist/edge/index.d.ts +20 -13
- package/dist/edge/index.js +55 -26
- package/dist/{entitlements-DvJXoI02.d.ts → entitlements-DUxU4oHe.d.ts} +2 -2
- package/dist/env/index.d.ts +2 -2
- package/dist/env/index.js +34 -1
- package/dist/{errors-Bl3rkOzo.js → errors-DtwXa6b8.js} +2 -1
- package/dist/events/index.d.ts +3 -2
- package/dist/events/index.js +69 -16
- package/dist/events-aIO7vsIk.d.ts +230 -0
- package/dist/executor-BunPOO-k.d.ts +402 -0
- package/dist/{executor-B26lgbHD.d.ts → executor-Cghdstwu.d.ts} +1 -2
- package/dist/{executor-C57jx2pn.js → executor-XycESQPH.js} +3 -3
- package/dist/hono/index.d.ts +27 -23
- package/dist/hono/index.js +46 -11
- package/dist/impersonation-VfaGc4Q_.js +41 -0
- package/dist/{index-BNsABq7P.d.ts → index-BGdgBPdf.d.ts} +66 -25
- package/dist/{index-qriRM9cZ.d.ts → index-C7f8cOBM.d.ts} +4 -4
- package/dist/{index-Dy6kuF0P.d.ts → index-CLg87OBW.d.ts} +6 -1
- package/dist/{index-GV77NpRP.d.ts → index-DOESKG27.d.ts} +34 -9
- package/dist/{index-CriFFJ_p.d.ts → index-DgILJRXj.d.ts} +43 -17
- package/dist/{index-UJ-LUxtI.d.ts → index-DmXSxbLi.d.ts} +14 -14
- package/dist/{index-Cf-D2jk1.d.ts → index-Dxn2a5cw.d.ts} +2 -2
- package/dist/{index-CTTMS6_1.d.ts → index-SaTsEfGP.d.ts} +86 -9
- package/dist/{index-CADlNHK-.d.ts → index-fag8VJZ2.d.ts} +5 -6
- package/dist/index.d.ts +34 -17
- package/dist/index.js +15 -14
- package/dist/jobs/index.d.ts +147 -95
- package/dist/jobs/index.js +773 -250
- package/dist/{json-schema--aOXAGfU.js → json-schema-m1fiwKgN.js} +23 -2
- package/dist/kit-events-CTFDfSwb.js +60 -0
- package/dist/kit-transport-B82k1djG.d.ts +33 -0
- package/dist/kit-transport-DJlHQUBU.js +55 -0
- package/dist/{config-Be4GwsqI.js → kits-CGLLrNPd.js} +38 -10
- package/dist/list/index.d.ts +1 -1
- package/dist/list/index.js +3 -3
- package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
- package/dist/{live-QE3UPbGm.d.ts → live-D9W2M5aO.d.ts} +16 -15
- package/dist/lookup-BaP5bI27.js +18 -0
- package/dist/mcp/index.d.ts +39 -22
- package/dist/mcp/index.js +39 -25
- package/dist/{mfa-x3V3vGh-.d.ts → mfa-CusDgPaD.d.ts} +5 -1
- package/dist/next/image/index.js +6 -3
- package/dist/next/index.d.ts +60 -36
- package/dist/next/index.js +167 -50
- package/dist/notifications/index.d.ts +162 -0
- package/dist/notifications/index.js +264 -0
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +6 -6
- package/dist/orgs/index.d.ts +132 -0
- package/dist/orgs/index.js +245 -0
- package/dist/orpc/index.d.ts +37 -20
- package/dist/orpc/index.js +24 -11
- package/dist/otel/index.d.ts +24 -5
- package/dist/otel/index.js +124 -64
- package/dist/permdock-sql-C2Inc6Xc.d.ts +29 -0
- package/dist/permdock-sql-DgOfeixi.js +51 -0
- package/dist/plugin-DwARMuQp.js +59 -0
- package/dist/{plugin-DVRB8qNE.d.ts → plugin-o144f322.d.ts} +17 -5
- package/dist/plugins/actor/index.d.ts +5 -2
- package/dist/plugins/actor/index.js +22 -8
- package/dist/plugins/rules/index.d.ts +2 -2
- package/dist/plugins/rules/index.js +52 -17
- package/dist/plugins/soft-delete/index.d.ts +3 -3
- package/dist/plugins/soft-delete/index.js +14 -5
- package/dist/plugins/tenant/index.d.ts +3 -3
- package/dist/plugins/tenant/index.js +45 -21
- package/dist/plugins/timestamps/index.d.ts +1 -1
- package/dist/plugins/timestamps/index.js +4 -3
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/plugins/validation/index.js +26 -6
- package/dist/{pool-B9qsLyFR.d.ts → pool-C9voM4Kw.d.ts} +24 -6
- package/dist/postgres/index.d.ts +5 -5
- package/dist/postgres/index.js +20 -10
- package/dist/{postgrest-DmBlevh-.d.ts → postgrest-CruYKAvV.d.ts} +1 -1
- package/dist/{problem-CGt1ADix.js → problem-BW1KhzSG.js} +2 -1
- package/dist/{problem-Z2RTQjZD.d.ts → problem-Blxe8S31.d.ts} +1 -1
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +3 -3
- package/dist/{query-BdKLTPlj.js → query-CCbo44lG.js} +18 -18
- package/dist/queue-BYUCjr59.d.ts +252 -0
- package/dist/react/index.d.ts +8 -7
- package/dist/react/index.js +4 -3
- package/dist/react/server.d.ts +16 -5
- package/dist/react/server.js +12 -4
- package/dist/react/session.d.ts +10 -4
- package/dist/react/session.js +11 -3
- package/dist/{react-DNBYNazu.js → react-C_s7kiNz.js} +138 -46
- package/dist/{read-set-D0qBcboM.js → read-set-DQFt1N_Y.js} +71 -15
- package/dist/realtime/index.d.ts +3 -3
- package/dist/realtime/index.js +14 -12
- package/dist/{index-kpgopLNv.d.ts → refresh-BTrQ_ZTp.d.ts} +6 -3
- package/dist/{resolve-BRciX2jK.d.ts → resolve-C15TJq77.d.ts} +22 -11
- package/dist/{resource-D30rp0GN.js → resource-CRxxwkQq.js} +24 -9
- package/dist/{resource-CwVgiI5q.d.ts → resource-D8iqWMr-.d.ts} +6 -6
- package/dist/respond-D2OQl62-.d.ts +371 -0
- package/dist/{result-DWXatkd6.js → result-BKiliPY7.js} +2 -2
- package/dist/server/index.d.ts +17 -15
- package/dist/server/index.js +16 -22
- package/dist/server-Csx2sRjg.js +655 -0
- package/dist/{shared-_6-uPL7E.js → shared-D1dRUrAg.js} +19 -4
- package/dist/signers-Cc6r98SW.d.ts +162 -0
- package/dist/{simplify-LakqK1vH.js → simplify-_0oUKqCd.js} +27 -95
- package/dist/sql/index.d.ts +247 -10
- package/dist/sql/index.js +8591 -780
- package/dist/{sql-BIgk12ew.js → sql-Coh6n4cC.js} +11 -3
- package/dist/ssr/index.d.ts +4 -4
- package/dist/ssr/index.js +1 -2
- package/dist/{standard-FUi3Z3-7.js → standard-D7r6dMUu.js} +6 -3
- package/dist/{standard-eudBiRk1.d.ts → standard-J4YgMOLm.d.ts} +1 -1
- package/dist/{stats-D78UQ8Yu.js → stats-Bqob3WqT.js} +34 -9
- package/dist/storage/index.d.ts +4 -4
- package/dist/storage/index.js +174 -27
- package/dist/support-DT-OhSxD.d.ts +88 -0
- package/dist/support-Dk6vdmEw.js +291 -0
- package/dist/support-view-Da5peKFg.d.ts +17 -0
- package/dist/support-view-g4YLBeqX.js +18 -0
- package/dist/{tables-Dhha3BXM.js → tables-Cb-3_VWc.js} +14 -0
- package/dist/{permdock-sql-Bta_G0v-.js → template-TxrGI5jR.js} +2 -31
- package/dist/{temporal-BwshQk0W.js → temporal-CVlIV2DZ.js} +17 -4
- package/dist/{temporal-required-CMxeSVPo.js → temporal-required-CAt4Dc9Z.js} +2 -2
- package/dist/testing/index.d.ts +113 -24
- package/dist/testing/index.js +375 -47
- package/dist/{types-DONv9SHN.d.ts → types-Dnf_wRDz.d.ts} +26 -3
- package/dist/user-change-CHFEUro1.js +49 -0
- package/dist/{webhooks-CAIFQSTM.js → verify-Ce49ETPz.js} +38 -19
- package/dist/{version-BfpG2gks.js → version-DM_Roffb.js} +1 -1
- package/dist/{view-3Po_PVlr.d.ts → view-BEf0diC5.d.ts} +10 -5
- package/dist/{mfa-BxoR1RkN.js → view-Bq64ki8-.js} +210 -64
- package/dist/webhooks/index.d.ts +136 -5
- package/dist/webhooks/index.js +588 -2
- package/dist/wire-D2dT86vi.js +35 -0
- package/package.json +50 -10
- package/schemas/config-v1.json +131 -1
- package/schemas/doctor-report-v1.json +10 -0
- package/skills/better-supabase/SKILL.md +60 -10
- package/skills/better-supabase/references/plugins.md +13 -14
- package/skills/better-supabase/references/troubleshooting.md +25 -4
- package/skills/better-supabase-api/SKILL.md +74 -19
- package/skills/better-supabase-api/references/adapters.md +48 -27
- package/skills/better-supabase-auth/SKILL.md +149 -0
- package/skills/better-supabase-auth/references/permdock.md +100 -0
- package/skills/better-supabase-testing/SKILL.md +58 -4
- package/dist/claims-CoTobNC-.js +0 -25
- package/dist/events-Do8jXh4D.d.ts +0 -84
- package/dist/executor-DynmIWhq.d.ts +0 -195
- package/dist/invalidate-DbxuL2jL.js +0 -18
- package/dist/permdock-sql-DImJULY-.d.ts +0 -17
- package/dist/plugin-BqR6wKMB.js +0 -23
- package/dist/respond-C44EZAJo.js +0 -399
- package/dist/respond-DAkPIdTH.d.ts +0 -175
- package/dist/result-c2OYgCV2.d.ts +0 -203
- package/dist/view-wZ-9qIUz.js +0 -45
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { r as definePlugin } from "../../plugin-DwARMuQp.js";
|
|
2
|
+
import { a as insertsOnly, i as guardManaged, t as dbName, u as withDefault } from "../../shared-D1dRUrAg.js";
|
|
3
3
|
//#region src/plugins/actor/index.ts
|
|
4
4
|
function defaultActor(context) {
|
|
5
5
|
const actor = context.actor;
|
|
@@ -8,30 +8,44 @@ function defaultActor(context) {
|
|
|
8
8
|
/**
|
|
9
9
|
* Stamps the columns generated as `Flags.actor`: `createdBy` on insert and
|
|
10
10
|
* `updatedBy` on insert and update. Soft deletes are updates, so they record
|
|
11
|
-
* who deleted the row.
|
|
11
|
+
* who deleted the row. `impersonatedBy` gets `context.actor.impersonator` on
|
|
12
|
+
* an impersonated insert or update and is left alone otherwise, so a user's
|
|
13
|
+
* own update keeps the stamp, like the SQL kit's `track_actor`. Without an
|
|
14
|
+
* actor (anonymous requests) nothing is set.
|
|
12
15
|
*/
|
|
13
16
|
function actor(options = {}) {
|
|
14
17
|
const resolve = options.resolve ?? defaultActor;
|
|
15
18
|
return definePlugin({
|
|
16
19
|
name: "actor",
|
|
17
|
-
beforeMutation(op, { table, context }) {
|
|
20
|
+
beforeMutation(op, { table, context, options }) {
|
|
18
21
|
const flags = table.flags.actor;
|
|
19
22
|
if (!flags) return op;
|
|
20
|
-
const id = resolve(context);
|
|
21
|
-
if (id === void 0) return op;
|
|
22
23
|
const created = dbName(table, flags.createdBy);
|
|
23
24
|
const updated = dbName(table, flags.updatedBy);
|
|
25
|
+
const impersonated = dbName(table, flags.impersonatedBy);
|
|
26
|
+
guardManaged(op, [
|
|
27
|
+
created,
|
|
28
|
+
updated,
|
|
29
|
+
impersonated
|
|
30
|
+
], "actor", options);
|
|
31
|
+
const id = resolve(context);
|
|
32
|
+
if (id === void 0) return op;
|
|
33
|
+
const impersonator = context.actor?.impersonator;
|
|
34
|
+
const stamp = (row) => {
|
|
35
|
+
const stamped = withDefault(row, updated, id);
|
|
36
|
+
return impersonator === void 0 ? stamped : withDefault(stamped, impersonated, impersonator);
|
|
37
|
+
};
|
|
24
38
|
switch (op.kind) {
|
|
25
39
|
case "insert": {
|
|
26
40
|
const stampCreated = insertsOnly(op);
|
|
27
41
|
return {
|
|
28
42
|
...op,
|
|
29
|
-
rows: op.rows.map((row) =>
|
|
43
|
+
rows: op.rows.map((row) => stamp(stampCreated ? withDefault(row, created, id) : row))
|
|
30
44
|
};
|
|
31
45
|
}
|
|
32
46
|
case "update": return {
|
|
33
47
|
...op,
|
|
34
|
-
set:
|
|
48
|
+
set: stamp(op.set)
|
|
35
49
|
};
|
|
36
50
|
case "delete": return op;
|
|
37
51
|
default: return op;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { U as Operation } from "../../executor-BunPOO-k.js";
|
|
2
|
+
import { h as RepositoryExtension, p as Plugin } from "../../plugin-o144f322.js";
|
|
3
3
|
//#region src/plugins/rules/index.d.ts
|
|
4
4
|
export type RuleLevel = "off" | "warn" | "error";
|
|
5
5
|
/** A level, or a level with the rule's option: `['error', 500]`. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { n as dbError, t as DbException } from "../../errors-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { n as dbError, t as DbException } from "../../errors-DtwXa6b8.js";
|
|
2
|
+
import { t as lookupOf } from "../../lookup-BaP5bI27.js";
|
|
3
|
+
import { r as definePlugin } from "../../plugin-DwARMuQp.js";
|
|
4
|
+
import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "../../claims-BAf6c7is.js";
|
|
4
5
|
//#region src/plugins/rules/index.ts
|
|
5
6
|
/** Catches data-exposure and correctness mistakes; everything else off. */
|
|
6
7
|
function safe() {
|
|
@@ -40,17 +41,37 @@ function levelOf(setting) {
|
|
|
40
41
|
function optionOf(setting, fallback) {
|
|
41
42
|
return Array.isArray(setting) ? setting[1] : fallback;
|
|
42
43
|
}
|
|
44
|
+
const depths = /* @__PURE__ */ new WeakMap();
|
|
43
45
|
function includeDepth(selection) {
|
|
46
|
+
let depth = depths.get(selection);
|
|
47
|
+
if (depth === void 0) {
|
|
48
|
+
depth = computeIncludeDepth(selection);
|
|
49
|
+
depths.set(selection, depth);
|
|
50
|
+
}
|
|
51
|
+
return depth;
|
|
52
|
+
}
|
|
53
|
+
function computeIncludeDepth(selection) {
|
|
44
54
|
let depth = 0;
|
|
45
55
|
for (const include of selection.includes) if (include.count !== void 0 || include.aggregate !== void 0) depth = Math.max(depth, 1);
|
|
46
56
|
else depth = Math.max(depth, 1 + includeDepth(include.selection));
|
|
47
57
|
return depth;
|
|
48
58
|
}
|
|
59
|
+
const sensitiveByTable = /* @__PURE__ */ new WeakMap();
|
|
60
|
+
function sensitiveOf(table) {
|
|
61
|
+
let sensitive = sensitiveByTable.get(table);
|
|
62
|
+
if (!sensitive) {
|
|
63
|
+
sensitive = new Set(lookupOf(table).entries.filter(([, column]) => column.sensitive).map(([, column]) => column.db));
|
|
64
|
+
sensitiveByTable.set(table, sensitive);
|
|
65
|
+
}
|
|
66
|
+
return sensitive;
|
|
67
|
+
}
|
|
49
68
|
function sensitiveColumns(selection, table) {
|
|
50
69
|
const found = [];
|
|
51
|
-
const sensitive =
|
|
52
|
-
|
|
53
|
-
|
|
70
|
+
const sensitive = sensitiveOf(table);
|
|
71
|
+
if (sensitive.size > 0) {
|
|
72
|
+
for (const column of selection.columns) if (sensitive.has(column.column)) found.push(`${table.key}.${column.column}`);
|
|
73
|
+
for (const measure of selection.aggregate?.measures ?? []) if (sensitive.has(measure.column)) found.push(`${table.key}.${measure.column}`);
|
|
74
|
+
}
|
|
54
75
|
for (const include of selection.includes) found.push(...sensitiveColumns(include.selection, include.target));
|
|
55
76
|
return found;
|
|
56
77
|
}
|
|
@@ -73,11 +94,21 @@ function bucketTemplates(schema) {
|
|
|
73
94
|
}
|
|
74
95
|
return templates;
|
|
75
96
|
}
|
|
97
|
+
const urlColumnsByTable = /* @__PURE__ */ new WeakMap();
|
|
98
|
+
/** Scalar text columns named `*_url`, the only ones the rule inspects. */
|
|
99
|
+
function urlColumns(table) {
|
|
100
|
+
let columns = urlColumnsByTable.get(table);
|
|
101
|
+
if (!columns) {
|
|
102
|
+
columns = lookupOf(table).entries.map(([, column]) => column).filter((column) => column.db.endsWith("_url") && !column.array && TEXT_TYPES.has(column.type));
|
|
103
|
+
urlColumnsByTable.set(table, columns);
|
|
104
|
+
}
|
|
105
|
+
return columns;
|
|
106
|
+
}
|
|
76
107
|
function storedObjectColumn(op, schema) {
|
|
77
108
|
const rows = op.kind === "insert" ? op.rows : op.kind === "update" ? [op.set] : [];
|
|
78
109
|
if (rows.length === 0) return void 0;
|
|
79
|
-
for (const column of
|
|
80
|
-
if (!rows.some((row) => column.db in row)
|
|
110
|
+
for (const column of urlColumns(op.table)) {
|
|
111
|
+
if (!rows.some((row) => column.db in row)) continue;
|
|
81
112
|
const path = `${column.db.slice(0, -4)}_path`;
|
|
82
113
|
if (column.storage !== void 0) return `"${column.db}" holds paths in bucket "${column.storage}"; name it "${path}"`;
|
|
83
114
|
if (rows.some((row) => {
|
|
@@ -87,29 +118,33 @@ function storedObjectColumn(op, schema) {
|
|
|
87
118
|
}
|
|
88
119
|
}
|
|
89
120
|
function checks(rules) {
|
|
121
|
+
const maxLimit = optionOf(rules.maxLimit, 1e3);
|
|
122
|
+
const maxDepth = optionOf(rules.maxIncludeDepth, 3);
|
|
90
123
|
return {
|
|
91
|
-
noUnboundedFindMany: (op) => op.kind === "select" && op.single === void 0 && !op.head && op.limit === void 0 ? "findMany without limit reads every visible row" : void 0,
|
|
124
|
+
noUnboundedFindMany: (op) => op.kind === "select" && op.single === void 0 && !op.head && op.limit === void 0 && op.selection.aggregate === void 0 ? "findMany without limit reads every visible row" : void 0,
|
|
92
125
|
maxLimit: (op) => {
|
|
93
|
-
|
|
94
|
-
|
|
126
|
+
if (op.kind !== "select" || op.limit === void 0) return;
|
|
127
|
+
const limit = op.lookAhead === true ? op.limit - 1 : op.limit;
|
|
128
|
+
return limit > maxLimit ? `limit ${limit} is above the maximum of ${maxLimit}` : void 0;
|
|
95
129
|
},
|
|
96
130
|
requireOrderByForCursor: (op) => op.kind === "select" && !op.head && op.orderBy.length === 0 && (op.offset !== void 0 || op.limit !== void 0 && op.limit > 1) ? "paging without orderBy returns rows in no stable order" : void 0,
|
|
97
131
|
maxIncludeDepth: (op) => {
|
|
98
|
-
const max =
|
|
132
|
+
const max = maxDepth;
|
|
99
133
|
const selection = op.kind === "select" ? op.selection : op.returning;
|
|
100
134
|
const depth = selection ? includeDepth(selection) : 0;
|
|
101
135
|
return depth > max ? `includes nest ${depth} levels deep (maximum ${max})` : void 0;
|
|
102
136
|
},
|
|
103
137
|
requireTenantContext: (op, { context, schema }) => {
|
|
104
138
|
if (!op.table.flags.tenant || context.actor?.kind === "service") return;
|
|
105
|
-
|
|
106
|
-
|
|
139
|
+
if (typeof context.tenant === "string") return;
|
|
140
|
+
const claim = optionOf(rules.requireTenantContext, void 0);
|
|
141
|
+
const paths = claim === void 0 ? tenantClaimPaths(claimsOf(schema).tenant) : [claim];
|
|
142
|
+
return paths.some((path) => claimAt(context.claims, path) !== void 0) ? void 0 : `"${op.table.key}" is tenant-scoped but the request has no tenant (context.tenant or claim ${paths.map((path) => `"${path}"`).join(" or ")})`;
|
|
107
143
|
},
|
|
108
144
|
noAdminInBrowser: (_op, { context }) => context.actor?.kind === "service" && isBrowser() ? "a service-role connection is running in a browser" : void 0,
|
|
109
145
|
noSensitiveSelect: (op, { options }) => {
|
|
110
|
-
if (options["sensitive"] === true) return;
|
|
111
|
-
const
|
|
112
|
-
const columns = selection ? sensitiveColumns(selection, op.table) : [];
|
|
146
|
+
if (options["sensitive"] === true || op.kind !== "select") return;
|
|
147
|
+
const columns = sensitiveColumns(op.selection, op.table);
|
|
113
148
|
return columns.length > 0 ? `reads sensitive column(s) ${columns.join(", ")}; pass { sensitive: true } to allow` : void 0;
|
|
114
149
|
},
|
|
115
150
|
noDeleteManyWithoutWhere: (op) => op.kind === "delete" && op.where === void 0 ? "delete without where removes every visible row" : void 0,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { w as PrimaryKeyValue } from "../../types-Dnf_wRDz.js";
|
|
2
|
+
import { a as AsyncResult } from "../../executor-BunPOO-k.js";
|
|
3
|
+
import { h as RepositoryExtension, o as HasFlag, p as Plugin } from "../../plugin-o144f322.js";
|
|
4
4
|
//#region src/plugins/soft-delete/index.d.ts
|
|
5
5
|
export interface SoftDeleteFindArgs {
|
|
6
6
|
/** Include soft-deleted rows of the queried table. */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as and } from "../../types-6cYK9pbJ.js";
|
|
2
|
-
import { i as ok, t as AsyncResult } from "../../result-
|
|
3
|
-
import {
|
|
2
|
+
import { i as ok, t as AsyncResult } from "../../result-BKiliPY7.js";
|
|
3
|
+
import { r as definePlugin } from "../../plugin-DwARMuQp.js";
|
|
4
4
|
import { n as scopeOperation } from "../../scope-CDHcS7dE.js";
|
|
5
|
-
import { a as
|
|
5
|
+
import { a as insertsOnly, i as guardManaged, o as isNotNull, s as isNull, t as dbName, u as withDefault } from "../../shared-D1dRUrAg.js";
|
|
6
6
|
//#region src/plugins/soft-delete/index.ts
|
|
7
7
|
function deletedColumn(table) {
|
|
8
8
|
return dbName(table, table.flags.softDelete);
|
|
@@ -39,9 +39,17 @@ function softDelete() {
|
|
|
39
39
|
};
|
|
40
40
|
},
|
|
41
41
|
beforeMutation(op, { table, options, now }) {
|
|
42
|
-
if (op.kind !== "delete" || options["hard"] === true) return op;
|
|
43
42
|
const column = deletedColumn(table);
|
|
44
43
|
if (!column) return op;
|
|
44
|
+
guardManaged(op, [column], "softDelete", options);
|
|
45
|
+
if (op.kind === "insert") {
|
|
46
|
+
if (insertsOnly(op)) return op;
|
|
47
|
+
return {
|
|
48
|
+
...op,
|
|
49
|
+
rows: op.rows.map((row) => withDefault(row, column, null))
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (op.kind !== "delete" || options["hard"] === true) return op;
|
|
45
53
|
return {
|
|
46
54
|
kind: "update",
|
|
47
55
|
table,
|
|
@@ -58,7 +66,8 @@ function softDelete() {
|
|
|
58
66
|
const result = await update(key, { [flag]: null }, {
|
|
59
67
|
...args,
|
|
60
68
|
withDeleted: true,
|
|
61
|
-
returning: false
|
|
69
|
+
returning: false,
|
|
70
|
+
override: true
|
|
62
71
|
});
|
|
63
72
|
return result.ok ? ok(void 0) : result;
|
|
64
73
|
}) };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { j as SchemaMeta } from "../../types-Dnf_wRDz.js";
|
|
2
|
+
import { g as RequestContext, h as RepositoryExtension, o as HasFlag, p as Plugin } from "../../plugin-o144f322.js";
|
|
3
3
|
//#region src/plugins/tenant/index.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Dotted paths to the string claims of `C` (up to three levels), e.g.
|
|
@@ -7,7 +7,7 @@ import { f as Plugin, h as RequestContext, m as RepositoryExtension, o as HasFla
|
|
|
7
7
|
*/
|
|
8
8
|
export type ClaimPath<C> = unknown extends C ? string : StringPaths<C, [1, 2, 3]>;
|
|
9
9
|
type StringPaths<T, Depth extends readonly unknown[]> = T extends object ? T extends readonly unknown[] ? never : { [K in keyof T & string]-?: (NonNullable<T[K]> extends string ? K : never) | (Depth extends readonly [unknown, ...infer Rest] ? `${K}.${StringPaths<NonNullable<T[K]>, Rest>}` : never); }[keyof T & string] : never;
|
|
10
|
-
/** `C` is the claims type (`
|
|
10
|
+
/** `C` is the claims type (`betterSupabase.claims(schema)`'s output); it types `claim`. */
|
|
11
11
|
export interface TenantOptions<C = unknown> {
|
|
12
12
|
/**
|
|
13
13
|
* JWT claim path(s) holding the tenant id when `context.tenant` is not set.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { n as dbError, t as DbException } from "../../errors-
|
|
2
|
-
import {
|
|
1
|
+
import { n as dbError, t as DbException } from "../../errors-DtwXa6b8.js";
|
|
2
|
+
import { a as recordTenant, o as spansAllTenants, r as definePlugin } from "../../plugin-DwARMuQp.js";
|
|
3
3
|
import { n as scopeOperation } from "../../scope-CDHcS7dE.js";
|
|
4
|
-
import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "../../claims-
|
|
5
|
-
import { n as equals, r as forbidden, t as dbName } from "../../shared-
|
|
4
|
+
import { i as tenantClaimPaths, n as claimAt, r as claimsOf } from "../../claims-BAf6c7is.js";
|
|
5
|
+
import { a as insertsOnly, n as equals, r as forbidden, t as dbName } from "../../shared-D1dRUrAg.js";
|
|
6
6
|
//#region src/plugins/tenant/index.ts
|
|
7
7
|
/**
|
|
8
8
|
* The tenant for a request: `context.tenant`, then the configured claim.
|
|
@@ -18,6 +18,11 @@ function resolveTenant(context, options = {}, schema) {
|
|
|
18
18
|
if (value !== void 0) return value;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
/** Tenant columns may be numeric; the resolved tenant is always a string. */
|
|
22
|
+
function sameTenant(value, id) {
|
|
23
|
+
if (value === id) return true;
|
|
24
|
+
return (typeof value === "number" || typeof value === "bigint") && String(value) === id;
|
|
25
|
+
}
|
|
21
26
|
function tenantColumn(table) {
|
|
22
27
|
return dbName(table, table.flags.tenant);
|
|
23
28
|
}
|
|
@@ -30,17 +35,34 @@ function tenantColumn(table) {
|
|
|
30
35
|
*/
|
|
31
36
|
function tenant(options = {}) {
|
|
32
37
|
const onMissing = options.onMissing ?? "error";
|
|
38
|
+
/** A context is fixed for a connection, so its tenant is resolved once. */
|
|
39
|
+
const resolved = /* @__PURE__ */ new WeakMap();
|
|
40
|
+
const resolvedFor = (context, schema) => {
|
|
41
|
+
let id = resolved.get(context);
|
|
42
|
+
if (id === void 0 && !resolved.has(context)) {
|
|
43
|
+
id = resolveTenant(context, options, schema);
|
|
44
|
+
resolved.set(context, id);
|
|
45
|
+
if (id !== void 0) recordTenant(context, id);
|
|
46
|
+
}
|
|
47
|
+
return id;
|
|
48
|
+
};
|
|
49
|
+
const missing = (table) => {
|
|
50
|
+
throw new DbException(dbError("forbidden", `No tenant in the request context for "${table.key}"`));
|
|
51
|
+
};
|
|
33
52
|
const current = (table, context, schema) => {
|
|
34
|
-
const id =
|
|
35
|
-
if (id === void 0 && onMissing === "error" && tenantColumn(table))
|
|
53
|
+
const id = resolvedFor(context, schema);
|
|
54
|
+
if (id === void 0 && onMissing === "error" && tenantColumn(table)) missing(table);
|
|
36
55
|
return id;
|
|
37
56
|
};
|
|
38
57
|
return definePlugin({
|
|
39
58
|
name: "tenant",
|
|
40
59
|
transformQuery(op, { context, schema, options: call }) {
|
|
41
|
-
if (call["allTenants"] === true) return op;
|
|
42
|
-
const id =
|
|
43
|
-
if (id === void 0)
|
|
60
|
+
if (call["allTenants"] === true || spansAllTenants(context)) return op;
|
|
61
|
+
const id = resolvedFor(context, schema);
|
|
62
|
+
if (id === void 0) {
|
|
63
|
+
if (onMissing === "error") scopeOperation(op, (table) => tenantColumn(table) ? missing(table) : void 0);
|
|
64
|
+
return op;
|
|
65
|
+
}
|
|
44
66
|
return scopeOperation(op, (table) => {
|
|
45
67
|
const column = tenantColumn(table);
|
|
46
68
|
return column ? equals(column, id) : void 0;
|
|
@@ -48,22 +70,24 @@ function tenant(options = {}) {
|
|
|
48
70
|
},
|
|
49
71
|
beforeMutation(op, { table, context, schema, options: call }) {
|
|
50
72
|
const column = tenantColumn(table);
|
|
51
|
-
if (!column || call["allTenants"] === true) return op;
|
|
73
|
+
if (!column || call["allTenants"] === true || spansAllTenants(context)) return op;
|
|
52
74
|
const id = current(table, context, schema);
|
|
53
75
|
if (id === void 0) return op;
|
|
54
76
|
switch (op.kind) {
|
|
55
|
-
case "insert":
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
77
|
+
case "insert":
|
|
78
|
+
if (!insertsOnly(op) && !op.onConflict?.columns.includes(column)) forbidden(`An upsert on ${table.key} that updates on conflict needs the tenant column "${column}" in its conflict target`);
|
|
79
|
+
return {
|
|
80
|
+
...op,
|
|
81
|
+
rows: op.rows.map((row) => {
|
|
82
|
+
if (column in row && !sameTenant(row[column], id)) forbidden(`Cannot write a ${table.key} row for another tenant`);
|
|
83
|
+
return {
|
|
84
|
+
...row,
|
|
85
|
+
[column]: id
|
|
86
|
+
};
|
|
87
|
+
})
|
|
88
|
+
};
|
|
65
89
|
case "update":
|
|
66
|
-
if (column in op.set && op.set[column]
|
|
90
|
+
if (column in op.set && !sameTenant(op.set[column], id)) forbidden(`Cannot move a ${table.key} row to another tenant`);
|
|
67
91
|
return op;
|
|
68
92
|
case "delete": return op;
|
|
69
93
|
default: return op;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { r as definePlugin } from "../../plugin-DwARMuQp.js";
|
|
2
|
+
import { a as insertsOnly, i as guardManaged, t as dbName, u as withDefault } from "../../shared-D1dRUrAg.js";
|
|
3
3
|
//#region src/plugins/timestamps/index.ts
|
|
4
4
|
/**
|
|
5
5
|
* Stamps the columns generated as `Flags.timestamps`: `createdAt` on insert,
|
|
@@ -9,11 +9,12 @@ import { i as insertsOnly, l as withDefault, t as dbName } from "../../shared-_6
|
|
|
9
9
|
function timestamps() {
|
|
10
10
|
return definePlugin({
|
|
11
11
|
name: "timestamps",
|
|
12
|
-
beforeMutation(op, { table, now }) {
|
|
12
|
+
beforeMutation(op, { table, now, options }) {
|
|
13
13
|
const flags = table.flags.timestamps;
|
|
14
14
|
if (!flags) return op;
|
|
15
15
|
const created = dbName(table, flags.createdAt);
|
|
16
16
|
const updated = dbName(table, flags.updatedAt);
|
|
17
|
+
guardManaged(op, [created, updated], "timestamps", options);
|
|
17
18
|
const stamp = now().toString();
|
|
18
19
|
switch (op.kind) {
|
|
19
20
|
case "insert": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as StandardSchemaV1 } from "../../standard-
|
|
1
|
+
import { p as Plugin } from "../../plugin-o144f322.js";
|
|
2
|
+
import { t as StandardSchemaV1 } from "../../standard-J4YgMOLm.js";
|
|
3
3
|
//#region src/plugins/validation/index.d.ts
|
|
4
4
|
export interface TableValidators {
|
|
5
5
|
/** Validates inserts and upserts, with app-cased keys. */
|
|
@@ -1,13 +1,33 @@
|
|
|
1
|
-
import { n as dbError, t as DbException } from "../../errors-
|
|
2
|
-
import { n as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { n as dbError, t as DbException } from "../../errors-DtwXa6b8.js";
|
|
2
|
+
import { n as decodeValue, r as encodeValue } from "../../wire-D2dT86vi.js";
|
|
3
|
+
import { r as definePlugin } from "../../plugin-DwARMuQp.js";
|
|
4
|
+
import { t as validate } from "../../standard-D7r6dMUu.js";
|
|
5
|
+
import { c as toApp, l as toDb } from "../../shared-D1dRUrAg.js";
|
|
5
6
|
//#region src/plugins/validation/index.ts
|
|
7
|
+
/**
|
|
8
|
+
* Rows reach plugins in wire form (ISO text, decimal text), while generated
|
|
9
|
+
* validators expect the column codecs' app values (Temporal, `bigint`).
|
|
10
|
+
*/
|
|
11
|
+
function decoded(table, row) {
|
|
12
|
+
const app = toApp(table, row);
|
|
13
|
+
for (const [name, value] of Object.entries(app)) {
|
|
14
|
+
const codec = table.columns[name]?.codec;
|
|
15
|
+
if (codec === void 0 || typeof value !== "string") continue;
|
|
16
|
+
try {
|
|
17
|
+
app[name] = decodeValue(codec, value);
|
|
18
|
+
} catch {}
|
|
19
|
+
}
|
|
20
|
+
return app;
|
|
21
|
+
}
|
|
22
|
+
function encoded(row) {
|
|
23
|
+
for (const [name, value] of Object.entries(row)) row[name] = encodeValue(value);
|
|
24
|
+
return row;
|
|
25
|
+
}
|
|
6
26
|
async function check(schema, table, row, label, index) {
|
|
7
|
-
const result = await validate(schema,
|
|
27
|
+
const result = await validate(schema, decoded(table, row), label);
|
|
8
28
|
if (result.ok) {
|
|
9
29
|
const output = result.data;
|
|
10
|
-
return typeof output === "object" && output !== null ? toDb(table, output) : { ...row };
|
|
30
|
+
return typeof output === "object" && output !== null ? encoded(toDb(table, output)) : { ...row };
|
|
11
31
|
}
|
|
12
32
|
const error = result.error;
|
|
13
33
|
if (index === void 0 || error.kind !== "validation") throw new DbException(error);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as Executor } from "./executor-BunPOO-k.js";
|
|
2
|
+
import { t as SqlClient } from "./executor-Cghdstwu.js";
|
|
2
3
|
//#region src/postgres/pool.d.ts
|
|
3
4
|
/** The part of a `pg` pool client `createPostgres` uses. */
|
|
4
5
|
interface PgPoolClient {
|
|
@@ -47,17 +48,34 @@ interface SqlClaims {
|
|
|
47
48
|
readonly role?: string;
|
|
48
49
|
readonly [claim: string]: unknown;
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
+
/** What every transaction of a user session sets besides the claims and role. */
|
|
52
|
+
interface SessionOptions {
|
|
53
|
+
/**
|
|
54
|
+
* Transaction-local settings, e.g. `{ 'better_supabase.tenant': id }`.
|
|
55
|
+
* Names need a dot (custom settings); `role` and `request.jwt.claims` are
|
|
56
|
+
* set from the claims.
|
|
57
|
+
*/
|
|
58
|
+
readonly settings?: Readonly<Record<string, string>>;
|
|
59
|
+
/** Runs every transaction with `begin read only`: writes fail with 25006. */
|
|
60
|
+
readonly readOnly?: boolean;
|
|
61
|
+
}
|
|
62
|
+
interface BetterPostgres {
|
|
51
63
|
/** Connects as the connection-string role. On Supabase that bypasses RLS. */
|
|
52
64
|
readonly admin: SqlClient;
|
|
53
65
|
/** Runs every query as the given user, with RLS, like PostgREST does. */
|
|
54
|
-
asUser(claims: SqlClaims): SqlClient;
|
|
66
|
+
asUser(claims: SqlClaims, options?: SessionOptions): SqlClient;
|
|
55
67
|
/** Runs every query as `anon`. */
|
|
56
68
|
readonly anon: SqlClient;
|
|
69
|
+
/**
|
|
70
|
+
* Repositories' executor as the given user (`postgresExecutor(asUser(claims))`).
|
|
71
|
+
* `createServer` calls it for `ctx.sql`, so only apps that pass `postgres`
|
|
72
|
+
* bundle the SQL compiler.
|
|
73
|
+
*/
|
|
74
|
+
executorFor(claims: SqlClaims, options?: SessionOptions): Executor;
|
|
57
75
|
/** Runs `fn` in one transaction. Pass claims to run it as a user. */
|
|
58
76
|
transaction<T>(fn: (client: SqlClient) => Promise<T>, options?: {
|
|
59
77
|
readonly claims?: SqlClaims;
|
|
60
|
-
}): Promise<T>;
|
|
78
|
+
} & SessionOptions): Promise<T>;
|
|
61
79
|
end(): Promise<void>;
|
|
62
80
|
[Symbol.asyncDispose](): Promise<void>;
|
|
63
81
|
}
|
|
@@ -66,6 +84,6 @@ interface Postgres {
|
|
|
66
84
|
* transaction) runs in its own transaction; claims and role are
|
|
67
85
|
* transaction-local, so nothing leaks back into the pool.
|
|
68
86
|
*/
|
|
69
|
-
declare function createPostgres(options?: PostgresOptions):
|
|
87
|
+
declare function createPostgres(options?: PostgresOptions): BetterPostgres;
|
|
70
88
|
//#endregion
|
|
71
|
-
export { PostgresTimeouts as a, PostgresOptions as i,
|
|
89
|
+
export { PostgresTimeouts as a, createPostgres as c, PostgresOptions as i, PgPool as n, SessionOptions as o, PgPoolClient as r, SqlClaims as s, BetterPostgres as t };
|
package/dist/postgres/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as fromPgError, r as postgresExecutor, t as SqlClient } from "../executor-
|
|
3
|
-
import { a as PostgresTimeouts, i as PostgresOptions, n as
|
|
4
|
-
import { t as Compiler } from "../compiler-
|
|
1
|
+
import { U as Operation } from "../executor-BunPOO-k.js";
|
|
2
|
+
import { n as fromPgError, r as postgresExecutor, t as SqlClient } from "../executor-Cghdstwu.js";
|
|
3
|
+
import { a as PostgresTimeouts, c as createPostgres, i as PostgresOptions, n as PgPool, o as SessionOptions, r as PgPoolClient, s as SqlClaims, t as BetterPostgres } from "../pool-C9voM4Kw.js";
|
|
4
|
+
import { t as Compiler } from "../compiler-BXH_aZ7N.js";
|
|
5
5
|
//#region src/compile/sql.d.ts
|
|
6
6
|
interface SqlQuery {
|
|
7
7
|
readonly text: string;
|
|
@@ -30,4 +30,4 @@ export declare function compileSql(op: Operation): SqlPlan;
|
|
|
30
30
|
//#region src/postgres/compiler.d.ts
|
|
31
31
|
export declare const sqlCompiler: Compiler<SqlPlan>;
|
|
32
32
|
//#endregion
|
|
33
|
-
export { type
|
|
33
|
+
export { type BetterPostgres, type PgPool, type PgPoolClient, type PostgresOptions, type PostgresTimeouts, type SessionOptions, type SqlClaims, type SqlClient, type SqlPlan, type SqlQuery, createPostgres, fromPgError, postgresExecutor };
|
package/dist/postgres/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as quoteIdent, t as compileSql } from "../sql-
|
|
2
|
-
import { n as postgresExecutor, t as fromPgError } from "../executor-
|
|
1
|
+
import { n as quoteIdent, t as compileSql } from "../sql-Coh6n4cC.js";
|
|
2
|
+
import { n as postgresExecutor, t as fromPgError } from "../executor-XycESQPH.js";
|
|
3
3
|
import { Pool } from "pg";
|
|
4
4
|
//#region src/postgres/pool.ts
|
|
5
5
|
const DEFAULT_TIMEOUTS = {
|
|
@@ -22,6 +22,10 @@ function openPool(options) {
|
|
|
22
22
|
idleTimeoutMillis: options.idleTimeout ?? 1e4
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
|
+
const RESERVED_SETTINGS = /* @__PURE__ */ new Set(["role", "request.jwt.claims"]);
|
|
26
|
+
function checkSettings(settings = {}) {
|
|
27
|
+
for (const name of Object.keys(settings)) if (!name.includes(".") || RESERVED_SETTINGS.has(name)) throw new TypeError(`Session setting "${name}": use a custom setting with a dot, such as better_supabase.tenant`);
|
|
28
|
+
}
|
|
25
29
|
/**
|
|
26
30
|
* A pooled Postgres connection for jobs, scripts and tests. Each query (or
|
|
27
31
|
* transaction) runs in its own transaction; claims and role are
|
|
@@ -39,8 +43,8 @@ function createPostgres(options = {}) {
|
|
|
39
43
|
};
|
|
40
44
|
/** Opens the transaction, then sets the timeouts, claims and role in one round trip. */
|
|
41
45
|
async function begin(client, session) {
|
|
42
|
-
await client.query("begin");
|
|
43
|
-
const settings =
|
|
46
|
+
await client.query(session?.readOnly ? "begin read only" : "begin");
|
|
47
|
+
const settings = Object.entries(session?.settings ?? {});
|
|
44
48
|
const timeout = session?.role === "authenticated" ? timeouts.authenticated : session?.role === "anon" ? timeouts.anon : timeouts.admin;
|
|
45
49
|
if (timeout !== void 0) settings.push(["statement_timeout", String(Math.trunc(timeout))]);
|
|
46
50
|
if (options.idleInTransactionTimeout !== void 0) settings.push(["idle_in_transaction_session_timeout", String(Math.trunc(options.idleInTransactionTimeout))]);
|
|
@@ -73,18 +77,24 @@ function createPostgres(options = {}) {
|
|
|
73
77
|
queryRaw: (text, params) => transaction(session, (client) => client.queryRaw(text, params)),
|
|
74
78
|
transaction: (fn) => transaction(session, fn)
|
|
75
79
|
});
|
|
76
|
-
const sessionFor = (claims) =>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
const sessionFor = (claims, sessionOptions = {}) => {
|
|
81
|
+
checkSettings(sessionOptions.settings);
|
|
82
|
+
return {
|
|
83
|
+
claims,
|
|
84
|
+
role: roleOf(claims),
|
|
85
|
+
...sessionOptions.settings ? { settings: sessionOptions.settings } : {},
|
|
86
|
+
...sessionOptions.readOnly ? { readOnly: true } : {}
|
|
87
|
+
};
|
|
88
|
+
};
|
|
80
89
|
return {
|
|
81
90
|
admin: clientFor(void 0),
|
|
82
91
|
anon: clientFor({
|
|
83
92
|
claims: { role: "anon" },
|
|
84
93
|
role: "anon"
|
|
85
94
|
}),
|
|
86
|
-
asUser: (claims) => clientFor(sessionFor(claims)),
|
|
87
|
-
|
|
95
|
+
asUser: (claims, sessionOptions) => clientFor(sessionFor(claims, sessionOptions)),
|
|
96
|
+
executorFor: (claims, sessionOptions) => postgresExecutor(clientFor(sessionFor(claims, sessionOptions))),
|
|
97
|
+
transaction: (fn, txOptions) => transaction(txOptions?.claims ? sessionFor(txOptions.claims, txOptions) : void 0, fn),
|
|
88
98
|
end: () => pool.end(),
|
|
89
99
|
[Symbol.asyncDispose]: () => pool.end()
|
|
90
100
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as dbError } from "./errors-
|
|
1
|
+
import { n as dbError } from "./errors-DtwXa6b8.js";
|
|
2
2
|
//#region src/core/problem.ts
|
|
3
3
|
const PROBLEM_TYPE_BASE = "https://bettersupabase.com/problems/";
|
|
4
4
|
const PROBLEM_CONTENT_TYPE = "application/problem+json";
|
|
@@ -12,6 +12,7 @@ const TITLES = {
|
|
|
12
12
|
not_null: "Required value missing",
|
|
13
13
|
exclusion: "Exclusion constraint violated",
|
|
14
14
|
invalid_input: "Invalid input",
|
|
15
|
+
invalid_value: "Stored value not representable",
|
|
15
16
|
raised: "Request rejected",
|
|
16
17
|
timeout: "Timed out",
|
|
17
18
|
serialization: "Concurrent update, retry",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as DbError, v as DbErrorKind, w as ValidationIssue } from "./executor-BunPOO-k.js";
|
|
2
2
|
//#region src/core/problem.d.ts
|
|
3
3
|
/** RFC 9457 Problem Details, with the `DbError` fields as extension members. */
|
|
4
4
|
interface ProblemDetails {
|
package/dist/query/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { type
|
|
1
|
+
import { a as MutationOptionsOf, c as QueryKeyOf, d as createQueries, f as invalidateOnMutation, h as invalidateTables, i as InfiniteOptionsOf, l as QueryOptionsOf, m as BetterQueryMeta, n as clearOnUserChange, o as QueriesOptions, p as queryCache, r as BetterQueries, s as QueryHelpers, t as UserChangeSource, u as TableQueries } from "../index-DgILJRXj.js";
|
|
2
|
+
export { type BetterQueries, type BetterQueryMeta, type InfiniteOptionsOf, type MutationOptionsOf, type QueriesOptions, type QueryHelpers, type QueryKeyOf, type QueryOptionsOf, type TableQueries, type UserChangeSource, clearOnUserChange, createQueries, invalidateOnMutation, invalidateTables, queryCache };
|
package/dist/query/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as invalidateOnMutation, r as queryCache, t as createQueries } from "../query-
|
|
3
|
-
export { createQueries, invalidateOnMutation, invalidateTables, queryCache };
|
|
1
|
+
import { n as invalidateTables, t as clearOnUserChange } from "../user-change-CHFEUro1.js";
|
|
2
|
+
import { n as invalidateOnMutation, r as queryCache, t as createQueries } from "../query-CCbo44lG.js";
|
|
3
|
+
export { clearOnUserChange, createQueries, invalidateOnMutation, invalidateTables, queryCache };
|