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,222 @@
|
|
|
1
|
+
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { g as listPermissions } from "./permissions-DC7GROPA.js";
|
|
3
|
+
import { t as createPermDock$1 } from "./permdock-yoZ7EjxX.js";
|
|
4
|
+
import { n as isActor } from "./subject-C6dLxqHU.js";
|
|
5
|
+
import { a as problemFromDecision, i as notFoundProblem, o as problemResponse, t as PROBLEM_BASE } from "./problem-Cgp9-KZA.js";
|
|
6
|
+
import { n as createEvaluationsHandler, r as InvalidSignatureError, t as applyApprovalResume } from "./evaluations-DsAU9ppl.js";
|
|
7
|
+
//#region src/server/create.ts
|
|
8
|
+
/** Resolves an adapter `tenant` option against its framework context; a throw is no tenant. */
|
|
9
|
+
async function tenantScope(option, context) {
|
|
10
|
+
if (option === void 0 || typeof option === "string") return { tenant: option };
|
|
11
|
+
try {
|
|
12
|
+
return { tenant: await option(context) };
|
|
13
|
+
} catch {
|
|
14
|
+
return { tenant: void 0 };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function resolveActor(request, options) {
|
|
18
|
+
const verified = options.webBotAuth === void 0 ? void 0 : await options.webBotAuth(request);
|
|
19
|
+
if (verified !== void 0) return verified;
|
|
20
|
+
if (options.actor === void 0) return;
|
|
21
|
+
try {
|
|
22
|
+
const resolved = await options.actor(request);
|
|
23
|
+
return isActor(resolved) ? resolved : void 0;
|
|
24
|
+
} catch {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const NO_TENANT = "\0";
|
|
29
|
+
function createPermDock(policy, options) {
|
|
30
|
+
return createKernel(policy, options);
|
|
31
|
+
}
|
|
32
|
+
function problemFor(decision, init, approval) {
|
|
33
|
+
if (init?.permission !== void 0) return problemFromDecision(decision, init.permission, {
|
|
34
|
+
principal: null,
|
|
35
|
+
context: {}
|
|
36
|
+
}, compact({
|
|
37
|
+
instance: init.instance,
|
|
38
|
+
approval
|
|
39
|
+
}));
|
|
40
|
+
return problemResponse({
|
|
41
|
+
type: `${PROBLEM_BASE}/denied`,
|
|
42
|
+
title: "Permission denied",
|
|
43
|
+
status: 403,
|
|
44
|
+
detail: decision.outcome
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The kernel behind every HTTP adapter. The subject and actor are resolved
|
|
49
|
+
* once per `Request`; one instance is cached per `(Request, tenant)`, so a
|
|
50
|
+
* global middleware and a later tenant-scoped `protect` never share a tenant.
|
|
51
|
+
*/
|
|
52
|
+
function createKernel(policy, options) {
|
|
53
|
+
const adapter = options.adapter ?? "server";
|
|
54
|
+
const subjects = /* @__PURE__ */ new WeakMap();
|
|
55
|
+
const instances = /* @__PURE__ */ new WeakMap();
|
|
56
|
+
const resolveSubject = (request) => {
|
|
57
|
+
const hit = subjects.get(request);
|
|
58
|
+
if (hit !== void 0) return hit;
|
|
59
|
+
const resolved = (async () => {
|
|
60
|
+
const actor = await resolveActor(request, options);
|
|
61
|
+
let user = null;
|
|
62
|
+
try {
|
|
63
|
+
user = await options.subject(request);
|
|
64
|
+
} catch {
|
|
65
|
+
user = null;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
user,
|
|
69
|
+
actor
|
|
70
|
+
};
|
|
71
|
+
})();
|
|
72
|
+
subjects.set(request, resolved);
|
|
73
|
+
return resolved;
|
|
74
|
+
};
|
|
75
|
+
const freshSubject = async (request) => {
|
|
76
|
+
const actor = await resolveActor(request, options);
|
|
77
|
+
try {
|
|
78
|
+
return {
|
|
79
|
+
user: await options.subject(request),
|
|
80
|
+
actor
|
|
81
|
+
};
|
|
82
|
+
} catch {
|
|
83
|
+
return {
|
|
84
|
+
user: null,
|
|
85
|
+
actor
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const instanceFor = async ({ user, actor }, tenant) => {
|
|
90
|
+
const coreOptions = compact({
|
|
91
|
+
tenant,
|
|
92
|
+
memberships: options.memberships,
|
|
93
|
+
relations: options.relations,
|
|
94
|
+
entitlements: options.entitlements,
|
|
95
|
+
customRoles: options.customRoles,
|
|
96
|
+
policies: options.policies,
|
|
97
|
+
sink: options.sink,
|
|
98
|
+
limits: options.limits,
|
|
99
|
+
actor
|
|
100
|
+
});
|
|
101
|
+
const permdock = await createPermDock$1(policy, user, coreOptions);
|
|
102
|
+
const remote = options.pdp === void 0 ? void 0 : await options.pdp(policy, user, coreOptions);
|
|
103
|
+
return {
|
|
104
|
+
permdock: options.wrap === void 0 ? permdock : options.wrap(permdock),
|
|
105
|
+
remote
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
const build = async (request, scope) => {
|
|
109
|
+
const { tenant } = scope ?? await tenantScope(options.tenant, request);
|
|
110
|
+
let byTenant = instances.get(request);
|
|
111
|
+
if (byTenant === void 0) {
|
|
112
|
+
byTenant = /* @__PURE__ */ new Map();
|
|
113
|
+
instances.set(request, byTenant);
|
|
114
|
+
}
|
|
115
|
+
const key = tenant ?? NO_TENANT;
|
|
116
|
+
const hit = byTenant.get(key);
|
|
117
|
+
if (hit !== void 0) return hit;
|
|
118
|
+
const built = (async () => instanceFor(await resolveSubject(request), tenant))();
|
|
119
|
+
byTenant.set(key, built);
|
|
120
|
+
return built;
|
|
121
|
+
};
|
|
122
|
+
const connection = async (request, connectionOptions = {}, scope) => {
|
|
123
|
+
const { tenant } = scope ?? await tenantScope(options.tenant, request);
|
|
124
|
+
const { openConnection } = await import("./connection-JvqwHODC.js");
|
|
125
|
+
return openConnection({
|
|
126
|
+
open: async () => (await build(request, { tenant })).permdock,
|
|
127
|
+
rebuild: async () => (await instanceFor(await freshSubject(request), tenant)).permdock,
|
|
128
|
+
tenant,
|
|
129
|
+
...options.revocations === void 0 ? {} : { feed: options.revocations },
|
|
130
|
+
adapter,
|
|
131
|
+
options: connectionOptions
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
const permdock = async (request, scope) => (await build(request, scope)).permdock;
|
|
135
|
+
const protect = (permission, loadData, protectOptions = {}) => async (request, scope) => {
|
|
136
|
+
let instance;
|
|
137
|
+
let remote;
|
|
138
|
+
try {
|
|
139
|
+
({permdock: instance, remote} = await build(request, scope));
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (error instanceof InvalidSignatureError) return {
|
|
142
|
+
ok: false,
|
|
143
|
+
response: error.response
|
|
144
|
+
};
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
let data;
|
|
148
|
+
if (loadData !== void 0) {
|
|
149
|
+
const loaded = await loadData(request);
|
|
150
|
+
if (loaded === null || loaded === void 0) return {
|
|
151
|
+
ok: false,
|
|
152
|
+
response: notFoundProblem()
|
|
153
|
+
};
|
|
154
|
+
data = loaded;
|
|
155
|
+
}
|
|
156
|
+
const decideOptions = compact({
|
|
157
|
+
source: "adapter",
|
|
158
|
+
adapter,
|
|
159
|
+
...protectOptions.trusted === true ? { trusted: true } : {
|
|
160
|
+
trusted: false,
|
|
161
|
+
boundary: "http-body"
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
const raw = remote === void 0 ? instance.decide(permission, data, decideOptions) : await remote.decide(permission, data, decideOptions).catch(() => ({
|
|
165
|
+
outcome: "denied",
|
|
166
|
+
denials: [{
|
|
167
|
+
role: null,
|
|
168
|
+
reason: "pdp-unavailable"
|
|
169
|
+
}],
|
|
170
|
+
alternatives: []
|
|
171
|
+
}));
|
|
172
|
+
const decision = await applyApprovalResume(raw, permission, instance, options.store, request, compact({
|
|
173
|
+
type: permission.resource,
|
|
174
|
+
id: data !== null && typeof data === "object" && "id" in data && (typeof data.id === "string" || typeof data.id === "number") ? String(data.id) : void 0
|
|
175
|
+
}), adapter);
|
|
176
|
+
if (decision.outcome === "granted") return {
|
|
177
|
+
ok: true,
|
|
178
|
+
permdock: instance,
|
|
179
|
+
decision,
|
|
180
|
+
data
|
|
181
|
+
};
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
response: problemFromDecision(decision, permission, instance.subject, compact({
|
|
185
|
+
approval: options.approval,
|
|
186
|
+
credentials: request.headers.has("authorization"),
|
|
187
|
+
disclosure: data === void 0 ? void 0 : policy.resources.get(permission.resource)?.disclosure
|
|
188
|
+
}))
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
const openapi = {
|
|
192
|
+
security: (permission) => ({
|
|
193
|
+
security: [{ oauth2: [permission.scope] }],
|
|
194
|
+
"x-permdock-permissions": [permission.key]
|
|
195
|
+
}),
|
|
196
|
+
securitySchemes: () => {
|
|
197
|
+
const scopes = {};
|
|
198
|
+
for (const leaf of listPermissions(policy.permissions)) scopes[leaf.scope] = leaf.meta.title ?? leaf.key;
|
|
199
|
+
return { oauth2: {
|
|
200
|
+
type: "oauth2",
|
|
201
|
+
flows: {},
|
|
202
|
+
scopes
|
|
203
|
+
} };
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const permdockHandler = (scope) => createEvaluationsHandler(compact({
|
|
207
|
+
policy,
|
|
208
|
+
resolve: scope === void 0 ? permdock : async (request) => permdock(request, await scope(request)),
|
|
209
|
+
store: options.store,
|
|
210
|
+
adapter
|
|
211
|
+
}));
|
|
212
|
+
return {
|
|
213
|
+
permdock,
|
|
214
|
+
protect,
|
|
215
|
+
connection,
|
|
216
|
+
problem: (decision, init) => problemFor(decision, init, options.approval),
|
|
217
|
+
openapi,
|
|
218
|
+
permdockHandler
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
//#endregion
|
|
222
|
+
export { createPermDock as n, tenantScope as r, createKernel as t };
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { n as isReadonlyArray, t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { n as freezeDeep } from "./freeze-y1_jQL4v.js";
|
|
3
|
+
import { a as formerKeys, g as listPermissions } from "./permissions-DC7GROPA.js";
|
|
4
|
+
import { u as coveredByDelegation } from "./snapshot-DE8dE_hz.js";
|
|
5
|
+
import { n as sha256, t as bytesToBase64Url } from "./sha256-BO0swRXL.js";
|
|
6
|
+
import { t as anonymousSubject } from "./subject-C6dLxqHU.js";
|
|
7
|
+
import { a as ownRecord, n as idList, r as isId } from "./capability-B68OFnZx.js";
|
|
8
|
+
//#region src/core/revocations.ts
|
|
9
|
+
function isRevocationEvent(value) {
|
|
10
|
+
if (value === null || typeof value !== "object") return false;
|
|
11
|
+
const event = value;
|
|
12
|
+
return typeof event["principal"] === "string" && event["principal"].length > 0 && (event["kind"] === "session-revoked" || event["kind"] === "changed") && (event["session"] === void 0 || typeof event["session"] === "string") && (event["tenant"] === void 0 || typeof event["tenant"] === "string");
|
|
13
|
+
}
|
|
14
|
+
/** In-process feed; a multi-replica app bridges `revoke` to its own pub/sub. */
|
|
15
|
+
function memoryRevocationFeed() {
|
|
16
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
subscribe(listener) {
|
|
19
|
+
listeners.add(listener);
|
|
20
|
+
return () => {
|
|
21
|
+
listeners.delete(listener);
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
revoke(event) {
|
|
25
|
+
if (!isRevocationEvent(event)) throw new TypeError("PermDock: invalid revocation event.");
|
|
26
|
+
const frozen = Object.freeze({ ...event });
|
|
27
|
+
for (const listener of listeners) try {
|
|
28
|
+
listener(frozen);
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/core/credential.ts
|
|
35
|
+
const MAX_ENTRIES = 64;
|
|
36
|
+
const MAX_NAME = 256;
|
|
37
|
+
function policies(policy) {
|
|
38
|
+
return isReadonlyArray(policy) ? policy : [policy];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The first rule of `policy` the credential breaks, or `undefined`. A key
|
|
42
|
+
* without `expiresAt` passes only when some policy sets `allowNoExpiry` and
|
|
43
|
+
* none sets `maxTtl`; an empty list therefore refuses it.
|
|
44
|
+
*/
|
|
45
|
+
function credentialPolicyViolation(credential, policy) {
|
|
46
|
+
const list = policies(policy);
|
|
47
|
+
for (const item of list) if (item.kinds !== void 0 && !item.kinds.includes(credential.kind)) return "kind";
|
|
48
|
+
if (credential.expiresAt === void 0) return list.some((item) => item.allowNoExpiry === true) && list.every((item) => item.maxTtl === void 0) ? void 0 : "no-expiry";
|
|
49
|
+
for (const item of list) {
|
|
50
|
+
const max = item.maxTtl;
|
|
51
|
+
if (max !== void 0 && (typeof max !== "number" || !Number.isFinite(max) || max < 0 || credential.expiresAt - credential.createdAt > max)) return "ttl";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function parsePermissions(value) {
|
|
55
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > MAX_ENTRIES) return;
|
|
56
|
+
const out = [];
|
|
57
|
+
for (const item of value) {
|
|
58
|
+
const entry = ownRecord(item);
|
|
59
|
+
if (entry === void 0 || !isId(entry["permission"])) return;
|
|
60
|
+
const ids = entry["ids"] === void 0 ? void 0 : idList(entry["ids"]);
|
|
61
|
+
if (entry["ids"] !== void 0 && ids === void 0) return;
|
|
62
|
+
out.push(compact({
|
|
63
|
+
permission: entry["permission"],
|
|
64
|
+
ids
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
function isTime(value) {
|
|
70
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Validates an untrusted credential record and returns a frozen copy with
|
|
74
|
+
* only the v1 fields, or `undefined`. Unknown fields are dropped; a wrong
|
|
75
|
+
* type in a known field, a service credential without `tenant` and `roles`,
|
|
76
|
+
* or a user credential with either, rejects the whole record.
|
|
77
|
+
*/
|
|
78
|
+
function parseCredential(input) {
|
|
79
|
+
const value = ownRecord(input);
|
|
80
|
+
if (value === void 0 || value["v"] !== 1 || !isId(value["id"])) return;
|
|
81
|
+
if (value["kind"] !== "user" && value["kind"] !== "service") return;
|
|
82
|
+
if (!isId(value["principal"]) || !isId(value["createdBy"])) return;
|
|
83
|
+
const permissions = parsePermissions(value["permissions"]);
|
|
84
|
+
if (permissions === void 0 || !isTime(value["createdAt"])) return;
|
|
85
|
+
if (value["expiresAt"] !== void 0 && !isTime(value["expiresAt"])) return;
|
|
86
|
+
if (value["name"] !== void 0 && (typeof value["name"] !== "string" || value["name"].length > MAX_NAME)) return;
|
|
87
|
+
let tenant;
|
|
88
|
+
let roles;
|
|
89
|
+
if (value["kind"] === "service") {
|
|
90
|
+
roles = idList(value["roles"]);
|
|
91
|
+
if (!isId(value["tenant"]) || roles === void 0) return;
|
|
92
|
+
tenant = value["tenant"];
|
|
93
|
+
} else if (value["tenant"] !== void 0 || value["roles"] !== void 0) return;
|
|
94
|
+
return freezeDeep(compact({
|
|
95
|
+
v: 1,
|
|
96
|
+
id: value["id"],
|
|
97
|
+
kind: value["kind"],
|
|
98
|
+
principal: value["principal"],
|
|
99
|
+
tenant,
|
|
100
|
+
roles,
|
|
101
|
+
permissions,
|
|
102
|
+
createdBy: value["createdBy"],
|
|
103
|
+
createdAt: value["createdAt"],
|
|
104
|
+
expiresAt: value["expiresAt"],
|
|
105
|
+
name: value["name"]
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
function leafByKey(tree) {
|
|
109
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
110
|
+
for (const leaf of listPermissions(tree)) {
|
|
111
|
+
byKey.set(leaf.key, leaf);
|
|
112
|
+
for (const old of formerKeys(leaf)) byKey.set(old, leaf);
|
|
113
|
+
}
|
|
114
|
+
return byKey;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The delegation a credential narrows its principal to: OAuth scopes for
|
|
118
|
+
* permissions on every instance, one RFC 9396 entry per id otherwise. A key
|
|
119
|
+
* the definitions no longer declare is dropped, so a credential whose every
|
|
120
|
+
* key is gone delegates nothing and every check is denied.
|
|
121
|
+
*/
|
|
122
|
+
function credentialDelegation(credential, permissions) {
|
|
123
|
+
const leaves = leafByKey(permissions);
|
|
124
|
+
const scopes = [];
|
|
125
|
+
const details = [];
|
|
126
|
+
for (const entry of credential.permissions) {
|
|
127
|
+
const leaf = leaves.get(entry.permission);
|
|
128
|
+
if (leaf === void 0) continue;
|
|
129
|
+
if (entry.ids === void 0) {
|
|
130
|
+
scopes.push(leaf.scope);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
for (const id of entry.ids) details.push({
|
|
134
|
+
type: leaf.resource,
|
|
135
|
+
actions: [leaf.action],
|
|
136
|
+
identifier: id
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return compact({
|
|
140
|
+
scopes: scopes.length > 0 || details.length === 0 ? scopes : void 0,
|
|
141
|
+
authorizationDetails: details.length > 0 ? details : void 0
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The subject a verified credential acts as. A `user` credential is its
|
|
146
|
+
* owner, passed live as `owner` (roles and memberships as of this request),
|
|
147
|
+
* with the credential's delegation: every check is the owner's rights
|
|
148
|
+
* intersected with the key's. A `service` credential is a `service`
|
|
149
|
+
* principal whose only membership is `roles` in `tenant`. An owner whose id
|
|
150
|
+
* is not the credential's `principal`, or who is not a user, is anonymous.
|
|
151
|
+
*/
|
|
152
|
+
function credentialSubject(credential, options) {
|
|
153
|
+
const delegation = credentialDelegation(credential, options.permissions);
|
|
154
|
+
let principal;
|
|
155
|
+
if (credential.kind === "user") {
|
|
156
|
+
const owner = options.owner ?? {
|
|
157
|
+
id: credential.principal,
|
|
158
|
+
kind: "user"
|
|
159
|
+
};
|
|
160
|
+
if (owner.id !== credential.principal || owner.kind !== void 0 && owner.kind !== "user") return anonymousSubject();
|
|
161
|
+
principal = {
|
|
162
|
+
...owner,
|
|
163
|
+
kind: "user",
|
|
164
|
+
credential
|
|
165
|
+
};
|
|
166
|
+
} else {
|
|
167
|
+
const membership = compact({
|
|
168
|
+
tenant: credential.tenant,
|
|
169
|
+
roles: credential.roles ?? [],
|
|
170
|
+
via: "credential"
|
|
171
|
+
});
|
|
172
|
+
principal = compact({
|
|
173
|
+
id: credential.principal,
|
|
174
|
+
kind: "service",
|
|
175
|
+
tenant: credential.tenant,
|
|
176
|
+
memberships: [membership],
|
|
177
|
+
credential
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return freezeDeep(compact({
|
|
181
|
+
principal,
|
|
182
|
+
delegation,
|
|
183
|
+
context: {},
|
|
184
|
+
expiresAt: credential.expiresAt
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
function credentialToken(credential) {
|
|
188
|
+
const payload = JSON.stringify({
|
|
189
|
+
t: "credential",
|
|
190
|
+
id: credential.id,
|
|
191
|
+
kind: credential.kind,
|
|
192
|
+
principal: credential.principal,
|
|
193
|
+
tenant: credential.tenant ?? null,
|
|
194
|
+
roles: credential.roles ?? null,
|
|
195
|
+
permissions: credential.permissions,
|
|
196
|
+
createdBy: credential.createdBy,
|
|
197
|
+
expiresAt: credential.expiresAt ?? null,
|
|
198
|
+
name: credential.name ?? null
|
|
199
|
+
});
|
|
200
|
+
return `pd1.${bytesToBase64Url(sha256(payload))}`;
|
|
201
|
+
}
|
|
202
|
+
function denied(reason, detail) {
|
|
203
|
+
return freezeDeep({
|
|
204
|
+
outcome: "denied",
|
|
205
|
+
denials: [compact({
|
|
206
|
+
role: null,
|
|
207
|
+
reason,
|
|
208
|
+
detail
|
|
209
|
+
})]
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function permissionEntries(request, declared) {
|
|
213
|
+
if (!isReadonlyArray(request.permissions) || request.permissions.length === 0 || request.permissions.length > MAX_ENTRIES) return;
|
|
214
|
+
const out = [];
|
|
215
|
+
for (const item of request.permissions) {
|
|
216
|
+
const entry = permissionEntry(item);
|
|
217
|
+
if (entry === void 0 || declared.get(entry.leaf.key) === void 0) return;
|
|
218
|
+
out.push(entry);
|
|
219
|
+
}
|
|
220
|
+
return out;
|
|
221
|
+
}
|
|
222
|
+
function permissionEntry(item) {
|
|
223
|
+
if (!isScopedInput(item)) return { leaf: item };
|
|
224
|
+
const ids = idList(item.ids);
|
|
225
|
+
return ids === void 0 ? void 0 : {
|
|
226
|
+
leaf: item.permission,
|
|
227
|
+
ids
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function isScopedInput(item) {
|
|
231
|
+
return "permission" in item && "ids" in item;
|
|
232
|
+
}
|
|
233
|
+
function refuse(reason, detail) {
|
|
234
|
+
return {
|
|
235
|
+
ok: false,
|
|
236
|
+
decision: denied(reason, detail)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function checkRequest(permdock, request, now) {
|
|
240
|
+
const creator = permdock.subject.principal;
|
|
241
|
+
if (creator === null) return refuse("anonymous");
|
|
242
|
+
if (creator.kind === "link" || "credential" in creator) return refuse("exceeds-creator", { creator: creator.kind === "link" ? "link" : "credential" });
|
|
243
|
+
const entries = permissionEntries(request, leafByKey(permdock.permissions));
|
|
244
|
+
if (entries === void 0 || !isId(request.id) || request.expiresAt !== void 0 && (!isTime(request.expiresAt) || request.expiresAt <= now)) return refuse("validation");
|
|
245
|
+
const subject = permdock.subject;
|
|
246
|
+
for (const entry of entries) for (const id of entry.ids ?? [void 0]) if (coveredByDelegation(entry.leaf, subject.delegation, id, subject.actor !== void 0) !== void 0) return refuse("exceeds-creator", { permission: entry.leaf.key });
|
|
247
|
+
const credential = parseCredential(compact({
|
|
248
|
+
v: 1,
|
|
249
|
+
id: request.id,
|
|
250
|
+
kind: request.kind,
|
|
251
|
+
principal: request.kind === "service" ? request.principal ?? request.id : creator.id,
|
|
252
|
+
tenant: request.kind === "service" ? request.tenant : void 0,
|
|
253
|
+
roles: request.kind === "service" ? request.roles : void 0,
|
|
254
|
+
permissions: entries.map((entry) => compact({
|
|
255
|
+
permission: entry.leaf.key,
|
|
256
|
+
ids: entry.ids
|
|
257
|
+
})),
|
|
258
|
+
createdBy: creator.id,
|
|
259
|
+
createdAt: now,
|
|
260
|
+
expiresAt: request.expiresAt === void 0 ? void 0 : Math.floor(request.expiresAt),
|
|
261
|
+
name: request.name
|
|
262
|
+
}));
|
|
263
|
+
if (credential === void 0) return refuse("validation");
|
|
264
|
+
if (credential.tenant !== void 0) {
|
|
265
|
+
const tenant = credential.tenant;
|
|
266
|
+
if (!permdock.tenants().includes(tenant)) return refuse("exceeds-creator", { tenant });
|
|
267
|
+
const roles = new Set(permdock.assignableRoles({ tenant }).map((role) => role.key));
|
|
268
|
+
for (const name of credential.roles ?? []) if (!roles.has(name)) return refuse("exceeds-creator", { role: name });
|
|
269
|
+
const ceiling = new Set(permdock.assignablePermissions({ tenant }).map((leaf) => leaf.key));
|
|
270
|
+
for (const entry of credential.permissions) if (!ceiling.has(entry.permission)) return refuse("exceeds-creator", { permission: entry.permission });
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
ok: true,
|
|
274
|
+
credential
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* The tenant whose `credentials` policy governs a credential: a service
|
|
279
|
+
* key's own tenant, otherwise `active` (the creator's or the request's).
|
|
280
|
+
*/
|
|
281
|
+
function credentialTenant(credential, active) {
|
|
282
|
+
return credential.tenant ?? active;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Decides whether the subject of `permdock` may create the credential in
|
|
286
|
+
* `request`. The creator must be a signed-in user or service that is not
|
|
287
|
+
* itself a link or a credential; a delegated creator hands out only what its
|
|
288
|
+
* delegation covers. A service key's tenant must be one the creator is a
|
|
289
|
+
* member of, its roles among the creator's `assignableRoles` there and its
|
|
290
|
+
* permissions within `assignablePermissions` there (`exceeds-creator`). The
|
|
291
|
+
* `credentials` policy of the key's tenant (a service key's own, a user
|
|
292
|
+
* key's the creator's active tenant) then applies (`credential-policy`; a
|
|
293
|
+
* settings source that throws denies with `rule: 'unavailable'`), and
|
|
294
|
+
* `approval` makes the result `approval-required` until `approved` carries
|
|
295
|
+
* its token. PermDock never stores the credential; the application does,
|
|
296
|
+
* after a `granted` result.
|
|
297
|
+
*/
|
|
298
|
+
async function decideCredential(permdock, request, options = {}) {
|
|
299
|
+
const checked = checkRequest(permdock, request, options.now ?? Math.floor(Date.now() / 1e3));
|
|
300
|
+
if (!checked.ok) return checked.decision;
|
|
301
|
+
const { credential } = checked;
|
|
302
|
+
const tenant = credentialTenant(credential, permdock.subject.principal?.tenant);
|
|
303
|
+
let policy;
|
|
304
|
+
if (options.settings !== void 0 && tenant !== void 0) try {
|
|
305
|
+
policy = (await options.settings.settingsFor(tenant))?.credentials;
|
|
306
|
+
} catch {
|
|
307
|
+
return denied("credential-policy", { rule: "unavailable" });
|
|
308
|
+
}
|
|
309
|
+
const list = policy === void 0 ? [] : [policy];
|
|
310
|
+
const violation = credentialPolicyViolation(credential, list);
|
|
311
|
+
if (violation !== void 0) return denied("credential-policy", { rule: violation });
|
|
312
|
+
if (list.some((item) => item.approval === true)) {
|
|
313
|
+
const token = credentialToken(credential);
|
|
314
|
+
if (options.approved !== token) return freezeDeep({
|
|
315
|
+
outcome: "approval-required",
|
|
316
|
+
credential,
|
|
317
|
+
token
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return freezeDeep({
|
|
321
|
+
outcome: "granted",
|
|
322
|
+
credential
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
//#endregion
|
|
326
|
+
export { decideCredential as a, credentialTenant as i, credentialPolicyViolation as n, parseCredential as o, credentialSubject as r, memoryRevocationFeed as s, credentialDelegation as t };
|