better-supabase 0.4.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 +2 -0
- package/dist/channel-FQW-CnGR.d.ts +70 -0
- package/dist/cli/bin.js +1 -1
- package/dist/cli/codemod-DqV7612m.js +388 -0
- package/dist/cli/{config-D9R0o1LH.js → config-CPVpXP5I.js} +78 -8
- package/dist/cli/{config-SSKSTUl2.js → config-dtoekM0v.js} +1 -1
- package/dist/cli/{read-sets-CMa29t9a.js → diff-SjkO5rNr.js} +1 -220
- package/dist/cli/{dist-CFgGknmZ.js → dist-DBPdlPYK.js} +4 -4
- package/dist/cli/{dist-B1MvLv-M.js → dist-DreZ24Sz.js} +1 -1
- package/dist/cli/{dist-Du7VnEUG.js → dist-xn4wlboc.js} +112 -1
- package/dist/cli/{doctor-BOym3mbL.js → doctor-L7Z8mYTx.js} +531 -50
- package/dist/cli/{env-BZ0uy8XK.js → env-DmKv_G4A.js} +1 -1
- package/dist/cli/gen-BJc9vdyu.js +2 -0
- package/dist/cli/{gen-Ccn_p90L.js → gen-C2osRcr5.js} +283 -87
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +4 -4
- package/dist/cli/{init-ClnxRYBF.js → init-Saf5-R9T.js} +2 -2
- package/dist/cli/{introspect-DxqfkVIv.js → introspect--H7oGmcd.js} +2 -2
- package/dist/cli/{openapi-8WHjxiTJ.js → openapi-Cp5Fyta-.js} +1 -1
- package/dist/cli/read-sets-BfMQcKy8.js +289 -0
- package/dist/cli/{run-CP20LKk_.js → run-BKR2W_79.js} +16 -12
- package/dist/cli/{seed-5J6eu_Xg.js → seed-CUlqWh-8.js} +1 -1
- package/dist/cli/sql-DzPbfngx.js +348 -0
- package/dist/cli/{version-5mW_8sY1.js → version-BDJuO0UR.js} +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +3 -10
- package/dist/clone-BfgmLU90.js +21 -0
- package/dist/{compiler-DB3aSFOA.d.ts → compiler-BXH_aZ7N.d.ts} +2 -2
- package/dist/config/index.d.ts +4 -4
- package/dist/config/index.js +4 -4
- package/dist/{config-CbvFmGD8.js → config-DreERlKo.js} +1 -1
- package/dist/{config-C1CYcm6o.d.ts → config-T_ejwyd3.d.ts} +176 -11
- package/dist/{define-CRS2MRV3.d.ts → define-Bp_BZa5h.d.ts} +11 -7
- package/dist/{define-Bh0AqTik.js → define-cNKzqwL_.js} +202 -16
- package/dist/edge/index.d.ts +16 -5
- package/dist/edge/index.js +10 -7
- package/dist/{entitlements-Dm-FHpNH.d.ts → entitlements-DUxU4oHe.d.ts} +1 -1
- package/dist/env/index.d.ts +2 -2
- package/dist/env/index.js +34 -1
- package/dist/{errors-L0xK41y_.js → errors-DtwXa6b8.js} +1 -0
- package/dist/events/index.d.ts +3 -2
- package/dist/events/index.js +65 -12
- package/dist/events-aIO7vsIk.d.ts +230 -0
- package/dist/{result-CqEsbgYs.d.ts → executor-BunPOO-k.d.ts} +200 -1
- package/dist/{executor-CZ7ImRiD.d.ts → executor-Cghdstwu.d.ts} +1 -2
- package/dist/{executor-CVt6dD0B.js → executor-XycESQPH.js} +3 -3
- package/dist/hono/index.d.ts +17 -6
- package/dist/hono/index.js +40 -5
- package/dist/impersonation-VfaGc4Q_.js +41 -0
- package/dist/{index-BBdvo-5d.d.ts → index-BGdgBPdf.d.ts} +49 -6
- package/dist/{index-BhHEC04r.d.ts → index-C7f8cOBM.d.ts} +2 -2
- package/dist/{index-Dy6kuF0P.d.ts → index-CLg87OBW.d.ts} +6 -1
- package/dist/{index-D5IfUIDh.d.ts → index-DOESKG27.d.ts} +33 -8
- package/dist/{index-DFmOpBGC.d.ts → index-DgILJRXj.d.ts} +35 -9
- package/dist/{index-RlLXd8dL.d.ts → index-DmXSxbLi.d.ts} +4 -4
- package/dist/{index-Cf-D2jk1.d.ts → index-Dxn2a5cw.d.ts} +2 -2
- package/dist/{index-528Ugmyp.d.ts → index-SaTsEfGP.d.ts} +76 -8
- package/dist/{index-BAy4tsAP.d.ts → index-fag8VJZ2.d.ts} +3 -4
- package/dist/index.d.ts +30 -13
- package/dist/index.js +10 -9
- package/dist/jobs/index.d.ts +147 -101
- package/dist/jobs/index.js +744 -237
- package/dist/{json-schema-DP6V7cbr.js → json-schema-m1fiwKgN.js} +22 -1
- 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-BpxDfnbg.js → kits-CGLLrNPd.js} +37 -9
- package/dist/list/index.d.ts +1 -1
- package/dist/{live-BHakSWWo.d.ts → live-D9W2M5aO.d.ts} +6 -5
- package/dist/mcp/index.d.ts +25 -8
- package/dist/mcp/index.js +23 -14
- package/dist/{mfa-C7MNQ1Ob.d.ts → mfa-CusDgPaD.d.ts} +5 -1
- package/dist/next/index.d.ts +31 -10
- package/dist/next/index.js +136 -27
- 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 +2 -2
- package/dist/orgs/index.d.ts +132 -0
- package/dist/orgs/index.js +245 -0
- package/dist/orpc/index.d.ts +28 -8
- package/dist/orpc/index.js +16 -3
- package/dist/otel/index.d.ts +21 -2
- package/dist/otel/index.js +50 -9
- 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-bNhvJwRh.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 +15 -10
- 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 +2 -2
- package/dist/plugins/tenant/index.js +38 -20
- 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-DFwEQwmN.d.ts → pool-C9voM4Kw.d.ts} +17 -6
- package/dist/postgres/index.d.ts +5 -5
- package/dist/postgres/index.js +20 -11
- package/dist/{postgrest-Bc-0Xw62.d.ts → postgrest-CruYKAvV.d.ts} +1 -1
- package/dist/{problem-BihjPR0t.js → problem-BW1KhzSG.js} +2 -1
- package/dist/{problem-U8UEKccv.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-BMMSWbI7.js → query-CCbo44lG.js} +2 -2
- 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 +14 -3
- package/dist/react/server.js +10 -2
- package/dist/react/session.d.ts +7 -1
- package/dist/react/session.js +9 -1
- package/dist/{react-CQHMaESR.js → react-C_s7kiNz.js} +103 -11
- package/dist/{read-set-FWK8qQ58.js → read-set-DQFt1N_Y.js} +22 -1
- package/dist/realtime/index.d.ts +3 -3
- package/dist/realtime/index.js +5 -4
- package/dist/{refresh-BwYkyNOQ.d.ts → refresh-BTrQ_ZTp.d.ts} +1 -1
- package/dist/{resolve-BAqQcwMW.d.ts → resolve-C15TJq77.d.ts} +11 -5
- package/dist/{resource-My_y-Syh.js → resource-CRxxwkQq.js} +22 -7
- package/dist/{resource-BJcaIfxi.d.ts → resource-D8iqWMr-.d.ts} +5 -5
- package/dist/respond-D2OQl62-.d.ts +371 -0
- package/dist/{result-Bj6yt33D.js → result-BKiliPY7.js} +1 -1
- package/dist/server/index.d.ts +14 -12
- package/dist/server/index.js +11 -17
- package/dist/{server-BA75B0mT.js → server-Csx2sRjg.js} +251 -34
- package/dist/{shared-DnoCdMDr.js → shared-D1dRUrAg.js} +16 -2
- package/dist/signers-Cc6r98SW.d.ts +162 -0
- package/dist/{simplify-Cqvfr9dj.js → simplify-_0oUKqCd.js} +4 -115
- package/dist/sql/index.d.ts +247 -10
- package/dist/sql/index.js +8590 -779
- package/dist/{sql-B34HU2DI.js → sql-Coh6n4cC.js} +9 -2
- package/dist/ssr/index.d.ts +4 -4
- package/dist/ssr/index.js +1 -2
- package/dist/{standard-BRyBGTtp.js → standard-D7r6dMUu.js} +6 -3
- package/dist/{standard-BsaCYQJc.d.ts → standard-J4YgMOLm.d.ts} +1 -1
- package/dist/{stats-C_YxA2r1.js → stats-Bqob3WqT.js} +4 -4
- package/dist/storage/index.d.ts +4 -4
- package/dist/storage/index.js +155 -26
- 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/{permdock-sql-C4KFzLc9.js → template-TxrGI5jR.js} +2 -31
- package/dist/{temporal-BwshQk0W.js → temporal-CVlIV2DZ.js} +17 -4
- package/dist/{temporal-required-CBNHT6ni.js → temporal-required-CAt4Dc9Z.js} +2 -2
- package/dist/testing/index.d.ts +100 -10
- package/dist/testing/index.js +336 -8
- package/dist/{types-DONv9SHN.d.ts → types-Dnf_wRDz.d.ts} +26 -3
- package/dist/user-change-CHFEUro1.js +49 -0
- package/dist/{webhooks-Bh_Jf_-l.js → verify-Ce49ETPz.js} +5 -5
- package/dist/{version-Bmf7_FzM.js → version-DM_Roffb.js} +1 -1
- package/dist/{view-B64o81wp.d.ts → view-BEf0diC5.d.ts} +8 -3
- package/dist/{mfa-byfjruR9.js → view-Bq64ki8-.js} +95 -38
- package/dist/webhooks/index.d.ts +135 -4
- package/dist/webhooks/index.js +588 -2
- package/dist/wire-D2dT86vi.js +35 -0
- package/package.json +16 -8
- package/schemas/config-v1.json +131 -1
- package/schemas/doctor-report-v1.json +10 -0
- package/skills/better-supabase/SKILL.md +9 -6
- package/skills/better-supabase/references/plugins.md +6 -3
- package/skills/better-supabase/references/troubleshooting.md +1 -0
- package/skills/better-supabase-api/SKILL.md +9 -2
- package/skills/better-supabase-api/references/adapters.md +11 -8
- package/skills/better-supabase-auth/SKILL.md +3 -0
- package/skills/better-supabase-auth/references/permdock.md +56 -11
- package/dist/cli/gen-D5cLCULx.js +0 -2
- package/dist/cli/sql-D4VbqmXi.js +0 -199
- package/dist/events-B21UOhvP.d.ts +0 -84
- package/dist/executor-B5IoUxLE.d.ts +0 -195
- package/dist/invalidate-CgxmRamI.js +0 -24
- package/dist/permdock-sql-DImJULY-.d.ts +0 -17
- package/dist/plugin-BqR6wKMB.js +0 -23
- package/dist/respond-DgIbdrt8.d.ts +0 -194
- package/dist/view-BrJI2LKp.js +0 -45
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { i as importModule } from "./config-CPVpXP5I.js";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { KIT_ID_TYPES, compileReadSets, kitIdType } from "better-supabase/sql";
|
|
6
|
+
import { isReadSet } from "better-supabase";
|
|
7
|
+
//#region src/cli/permdock.ts
|
|
8
|
+
const PERMDOCK_CONFIGS = [
|
|
9
|
+
"permdock.config.ts",
|
|
10
|
+
"permdock.config.mts",
|
|
11
|
+
"permdock.config.js",
|
|
12
|
+
"permdock.config.mjs"
|
|
13
|
+
];
|
|
14
|
+
/** The PermDock config file in `root`, if there is one. */
|
|
15
|
+
function permdockConfig(root) {
|
|
16
|
+
return PERMDOCK_CONFIGS.find((file) => existsSync(resolve(root, file)));
|
|
17
|
+
}
|
|
18
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
|
+
const isString = (value) => typeof value === "string";
|
|
20
|
+
const strings = (value) => Array.isArray(value) ? value.filter(isString) : [];
|
|
21
|
+
const column = (value) => isRecord(value) && isString(value["column"]) ? { column: value["column"] } : void 0;
|
|
22
|
+
function manifestValue(value, accept) {
|
|
23
|
+
if (!isRecord(value)) return void 0;
|
|
24
|
+
if (isString(value["column"])) return { column: value["column"] };
|
|
25
|
+
return accept(value["value"]) ? { value: value["value"] } : void 0;
|
|
26
|
+
}
|
|
27
|
+
const roleValue = (value) => isString(value) || Array.isArray(value) && value.every(isString);
|
|
28
|
+
function membership(value) {
|
|
29
|
+
if (!isRecord(value) || !isString(value["table"])) return void 0;
|
|
30
|
+
const user = column(value["user"]);
|
|
31
|
+
const id = column(value["id"]);
|
|
32
|
+
const scope = manifestValue(value["scope"], isString);
|
|
33
|
+
if (!user || !id || !scope) return void 0;
|
|
34
|
+
const role = manifestValue(value["role"], roleValue);
|
|
35
|
+
const expiresAt = column(value["expiresAt"]);
|
|
36
|
+
return {
|
|
37
|
+
table: value["table"],
|
|
38
|
+
user,
|
|
39
|
+
scope,
|
|
40
|
+
id,
|
|
41
|
+
...role ? { role } : {},
|
|
42
|
+
...expiresAt ? { expiresAt } : {},
|
|
43
|
+
columns: strings(value["columns"])
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** Reads a parsed manifest; throws with the reason when it isn't version 1. */
|
|
47
|
+
function parseManifest(json) {
|
|
48
|
+
if (!isRecord(json)) throw new TypeError("not a JSON object");
|
|
49
|
+
if (json["version"] !== 1) throw new TypeError(`version ${String(json["version"])} is not supported (this release reads version 1)`);
|
|
50
|
+
const hook = json["hook"];
|
|
51
|
+
const rls = json["rls"];
|
|
52
|
+
if (isRecord(rls) && rls["mode"] !== "jwt" && rls["mode"] !== "database") throw new TypeError(`rls.mode ${JSON.stringify(rls["mode"])} is not supported (this release reads "jwt" and "database")`);
|
|
53
|
+
const budget = isRecord(json["budget"]) ? json["budget"]["bytes"] : void 0;
|
|
54
|
+
return {
|
|
55
|
+
version: 1,
|
|
56
|
+
...typeof budget === "number" ? { budget } : {},
|
|
57
|
+
...isRecord(hook) && isString(hook["schema"]) && isString(hook["function"]) ? { hook: {
|
|
58
|
+
schema: hook["schema"],
|
|
59
|
+
function: hook["function"]
|
|
60
|
+
} } : {},
|
|
61
|
+
...isString(json["tenantClaim"]) ? { tenantClaim: json["tenantClaim"] } : {},
|
|
62
|
+
claims: (Array.isArray(json["claims"]) ? json["claims"] : []).flatMap((claim) => isRecord(claim) && isString(claim["name"]) && isString(claim["source"]) ? [{
|
|
63
|
+
name: claim["name"],
|
|
64
|
+
source: claim["source"]
|
|
65
|
+
}] : []),
|
|
66
|
+
memberships: (Array.isArray(json["memberships"]) ? json["memberships"] : []).flatMap((entry) => {
|
|
67
|
+
const parsed = membership(entry);
|
|
68
|
+
return parsed ? [parsed] : [];
|
|
69
|
+
}),
|
|
70
|
+
...isRecord(rls) && isString(rls["schema"]) ? { rls: {
|
|
71
|
+
schema: rls["schema"],
|
|
72
|
+
mode: rls["mode"] === "jwt" ? "jwt" : "database",
|
|
73
|
+
...isString(rls["tenantClaim"]) ? { tenantClaim: rls["tenantClaim"] } : {},
|
|
74
|
+
scopes: (Array.isArray(rls["scopes"]) ? rls["scopes"] : []).flatMap((scope) => isRecord(scope) && isString(scope["name"]) ? [{
|
|
75
|
+
name: scope["name"],
|
|
76
|
+
...isString(scope["type"]) ? { type: scope["type"] } : {},
|
|
77
|
+
...isString(scope["within"]) ? { within: scope["within"] } : {}
|
|
78
|
+
}] : []),
|
|
79
|
+
helpers: (Array.isArray(rls["helpers"]) ? rls["helpers"] : []).flatMap((helper) => isRecord(helper) && isString(helper["name"]) && isString(helper["args"]) && isString(helper["returns"]) ? [{
|
|
80
|
+
name: helper["name"],
|
|
81
|
+
args: helper["args"],
|
|
82
|
+
returns: helper["returns"],
|
|
83
|
+
execute: strings(helper["execute"])
|
|
84
|
+
}] : [])
|
|
85
|
+
} } : {},
|
|
86
|
+
decidingColumns: strings(json["decidingColumns"])
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The keys of a parsed `permissions.catalog.json`, each with its scope and
|
|
91
|
+
* its `rowConditions` flag when it is a boolean. A non-boolean flag is
|
|
92
|
+
* dropped, so `permdockKeyStatus` reads the key as unknown. Throws unless
|
|
93
|
+
* the catalog is version 1.
|
|
94
|
+
*/
|
|
95
|
+
function parseCatalog(json) {
|
|
96
|
+
if (!isRecord(json) || !Array.isArray(json["permissions"])) throw new TypeError("has no permissions array");
|
|
97
|
+
if (json["version"] !== 1) throw new TypeError(`version ${String(json["version"])} is not supported (this release reads version 1)`);
|
|
98
|
+
return { permissions: json["permissions"].flatMap((permission) => {
|
|
99
|
+
if (!isRecord(permission) || !isString(permission["key"])) return [];
|
|
100
|
+
const flag = permission["rowConditions"];
|
|
101
|
+
const scope = permission["scope"];
|
|
102
|
+
return [{
|
|
103
|
+
key: permission["key"],
|
|
104
|
+
...typeof flag === "boolean" ? { rowConditions: flag } : {},
|
|
105
|
+
...isString(scope) ? { scope } : {}
|
|
106
|
+
}];
|
|
107
|
+
}) };
|
|
108
|
+
}
|
|
109
|
+
async function readJson(root, path) {
|
|
110
|
+
const absolute = resolve(root, path);
|
|
111
|
+
if (!existsSync(absolute)) return { missing: true };
|
|
112
|
+
try {
|
|
113
|
+
return { json: JSON.parse(await readFile(absolute, "utf8")) };
|
|
114
|
+
} catch (cause) {
|
|
115
|
+
return { problem: `${path}: ${cause instanceof Error ? cause.message : String(cause)}` };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Reads PermDock's JSON outputs: the manifest `permdock supabase inspect
|
|
120
|
+
* --out` writes and the catalog `permdock catalog` writes. Nothing is
|
|
121
|
+
* imported from PermDock. Returns `undefined` when the project has neither a
|
|
122
|
+
* PermDock config nor a manifest.
|
|
123
|
+
*/
|
|
124
|
+
async function readPermdock(root, paths) {
|
|
125
|
+
const config = permdockConfig(root);
|
|
126
|
+
const problems = [];
|
|
127
|
+
const manifestFile = await readJson(root, paths.manifest);
|
|
128
|
+
let manifest;
|
|
129
|
+
if ("json" in manifestFile) try {
|
|
130
|
+
manifest = parseManifest(manifestFile.json);
|
|
131
|
+
} catch (cause) {
|
|
132
|
+
problems.push(`${paths.manifest}: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
133
|
+
}
|
|
134
|
+
else if ("problem" in manifestFile) problems.push(manifestFile.problem);
|
|
135
|
+
if (!config && !manifest && "missing" in manifestFile) return void 0;
|
|
136
|
+
const catalogFile = await readJson(root, paths.catalog);
|
|
137
|
+
let catalog;
|
|
138
|
+
if ("json" in catalogFile) try {
|
|
139
|
+
catalog = parseCatalog(catalogFile.json);
|
|
140
|
+
} catch (cause) {
|
|
141
|
+
problems.push(`${paths.catalog}: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
142
|
+
}
|
|
143
|
+
else if ("problem" in catalogFile) problems.push(catalogFile.problem);
|
|
144
|
+
return {
|
|
145
|
+
...config ? { config } : {},
|
|
146
|
+
manifestPath: paths.manifest,
|
|
147
|
+
...manifest ? { manifest } : {},
|
|
148
|
+
catalogPath: paths.catalog,
|
|
149
|
+
...catalog ? { catalog } : {},
|
|
150
|
+
problems
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** How findings name the PermDock project: its config file or its manifest. */
|
|
154
|
+
const permdockSource = (project) => project.config ?? project.manifestPath;
|
|
155
|
+
const HOOK_MARKER = /^--\s*permdock:hook\s+v(\d+)([^\n]*)$/m;
|
|
156
|
+
const GRANTS_MARKER = /^--\s*permdock:grants\s+v(\d+)([^\n]*)$/m;
|
|
157
|
+
function markerFields(rest) {
|
|
158
|
+
const fields = /* @__PURE__ */ new Map();
|
|
159
|
+
for (const match of rest.matchAll(/(\w+)=(\S*)/g)) fields.set(match[1], match[2]);
|
|
160
|
+
return fields;
|
|
161
|
+
}
|
|
162
|
+
/** The `-- permdock:hook v1 schema=... tenant=... budget=... claims=...` line PermDock's hook file starts with. */
|
|
163
|
+
function parseHookMarker(sql) {
|
|
164
|
+
const match = HOOK_MARKER.exec(sql);
|
|
165
|
+
if (!match) return void 0;
|
|
166
|
+
const fields = markerFields(match[2]);
|
|
167
|
+
const budget = Number(fields.get("budget"));
|
|
168
|
+
const schema = fields.get("schema");
|
|
169
|
+
const tenantClaim = fields.get("tenant");
|
|
170
|
+
return {
|
|
171
|
+
version: Number(match[1]),
|
|
172
|
+
...schema ? { schema } : {},
|
|
173
|
+
...tenantClaim ? { tenantClaim } : {},
|
|
174
|
+
...Number.isFinite(budget) && fields.has("budget") ? { budget } : {},
|
|
175
|
+
claims: (fields.get("claims") ?? "").split(",").filter(Boolean)
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/** The `-- permdock:grants v1 schema=...` line of the migration `--grants-out` writes. */
|
|
179
|
+
function parseGrantsMarker(sql) {
|
|
180
|
+
const match = GRANTS_MARKER.exec(sql);
|
|
181
|
+
if (!match) return void 0;
|
|
182
|
+
const schema = markerFields(match[2]).get("schema");
|
|
183
|
+
return {
|
|
184
|
+
version: Number(match[1]),
|
|
185
|
+
...schema ? { schema } : {}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* PermDock mode, when the project uses PermDock and `entitlements.permdock`
|
|
190
|
+
* is not `false`. The scope is `entitlements.permdock.scope`, which must be
|
|
191
|
+
* one of the manifest's `rls.scopes`, else the one scope without `within`.
|
|
192
|
+
* No root scope, or more than one, is invalid rather than a guess. A
|
|
193
|
+
* PermDock project without a readable manifest or without its `rls` block
|
|
194
|
+
* is invalid too, so the module never falls back to `tenant` on its own.
|
|
195
|
+
*/
|
|
196
|
+
function entitlementsMode(config, project) {
|
|
197
|
+
const setting = config.entitlements.permdock;
|
|
198
|
+
if (setting === false || !project) return { kind: "tenant" };
|
|
199
|
+
const optOut = "or set entitlements.permdock: false to keep the tenant module's memberships.";
|
|
200
|
+
if (!project.manifest) {
|
|
201
|
+
const problem = project.problems.find((entry) => entry.startsWith(project.manifestPath));
|
|
202
|
+
return {
|
|
203
|
+
kind: "invalid",
|
|
204
|
+
problem: problem ? `Could not read PermDock's manifest: ${problem}. Run \`permdock supabase inspect --out\` with a current PermDock, ${optOut}` : `${permdockSource(project)} is a PermDock project, but there is no ${project.manifestPath}. Run \`permdock supabase inspect --out\`, ${optOut}`
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
const rls = project.manifest.rls;
|
|
208
|
+
if (!rls) return {
|
|
209
|
+
kind: "invalid",
|
|
210
|
+
problem: `${project.manifestPath} has no rls block, so the entitlements module can't find PermDock's membership helpers. Run \`permdock rls generate\`, then \`permdock supabase inspect --out\`, ${optOut}`
|
|
211
|
+
};
|
|
212
|
+
const names = rls.scopes.map((scope) => scope.name).join(", ") || "none";
|
|
213
|
+
let scope;
|
|
214
|
+
if (setting.scope === void 0) {
|
|
215
|
+
const roots = rls.scopes.filter((entry) => entry.within === void 0);
|
|
216
|
+
if (roots.length !== 1) return {
|
|
217
|
+
kind: "invalid",
|
|
218
|
+
problem: `${project.manifestPath} has no single root scope (${roots.map((entry) => entry.name).join(", ") || "none"}), so the entitlements module can't tell which scope tenants are. Set entitlements.permdock: { scope } to one of ${names}.`
|
|
219
|
+
};
|
|
220
|
+
scope = roots[0].name;
|
|
221
|
+
} else {
|
|
222
|
+
scope = setting.scope;
|
|
223
|
+
if (!rls.scopes.some((entry) => entry.name === scope)) return {
|
|
224
|
+
kind: "invalid",
|
|
225
|
+
problem: `entitlements.permdock.scope is "${scope}", but ${project.manifestPath} has the scopes ${names}. Set entitlements.permdock: { scope } to one of them, or remove it to use the root scope.`
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
const declared = rls.scopes.find((entry) => entry.name === scope)?.type;
|
|
229
|
+
if (declared === void 0) return {
|
|
230
|
+
kind: "invalid",
|
|
231
|
+
problem: `${project.manifestPath} gives scope "${scope}" no type, so the entitlements module can't tell its id type. Run \`permdock supabase inspect --out\` with a current PermDock.`
|
|
232
|
+
};
|
|
233
|
+
const type = kitIdType(declared);
|
|
234
|
+
if (type === void 0) return {
|
|
235
|
+
kind: "invalid",
|
|
236
|
+
problem: `${project.manifestPath} gives scope "${scope}" the type ${declared}, but the entitlements module renders only ${KIT_ID_TYPES.join(", ").replace(/, (?=[^,]*$)/, " or ")} ids.`
|
|
237
|
+
};
|
|
238
|
+
return {
|
|
239
|
+
kind: "permdock",
|
|
240
|
+
permdock: {
|
|
241
|
+
schema: rls.schema,
|
|
242
|
+
scope,
|
|
243
|
+
idType: type,
|
|
244
|
+
memberships: project.manifest.memberships.map((source) => ({
|
|
245
|
+
table: source.table,
|
|
246
|
+
userColumn: source.user.column,
|
|
247
|
+
scope: source.scope,
|
|
248
|
+
idColumn: source.id.column
|
|
249
|
+
}))
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* The helpers the `entitlements` module calls for the chosen scope:
|
|
255
|
+
* `member_<scope>_ids` from `has_entitlement` as `authenticated`, and
|
|
256
|
+
* `member_<scope>_ids_for` from `feature_claims`, which PermDock's hook runs
|
|
257
|
+
* as `supabase_auth_admin`.
|
|
258
|
+
*/
|
|
259
|
+
const entitlementRequirements = (permdock) => [{
|
|
260
|
+
kind: "member",
|
|
261
|
+
helper: `${permdock.schema}.member_${permdock.scope}_ids`,
|
|
262
|
+
caller: "has_entitlement",
|
|
263
|
+
role: "authenticated"
|
|
264
|
+
}, {
|
|
265
|
+
kind: "member-for",
|
|
266
|
+
helper: `${permdock.schema}.member_${permdock.scope}_ids_for`,
|
|
267
|
+
caller: "feature_claims",
|
|
268
|
+
role: "supabase_auth_admin"
|
|
269
|
+
}];
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region src/cli/read-sets.ts
|
|
272
|
+
/** Every read set exported by the modules in `config.readSets`. */
|
|
273
|
+
async function loadReadSets(config) {
|
|
274
|
+
const sets = [];
|
|
275
|
+
for (const entry of config.readSets) {
|
|
276
|
+
const loaded = await importModule(resolve(config.root, entry));
|
|
277
|
+
const found = Object.values(loaded).filter(isReadSet);
|
|
278
|
+
if (found.length === 0) throw new Error(`${entry} exports no read set (defineReadSet)`);
|
|
279
|
+
for (const set of found) if (!sets.includes(set)) sets.push(set);
|
|
280
|
+
}
|
|
281
|
+
return sets;
|
|
282
|
+
}
|
|
283
|
+
/** The compiled functions for `config.readSets`; empty when none are configured. */
|
|
284
|
+
async function compiledReadSets(config) {
|
|
285
|
+
if (config.readSets.length === 0) return [];
|
|
286
|
+
return compileReadSets(await loadReadSets(config));
|
|
287
|
+
}
|
|
288
|
+
//#endregion
|
|
289
|
+
export { parseHookMarker as a, parseGrantsMarker as i, entitlementRequirements as n, permdockSource as o, entitlementsMode as r, readPermdock as s, compiledReadSets as t };
|
|
@@ -2,7 +2,7 @@ import { n as __toESM } from "./rolldown-runtime-BPOCksWG.js";
|
|
|
2
2
|
import { c as parseArgs$2, i as joinRepeated, l as renderUsage, n as cliContext, o as listArgs, s as defineCommand, t as GLOBAL_ARGS, u as runCommand } from "./command-CK14fP91.js";
|
|
3
3
|
import { n as CliError, r as toCliError } from "./errors-4v4DTtda.js";
|
|
4
4
|
import { n as highlight, r as painter } from "./style-C0NFdJRL.js";
|
|
5
|
-
import { t as VERSION } from "./version-
|
|
5
|
+
import { t as VERSION } from "./version-BDJuO0UR.js";
|
|
6
6
|
import { stripVTControlCharacters } from "node:util";
|
|
7
7
|
import { resolve } from "node:path";
|
|
8
8
|
//#region src/cli/legacy.ts
|
|
@@ -134,11 +134,11 @@ function renderError(error, options) {
|
|
|
134
134
|
//#region src/cli/run.ts
|
|
135
135
|
const COMMANDS = /* @__PURE__ */ new Map([
|
|
136
136
|
["init", {
|
|
137
|
-
load: () => import("./init-
|
|
137
|
+
load: () => import("./init-Saf5-R9T.js").then((m) => m.initCommand),
|
|
138
138
|
description: "Writes better-supabase.config.ts, src/lib/supabase/index.ts and glue for the frameworks in package.json"
|
|
139
139
|
}],
|
|
140
140
|
["add", {
|
|
141
|
-
load: () => import("./init-
|
|
141
|
+
load: () => import("./init-Saf5-R9T.js").then((m) => m.addCommand),
|
|
142
142
|
description: "Adds glue for an integration to an existing project"
|
|
143
143
|
}],
|
|
144
144
|
["env", {
|
|
@@ -154,28 +154,32 @@ const COMMANDS = /* @__PURE__ */ new Map([
|
|
|
154
154
|
description: "Installs the Agent Skills that ship with this version of better-supabase"
|
|
155
155
|
}],
|
|
156
156
|
["gen", {
|
|
157
|
-
load: () => import("./gen-
|
|
157
|
+
load: () => import("./gen-BJc9vdyu.js").then((m) => m.genCommand),
|
|
158
158
|
description: "Writes database.types.ts, generated.ts and its metadata module from the database"
|
|
159
159
|
}],
|
|
160
160
|
["introspect", {
|
|
161
|
-
load: () => import("./introspect
|
|
161
|
+
load: () => import("./introspect--H7oGmcd.js").then((m) => m.introspectCommand),
|
|
162
162
|
description: "Saves the database schema as a snapshot for offline gen"
|
|
163
163
|
}],
|
|
164
164
|
["openapi", {
|
|
165
|
-
load: () => import("./openapi-
|
|
165
|
+
load: () => import("./openapi-Cp5Fyta-.js").then((m) => m.openapiCommand),
|
|
166
166
|
description: "Writes the document your createOpenApi() module exports, so CI can check it for drift"
|
|
167
167
|
}],
|
|
168
168
|
["seed", {
|
|
169
|
-
load: () => import("./seed-
|
|
169
|
+
load: () => import("./seed-CUlqWh-8.js").then((m) => m.seedCommand),
|
|
170
170
|
description: "Renders the fixtures from defineSeed() (better-supabase/testing) to SQL"
|
|
171
171
|
}],
|
|
172
172
|
["doctor", {
|
|
173
|
-
load: () => import("./doctor-
|
|
173
|
+
load: () => import("./doctor-L7Z8mYTx.js").then((m) => m.doctorCommand),
|
|
174
174
|
description: "Checks RLS, indexes, drift, auth config and env files; exits 1 on errors, or on warnings with --strict"
|
|
175
175
|
}],
|
|
176
176
|
["sql", {
|
|
177
|
-
load: () => import("./sql-
|
|
178
|
-
description: "Lists, adds, syncs and prints SQL kit modules"
|
|
177
|
+
load: () => import("./sql-DzPbfngx.js").then((m) => m.sqlCommand),
|
|
178
|
+
description: "Lists, adds, syncs, upgrades and prints SQL kit modules"
|
|
179
|
+
}],
|
|
180
|
+
["codemod", {
|
|
181
|
+
load: () => import("./codemod-DqV7612m.js").then((m) => m.codemodCommand),
|
|
182
|
+
description: "Rewrites imports and calls for renamed better-supabase APIs"
|
|
179
183
|
}]
|
|
180
184
|
]);
|
|
181
185
|
function registerCommand(name, command, help) {
|
|
@@ -308,8 +312,8 @@ async function run(argv, options = {}) {
|
|
|
308
312
|
try {
|
|
309
313
|
const [loaded, { loadConfig }, { parseEnv }] = await Promise.all([
|
|
310
314
|
load(),
|
|
311
|
-
import("./config-
|
|
312
|
-
import("./env-
|
|
315
|
+
import("./config-dtoekM0v.js"),
|
|
316
|
+
import("./env-DmKv_G4A.js")
|
|
313
317
|
]);
|
|
314
318
|
command = loaded;
|
|
315
319
|
const globals = parseArgs$2(rest, GLOBAL_ARGS);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as defineCliCommand } from "./command-CK14fP91.js";
|
|
2
2
|
import { r as writeIfChanged, t as display } from "./io-k41_z-jT.js";
|
|
3
|
-
import { r as importExport, s as stdinDatabaseUrl, t as databaseUrl } from "./config-
|
|
3
|
+
import { r as importExport, s as stdinDatabaseUrl, t as databaseUrl } from "./config-CPVpXP5I.js";
|
|
4
4
|
import { n as withSpinner } from "./prompts-BNcNfAve.js";
|
|
5
5
|
import { t as connect } from "./db-DOBPt660.js";
|
|
6
6
|
import { resolve } from "node:path";
|