permdock 0.0.0 → 0.1.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 +268 -1
- package/dist/a2a/index.d.ts +178 -0
- package/dist/a2a/index.js +271 -0
- package/dist/ai-sdk/index.d.ts +74 -0
- package/dist/ai-sdk/index.js +137 -0
- package/dist/approval-required-TzNB9oQA.js +6 -0
- package/dist/approvals/index.d.ts +3 -0
- package/dist/approvals/index.js +4 -0
- package/dist/approvals-DaxY-Bdg.js +218 -0
- package/dist/approvers-aH0PJkmf.js +20 -0
- package/dist/arazzo-CTeVuXr5.js +70 -0
- package/dist/arazzo-aoTkqYsJ.js +54 -0
- package/dist/authzen/index.d.ts +48 -0
- package/dist/authzen/index.js +336 -0
- package/dist/better-auth/index.d.ts +92 -0
- package/dist/better-auth/index.js +324 -0
- package/dist/budget-JqcRqyhK.d.ts +11 -0
- package/dist/budget-NbEtbJC_.js +11 -0
- package/dist/capability-B68OFnZx.js +171 -0
- package/dist/capability-BDG_nkxt.d.ts +99 -0
- package/dist/catalog/index.d.ts +12 -0
- package/dist/catalog/index.js +2 -0
- package/dist/catalog-B0E6bggc.js +48 -0
- package/dist/catalog-H-vFGwWK.js +55 -0
- package/dist/catalog-doc-BSo_Q_-6.js +298 -0
- package/dist/catalog-idsHc0vo.js +2 -0
- package/dist/catalog-path-CnI0XTFK.js +12 -0
- package/dist/claude-agent/index.d.ts +81 -0
- package/dist/claude-agent/index.js +83 -0
- package/dist/clerk/index.d.ts +56 -0
- package/dist/clerk/index.js +280 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +20 -0
- package/dist/cli/index.d.ts +46 -0
- package/dist/cli/index.js +5 -0
- package/dist/cloud/index.d.ts +91 -0
- package/dist/cloud/index.js +390 -0
- package/dist/cloud-BNQTrmrr.js +50 -0
- package/dist/cloud-Cuxr6Czw.js +117 -0
- package/dist/collect-B7_TIfmg.js +49 -0
- package/dist/collect-O-tOtbnk.js +350 -0
- package/dist/collect-fRPAQIWb.js +2 -0
- package/dist/commands-BMh_Etm2.js +93 -0
- package/dist/compact-y6vfu2_f.js +19 -0
- package/dist/compare-pfyVnBjE.js +12 -0
- package/dist/compile-CQbvyIBr.d.ts +30 -0
- package/dist/compile-D22iwvuV.js +558 -0
- package/dist/config-BPYmjTOp.js +26 -0
- package/dist/connection-JvqwHODC.js +194 -0
- package/dist/context-CKEAabd7.js +73 -0
- package/dist/context-gtAwAILx.js +6 -0
- package/dist/convex/index.d.ts +40 -0
- package/dist/convex/index.js +55 -0
- package/dist/create-BKF3dgFk.d.ts +162 -0
- package/dist/create-CSkhDU9T.js +222 -0
- package/dist/credential-B_rkUNlY.js +326 -0
- package/dist/credentials-BgRX3WEg.js +268 -0
- package/dist/describe-Bt1YD5uS.js +99 -0
- package/dist/describe-DernyItf.d.ts +37 -0
- package/dist/diff-BUzf5Poi.js +48 -0
- package/dist/diff-x5Il8LVa.js +418 -0
- package/dist/digest-B3kc_PgQ.d.ts +19 -0
- package/dist/digest-BI-6aa6d.js +27 -0
- package/dist/doctor-BGle8Gqi.js +1314 -0
- package/dist/doctor-Bqo6FwUa.js +53 -0
- package/dist/drizzle/index.d.ts +72 -0
- package/dist/drizzle/index.js +160 -0
- package/dist/duration-xK2jGFVc.js +25 -0
- package/dist/elysia/index.d.ts +71 -0
- package/dist/elysia/index.js +103 -0
- package/dist/errors-DSMnAVNa.js +43 -0
- package/dist/errors-DbZ1YOnb.d.ts +138 -0
- package/dist/errors-Iy71s7Oj.js +177 -0
- package/dist/errors-m3u9TmDu.js +27 -0
- package/dist/evaluations-DsAU9ppl.js +479 -0
- package/dist/eve/index.d.ts +95 -0
- package/dist/eve/index.js +181 -0
- package/dist/express/index.d.ts +46 -0
- package/dist/express/index.js +108 -0
- package/dist/fastify/index.d.ts +56 -0
- package/dist/fastify/index.js +141 -0
- package/dist/files-B_wAGYmt.js +121 -0
- package/dist/fixtures-Cvaw0gDG.js +64 -0
- package/dist/freeze-y1_jQL4v.js +31 -0
- package/dist/from-snapshot-BMGnhmgv.js +552 -0
- package/dist/generate-CH7ThJ14.js +173 -0
- package/dist/grantee-Bv04_Vzf.js +521 -0
- package/dist/headers-B5RRv3Xm.js +6 -0
- package/dist/headers-C8SHQccD.d.ts +6 -0
- package/dist/helpers-DnSOrhB9.js +682 -0
- package/dist/hono/index.d.ts +70 -0
- package/dist/hono/index.js +131 -0
- package/dist/hosted-BwKQ1BTA.js +265 -0
- package/dist/http-DPuDaChb.d.ts +13 -0
- package/dist/http-GgVApX1k.js +111 -0
- package/dist/index-CltcQ4Bf.d.ts +138 -0
- package/dist/index-LF_hS-yn.d.ts +177 -0
- package/dist/index-fG6NSXlc.d.ts +9 -0
- package/dist/index-xIxJLwOQ.d.ts +415 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +21 -0
- package/dist/jwt/index.d.ts +87 -0
- package/dist/jwt/index.js +571 -0
- package/dist/kernel-YOGCWNLf.js +211 -0
- package/dist/kysely/index.d.ts +77 -0
- package/dist/kysely/index.js +129 -0
- package/dist/load-BZ24CpZP.js +69 -0
- package/dist/load-QOOm1z70.js +2 -0
- package/dist/load-jose-BL6LH4bL.js +11 -0
- package/dist/lru-8q4WZjBV.js +28 -0
- package/dist/manifest-DDQbC6K0.d.ts +118 -0
- package/dist/map-DowSO96j.js +158 -0
- package/dist/map-claims-B_6I1Rn-.js +360 -0
- package/dist/map-error-RJ3ZsUyA.js +16 -0
- package/dist/markers-B0hYLvMD.js +60 -0
- package/dist/may-use-CnFEjVEp.js +37 -0
- package/dist/mcp/index.d.ts +127 -0
- package/dist/mcp/index.js +563 -0
- package/dist/nest/index.d.ts +80 -0
- package/dist/nest/index.js +270 -0
- package/dist/next/client.d.ts +24 -0
- package/dist/next/client.js +31 -0
- package/dist/next/index.d.ts +110 -0
- package/dist/next/index.js +195 -0
- package/dist/next/plugin.d.ts +14 -0
- package/dist/next/plugin.js +2 -0
- package/dist/node/index.d.ts +43 -0
- package/dist/node/index.js +66 -0
- package/dist/openai/index.d.ts +71 -0
- package/dist/openai/index.js +105 -0
- package/dist/openapi/index.d.ts +93 -0
- package/dist/openapi/index.js +3 -0
- package/dist/openapi-CwePaF7C.js +164 -0
- package/dist/openapi-DWD0Uc_4.js +250 -0
- package/dist/openapi-DcqM8nU7.js +306 -0
- package/dist/openapi-import-BWRUNNeW.js +5959 -0
- package/dist/openapi-schema-D8j_T9tO.js +6902 -0
- package/dist/orpc/index.d.ts +64 -0
- package/dist/orpc/index.js +188 -0
- package/dist/otel/index.d.ts +13 -0
- package/dist/otel/index.js +202 -0
- package/dist/package-root-zGkxO3oN.js +30 -0
- package/dist/parse-DPfIvFMU.js +135 -0
- package/dist/pdp/index.d.ts +22 -0
- package/dist/pdp/index.js +795 -0
- package/dist/peer-BOr_kJE1.js +31 -0
- package/dist/permdock-yoZ7EjxX.js +2956 -0
- package/dist/permissions-B4apnahQ.d.ts +185 -0
- package/dist/permissions-B8vCg_bI.d.ts +52 -0
- package/dist/permissions-CofRqesP.js +142 -0
- package/dist/permissions-DC7GROPA.js +600 -0
- package/dist/pg-4GJWDUxG.js +953 -0
- package/dist/pins-CqE1jZuF.js +12 -0
- package/dist/plugin-4gr7IxFJ.js +65 -0
- package/dist/policy-ANp36PnI.js +971 -0
- package/dist/policy-CInmNGkM.d.ts +1959 -0
- package/dist/policy-Cq2fB8Q5.d.ts +20 -0
- package/dist/prisma/index.d.ts +135 -0
- package/dist/prisma/index.js +430 -0
- package/dist/problem-Cgp9-KZA.js +226 -0
- package/dist/prompt-CXYhLfsS.js +32 -0
- package/dist/protected-B4K3BKoX.js +138 -0
- package/dist/protected-BuPAycJT.d.ts +26 -0
- package/dist/protected-wY7nXhY9.d.ts +23 -0
- package/dist/provider-_wx46HpB.js +48 -0
- package/dist/provider-wTAUda2v.d.ts +6 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +6 -0
- package/dist/react/provider-client.d.ts +2 -0
- package/dist/react/provider-client.js +3 -0
- package/dist/react-native/index.d.ts +42 -0
- package/dist/react-native/index.js +174 -0
- package/dist/refs-ChLSxbST.js +90 -0
- package/dist/relations-r4soIFZB.js +426 -0
- package/dist/revocations-Cy06JNx2.d.ts +21 -0
- package/dist/rls-BOFU3chG.js +233 -0
- package/dist/rls-CJVja9Ww.js +2119 -0
- package/dist/rls-graph-DxQ39PJj.js +371 -0
- package/dist/rls-helpers-BxRuif0l.js +1346 -0
- package/dist/rls-import-CXV6LBlS.js +942 -0
- package/dist/rls-migrate-DrFPbf8p.js +366 -0
- package/dist/row-check-BajTgQZ-.d.ts +43 -0
- package/dist/run-CJ6UvS3a.js +155 -0
- package/dist/runtime-DP9ttFh1.js +27 -0
- package/dist/saas-BRrZzJkM.js +1193 -0
- package/dist/schema-P8yoma__.js +296 -0
- package/dist/scim/index.d.ts +2 -0
- package/dist/scim/index.js +2 -0
- package/dist/scim-9NFa0XVZ.js +1445 -0
- package/dist/scopes-cKVp_WTw.js +212 -0
- package/dist/server/index.d.ts +123 -0
- package/dist/server/index.js +8 -0
- package/dist/sha256-BO0swRXL.js +150 -0
- package/dist/sink-Bd9PSyfq.js +141 -0
- package/dist/sink-Cfr9-7YC.d.ts +104 -0
- package/dist/skills-C_lpV4Jx.js +50 -0
- package/dist/skills-Dx3QLnMY.js +110 -0
- package/dist/snapshot-DE8dE_hz.js +1051 -0
- package/dist/solid/index.d.ts +63 -0
- package/dist/solid/index.js +197 -0
- package/dist/source-DoBBYJi2.js +6 -0
- package/dist/sources-DOpW5Ila.d.ts +347 -0
- package/dist/sources-DVHM3Mwq.js +284 -0
- package/dist/sql-Bll1d7y0.js +22 -0
- package/dist/src-CTNT-PBW.js +430 -0
- package/dist/ssf/index.d.ts +3 -0
- package/dist/ssf/index.js +622 -0
- package/dist/store-Bq90395i.d.ts +27 -0
- package/dist/store-C6hFW6ta.js +508 -0
- package/dist/stores-CkG2HrSg.js +140 -0
- package/dist/stores-CvOnu_2T.d.ts +41 -0
- package/dist/stream-BhMfZOwr.d.ts +12 -0
- package/dist/stream-Q_xlB6Ko.js +52 -0
- package/dist/style-CTm1AXDT.js +22 -0
- package/dist/subject-C6dLxqHU.js +24 -0
- package/dist/subject-settings-xt7V845g.js +82 -0
- package/dist/supabase/index.d.ts +67 -0
- package/dist/supabase/index.js +4 -0
- package/dist/supabase/middleware.d.ts +77 -0
- package/dist/supabase/middleware.js +68 -0
- package/dist/supabase-D8UlBA7Z.js +83 -0
- package/dist/supabase-DTxGtYdi.js +796 -0
- package/dist/supabase-hook-DW-xP4hU.js +2 -0
- package/dist/supabase-hook-D_OqGb_V.js +1528 -0
- package/dist/svelte/Protected.svelte +34 -0
- package/dist/svelte/index.d.ts +10 -0
- package/dist/svelte/index.js +53 -0
- package/dist/svelte/runtime.d.ts +6 -0
- package/dist/svelte/runtime.js +3 -0
- package/dist/svelte/source.d.ts +10 -0
- package/dist/svelte/source.js +8 -0
- package/dist/terminal/index.d.ts +171 -0
- package/dist/terminal/index.js +821 -0
- package/dist/testing/index.d.ts +656 -0
- package/dist/testing/index.js +3208 -0
- package/dist/testing/saas/index.d.ts +194 -0
- package/dist/testing/saas/index.js +3 -0
- package/dist/testing/saas/permissions.d.ts +2 -0
- package/dist/testing/saas/permissions.js +2 -0
- package/dist/text-diff-BdkkYSbi.js +15 -0
- package/dist/thenable-okc2xDsj.js +10 -0
- package/dist/timeout-D51niuQP.js +8 -0
- package/dist/trpc/index.d.ts +80 -0
- package/dist/trpc/index.js +205 -0
- package/dist/types-B8w5PFtS.d.ts +141 -0
- package/dist/types-B9dmiiab.d.ts +66 -0
- package/dist/types-BBK-exvJ.d.ts +177 -0
- package/dist/types-BvBk1wgn.d.ts +118 -0
- package/dist/types-CxquUByI.d.ts +9 -0
- package/dist/types-D6Z6-rKJ.d.ts +312 -0
- package/dist/types-DbWdEfcm.d.ts +87 -0
- package/dist/types-bva3i4Gf.d.ts +98 -0
- package/dist/types-i4BAOvdb.d.ts +97 -0
- package/dist/unplugin/index.d.ts +7 -0
- package/dist/unplugin/index.js +30 -0
- package/dist/usage-1ozMubLY.js +42 -0
- package/dist/usage-CUnK6Ou9.js +530 -0
- package/dist/usage-PyEor6GA.js +2 -0
- package/dist/validity-D0uRmJKJ.js +224 -0
- package/dist/verifier-B90agnhl.js +461 -0
- package/dist/version-CnSh33Fj.js +16 -0
- package/dist/vocabulary-Dk0fs-Jk.d.ts +56 -0
- package/dist/vue/index.d.ts +57 -0
- package/dist/vue/index.js +203 -0
- package/dist/webmcp/index.d.ts +75 -0
- package/dist/webmcp/index.js +313 -0
- package/package.json +423 -4
- package/rulesets/permdock.yaml +29 -0
- package/schemas/catalog-v1.json +507 -0
- package/schemas/openapi/oas-3.1.json +1298 -0
- package/schemas/openapi/oas-3.2.json +1516 -0
- package/schemas/openapi/overlay-1.1.json +79 -0
- package/schemas/supabase-claims-v1.json +139 -0
- package/schemas/supabase-manifest-v1.json +217 -0
- package/skills/permdock/SKILL.md +66 -0
- package/skills/permdock-agents/SKILL.md +77 -0
- package/skills/permdock-agents/references/runtimes.md +211 -0
- package/skills/permdock-approvals/SKILL.md +80 -0
- package/skills/permdock-approvals/references/stores-and-resume.md +83 -0
- package/skills/permdock-audit/SKILL.md +67 -0
- package/skills/permdock-credentials/SKILL.md +55 -0
- package/skills/permdock-credentials/references/tokens-keys-links.md +127 -0
- package/skills/permdock-data/SKILL.md +57 -0
- package/skills/permdock-data/references/queries-and-rls.md +54 -0
- package/skills/permdock-data/references/relationships.md +65 -0
- package/skills/permdock-tenancy/SKILL.md +77 -0
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +83 -0
- package/skills/permdock-wire/SKILL.md +116 -0
- package/skills/permdock-wire/references/adapters.md +480 -0
- package/skills/permdock-wire/references/policy-options.md +43 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { i as sqlFiles } from "./files-B_wAGYmt.js";
|
|
2
|
+
import { i as quoteSqlLiteral, n as escapeSqlIdent } from "./sql-Bll1d7y0.js";
|
|
3
|
+
import "./sources-DVHM3Mwq.js";
|
|
4
|
+
import { t as HELPERS } from "./rls-helpers-BxRuif0l.js";
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { relative, resolve } from "node:path";
|
|
7
|
+
import { parse } from "pgsql-parser";
|
|
8
|
+
//#region src/cli/rls-migrate.ts
|
|
9
|
+
function migrateTarget(generated) {
|
|
10
|
+
const granted = /* @__PURE__ */ new Map();
|
|
11
|
+
for (const row of generated.seeds ?? []) {
|
|
12
|
+
if (row.effect !== "allow") continue;
|
|
13
|
+
let keys = granted.get(row.scope);
|
|
14
|
+
if (keys === void 0) {
|
|
15
|
+
keys = /* @__PURE__ */ new Set();
|
|
16
|
+
granted.set(row.scope, keys);
|
|
17
|
+
}
|
|
18
|
+
keys.add(row.grantKey);
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
schema: generated.schema ?? "permdock",
|
|
22
|
+
sql: generated.text,
|
|
23
|
+
permissions: new Set(generated.keys?.permissions ?? []),
|
|
24
|
+
rowConditions: new Set(generated.keys?.rowConditions ?? []),
|
|
25
|
+
granted,
|
|
26
|
+
renamed: generated.keys?.renamed ?? {}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function isNode(value) {
|
|
30
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31
|
+
}
|
|
32
|
+
function child(node, key) {
|
|
33
|
+
return isNode(node) ? node[key] : void 0;
|
|
34
|
+
}
|
|
35
|
+
function list(value) {
|
|
36
|
+
return Array.isArray(value) ? value : [];
|
|
37
|
+
}
|
|
38
|
+
/** libpg_query reports byte offsets; this maps them onto string indices. */
|
|
39
|
+
function charIndex(text) {
|
|
40
|
+
if (Buffer.byteLength(text) === text.length) return (byte) => byte;
|
|
41
|
+
const map = [];
|
|
42
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
43
|
+
const code = text.codePointAt(index) ?? 0;
|
|
44
|
+
const size = Buffer.byteLength(String.fromCodePoint(code));
|
|
45
|
+
for (let byte = 0; byte < size; byte += 1) map.push(index);
|
|
46
|
+
if (code > 65535) index += 1;
|
|
47
|
+
}
|
|
48
|
+
return (byte) => map[byte] ?? text.length;
|
|
49
|
+
}
|
|
50
|
+
/** The index just past the `)` closing the call that starts at `start`. */
|
|
51
|
+
function callEnd(text, start) {
|
|
52
|
+
let depth = 0;
|
|
53
|
+
for (let index = start; index < text.length; index += 1) {
|
|
54
|
+
const char = text[index];
|
|
55
|
+
if (char === "'" || char === "\"") {
|
|
56
|
+
const close = text.indexOf(char, index + 1);
|
|
57
|
+
if (close === -1) return -1;
|
|
58
|
+
index = close;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (char === "-" && text[index + 1] === "-") {
|
|
62
|
+
const close = text.indexOf("\n", index);
|
|
63
|
+
index = close === -1 ? text.length : close;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (char === "/" && text[index + 1] === "*") {
|
|
67
|
+
const close = text.indexOf("*/", index + 2);
|
|
68
|
+
index = close === -1 ? text.length : close + 1;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (char === "(") depth += 1;
|
|
72
|
+
else if (char === ")") {
|
|
73
|
+
depth -= 1;
|
|
74
|
+
if (depth === 0) return index + 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return -1;
|
|
78
|
+
}
|
|
79
|
+
const IDENTIFIER = String.raw`(?:"(?:[^"]|"")+"|[A-Za-z_][\w$]*)`;
|
|
80
|
+
const COLUMN = new RegExp(String.raw`${IDENTIFIER}(?:\s*\.\s*${IDENTIFIER})*`, "uy");
|
|
81
|
+
function columnText(text, start) {
|
|
82
|
+
COLUMN.lastIndex = start;
|
|
83
|
+
return COLUMN.exec(text)?.[0];
|
|
84
|
+
}
|
|
85
|
+
function lineOf(text, index) {
|
|
86
|
+
let line = 1;
|
|
87
|
+
for (let at = text.indexOf("\n"); at !== -1 && at < index;) {
|
|
88
|
+
line += 1;
|
|
89
|
+
at = text.indexOf("\n", at + 1);
|
|
90
|
+
}
|
|
91
|
+
return line;
|
|
92
|
+
}
|
|
93
|
+
function stringConst(node) {
|
|
94
|
+
const value = child(child(child(node, "A_Const"), "sval"), "sval");
|
|
95
|
+
return typeof value === "string" ? value : void 0;
|
|
96
|
+
}
|
|
97
|
+
function isNullConst(node) {
|
|
98
|
+
return child(child(node, "A_Const"), "isnull") === true;
|
|
99
|
+
}
|
|
100
|
+
const literal = quoteSqlLiteral;
|
|
101
|
+
/** The PermDock key for a legacy one: `keys` first, then `renamed`, then the longest matching prefix. */
|
|
102
|
+
function mapKey(config, key, renamed = {}) {
|
|
103
|
+
const exact = config.keys?.[key];
|
|
104
|
+
if (exact !== void 0) return exact;
|
|
105
|
+
if (Object.hasOwn(renamed, key)) return renamed[key] ?? key;
|
|
106
|
+
const prefix = Object.keys(config.prefixes ?? {}).filter((candidate) => key.startsWith(candidate)).toSorted((a, b) => b.length - a.length)[0];
|
|
107
|
+
return prefix === void 0 ? key : `${config.prefixes?.[prefix] ?? ""}${key.slice(prefix.length)}`;
|
|
108
|
+
}
|
|
109
|
+
function skip(reason, detail) {
|
|
110
|
+
return {
|
|
111
|
+
reason,
|
|
112
|
+
detail
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
var Rewriter = class {
|
|
116
|
+
#config;
|
|
117
|
+
#target;
|
|
118
|
+
#text;
|
|
119
|
+
#at;
|
|
120
|
+
constructor(config, target, text) {
|
|
121
|
+
this.#config = config;
|
|
122
|
+
this.#target = target;
|
|
123
|
+
this.#text = text;
|
|
124
|
+
this.#at = charIndex(text);
|
|
125
|
+
}
|
|
126
|
+
#helper(name) {
|
|
127
|
+
const { schema, sql } = this.#target;
|
|
128
|
+
const quoted = escapeSqlIdent(schema);
|
|
129
|
+
if (!sql.includes(`function ${quoted}.${name}(`)) return;
|
|
130
|
+
return /^[a-z_][a-z0-9_$]*$/u.test(schema) ? `${schema}.${name}` : `${quoted}.${name}`;
|
|
131
|
+
}
|
|
132
|
+
#key(arg, scope) {
|
|
133
|
+
const legacy = stringConst(arg);
|
|
134
|
+
if (legacy === void 0) return skip("dynamic-key", "the key is not a string literal; map it by hand");
|
|
135
|
+
const key = mapKey(this.#config, legacy, this.#target.renamed);
|
|
136
|
+
if (!this.#target.permissions.has(key)) return skip("unknown-key", `${legacy} maps to ${key}, which the policy does not declare; add it to rls.migrate.keys or the vocabulary`);
|
|
137
|
+
if (this.#target.rowConditions.has(key)) return skip("row-conditions", `${key} has row conditions the helper cannot apply; let rls generate write this table's policy`);
|
|
138
|
+
if (this.#target.granted.get(scope)?.has(key) !== true) return skip("not-granted-on-scope", [...this.#target.granted.values()].some((keys) => keys.has(key)) ? `no role grants ${key} on ${scope}, so the helper would always deny` : `${key} has no unconditional allow row in role_permissions: a conditional, time-bounded or deny-mixed grant splits its grant key, so the helper would always deny`);
|
|
139
|
+
return { to: literal(key) };
|
|
140
|
+
}
|
|
141
|
+
#column(arg) {
|
|
142
|
+
const location = child(child(arg, "ColumnRef"), "location");
|
|
143
|
+
if (typeof location !== "number") return skip("not-a-column", "the id is an expression, not a plain column; rewrite it by hand");
|
|
144
|
+
const text = columnText(this.#text, this.#at(location));
|
|
145
|
+
return text === void 0 ? skip("not-a-column", "the id could not be read as a column") : { to: text };
|
|
146
|
+
}
|
|
147
|
+
#ids(scope, keyArg) {
|
|
148
|
+
const helper = this.#helper(`permitted_${scope}_ids`);
|
|
149
|
+
if (helper === void 0) return skip("missing-helper", `rls generate writes no permitted_${scope}_ids for this policy`);
|
|
150
|
+
const key = this.#key(keyArg, scope);
|
|
151
|
+
return "to" in key ? { to: `${helper}(${key.to})` } : key;
|
|
152
|
+
}
|
|
153
|
+
#row(scope, idArg, keyArg) {
|
|
154
|
+
const column = this.#column(idArg);
|
|
155
|
+
if (!("to" in column)) return column;
|
|
156
|
+
const ids = this.#ids(scope, keyArg);
|
|
157
|
+
return "to" in ids ? { to: `(${column.to} in (select ${ids.to}))` } : ids;
|
|
158
|
+
}
|
|
159
|
+
#global(keyArg, selected) {
|
|
160
|
+
const helper = this.#helper(HELPERS.has);
|
|
161
|
+
if (helper === void 0) return skip("missing-helper", `rls generate writes no ${HELPERS.has}`);
|
|
162
|
+
const key = this.#key(keyArg, "global");
|
|
163
|
+
if (!("to" in key)) return key;
|
|
164
|
+
const call = `${helper}(${key.to})`;
|
|
165
|
+
return { to: selected ? call : `(select ${call})` };
|
|
166
|
+
}
|
|
167
|
+
#membership(scope, idArg) {
|
|
168
|
+
const helper = this.#helper(`member_${scope}_ids`);
|
|
169
|
+
if (helper === void 0) return skip("missing-helper", `rls generate writes no member_${scope}_ids: ${scope} has no membership source`);
|
|
170
|
+
const column = this.#column(idArg);
|
|
171
|
+
return "to" in column ? { to: `(${column.to} in (select ${helper}()))` } : column;
|
|
172
|
+
}
|
|
173
|
+
#scoped(args, selected) {
|
|
174
|
+
const [scopeArg, idArg, keyArg] = args;
|
|
175
|
+
const named = stringConst(scopeArg);
|
|
176
|
+
if (named === void 0) return skip("unknown-scope", "the scope is not a string literal; rewrite it by hand");
|
|
177
|
+
if (this.#config.globalScopes?.includes(named) === true || isNullConst(idArg)) return this.#global(keyArg, selected);
|
|
178
|
+
return this.#row(this.#config.scopes?.[named] ?? named, idArg, keyArg);
|
|
179
|
+
}
|
|
180
|
+
/** `selected`: the call is already a `select` target, so `permdock_has` needs no wrapping subquery. */
|
|
181
|
+
rewrite(call, selected) {
|
|
182
|
+
const { helper, args } = call;
|
|
183
|
+
switch (helper.form) {
|
|
184
|
+
case "ids": return this.#ids(helper.scope, args[0]);
|
|
185
|
+
case "row": return this.#row(helper.scope, args[0], args[1]);
|
|
186
|
+
case "membership": return this.#membership(helper.scope, args[0]);
|
|
187
|
+
case "scoped": return this.#scoped(args, selected);
|
|
188
|
+
case "global": return this.#global(args[0], selected);
|
|
189
|
+
default: return helper;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
call(node) {
|
|
193
|
+
const name = list(node["funcname"]).map((part) => child(child(part, "String"), "sval")).at(-1);
|
|
194
|
+
const location = node["location"];
|
|
195
|
+
if (typeof name !== "string" || typeof location !== "number") return;
|
|
196
|
+
const helper = this.#config.helpers[name];
|
|
197
|
+
if (helper === void 0) return;
|
|
198
|
+
const start = this.#at(location);
|
|
199
|
+
return {
|
|
200
|
+
name,
|
|
201
|
+
helper,
|
|
202
|
+
args: list(node["args"]),
|
|
203
|
+
start,
|
|
204
|
+
end: callEnd(this.#text, start)
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
const POLICY_STATEMENTS = /* @__PURE__ */ new Set(["CreatePolicyStmt", "AlterPolicyStmt"]);
|
|
209
|
+
const BODY_STATEMENTS = /* @__PURE__ */ new Set(["CreateFunctionStmt", "DoStmt"]);
|
|
210
|
+
function bodyStrings(statement) {
|
|
211
|
+
const options = [...list(child(statement, "options")), ...list(child(statement, "args"))];
|
|
212
|
+
const found = [];
|
|
213
|
+
for (const option of options) {
|
|
214
|
+
const element = child(option, "DefElem");
|
|
215
|
+
if (child(element, "defname") !== "as") continue;
|
|
216
|
+
const arg = child(element, "arg");
|
|
217
|
+
const items = [child(arg, "String"), ...list(child(child(arg, "List"), "items")).map((item) => child(item, "String"))];
|
|
218
|
+
for (const item of items) {
|
|
219
|
+
const value = child(item, "sval");
|
|
220
|
+
if (typeof value === "string") found.push(value);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return found;
|
|
224
|
+
}
|
|
225
|
+
/** Rewrites the configured helper calls in one file's policies; everything else is reported. */
|
|
226
|
+
async function migrateSql(file, text, config, target) {
|
|
227
|
+
const rewrites = [];
|
|
228
|
+
const skipped = [];
|
|
229
|
+
const names = Object.keys(config.helpers);
|
|
230
|
+
if (!names.some((name) => text.includes(name))) return {
|
|
231
|
+
rewrites,
|
|
232
|
+
skipped,
|
|
233
|
+
text
|
|
234
|
+
};
|
|
235
|
+
let tree;
|
|
236
|
+
try {
|
|
237
|
+
tree = await parse(text);
|
|
238
|
+
} catch (cause) {
|
|
239
|
+
skipped.push({
|
|
240
|
+
file,
|
|
241
|
+
line: 1,
|
|
242
|
+
call: "",
|
|
243
|
+
reason: "unparsed",
|
|
244
|
+
detail: `the file does not parse: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
245
|
+
});
|
|
246
|
+
return {
|
|
247
|
+
rewrites,
|
|
248
|
+
skipped,
|
|
249
|
+
text
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const rewriter = new Rewriter(config, target, text);
|
|
253
|
+
const at = charIndex(text);
|
|
254
|
+
const edits = [];
|
|
255
|
+
const called = new RegExp(String.raw`\b(${names.map((name) => name.replaceAll(/[$]/gu, String.raw`\$`)).join("|")})\s*\(`, "gu");
|
|
256
|
+
const visit = (node, inPolicy, selected = false) => {
|
|
257
|
+
if (Array.isArray(node)) {
|
|
258
|
+
for (const item of node) visit(item, inPolicy);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (!isNode(node)) return;
|
|
262
|
+
for (const [kind, value] of Object.entries(node)) {
|
|
263
|
+
if (kind === "FuncCall" && isNode(value)) {
|
|
264
|
+
const call = rewriter.call(value);
|
|
265
|
+
if (call !== void 0) {
|
|
266
|
+
const source = call.end === -1 ? call.name : text.slice(call.start, call.end);
|
|
267
|
+
const line = lineOf(text, call.start);
|
|
268
|
+
if (!inPolicy) {
|
|
269
|
+
skipped.push({
|
|
270
|
+
file,
|
|
271
|
+
line,
|
|
272
|
+
call: source,
|
|
273
|
+
reason: "not-in-policy",
|
|
274
|
+
detail: "the call is outside a create or alter policy; rewrite it by hand"
|
|
275
|
+
});
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
const outcome = call.end === -1 ? skip("not-a-column", "the call could not be delimited") : rewriter.rewrite(call, selected);
|
|
279
|
+
if ("to" in outcome) {
|
|
280
|
+
edits.push({
|
|
281
|
+
start: call.start,
|
|
282
|
+
end: call.end,
|
|
283
|
+
to: outcome.to
|
|
284
|
+
});
|
|
285
|
+
rewrites.push({
|
|
286
|
+
file,
|
|
287
|
+
line,
|
|
288
|
+
from: source,
|
|
289
|
+
to: outcome.to
|
|
290
|
+
});
|
|
291
|
+
} else skipped.push({
|
|
292
|
+
file,
|
|
293
|
+
line,
|
|
294
|
+
call: source,
|
|
295
|
+
...outcome
|
|
296
|
+
});
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
visit(value, inPolicy || POLICY_STATEMENTS.has(kind), kind === "ResTarget" || selected && kind === "val");
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
for (const raw of list(child(tree, "stmts"))) {
|
|
304
|
+
const statement = child(raw, "stmt");
|
|
305
|
+
const offset = child(raw, "stmt_location");
|
|
306
|
+
const statementStart = at(typeof offset === "number" ? offset : 0);
|
|
307
|
+
const kind = isNode(statement) ? Object.keys(statement)[0] : void 0;
|
|
308
|
+
if (kind !== void 0 && BODY_STATEMENTS.has(kind)) {
|
|
309
|
+
for (const body of bodyStrings(child(statement, kind))) {
|
|
310
|
+
const bodyStart = text.indexOf(body, statementStart);
|
|
311
|
+
for (const match of body.matchAll(called)) skipped.push({
|
|
312
|
+
file,
|
|
313
|
+
line: lineOf(text, (bodyStart === -1 ? statementStart : bodyStart) + (match.index ?? 0)),
|
|
314
|
+
call: match[1] ?? "",
|
|
315
|
+
reason: "function-body",
|
|
316
|
+
detail: "the call is inside a function body, which runs with its own privileges; rewrite it by hand"
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
visit(statement, false);
|
|
322
|
+
}
|
|
323
|
+
let out = text;
|
|
324
|
+
for (const edit of edits.toSorted((a, b) => b.start - a.start)) out = `${out.slice(0, edit.start)}${edit.to}${out.slice(edit.end)}`;
|
|
325
|
+
return {
|
|
326
|
+
rewrites,
|
|
327
|
+
skipped,
|
|
328
|
+
text: out
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function describe(report, write) {
|
|
332
|
+
const lines = [...report.rewrites.map((item) => `${item.file}:${String(item.line)} ${item.from} -> ${item.to}`), ...report.skipped.map((item) => `skipped ${item.file}:${String(item.line)} ${item.call}: ${item.detail}`)];
|
|
333
|
+
const files = new Set(report.rewrites.map((item) => item.file)).size;
|
|
334
|
+
const unknown = report.skipped.filter((item) => item.reason === "unknown-key").length;
|
|
335
|
+
lines.push(`rls migrate: ${write ? "rewrote" : "would rewrite"} ${String(report.rewrites.length)} call(s) in ${String(files)} file(s), skipped ${String(report.skipped.length)}${unknown === 0 ? "" : `, ${String(unknown)} with an unknown key`}${write ? "" : "; --write applies them"}`);
|
|
336
|
+
return lines.join("\n");
|
|
337
|
+
}
|
|
338
|
+
/** `permdock rls migrate`: a dry run unless `write`; exits 1 while a key is unknown. */
|
|
339
|
+
async function runRlsMigrate(input) {
|
|
340
|
+
const root = resolve(input.cwd, input.sql);
|
|
341
|
+
if (!existsSync(root)) return {
|
|
342
|
+
code: 2,
|
|
343
|
+
output: `rls migrate --sql: ${input.sql} does not exist`
|
|
344
|
+
};
|
|
345
|
+
const files = sqlFiles(root, ["."]);
|
|
346
|
+
const rewrites = [];
|
|
347
|
+
const skipped = [];
|
|
348
|
+
for (const path of files) {
|
|
349
|
+
const file = relative(input.cwd, path);
|
|
350
|
+
const text = readFileSync(path, "utf8");
|
|
351
|
+
const result = await migrateSql(file, text, input.config, input.target);
|
|
352
|
+
rewrites.push(...result.rewrites);
|
|
353
|
+
skipped.push(...result.skipped);
|
|
354
|
+
if (input.write && result.text !== text) writeFileSync(path, result.text);
|
|
355
|
+
}
|
|
356
|
+
const report = {
|
|
357
|
+
rewrites,
|
|
358
|
+
skipped
|
|
359
|
+
};
|
|
360
|
+
return {
|
|
361
|
+
code: skipped.some((item) => item.reason === "unknown-key") ? 1 : 0,
|
|
362
|
+
output: input.json ? JSON.stringify(report, void 0, 2) : describe(report, input.write)
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
//#endregion
|
|
366
|
+
export { migrateTarget, runRlsMigrate };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/conditions/graph-sql.d.ts
|
|
2
|
+
/** Where the graph lives in the database, as the `toWhere` compilers take it. */
|
|
3
|
+
type RelationsMapping = {
|
|
4
|
+
/** The table of each resource the graph reads; default the resource name. */
|
|
5
|
+
readonly tables?: Readonly<Record<string, string>>;
|
|
6
|
+
/**
|
|
7
|
+
* A closure table (`resource`, `ancestor`, `descendant`, `depth`) such as
|
|
8
|
+
* the one `permdock rls` keeps. Without it, parent walks are a bounded
|
|
9
|
+
* recursive query over the resource's own table.
|
|
10
|
+
*/
|
|
11
|
+
readonly closure?: string;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/conditions/subject-settings.d.ts
|
|
15
|
+
type WithSubjectOptions = {
|
|
16
|
+
/** Which settings the generated policies read; match `rls.dialect`. Default `supabase`. */
|
|
17
|
+
readonly dialect?: "supabase" | "guc" | "neon";
|
|
18
|
+
/**
|
|
19
|
+
* `set local role` before the settings: `authenticated` with a principal, `anon` without.
|
|
20
|
+
* `false` keeps the connection's role, for a login role that RLS already applies to.
|
|
21
|
+
*/
|
|
22
|
+
readonly role?: "authenticated" | "anon" | false;
|
|
23
|
+
/** Prefix of the `guc` dialect's settings (`rls.gucPrefix`). Default `app`. */
|
|
24
|
+
readonly gucPrefix?: string;
|
|
25
|
+
/** Claim holding the principal's tenant (`rls.tenantClaim`). Default `tenant_id`. */
|
|
26
|
+
readonly tenantClaim?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Further claims from the verified token, such as `user_role` or `memberships` for `jwt`-mode
|
|
29
|
+
* helpers. `sub`, `role` and the tenant claim always come from the subject.
|
|
30
|
+
*/
|
|
31
|
+
readonly claims?: Readonly<Record<string, unknown>>;
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/conditions/row-check.d.ts
|
|
35
|
+
/** Whether the row a unique key names exists, and if so whether the filter keeps it. */
|
|
36
|
+
type RowCheck = {
|
|
37
|
+
readonly found: false;
|
|
38
|
+
} | {
|
|
39
|
+
readonly found: true;
|
|
40
|
+
readonly granted: boolean;
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
export { WithSubjectOptions as n, RelationsMapping as r, RowCheck as t };
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { a as cliVersion } from "./version-CnSh33Fj.js";
|
|
2
|
+
import { n as loadConfig, r as resolveCwd } from "./config-BPYmjTOp.js";
|
|
3
|
+
import { i as globalArgs, n as commands, o as resolveArgs, r as isCommand, s as stringArg, t as COMMAND_DESCRIPTIONS } from "./commands-BMh_Etm2.js";
|
|
4
|
+
import { i as exitCodeOf, n as cliErrorKind, r as cliProblem } from "./errors-DSMnAVNa.js";
|
|
5
|
+
import { defineCommand, parseArgs, renderUsage, runCommand } from "citty";
|
|
6
|
+
import { stripVTControlCharacters } from "node:util";
|
|
7
|
+
//#region src/cli/run.ts
|
|
8
|
+
const NAMES = Object.keys(commands).filter(isCommand);
|
|
9
|
+
async function run(argv, options) {
|
|
10
|
+
const stdoutChunks = [];
|
|
11
|
+
const stderrChunks = [];
|
|
12
|
+
const io = options?.io ?? {
|
|
13
|
+
stdout: (text) => {
|
|
14
|
+
stdoutChunks.push(text);
|
|
15
|
+
},
|
|
16
|
+
stderr: (text) => {
|
|
17
|
+
stderrChunks.push(text);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const writeOut = (text) => {
|
|
21
|
+
const line = lined(text);
|
|
22
|
+
io.stdout(line);
|
|
23
|
+
if (options?.io !== void 0) stdoutChunks.push(line);
|
|
24
|
+
};
|
|
25
|
+
const writeErr = (text) => {
|
|
26
|
+
const line = lined(text);
|
|
27
|
+
io.stderr(line);
|
|
28
|
+
if (options?.io !== void 0) stderrChunks.push(line);
|
|
29
|
+
};
|
|
30
|
+
const done = (code) => ({
|
|
31
|
+
code,
|
|
32
|
+
stdout: stdoutChunks.join(""),
|
|
33
|
+
stderr: stderrChunks.join("")
|
|
34
|
+
});
|
|
35
|
+
const flags = beforeSeparator(argv);
|
|
36
|
+
const globals = parseArgs([...flags], globalArgs);
|
|
37
|
+
const json = globals.json === true;
|
|
38
|
+
const color = io.color === true && globals.color !== false;
|
|
39
|
+
const plain = (text) => color ? text : stripVTControlCharacters(text);
|
|
40
|
+
const askedHelp = flags.includes("--help") || flags.includes("-h");
|
|
41
|
+
const first = globals._[0];
|
|
42
|
+
const name = first === "help" ? globals._[1] : first;
|
|
43
|
+
let result;
|
|
44
|
+
const contextFor = (cwd, config) => ({
|
|
45
|
+
cwd,
|
|
46
|
+
config,
|
|
47
|
+
io,
|
|
48
|
+
now: io.now?.() ?? /* @__PURE__ */ new Date(),
|
|
49
|
+
json,
|
|
50
|
+
color,
|
|
51
|
+
interactive: io.interactive === true && !json && globals.yes !== true,
|
|
52
|
+
report: (outcome) => {
|
|
53
|
+
result = outcome;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
/** A failed run: text on stderr, or Problem Details on stdout under `--json`. */
|
|
57
|
+
const fail = (kind, message, command) => {
|
|
58
|
+
if (json) writeOut(JSON.stringify(cliProblem(kind, message, command), null, 2));
|
|
59
|
+
else writeErr(message);
|
|
60
|
+
return done(exitCodeOf(kind));
|
|
61
|
+
};
|
|
62
|
+
if (name !== void 0 && !isCommand(name)) return fail("usage", `unknown command '${name}'. Use ${new Intl.ListFormat("en-GB", { type: "disjunction" }).format(NAMES)}.`);
|
|
63
|
+
if (name === void 0 && (flags.includes("--version") || flags.includes("-v"))) {
|
|
64
|
+
writeOut(cliVersion());
|
|
65
|
+
return done(0);
|
|
66
|
+
}
|
|
67
|
+
if (askedHelp || first === "help" || name === void 0) {
|
|
68
|
+
const root = rootCommand();
|
|
69
|
+
const usage = name === void 0 ? await renderUsage(root) : await renderUsage(await load(name, contextFor(options?.cwd ?? process.cwd(), {})), root);
|
|
70
|
+
if (name === void 0 && !askedHelp && first !== "help") {
|
|
71
|
+
writeErr(plain(usage));
|
|
72
|
+
return done(2);
|
|
73
|
+
}
|
|
74
|
+
writeOut(plain(usage));
|
|
75
|
+
return done(0);
|
|
76
|
+
}
|
|
77
|
+
const cwd = resolveCwd(stringArg(globals.cwd), options?.cwd ?? process.cwd());
|
|
78
|
+
let config;
|
|
79
|
+
try {
|
|
80
|
+
config = await loadConfig(cwd, stringArg(globals.config));
|
|
81
|
+
} catch (error) {
|
|
82
|
+
return fail(cliErrorKind(error), error instanceof Error ? error.message : String(error));
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const command = await load(name, contextFor(cwd, config));
|
|
86
|
+
const rawArgs = withoutCommand(argv, name);
|
|
87
|
+
await runCommand(command, { rawArgs: normaliseValues(rawArgs, await resolveArgs(command)) });
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (!(error instanceof Error)) return fail("usage", String(error), name);
|
|
90
|
+
if (error.name === "CLIError") return fail("usage", `${name}: ${stripVTControlCharacters(error.message)}`, name);
|
|
91
|
+
return fail(cliErrorKind(error), error.message, name);
|
|
92
|
+
}
|
|
93
|
+
if (result === void 0) return done(0);
|
|
94
|
+
writeOut(result.output);
|
|
95
|
+
return done(result.code);
|
|
96
|
+
}
|
|
97
|
+
/** The root help lists commands from a static table, so it loads none of them. */
|
|
98
|
+
function rootCommand() {
|
|
99
|
+
return defineCommand({
|
|
100
|
+
meta: {
|
|
101
|
+
name: "permdock",
|
|
102
|
+
description: "Collect, export, diff and check the permissions a PermDock policy declares"
|
|
103
|
+
},
|
|
104
|
+
args: {
|
|
105
|
+
...globalArgs,
|
|
106
|
+
version: {
|
|
107
|
+
type: "boolean",
|
|
108
|
+
alias: "v",
|
|
109
|
+
description: "Print the permdock version"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
subCommands: Object.fromEntries(NAMES.map((name) => [name, defineCommand({ meta: {
|
|
113
|
+
name,
|
|
114
|
+
description: COMMAND_DESCRIPTIONS[name]
|
|
115
|
+
} })]))
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async function load(name, ctx) {
|
|
119
|
+
return (await commands[name]())(ctx);
|
|
120
|
+
}
|
|
121
|
+
function lined(text) {
|
|
122
|
+
return text.endsWith("\n") ? text : `${text}\n`;
|
|
123
|
+
}
|
|
124
|
+
function beforeSeparator(argv) {
|
|
125
|
+
const end = argv.indexOf("--");
|
|
126
|
+
return end === -1 ? argv : argv.slice(0, end);
|
|
127
|
+
}
|
|
128
|
+
/** argv with the command name removed, wherever the global flags put it. */
|
|
129
|
+
function withoutCommand(argv, name) {
|
|
130
|
+
const index = argv.findIndex((token, i) => token === name && argv[i - 1] !== "--cwd" && argv[i - 1] !== "--config");
|
|
131
|
+
return argv.filter((_, i) => i !== index);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* A value never starts with `-` (bar `-` itself): `--out --check` is a bare
|
|
135
|
+
* `--out` and `--check`, as it was before citty, which would take `--check`
|
|
136
|
+
* as the value. A bare string flag reads as `''`; a bare enum flag keeps its
|
|
137
|
+
* default.
|
|
138
|
+
*/
|
|
139
|
+
function normaliseValues(rawArgs, def) {
|
|
140
|
+
const out = [];
|
|
141
|
+
for (const [i, token] of rawArgs.entries()) {
|
|
142
|
+
if (token === "--") {
|
|
143
|
+
out.push(...rawArgs.slice(i));
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
const arg = token.startsWith("--") ? def[token.slice(2)] : void 0;
|
|
147
|
+
const next = rawArgs[i + 1];
|
|
148
|
+
const bare = next === void 0 || next !== "-" && next.startsWith("-");
|
|
149
|
+
if (arg?.type === "enum" && bare) continue;
|
|
150
|
+
out.push(arg?.type === "string" && bare ? `${token}=` : token);
|
|
151
|
+
}
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
export { run as t };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/svelte/protected.ts
|
|
2
|
+
function protectedView(store, reference, data, tenant, _generation) {
|
|
3
|
+
const local = store.permissionState(reference, data);
|
|
4
|
+
return tenant === void 0 ? {
|
|
5
|
+
allowed: local.allowed,
|
|
6
|
+
status: local.status,
|
|
7
|
+
decision: local.decision,
|
|
8
|
+
slot: slotOf(local.allowed, local.status, local.decision)
|
|
9
|
+
} : tenantView(store.get().tenant(tenant), reference, data);
|
|
10
|
+
}
|
|
11
|
+
function tenantView(permdock, reference, data) {
|
|
12
|
+
const decision = permdock.decide(reference, data);
|
|
13
|
+
const allowed = decision.outcome === "granted";
|
|
14
|
+
return {
|
|
15
|
+
allowed,
|
|
16
|
+
status: "ready",
|
|
17
|
+
decision,
|
|
18
|
+
slot: slotOf(allowed, "ready", decision)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function slotOf(allowed, status, decision) {
|
|
22
|
+
if (status === "pending") return "pending";
|
|
23
|
+
if (!allowed || decision.outcome !== "granted") return "fallback";
|
|
24
|
+
return "default";
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { protectedView as t };
|