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,284 @@
|
|
|
1
|
+
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { a as quoteSqlTable, i as quoteSqlLiteral, r as quoteSqlIdent } from "./sql-Bll1d7y0.js";
|
|
3
|
+
//#region src/supabase/sources.ts
|
|
4
|
+
const ident = (name) => quoteSqlIdent(name);
|
|
5
|
+
const literal = quoteSqlLiteral;
|
|
6
|
+
function qualifiedName(name) {
|
|
7
|
+
return name.includes(".") ? name : `public.${name}`;
|
|
8
|
+
}
|
|
9
|
+
function qualified(name) {
|
|
10
|
+
return quoteSqlTable(qualifiedName(name));
|
|
11
|
+
}
|
|
12
|
+
function col(name) {
|
|
13
|
+
return `m.${ident(name)}`;
|
|
14
|
+
}
|
|
15
|
+
function activeRow(row, id) {
|
|
16
|
+
const parts = [`s.${ident(row.id)}::text = (${id})::text`];
|
|
17
|
+
if (row.disabledAt !== void 0) parts.push(`s.${ident(row.disabledAt)} is null`);
|
|
18
|
+
if (row.status !== void 0) {
|
|
19
|
+
const values = row.active ?? [];
|
|
20
|
+
if (values.length === 0) throw new TypeError("PermDock: a suspension status column needs its active values");
|
|
21
|
+
parts.push(`s.${ident(row.status)}::text = any(array[${values.map(literal).join(", ")}]::text[])`);
|
|
22
|
+
}
|
|
23
|
+
if (row.disabledAt === void 0 && row.status === void 0) throw new TypeError("PermDock: a suspension table needs disabledAt or status");
|
|
24
|
+
return `exists (select 1 from ${qualified(row.table)} s where ${parts.join(" and ")})`;
|
|
25
|
+
}
|
|
26
|
+
function filters(shape, owner) {
|
|
27
|
+
const lines = [owner];
|
|
28
|
+
if (shape.expiresAt !== void 0) {
|
|
29
|
+
const expires = col(shape.expiresAt);
|
|
30
|
+
lines.push(`(${expires} is null or ${expires} > now())`);
|
|
31
|
+
}
|
|
32
|
+
const users = shape.suspension?.users;
|
|
33
|
+
if (users !== void 0) lines.push(activeRow(users, col(shape.user)));
|
|
34
|
+
for (const [name, row] of Object.entries(shape.suspension?.scopes ?? {})) {
|
|
35
|
+
const id = shape.idOf(name);
|
|
36
|
+
if (id !== void 0) lines.push(`(${id} is null or ${activeRow(row, id)})`);
|
|
37
|
+
}
|
|
38
|
+
return lines;
|
|
39
|
+
}
|
|
40
|
+
function selectOf(shape, where, user) {
|
|
41
|
+
const fields = [
|
|
42
|
+
...user ? [`${col(shape.user)}::text as user_id`] : [],
|
|
43
|
+
`${shape.scope} as scope`,
|
|
44
|
+
`${shape.id} as id`,
|
|
45
|
+
`${shape.within} as within`,
|
|
46
|
+
`${shape.roles} as roles`,
|
|
47
|
+
`${shape.via} as via`,
|
|
48
|
+
`${shape.expiresAt === void 0 ? "null::bigint" : `floor(extract(epoch from ${col(shape.expiresAt)}))::bigint`} as expires_at`,
|
|
49
|
+
`${shape.grantedBy} as granted_by`,
|
|
50
|
+
`${shape.reason} as reason`,
|
|
51
|
+
`${shape.memberGroup} as member_group`,
|
|
52
|
+
`${shape.managed} as managed_by`,
|
|
53
|
+
`${shape.seats} as seats`
|
|
54
|
+
];
|
|
55
|
+
const group = [...user ? [col(shape.user)] : [], ...shape.groupBy];
|
|
56
|
+
return `select ${fields.join(", ")}
|
|
57
|
+
from ${qualified(shape.table)} m
|
|
58
|
+
where ${where.join("\n and ")}
|
|
59
|
+
group by ${group.join(", ")}`;
|
|
60
|
+
}
|
|
61
|
+
function sqlOf(shape) {
|
|
62
|
+
const suspension = shape.suspension;
|
|
63
|
+
return compact({
|
|
64
|
+
table: shape.table,
|
|
65
|
+
user: shape.user,
|
|
66
|
+
userType: `${qualified(shape.table)}.${ident(shape.user)}%type`,
|
|
67
|
+
reads: [...new Set([suspension?.users, ...Object.values(suspension?.scopes ?? {})].flatMap((row) => row === void 0 ? [] : [row.table]))],
|
|
68
|
+
managed: shape.managedColumn,
|
|
69
|
+
columns: [...new Set(shape.columns)],
|
|
70
|
+
manifest: {
|
|
71
|
+
table: qualifiedName(shape.table),
|
|
72
|
+
...shape.manifest,
|
|
73
|
+
columns: [...new Set(shape.columns)]
|
|
74
|
+
},
|
|
75
|
+
select: (user) => selectOf(shape, filters(shape, `${col(shape.user)} = ${user}`), false),
|
|
76
|
+
list: () => selectOf(shape, filters(shape, `${shape.scope} = $1::text and ${shape.id} = $2::text`), true)
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function rowsOf(result) {
|
|
80
|
+
return Array.isArray(result) ? result : result.rows;
|
|
81
|
+
}
|
|
82
|
+
function strings(value) {
|
|
83
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item !== "") : [];
|
|
84
|
+
}
|
|
85
|
+
function membershipOf(row) {
|
|
86
|
+
const roles = strings(row["roles"]);
|
|
87
|
+
if (typeof row["scope"] !== "string" || typeof row["id"] !== "string") return;
|
|
88
|
+
if (roles.length === 0) return;
|
|
89
|
+
const within = row["within"] !== null && typeof row["within"] === "object" && !Array.isArray(row["within"]) ? Object.fromEntries(Object.entries(row["within"]).filter((entry) => typeof entry[1] === "string")) : void 0;
|
|
90
|
+
const expires = typeof row["expires_at"] === "number" ? row["expires_at"] : typeof row["expires_at"] === "string" && row["expires_at"] !== "" ? Number(row["expires_at"]) : void 0;
|
|
91
|
+
const seats = strings(row["seats"]);
|
|
92
|
+
return compact({
|
|
93
|
+
scope: row["scope"],
|
|
94
|
+
id: row["id"],
|
|
95
|
+
within: within === void 0 || Object.keys(within).length === 0 ? void 0 : within,
|
|
96
|
+
roles: [...roles].toSorted(),
|
|
97
|
+
via: typeof row["via"] === "string" ? row["via"] : void 0,
|
|
98
|
+
expiresAt: Number.isFinite(expires) ? expires : void 0,
|
|
99
|
+
grantedBy: typeof row["granted_by"] === "string" && row["granted_by"] !== "" ? row["granted_by"] : void 0,
|
|
100
|
+
reason: typeof row["reason"] === "string" && row["reason"] !== "" ? row["reason"] : void 0,
|
|
101
|
+
member: typeof row["member_group"] === "string" && row["member_group"] !== "" ? { group: row["member_group"] } : void 0,
|
|
102
|
+
managedBy: row["managed_by"] === "idp" ? "idp" : void 0,
|
|
103
|
+
entitlements: seats.length === 0 ? void 0 : seats
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function sourceOf(sql, query) {
|
|
107
|
+
const run = async (text, values) => {
|
|
108
|
+
if (query === void 0) throw new TypeError(`PermDock: the ${sql.table} membership source needs query to resolve memberships`);
|
|
109
|
+
return rowsOf(await query(text, values));
|
|
110
|
+
};
|
|
111
|
+
return {
|
|
112
|
+
sql,
|
|
113
|
+
async membershipsFor(principal) {
|
|
114
|
+
return (await run(sql.select("$1"), [principal.id])).flatMap((row) => {
|
|
115
|
+
const membership = membershipOf(row);
|
|
116
|
+
return membership === void 0 ? [] : [membership];
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
async list(scope) {
|
|
120
|
+
return (await run(sql.list(), [scope.scope, scope.id])).flatMap((row) => {
|
|
121
|
+
const membership = membershipOf(row);
|
|
122
|
+
return membership === void 0 || typeof row["user_id"] !== "string" ? [] : [{
|
|
123
|
+
principal: { id: row["user_id"] },
|
|
124
|
+
membership
|
|
125
|
+
}];
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Memberships from one table holding every scope: a row per user, scope,
|
|
132
|
+
* instance and role (`user_id, scope, scope_id, role`), with optional
|
|
133
|
+
* `within`, `via`, expiry, owner and seat columns. Rows of the same instance
|
|
134
|
+
* merge into one membership.
|
|
135
|
+
*/
|
|
136
|
+
function fromTable(options) {
|
|
137
|
+
const c = options.columns ?? {};
|
|
138
|
+
const scope = `${col(c.scope ?? "scope")}::text`;
|
|
139
|
+
const id = `${col(c.id ?? "scope_id")}::text`;
|
|
140
|
+
const within = c.within === void 0 ? "null::jsonb" : col(c.within);
|
|
141
|
+
const optional = (name, cast) => name === void 0 ? `null::${cast}` : `${col(name)}::${cast}`;
|
|
142
|
+
return sourceOf(sqlOf({
|
|
143
|
+
table: options.table,
|
|
144
|
+
user: c.user ?? "user_id",
|
|
145
|
+
scope,
|
|
146
|
+
id,
|
|
147
|
+
within,
|
|
148
|
+
roles: `jsonb_agg(distinct ${col(c.role ?? "role")}::text order by ${col(c.role ?? "role")}::text)`,
|
|
149
|
+
via: optional(c.via, "text"),
|
|
150
|
+
expiresAt: c.expiresAt,
|
|
151
|
+
grantedBy: optional(c.grantedBy, "text"),
|
|
152
|
+
reason: optional(c.reason, "text"),
|
|
153
|
+
memberGroup: optional(c.group, "text"),
|
|
154
|
+
managed: optional(c.managedBy, "text"),
|
|
155
|
+
managedColumn: c.managedBy,
|
|
156
|
+
seats: c.seats === void 0 ? "null::jsonb" : `to_jsonb(${col(c.seats)})`,
|
|
157
|
+
idOf: (name) => `coalesce(case when ${scope} = ${literal(name)} then ${id} end${c.within === void 0 ? "" : `, ${within} ->> ${literal(name)}`})`,
|
|
158
|
+
groupBy: [
|
|
159
|
+
scope,
|
|
160
|
+
id,
|
|
161
|
+
...c.within === void 0 ? [] : [within],
|
|
162
|
+
...[
|
|
163
|
+
c.via,
|
|
164
|
+
c.expiresAt,
|
|
165
|
+
c.grantedBy,
|
|
166
|
+
c.reason,
|
|
167
|
+
c.group,
|
|
168
|
+
c.managedBy,
|
|
169
|
+
c.seats
|
|
170
|
+
].filter((name) => name !== void 0).map(col)
|
|
171
|
+
],
|
|
172
|
+
suspension: options.suspension,
|
|
173
|
+
columns: [
|
|
174
|
+
c.user ?? "user_id",
|
|
175
|
+
c.scope ?? "scope",
|
|
176
|
+
c.id ?? "scope_id",
|
|
177
|
+
c.role ?? "role",
|
|
178
|
+
...[
|
|
179
|
+
c.within,
|
|
180
|
+
c.via,
|
|
181
|
+
c.expiresAt
|
|
182
|
+
].filter((name) => name !== void 0)
|
|
183
|
+
],
|
|
184
|
+
manifest: compact({
|
|
185
|
+
user: { column: c.user ?? "user_id" },
|
|
186
|
+
scope: { column: c.scope ?? "scope" },
|
|
187
|
+
id: { column: c.id ?? "scope_id" },
|
|
188
|
+
role: { column: c.role ?? "role" },
|
|
189
|
+
within: c.within === void 0 ? void 0 : { column: c.within },
|
|
190
|
+
via: c.via === void 0 ? void 0 : { column: c.via },
|
|
191
|
+
expiresAt: c.expiresAt === void 0 ? void 0 : { column: c.expiresAt }
|
|
192
|
+
})
|
|
193
|
+
}), options.query);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Memberships from a table of one scope (`customer_contacts`): every row is a
|
|
197
|
+
* membership of `scope`, with roles from a column or fixed (`['contact']`), a
|
|
198
|
+
* fixed `via`, and ancestor ids from `within` columns.
|
|
199
|
+
*/
|
|
200
|
+
function fromJunction(options) {
|
|
201
|
+
if (!/^[a-z][a-z0-9_]*$/u.test(options.scope)) throw new TypeError(`PermDock: unsafe scope name '${options.scope}'`);
|
|
202
|
+
const idColumn = options.id ?? `${options.scope}_id`;
|
|
203
|
+
const withinEntries = Object.entries(options.within ?? {});
|
|
204
|
+
const fixed = typeof options.roles === "string" ? void 0 : options.roles;
|
|
205
|
+
if (fixed?.length === 0) throw new TypeError("PermDock: fromJunction needs at least one role");
|
|
206
|
+
const managedColumn = options.managedBy === void 0 ? void 0 : options.managedBy === "idp" ? "" : options.managedBy.column;
|
|
207
|
+
const groupColumn = options.group === void 0 || typeof options.group === "string" ? void 0 : options.group.column;
|
|
208
|
+
const shape = {
|
|
209
|
+
table: options.table,
|
|
210
|
+
user: options.user ?? "user_id",
|
|
211
|
+
scope: `${literal(options.scope)}::text`,
|
|
212
|
+
id: `${col(idColumn)}::text`,
|
|
213
|
+
within: withinEntries.length === 0 ? "null::jsonb" : `jsonb_build_object(${withinEntries.map(([name, column]) => `${literal(name)}, ${col(column)}::text`).join(", ")})`,
|
|
214
|
+
roles: fixed === void 0 ? `jsonb_agg(distinct ${col(options.roles)}::text order by ${col(options.roles)}::text)` : `jsonb_build_array(${fixed.map(literal).join(", ")})`,
|
|
215
|
+
via: options.via === void 0 ? "null::text" : `${literal(options.via)}::text`,
|
|
216
|
+
expiresAt: options.expiresAt,
|
|
217
|
+
grantedBy: options.grantedBy === void 0 ? "null::text" : `${col(options.grantedBy)}::text`,
|
|
218
|
+
reason: options.reason === void 0 ? "null::text" : `${col(options.reason)}::text`,
|
|
219
|
+
memberGroup: options.group === void 0 ? "null::text" : typeof options.group === "string" ? `${literal(options.group)}::text` : `${col(options.group.column)}::text`,
|
|
220
|
+
managed: managedColumn === void 0 ? "null::text" : managedColumn === "" ? `'idp'::text` : `${col(managedColumn)}::text`,
|
|
221
|
+
managedColumn,
|
|
222
|
+
seats: options.seats === void 0 ? "null::jsonb" : `to_jsonb(${col(options.seats)})`,
|
|
223
|
+
idOf: (name) => {
|
|
224
|
+
if (name === options.scope) return `${col(idColumn)}::text`;
|
|
225
|
+
const column = options.within?.[name];
|
|
226
|
+
return column === void 0 ? void 0 : `${col(column)}::text`;
|
|
227
|
+
},
|
|
228
|
+
groupBy: [
|
|
229
|
+
col(idColumn),
|
|
230
|
+
...withinEntries.map(([, column]) => col(column)),
|
|
231
|
+
...[
|
|
232
|
+
options.expiresAt,
|
|
233
|
+
options.grantedBy,
|
|
234
|
+
options.reason,
|
|
235
|
+
groupColumn,
|
|
236
|
+
managedColumn === "" ? void 0 : managedColumn,
|
|
237
|
+
options.seats
|
|
238
|
+
].filter((name) => name !== void 0).map(col)
|
|
239
|
+
],
|
|
240
|
+
suspension: options.suspension,
|
|
241
|
+
columns: [
|
|
242
|
+
options.user ?? "user_id",
|
|
243
|
+
idColumn,
|
|
244
|
+
...withinEntries.map(([, column]) => column),
|
|
245
|
+
...[typeof options.roles === "string" ? options.roles : void 0, options.expiresAt].filter((name) => name !== void 0)
|
|
246
|
+
],
|
|
247
|
+
manifest: compact({
|
|
248
|
+
user: { column: options.user ?? "user_id" },
|
|
249
|
+
scope: { value: options.scope },
|
|
250
|
+
id: { column: idColumn },
|
|
251
|
+
role: typeof options.roles === "string" ? { column: options.roles } : { value: [...options.roles] },
|
|
252
|
+
within: withinEntries.length === 0 ? void 0 : { columns: Object.fromEntries(withinEntries) },
|
|
253
|
+
via: options.via === void 0 ? void 0 : { value: options.via },
|
|
254
|
+
expiresAt: options.expiresAt === void 0 ? void 0 : { column: options.expiresAt }
|
|
255
|
+
})
|
|
256
|
+
};
|
|
257
|
+
return sourceOf({
|
|
258
|
+
...sqlOf(shape),
|
|
259
|
+
scope: options.scope,
|
|
260
|
+
holds: [options.scope, ...withinEntries.map(([name]) => name)],
|
|
261
|
+
list: () => selectOf(shape, filters(shape, `$1::text = ${literal(options.scope)} and ${col(idColumn)}::text = $2::text`), true)
|
|
262
|
+
}, options.query);
|
|
263
|
+
}
|
|
264
|
+
const AUTHZ_VERSION_TABLE = "permdock_authz_version";
|
|
265
|
+
/**
|
|
266
|
+
* The default schema of everything PermDock generates: helpers, seeds, the
|
|
267
|
+
* RBAC scaffold, the hook and the version table. Keep it out of the Data
|
|
268
|
+
* API's exposed schemas, so the `security definer` functions are not RPCs.
|
|
269
|
+
*/
|
|
270
|
+
const PERMDOCK_SCHEMA = "permdock";
|
|
271
|
+
/**
|
|
272
|
+
* Reads the authorization version `permdock supabase hook generate` keeps in
|
|
273
|
+
* `<schema>.permdock_authz_version`: pass it to `claimsFirst(sources, { version })`.
|
|
274
|
+
*/
|
|
275
|
+
function authzVersion(options) {
|
|
276
|
+
const table = qualified(`${options.schema ?? "permdock"}.${AUTHZ_VERSION_TABLE}`);
|
|
277
|
+
return async (principal) => {
|
|
278
|
+
const value = rowsOf(await options.query(`select version from ${table} where user_id = $1`, [principal.id]))[0]?.["version"];
|
|
279
|
+
const version = typeof value === "number" ? value : value === void 0 ? 0 : Number(value);
|
|
280
|
+
return Number.isFinite(version) ? version : void 0;
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
//#endregion
|
|
284
|
+
export { fromTable as a, fromJunction as i, PERMDOCK_SCHEMA as n, authzVersion as r, AUTHZ_VERSION_TABLE as t };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/core/sql.ts
|
|
2
|
+
/** A bare Postgres identifier PermDock emits unquoted-safe: letters, digits and `_`, not starting with a digit. */
|
|
3
|
+
const SQL_IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
4
|
+
/** A validated, double-quoted identifier; anything outside `SQL_IDENT` throws. */
|
|
5
|
+
function quoteSqlIdent(name, prefix = "PermDock") {
|
|
6
|
+
if (!SQL_IDENT.test(name)) throw new TypeError(`${prefix}: unsafe SQL identifier '${name}'`);
|
|
7
|
+
return `"${name}"`;
|
|
8
|
+
}
|
|
9
|
+
/** A schema-qualified name, each part validated by `quoteSqlIdent`. */
|
|
10
|
+
function quoteSqlTable(name, prefix = "PermDock") {
|
|
11
|
+
return name.split(".").map((part) => quoteSqlIdent(part, prefix)).join(".");
|
|
12
|
+
}
|
|
13
|
+
/** A single-quoted string literal with embedded quotes doubled. */
|
|
14
|
+
function quoteSqlLiteral(value) {
|
|
15
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
16
|
+
}
|
|
17
|
+
/** A double-quoted identifier read back from a database, embedded quotes doubled rather than refused. */
|
|
18
|
+
function escapeSqlIdent(name) {
|
|
19
|
+
return `"${name.replaceAll("\"", "\"\"")}"`;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { quoteSqlTable as a, quoteSqlLiteral as i, escapeSqlIdent as n, quoteSqlIdent as r, SQL_IDENT as t };
|